Selenium WebDriver Java: Change DOM before DOMContentLoaded - selenium

My aim is to change the DOM of a page before the DOMContentLoaded event. Let's say my JS would look like the code below and I want to change a value of an element:
document.addEventListener("DOMContentLoaded", function(event) {
console.log("Value of element foo: " + document.getElementById('foo').value);
});
I know to change the DOM with the JavascriptExecutor of Selenium WebDriver, but I'm missing how to get it to to execute right before 'DOMContentLoaded' (and maybe that's not the right approach).
// some hook or whatever to execute right before 'DOMContentLoaded' or wherever suitable
((JavascriptExecutor) webDriver).executeScript("document.getElementById('foo').value='hi there'");

In order to do that you will have to set the pageLoadStrategy from default normal to none.
This will pass the control to the next code line immediately after launching the page with driver.get() method without waiting for the page content to be loaded.

Related

waiting for an element while condition is still fullfilled

The wait helpers are very useful functions. But it seems they can wait only for an element to exist (Until...)
Is there a wait to say "wait while condition is still fullfilled" ?
Example, click some element and wait for some other element to disappear
You can try (at least with Java, I'm not sure if it's in the other languages) is the ExpectedConditions.not the method, which you can wrap around another ExpectedConditions.
An example would be something like:
new WebDriverWait(driver, 20).until(ExpectedConditions.not(ExpectedConditions.presenceOfElementLocated(By.cssSelector('#loading-spinner'))));
or you can try
new WebDriverWait(driver, 20).until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector('#loading-content')))
Selenium in Java has
wait.until(ExpectedConditions.invisibilityOfElementLocated(element));
and
wait.until(ExpectedConditions.stalenessOf(element));
methods.
Selenium in Python has invisibility_of_element_located and staleness_of methods too.
So you can create a method clicking on some element and waiting for it to disappear, like this:
public void clickVisibleDisappear(By element){
wait.until(ExpectedConditions.visibilityOfElementLocated(element)).click();
wait.until(ExpectedConditions.invisibilityOfElementLocated(element));
}
Or clicking on one element and waiting for some other element to disappear as you asked, like this:
public void clickVisibleDisappear(By element1, By element2){
wait.until(ExpectedConditions.visibilityOfElementLocated(element1)).click();
wait.until(ExpectedConditions.invisibilityOfElementLocated(element2));
}

How to click on save button in chrome print privew page using selenium Java

I am currently looking for a solution to click on Sava button in chrome print preview window with selenium Java.
Is there any way we can handel chrome print preview page?
I have tried with the Robot class, but it seems not reliable/stable for my application.
Could you please someone help me to achieve this with selenium Java.
I fail to see any "Save" button on print preview page for Chrome browser
Here is how you can click "Cancel" button, I believe you will be able to amend the code to match your requirements:
First of all make sure to wait for the preview page to be available using Explicit Wait
Change the context to the print preview window via WebDriver.switchTo() function
All the elements at the print preview page are hidden in ShadowDom therefore you will need to:
Locate the element which is the first parent of the element you're looking for
Get its ShadowRoot property and cast the result to a WebElement
Use the WebElement.findElement() function to locate the next parent
repeat above steps until you reach the desired button
Example code just in case:
new WebDriverWait(driver, 10).until(ExpectedConditions.numberOfWindowsToBe(2));
driver.switchTo().window(driver.getWindowHandles().stream().skip(1).findFirst().get());
WebElement printPreviewApp = driver.findElement(By.tagName("print-preview-app"));
WebElement printPreviewAppConten = expandShadowRoot(printPreviewApp, driver);
WebElement printPreviewSidebar = printPreviewAppConten.findElement(By.tagName("print-preview-sidebar"));
WebElement printPreviewSidebarContent = expandShadowRoot(printPreviewSidebar, driver);
WebElement printPreviewHeader = printPreviewSidebarContent.findElement(By.tagName("print-preview-header"));
WebElement printPreviewHeaderContent = expandShadowRoot(printPreviewHeader, driver);
printPreviewHeaderContent.findElements(By.tagName("paper-button")).get(1).click();
where expandShadowRoot function looks like:
private WebElement expandShadowRoot(WebElement parent, WebDriver driver) {
return (WebElement) ((JavascriptExecutor) driver).executeScript("return arguments[0].shadowRoot", parent);
}
Save button will not work because page is not part of webpage. selenium only support web based application.
But you can use SIKULI to handle above scenario.

Protractor getting DOM element and using their properties

I'm running e2e tests with Protractor and Selenium on a Polymer/Angular App.
Most of the elements are in the shadow DOM (I managed to handle it with custom css locators but it made my tests unstable as any change in the dom breaks them). The problem is that the devs have implemented a virtual scroll list :
Only a few items are loaded in the scroll list, next ones are loaded when you scroll.
I asked my devs how to deal with it and they told me I had to get the web-component and test it without protractor aka running commands like this :
document.querySelector('virtual-scroll').baseList
Where baseList is a public property of the tag.
I tried
var element = browser.executeScript('return document.querySelector("virtual-scroll")');
element.then(function (el){
console.log(el.$.baseList);
});
but the command above returns a WebElement. Is there any way to return the HTML DOM element as a javascript querySelector command does ?
EDIT : as requested the source code with the property of the scrollList that I want to get
If "virtual-scroll" is name of the shadow root element and baseList is an attribute of the element. You can get it with command below.
var baseList = browser.executeScript('return document.querySelector("virtual-scroll").baseList');
By the way, you can test the shadow DOM with Selenium. See an example below.
var shadowRootElement = browser.executeScript('return document.querySelector("virtual-scroll").shadowRoot');
var element = shadowRootElement.findElement(......);

Selenium Chrome webdriver can't find elements after content is reloaded

I'm testing a page where the div reloads with a form that has multiple textboxesand buttons. However after the div is reloaded the webdriver can't find any of the elements on the screen. I've tried different waits but it never finds the elements. However, when I try to find an element that didn't change (i.e. a top nav element) it finds it fine.
Driver.Instance.FindElement(By.Id("igtxttxt_CAge")).Click();
var wait = new WebDriverWait(Driver.Instance, TimeSpan.FromSeconds(10));
wait.Until(d => d.SwitchTo().ActiveElement().GetAttribute("id") == "igtxttxt_CAge");
Is there something I can do for when the div content is refreshed?
Error received:
no such element: Unable to locate element:
{"method":"id","selector":"igtxttxt_CAge"}
(Session info: chrome=56.0.2924.76)
(Driver info: chromedriver=2.27.440174
I found the answer to this question. I didn't realize until I looked at the HTML content that the Driver contained that the page I was loading was loaded in an iFrame.
Once I added this code:
Driver.Instance.SwitchTo().Frame("frame_Calculator");
Then the rest of my code worked as expected:
Driver.Instance.FindElement(By.Id("igtxttxt_CAge")).Click();
((IJavaScriptExecutor)Driver.Instance).ExecuteScript("$('#igtxttxt_CAge').trigger('focus')");
In your given scenario, I think fluentwait is better candidate than webdriverwait. You can try the following code. It will ignore all such no element not found exceptions while the webdriver waits.
FluentWait fluentWait = new FluentWait<>(webDriver) {
.withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(200, TimeUnit.MILLISECONDS);
.ignoring(NoSuchElementException.class, TimeoutException.class)
.ignoring(StaleElementReferenceException.class);
}
And the you can use it until your element is clickable or visible.
fluentWait.until(ExpectedConditions.visibilityOf(By.Id("igtxttxt_CAge")));
fluentWait.until(ExpectedConditions.elementToBeClickable(By.Id("igtxttxt_CAge")));
Hope this will help. here is a difference between webdriverwait and fluentwait.

Element is not clickable when another element covers it

I am writing a test that at some point navigates to another page. The first thing that page is will be to run a javascript that pops up a span with a message. After some seconds, that span will dissapear.
I am trying to click a link that will go below the span and chromedriver does not seem to allow that.
System.InvalidOperationException: unknown error: Element is not
clickable at point (165, 177). Other element would receive the click:
...
This is really an expected behavior and also a bit impresssive.
Can I click the link without waiting for the span to dissapear?
I have no suggestion how to click the element as long as the massage is displayed but you could skip waiting for it to disappear by removing it on your own using javascript and webDriver.executeScript:
How to make a DIV visible and invisible with JavaScript
I would suggest you to use "smart" wait that will verify that the window has disappeared.
It's implemented using WebDriverWait and ExpectedConditions.
Example in Java:
WebDriverWait wait = new WebDriverWait(driver, 10); //timeout after 10 seconds
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.ByCssSelector("CSS_POP_UP_SELECTOR")));
Or, you can try to use the following script to make element visible:
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("document.getElementById('BUTTON_ELEMENT_ID').style.display='block';");
Or, to try and hide the message:
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("document.getElementById('BUTTON_ELEMENT_ID').style.display='none';");
If you want your elements to keep their size when the not visible/visible, instead of 'display' change the 'visibility':
document.getElementById('BUTTON_ELEMENT_ID').style.visibility = 'hidden';
document.getElementById('BUTTON_ELEMENT_ID').style.visibility = 'visible';