Overview
Application user interfaces (UIs) can change over time, leading to test failures when elements are removed or become conditionally visible. For example, an element that was previously hidden behind a click action may now be visible by default. This article explains how to use Optional and Dependent steps to create resilient tests that can adapt to such UI changes without failing unnecessarily.
How It Works
Consider a scenario where a test fails because an element, such as an expansion arrow, is no longer present on the page. Previously, the test needed to click this arrow to reveal more information. Now, the information is visible by default, and the arrow has been removed.
The original test flow might have been:
- Verify the expansion arrow exists.
- Click the expansion arrow.
- Verify the information is now visible.
When the arrow is removed, the first step fails, stopping the test. To handle this and potential future UI changes gracefully, you can modify the steps as follows:
- Make the verification step Optional: The step that verifies the expansion arrow (e.g.,
Verify side arrow) should be marked as Optional. This means if the arrow is not found, the step will be skipped instead of failing the test. - Make the action step Dependent: The step that clicks the arrow (e.g.,
Click side arrow) should be marked as Dependent on the previous verification step. This ensures the click action is only attempted if the arrow was actually found.
This new configuration results in the following behavior:
- If the arrow is present: The Optional verification step will pass, and the Dependent click step will execute as intended.
- If the arrow is not present: The Optional verification step will be safely skipped, and because it was skipped, the Dependent click step will also be skipped.
In both cases, the test execution continues to the next steps without interruption, making the test stable across different UI versions.
Best Practices
Using Optional and Dependent steps is the recommended best practice for handling UI elements that may or may not be present. This approach is superior to simply skipping failed steps because it builds conditional logic directly into the test flow.
- It effectively handles incremental UI changes.
- It improves the long-term stability and maintainability of your tests.
- It avoids masking genuine application issues by clearly defining which elements are expected to be conditional.