Efficient URL Change Detection in Automated Tests

Cerosh Jacob
4 min readNov 27, 2023

--

Photo by Remotar Jobs on Unsplash

Effective test automation necessitates synchronizing actions and assertions, ensuring each step is only executed after completing the previous one. This is especially important when handling URL changes as the application’s state may change based on the new URL. This article discusses how the Playwright’s page.waitForURL() method offers a potent mechanism for managing URL changes, thereby ensuring test robustness and avoiding unreliable test cases.

When an automated action is performed in a front-end application, it initiates a sequence of events. The application under test captures and interprets these events, which can modify the control’s visual appearance, update its value, or trigger associated actions. If the control is data-driven, it may require synchronization with other application components to maintain data consistency. Following this processing, the user interface updates to reflect those changes. In cases involving navigation, the application may also manage routing and navigation logic, including URL modifications.

Successful test automation ensures that each action or assertion is dependent on the completion of the previous one. Test automation is a sequence of orchestrated actions. Modern automation frameworks provide mechanisms to synchronize actions, such as waiting for specific elements to appear or for URL changes to occur. Playwright also offers synchronization capabilities. Monitoring URL changes can be an effective strategy, but not all actions result in URL changes. This article focuses on situations where URL changes are part of the action sequence.

The page.waitForURL() method waits for the primary frame to navigate to the specified URL. It requires the expected URL as an argument and offers optional arguments such as timeout and waitUntil option. The default behaviour page.waitForURL() is to wait for the load event. However, in scenarios where the page might still be loaded asynchronously, it is often preferable to wait for the last visual element on the page to load. The expected URL can be specified as a string, a regular expression, or even a function. Let's consider an example for each option.

When specifying the expected URL, the simplest method is to use it as a string. This approach is easy to use, making it beginner-friendly. Despite its simplicity, it is both effective and efficient.

await page
.waitForURL('<https://playwright.dev/docs/api/class-page#page-wait-for-url>');

Consider a scenario where the same automated scripts need to be executed in different environments, and the URL will vary depending on the environment. For instance, the URL will contain .dev the development environment and .test in the testing environment. This is where regular expressions come in handy. The expected URL can be expressed using a regular expression to accommodate both environments, as demonstrated in the following example:

await page
.waitForURL('<https://playwright>.**/docs/api/class-page#page-wait-for-url');

When the expected URL is specified as a function, the number of situations it can handle depends on the ingenuity of the automation engineer. This document discusses a common scenario where the expected URL can be either of two. Consider an example where an initiated purchase action involves various backend interfaces. Upon successfully completing all interface interactions, the expected URL pattern for waiting will be /**?success=true However, due to unforeseen environmental factors, the purchase transactions may fail, resulting in an expected URL of /**?success=false Employing the traditional approach in this scenario may lead to a potentially flaky test case, as the test step will only succeed if the URL matches the specified expectation.

await this.page.waitForURL((currentUrl) => {
const urlAsString = currentUrl.href;
return urlAsString
.includes('/?success=true') || urlAsString.includes('/?success=false');
}, {timeout: 5000});

This code block halts test execution until the page URL matches either /?success=trueor /?success=false, verifying the transaction outcome. The callback function defines the condition for test continuation. It retrieves the URL string from the href property of the currentUrl object, which represents the complete URL path. The function checks if the URL string matches either of the expected URL patterns. The timeout limits the waiting period to 5 seconds.

Exercise caution and avoid hard-coding the expected URL directly. Instead, utilize a fixture to generate various expected URLs and employ it as needed. Whenever feasible, reconstruct the full URL. Employ regular expressions only in scenarios where specific values are unknown, such as session IDs. When dealing with IDs, utilize a regular expression that matches those IDs specifically, avoiding wildcards that match indiscriminately. Always leverage the current URL to generate the expected URL, ensuring the starting point is accurate. These recommendations aim to mitigate the risk of false positives or false negatives.

My recent publication compiled a comprehensive collection of 100 similar typescript programs. Each program not only elucidates essential Typescript concepts and expounds upon the significance of test automation but also provides practical guidance on its implementation using Playwright. This resource will undoubtedly be valuable if you look deeper into similar topics.

--

--