22

What I am trying to accomplish is browsing to a page, waiting for something to load and then taking and saving a screenshot.

The code I already have is

WebDriver driver = new FirefoxDriver();


driver.get("http://www.site.com");


driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

try {

    File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
    FileUtils.copyFile(scrFile, new File("/home/Desktop/image.png"));

} catch (Exception e) { 

       e.printStackTrace(); 
}

driver.close();

The reason I need to wait, even if the page is loaded is because it'll be loaded but on the site the content I'd like to take a picture of loads after a few seconds. For some reason the page is not waiting, is there another method that I can use to get the driver/page to wait for X amount of seconds?

Petr Mensik
  • 26,874
  • 17
  • 90
  • 115
user2612619
  • 1,119
  • 3
  • 11
  • 28

6 Answers6

16

You can locate an element that loads after the initial page loads and then make Selenium wait until that element is found.

WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("ID")));
user2612619
  • 1,119
  • 3
  • 11
  • 28
  • 3
    Just to mention that in this approach, the ExpectedCondition is tested every 500ms to see if the condition is fulfilled (here that the "ID" element is visible) up to the timeout (here set to 10). It's possible to write your own conditions too, for custom predicates. Documentation on this available here: http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp – anotherdave Nov 17 '13 at 15:56
8

That wouldnt really be a selenium specific thing. You just want java to sleep for a bit after loading the page but before taking the screenshot.

Thread.sleep(4000);

put that after your driver.get statement.

Jas
  • 888
  • 1
  • 8
  • 12
  • 3
    So if he was taking screenshots in each test in a suite of 1,000, and the element would normally load after 500ms, this approach would add an hour to the build time. – anotherdave Nov 17 '13 at 15:52
  • @sircapsalot If I want my browser to stay open an extra 2 seconds before it closes (I call .Quit()), how should I do that? – MStodd Nov 06 '16 at 18:56
  • 3
    Sorry - downvoted for using Thead.sleep. There are always other solutions, such as conditional waiting and so on – sashok_bg Aug 24 '17 at 14:10
5

If you want to delay a certain number of seconds, rather than to respond as soon as possible, here is a function for pause similar to what selenium IDE offers:

public void pause(Integer milliseconds){
    try {
        TimeUnit.MILLISECONDS.sleep(milliseconds);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

source

JohnP2
  • 1,899
  • 19
  • 17
3

The most simple of all.

Just try this and forget rest! The equivalent of this code can be used in any language. I am writing this in python.

import time
time.sleep(2)

this will make the compiler go to sleep for 2 seconds.

Community
  • 1
  • 1
2

Just in case it will help somebody, you should always try to avoid implicit waits and especially Thread#sleep as much as you can. If you do Thread.sleep(10), your code will always wait for 10 seconds even in case your page is ready after 1 sec. So this can slow your tests substantially if you use this often.

Better way is to use ExplicitWaits which you means you will wait exactly as long as some action happens or some element gets rendered on the page. So in your case, I would use explicit wait to check whether is everything loaded and then take a screenshot.

Petr Mensik
  • 26,874
  • 17
  • 90
  • 115
0
const { By, until } = require('selenium-webdriver');


this.wait = async function (amount: number) {
      try {
        await this.driver.wait(
          until.elementLocated(By.css('[data-test-id="does-not-exist"]')),
          amount,
          'Looking for element'
        );
      } catch (e) {
        console.log('waiting')
      }

We look for a css identifier that isn't there for x amount of seconds. This is typescript btw. This would be a method on some relevant class, or a function by itself. Use it like this

  const button = await this.findByCSSSelector('[data-test-id="get-quote-button"]')
  const actions = this.driver.actions({ bridge: true }); 
  await actions.move({origin: button }).perform();

  // Small pause to observe animation is working correctly in all browsers
  await this.wait(700)

  const carat = await this.findByCSSSelector('[data-test-id="carat"]');

This waits for .7 of a second so that you can see that whatever animation is working in your functional tests.

user3605834
  • 2,590
  • 1
  • 12
  • 5