I have a question regarding creating browser tests in Synthetic Monitoring. The website I'm testing generates dynamic IDs for DOM elements, which makes it unreliable to use id attributes for actions like clicking buttons or links.
I attempted to use full XPath expressions instead, but the site frequently introduces banners (e.g., announcements) that alter the DOM structure and shift element positions, causing the XPath to break.
I'm wondering if there's a more resilient approach to locating elements. For example, is it possible to run a JavaScript snippet to search for an element by its visible text or attribute value, and then use that reference in subsequent steps or click on the element via the JavaScript? If so, how can I implement this?
Alternatively, are there best practices or recommended locator strategies for handling dynamic content in Synthetic browser tests?
Yes, there is an "execute javascript" option for a step in your test. You should be able to write some javascript to locate the element you want to click. Specifically the querySelector() or querySelectorAll() methods should help you do that.
Thank you!
I wasn’t aware that we have access to the document object when writing JavaScript in Synthetic scripts—does the documentation explicitly mention this? If so, I’d love to have link and take a closer look.
Here’s what worked for me:
In my scenario, the parent element of the target has a static ID. Leveraging that, I crafted a JavaScript snippet that locates and returns the ID of the element containing the visible text the test needs to click. In the worst-case scenario, we could adapt the same logic to search across the entire page if needed.
Here is the JavaCode:
// Get the parent element
const parentId = 'contentSection'
const searchText='sign up'
const parentElement = document.getElementById(parentId);
if (!parentElement) {
console.warn(`Parent element with ID "${parentId}" not found.`);
return null;
}
// Normalize search text for case-insensitive comparison
const normalizedSearch = searchText.trim().toLowerCase();
// Search all descendant elements
const childElements = parentElement.querySelectorAll('*');
for (let child of childElements) {
if (child.textContent.trim().toLowerCase() === normalizedSearch) {
return child.id || null; // Return null if the element has no ID
}
}
// No match found
return null;