0

I've been running automation tests that execute relatively quickly in my local environment but are extremely slow in Sauce Labs.

The existing Java code appears to have two types of redundant page loading wait times

//1. set at the beginning of the test
 driver.manage().timeouts().pageLoadTimeout(40, TimeUnit.SECONDS);

//2. called before every UI interaction/assertion
(new WebDriverWait(wDriver, waitTime)).until((wDriver) -> {
return javascriptExecutor.execute_script("return document.readyState").equals("complete")
});

Is the pageLoadTimeout a type of implicit wait that might be causing a conflict with the second "document.readyState" explicit wait?

Is this entirely redundant, or are there any edge cases where one of these checks might not work, and the secondary method acts as a backup?

Any help is appreciated AJ

A. J. Green
  • 93
  • 2
  • 8

3 Answers3

1

pageLoadTimeout sets the time to wait for a page to load completely before throwing an error.

The WebDriverWait in your program ensures that your program waits for the document.readyState to be equal to "complete" atleast for the configured waitTime incase of a slowly loading page.

You can find a detailed discussion in Do we have any generic function to check if page has completely loaded in Selenium

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • Does it act as a wait at all? For example, if the webdriver clicked a navigation button that loaded a new page, would it prevent any new click actions from happening until the page load is completed? – A. J. Green Mar 17 '22 at 21:58
  • 1
    Of coarse _`pageLoadTimeout`_ works as intended, checkout the embedded discussion. Unfortunately _`pageLoadTimeout`_ isn't desined to prevent any new click actions from happening, but for that you have got [WebDriverWait](https://stackoverflow.com/a/50621712/7429447) at your disposal. – undetected Selenium Mar 17 '22 at 22:09
1

Are you sure you really need to wait for document.readyState -> complete before every UI interaction/assertion?
In case there are some heavy JavaScripts running on that page it may take significant time to reach the above state.
Practically in most cases all what you need is readiness / maturity state of a specific element you currently need to access.
So, instead of waiting for the entire page readyState complete state you may wait for visibility or clickability of that single, specific web element.
I believe this will reduce the delays you are talking about here.

Prophet
  • 32,350
  • 22
  • 54
  • 79
  • Might not be necessary for every interaction, it's just built into the current framework that wraps around every selenium action. I am wondering if there is something there that might cause such a significant slowdown when running in Sauce Labs vs running locally. From what I've seen the page loading times in the Sauce Lab tests are only moderately slower than my local tests. But the cucumber steps execute very slowly in comparison. – A. J. Green Mar 17 '22 at 22:06
  • In generic case the client won't release the control to the webdriver unless the _`document.readyState -> complete`_, so under the hood it's compulsary. – undetected Selenium Mar 17 '22 at 22:12
  • @undetectedSelenium AFAIK this is related to driver.get() method only. No? – Prophet Mar 17 '22 at 22:16
  • Yup, that's correct. In short that's _**navigation**_ – undetected Selenium Mar 17 '22 at 22:17
  • 1
    @A.J.Green I never worked in Sauce Labs, so I don't know. – Prophet Mar 17 '22 at 22:18
  • If so we don't have to add such wait before each UI interaction unless we need that. – Prophet Mar 17 '22 at 22:20
  • `it may take significant time to reach the above state` isn't true. what keeps that state from being reached is an asset that doesn't load. the readiness state will be complete when the JS is loaded, not when it has finished running. – titusfortner Mar 17 '22 at 22:30
  • 1
    @A.J.Green yes, each command is very fast when you execute it locally, but takes ~.2 seconds to send to a remote server (like Sauce Labs), so if you have a lot of commands it can add up to a much slower test. – titusfortner Mar 17 '22 at 22:32
  • @titusfortner Interesting. I assumed the Sauce Labs servers were local to my location, but the lag time might explain it. Would consolidating all wait and interaction commands into one javascript code string that is then executed at one time reduce the slowness? something like this: ` javascriptExecutor.execute_script("click command, wait command, assertion command"); ` – A. J. Green Mar 17 '22 at 22:56
  • 1
    @A.J.Green I would focus on accurate results and minimizing maintenance costs. The trickier you get with your code, the harder it is to know what's going on when something changes or breaks. The idea behind a grid/service is to improve throughput by running more tests at the same time and for that to more than compensate for each test being slower. – titusfortner Mar 17 '22 at 23:58
1

There are two different concepts here. The first is that with w3c you can now set a Page Load Strategy in the capabilities at the beginning of a session. This affects what Document readiness state the driver will wait for before returning control to the user. If the specified readiness state is not satisfied before the page load timeout, the driver is supposed to return an error.

Note that both of these things only apply to navigation events, so clicking an element that results in a page load should not trigger these.

To complicate things one more level, Chromedriver has an open bug for incorrectly:

wait[ing] for navigation to complete at the end of almost all commands

So for right now Chrome tests actually will wait for the specified document readiness state on clicks.

Finally, remember that for today's web there is typically a lot of content loaded dynamically via JavaScript, so even when the document readiness state is "complete" the DOM is unlikely to be in it's final state, which is why you are encouraged to use explicit waits for the things you actually want to interact with.

titusfortner
  • 4,099
  • 2
  • 15
  • 29
  • Thank you for breaking it down for me. Would using a single type explict wait based on ExpectedCondition visibility be sufficient for all the type of situations you describe? Something like this: ``` wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("/html/body/div[3]/Button"))); ``` This seems to cover page navigation and dynamically loaded content – A. J. Green Mar 17 '22 at 22:14
  • _Document readiness state the driver will wait for before returning control to the user_: Possibly you mean to say webdriver here. – undetected Selenium Mar 17 '22 at 22:14
  • 1
    Yes, I started ignoring page loads in my test code a while back and focused on making sure the element is in the state I need it to be in for the action I want to take on it. My actual approach is a little more complicated, I talk about it here — https://www.ministryoftesting.com/dojo/lessons/optimize-for-remote-execution-take-your-waiting-game-to-the-next-level-with-titus-fortner @undetectedSelenium — "to the user"/"to the user's code" same idea – titusfortner Mar 17 '22 at 22:27