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?
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")));
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.
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
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.
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.
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.
Related
Is there a way to extend the .click method of a WebElement?
I would like to add a few lines of code to it to accommodate some issues we have with an internal website.
I would like to add:
WebDriverWait wait = new WebDriverWait(driver, 5);
wait.until(ExpectedConditions.elementToBeClickable(pageElement));
Now I know that some of you will probably say just use implicit wait. I've thought about that but some of the pages I code against take 10-30 seconds to load. Some of the pages load very quickly but then the buttons that get displayed are conditional based on clicking other buttons and I get into a situation where I know the button should have loaded within 5 seconds. I'd rather not incur the 30 second wait on every button. This could happen literally hundreds of times and I don't want the script to take that long.
Is there a way to add an explicit wait to a click event?
Try FluentWait, This will check for element every 5 seconds.
Wait wait = new FluentWait(driver).withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS).ignoring(NoSuchElementException.class);
There isn't really a need to override .click() and as #lauda has stated in the comments, this is not a good practice. You don't need to add a lot of code to wait for the element to be clickable so the claim that it will add thousands of lines of code is not true. You can easily accomplish this with a single line of code... so no extra lines of code. Having said that... you should focus less on how many lines of code it will add and consider:
How easy is it going to be to maintain?
Am I adding unnecessary complexity to my code base?
Is it going to be more readable?
...and so on...
A sample click method for a representative button
public void clickButtonX()
{
new WebDriverWait(driver, timeOutInSeconds).until(ExpectedConditions.elementToBeClickable(buttonXLocator)).click();
}
where you have these declared at the top of the class
private By buttonXLocator = By.id("buttonXId");
private int timeOutInSeconds = 10;
Having said that... I don't think this is the right approach. With the page object model, you should have each page class handle waiting for the page to finish loading... then you won't have to wait for the buttons to load before clicking them. In the case where a button is loaded dynamically, the action that triggers the dynamic loading should wait for the load to complete.
package sandbox;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import common.Functions;
public class _PageTemplate
{
private WebDriver driver;
private By dynamicPageLoadLocator = By.id("someId");
private By buttonXLocator = By.id("buttonXId");
private By dynamicLinkLocator = By.id("dynamicLinkId");
private By dynamicSectionElementLocator = By.id("dynamicSectionId");
public _PageTemplate(WebDriver webDriver) throws IllegalStateException
{
Functions.waitForPageLoad(driver);
// see if we're on the right page
if (!driver.getCurrentUrl().contains("samplePage.jsp"))
{
throw new IllegalStateException("This is not the XXXX Sample page. Current URL: " + driver.getCurrentUrl());
}
// for dynamic pages, wait for a specific element to signal the dynamic load is complete
new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(dynamicPageLoadLocator));
}
public void clickButtonX()
{
// no wait needed here
driver.findElement(buttonXLocator).click();
}
public void clickDynamicLink()
{
// clicking this link triggers part of the page to change, reload, etc. ...
driver.findElement(dynamicLinkLocator).click();
// ... so after the click, we wait for the dynamic part of the page to finish by locating an element that is inside the dynamically
// loaded portion and wait for it to be visible
new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(dynamicSectionElementLocator));
}
}
where this is declared in some Utils class or whatever.
/**
* Waits for the browser to signal that the DOM is loaded. For dynamic pages, an extra wait may be necessary.
*/
public static void waitForPageLoad(WebDriver driver)
{
new WebDriverWait(driver, 30).until(new ExpectedCondition<Boolean>()
{
public Boolean apply(WebDriver webDriver)
{
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
});
}
Now with this framework, we no longer have to add code to each button to make sure that it's available before the click. I would suggest you take this approach to all your code. Wait only in the places it's needed rather than sprinkling waits everywhere.
Wait for the page to load
After triggering a dynamic page change, wait for the page change to complete
If you just do those two things, you will only have waits in very specific places and not need them everywhere (reducing complexity and confusion when debugging, etc.).
I am writing some automated tests using Fluentlenium and PhantomJS. I am having trouble accessing the id "#title". The test I have written is as follows:
#Test
public void testCreateButton() {
startAppWithCallback(new F.Callback<TestBrowser>() {
public void invoke(TestBrowser browser) throws InterruptedException {
CalendarPage calendarPage = browser.createPage(CalendarPage.class);
calendarPage.withDefaultUrl(BASE_URL);
calendarPage.go();
calendarPage.selectCreateButton();
calendarPage.typeTitle("Java Fundamentals");
browser.await().atMost(3, TimeUnit.SECONDS);
}
});
}
The test is running, and seems to be able to select the Create button, which should then open up a modal window, but for some reason it is having trouble seeing the id on this modal. The error message that I get is as follows:
org.openqa.selenium.NoSuchElementException: No element is displayed or enabled. Can't set a new value.
Is there something I am not doing when it comes to accessing the id on the modal window? Any help at all would be much appreciated.
Usually modal windows take some time to attach to the DOM of the page you are accessing. Though you have added 3 seconds to wait for the element to appear/ attach to the DOM but the time is not sufficient. I would not recommend to increase the timeout but would recommend to wait until for the element to appear and then move forward. for e.g. you could do following thing to wait for an element to appear on the page instead of waiting statically:
FluentWaitMatcher matcher = page.await().atMost(, TimeUnit.SECONDS).until(findPattern);
I'm starting an already installed app using appium.
After my driver is initialized. How do I make it poll-wait till certain activity is displayed?
I saw only this way to wait for activity when starting up
cap.setCapability("app-wait-activity", "activity-to-wait-for");
Is there any other way? How do I wait to another specific activity when not initializing. Say after a button click?
just sleep x seconds ?
Specific activity means some specific element is being displayed.
I use the following code to wait until some certain element on the screen:
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.elementToBeClickable(By
.xpath("//android.widget.Button[contains(#text, 'Log In')]")));
or:
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.presenceOfElementLocated(By
.xpath("//android.widget.TextView[contains(#resource-id, 'action_bar_title')]")));
WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("about_me")));
If you wish to know in detail how implicit and explicit wait can be used in Appium then visit this TUTORIAL
You can use the following code to poll the current activity every second. If you want to reduce polling time you can reduce sleep time to 500 and wait*2 :
public void waitForActivity(String desiredActivity, int wait) throws InterruptedException
{
int counter = 0;
do {
Thread.sleep(1000);
counter++;
} while(driver.currentActivity().contains(desiredActivity) && (counter<=wait));
log("Activity appeared :" + driver.currentActivity(), true);
}
I would suggest you to use WebDriverWait. Thread.sleep() is not a good way to use in your test scripts
long startTime = System.currentTimeMillis();
while(System.currentTimeMillis() - startTime < Time_Out)
if (getDriver().currentActivity().equals(activity))
break;
Also you could make use of the following:
getDriver().manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
or just:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
or something like the following:
Thread.sleep(5000);
It can be done by different ways using element. Webdriver provide “WebDriverWait”, “ExpectedCondition” classes to implement this.
ExpectedConditions class provide some set of predefine conditions to wait elements as:
elementSelectionStateToBe: an element state is selection.
elementToBeClickable: an element is present and clickable.
elementToBeSelected: element is selected
frameToBeAvailableAndSwitchToIt: frame is available and frame
selected. invisibilityOfElementLocated: an element is invisible
presenceOfAllElementsLocatedBy: present element located by.
refreshed: wait for a particular condition when page refresh.
textToBePresentInElement: text present on particular an element
textToBePresentInElementValue: and element value present for a
particular element. and many more
You can learn more ways to implement implicit and explicit wait by going through this url:
http://roadtoautomation.blogspot.in/2013/10/webdriver-implicit-and-explicit-wait.html
Hope it helps...
This question already has answers here:
How can I take a screenshot with Selenium WebDriver?
(48 answers)
Closed 6 years ago.
I am trying to take a screenshot of a webpage while selenium is running. I am using the following code for this purpose
WebDriver augmentedDriver = new Augmenter().augment(seleniumDriver);
File scrFile = ((TakesScreenshot)augmentedDriver).getScreenshotAs(OutputType.FILE);
Now it serves my purpose perfectly well except that whenever this method gets called the browser automatically gets into the default size and maximizes again.
And this continues every time the screenshot function gets called.
I am able to solve the problem If I am NOT using the selenium webdriver for taking the screenshots and using other java functions.
I wanted to know if anyone had similar problems/why I am having this problem. And is there any workaround?
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File("D:\\screenshot.jpg"));
This code will definitely help
It tries to adapt to page size and take the screenshot as small as possible or as large as needed for the whole page to fit. Apart from being annoying, it should not be a cause of any other problems and is therefore considered a better solution than taking a screenshot of just the actual viewport which could be missing some important piece of the page you're trying to examine.
If you're not happy about it, use Robot and its createScreenCapture() method.
Or, but it will only work for Firefox, you may try overriding the FirefoxDriver's method for screenshots. Not tested, no idea whether you'll be allowed to do it or not.
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("FirefoxDriver.prototype.screenshot = function(a){};");
and (if that's not enough) maybe even
js.executeScript("FirefoxDriver.prototype.saveScreenshot = function(a,b){};");
Inferred from here. The actual screenshooting code is here. You can replace the FirefoxDriver.prototype.screenshot function with your own that wouldn't take the maximum scrollable values for height and width...
The code to take the screenshot make use of getScreenshotAs method of TakesScreenshot interface. Following code will take screenshot of the webpage opened by webDriver instance.
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File("D:\\testScreenShot.jpg"));
Now in order to take screenshot in case of test failure we will use AfterMethod annotation of TestNG. In the AfterMethod annotation we will use ITestResult interface's getStatus() method that returns the test result and in case of failure we can use the above commands to take screenshot. Code snippet to take screenshot on test failure-
#AfterMethod
public void takeScreenShotOnFailure(ITestResult testResult) throws IOException {
if (testResult.getStatus() == ITestResult.FAILURE) {
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File("D:\\testScreenShot.jpg"));
}
}
For complete sample script refer to http://artoftesting.com/automationTesting/screenShotInSelenium.html
I have created a method for this, which is very easy to use. It takes the screenshot of the whole web page. It counts and name the screen shot depending on the number of screenshots, the method also stores the screenshot as .png file into src.
public static void screenshot(WebDriver driver)
{
System.out.println("Taking the screenshot.");
console_logs("Taking the screenshot.");
scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
try {
FileUtils.copyFile(scrFile, new File("src//tempOutput//webPage_screenshot_"+count+".png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
count++;
//return scrFile;
}
Using the method:
screenshot(driver);
In certain unknown situations selenium does not detect that a page has loaded when using the open method. I am using the Java API. For example (This code will not produce this error. I don't know of an externally visible page that will.):
Selenium browser = new DefaultSelenium("localhost", 4444, "*firefox", "http://www.google.com");
browser.start();
browser.open("http://www.google.com/webhp?hl=en");
browser.type("q", "hello world");
When the error occurs, the call to 'open' times out, even though you can clearly see that the page has loaded successfully before the timeout occurs. Increasing the timeout does not help. The call to 'type' never occurs, no progress is made.
How do you get selenium to recognize that the page has loaded when this error occurs?
I faced this problem quite recently.
All JS-based solutions didn't quite fit ICEFaces 2.x + Selenium 2.x/Webdriver combination I have.
What I did and what worked for me is the following:
In the corner of the screen, there's connection activity indicator.
<ice:outputConnectionStatus id="connectStat"
showPopupOnDisconnect="true"/>
In my Java unit test, I wait until its 'idle' image comes back again:
private void waitForAjax() throws InterruptedException {
for (int second = 0;; second++) {
if (second >= 60) fail("timeout");
try {
if ("visibility: visible;".equals(
selenium.getAttribute("top_right_form:connectStat:connection-idle#style"))) {
break;
}
} catch (Exception e) {
}
Thread.sleep(1000);
}
}
You can disable rendering of this indicator in production build, if showing it at the page is unnecessary, or use empty 1x1 gifs as its images.
Works 100% (with popups, pushed messages etc.) and relieves you from the hell of specifying waitForElement(...) for each element separately.
Hope this helps someone.
Maybe this will help you....
Consider the following method is in page called Functions.java
public static void waitForPageLoaded(WebDriver driver) {
ExpectedCondition<Boolean> expectation = new
ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor)driver).executeScript("return document.readyState").equals("complete");
}
};
WebDriverWait wait = new WebDriverWait(driver,30);
try {
wait.until(expectation);
} catch(Throwable error) {
Assert.assertFalse(true, "Timeout waiting for Page Load Request to complete.");
}
}
And you can call this method into your function. Since it is a static method, you can directly call with the class name.
public class Test(){
WebDriver driver;
#Test
public void testing(){
driver = new FirefoxDriver();
driver.get("http://www.gmail.com");
Functions.waitForPageLoaded(driver);
}
}
When I do Selenium testing, I wait to see if a certain element is visible (waitForVisible), then I do my action. I usually try to use an element after the one I'm typing in.
Using 'openAndWait' in place of 'open' will do the trick.
From the website:
Many Actions can be called with the "AndWait" suffix, e.g. "clickAndWait". This suffix tells Selenium that the action will cause the browser to make a call to the server, and that Selenium should wait for a new page to load.
Enabling the 'multiWindow' feature solved the issue, though I am not clear why.
SeleniumServer(int port, boolean slowResources, boolean multiWindow)
SeleniumServer server = new SeleniumServer(4444, false, true);
Any clarification would be helpful.
I've run into similar issues when using Selenium to test an application with iFrames. Basically, it seemed that once the primary page (the page containing the iframes) was loaded, Selenium was unable to determine when the iframe content had finished loading.
From looking at the source for the link you're trying to load, it looks like there's some Javascript that's creating additional page elements once the page has loaded. I can't be sure, but it's possible that this is what's causing the problem since it seems similar to the situation that I've encountered above.
Do you get the same sort of errors loading a static page? (ie, something with straight html)
If you're unable to get a better answer, try the selenium forums, they're usually quite active and the Selenium devs do respond to good questions.
http://clearspace.openqa.org/community/selenium_remote_control
Also, if you haven't already tried it, add a call to browser.WaitForPageToLoad("15000") after the call to open. I've found that doing this after every page transition makes my tests a little more solid, even though it shouldn't technically be required. (When Selenium detects that the page actually has loaded, it continues, so the actual timeout variable isn't really a concern..
Not a perfect solution, but I am using this method
$t1 = time(); // current timestamp
$this->selenium->waitForPageToLoad(30);
$t2 = time();
if ($t2 - $t1 >= 28) {
// page was not loaded
}
So, it is kind of checking if the page was not loaded during the specified time, so it is not loaded.
another idea is to modify AJAX API (to add some text after AJAX actions).
After ajax action was finished, before return, set invisible field to TRUE, selenium will find it and read as green-light
in html:
<input type='hidden' id="greenlight">
in selenium
if(driver.findElement(By.id("greenlight")).getAttr("value").equals("TRUE")){
// do something after page loading
}
If you page has no AJAX, try to seek footer of page (I also use Junit fail(""), you may use System.err.println() instead):
element.click();
int timeout =120;
// one loop = 0.5 sec, co it will be one minute
WebElement myFooter = null;
for(int i=0; i<timeout; i++){
myFooter = driver.findElement(By.id("footer"));
if(myFooter!= null){
break;
}
else{
timeout--;
}
}
if(timeout==0 && myFooter == null){
fail("ERROR! PAGE TIMEOUT");
}