Protractor: element not interactable - protractor

My test is failing due to error:
element not interactable Failed: element not interactable
(Session info: chrome=79.0.3945.130)
(Driver info: chromedriver=79.0.3945.16 (93fcc21110c10dbbd49bbff8f472335360e31d05-refs/branch-heads/3945#{#262}),platform=Windows NT 10.0.18362 x86_64)
Some info
selenium standalone 3.141.59
geckodriver v0-26.0
Google Chrome Version 79.0.3945.130 (Official Build) (64-bit)
This part of the code is for a non angular page.
As you can see on the code below, I added browser.sleep(), what didn't solve my problem
The element causing the problem is on the last line (id('column_header_44)
it('should compare the space size stored, against the value stored in app', function () {
browser.driver.manage().window().maximize();
browser.sleep(2000);
browser.switchTo().frame(element(by.className('designer-client-frame')).getWebElement());
browser.sleep(2000);
element(by.css('div:nth-child(1) > .ms-Link > .ms-navbar-node-caption > span')).click();//click in Item
browser.sleep(2000);
element(by.css('.horizontal-flex-container-item-layout--paigVxanvxFrIsRy2U02r:nth-child(3) .thm-head-a2-font-size-1--medflat > span')).click();//click in process
browser.sleep(2000);
element(by.css('.ms-ContextualMenu-item:nth-child(1) .thm-popp-a2-font-stack-2--minflat')).click();//click in Time phased
browser.sleep(3000);
element(by.id('column_header_44')).click();//click on item no
browser.sleep(3000);
})

You should avoid using browser.sleep as an explicit waiting method. Use Protractor specific methods instead.
A good way to use a wait before that click would be to wait until the element is present in the html DOM (presenceOf), then wait for it to be clickable (elementToBeClickable), and finally, execute the clicking action:
it('should compare the space size stored, against the value stored in app', async () => {
const EC = protractor.ExpectedConditions;
const your_element = element(by.id('column_header_44'));
await browser.wait(EC.presenceOf(your_element));
await browser.wait(EC.elementToBeClickable(your_element));
await your_element.click();
});

It gives such an error because it does not see the button on the screen. it has to be clicked with javascript.
<input id="myHeader"/>
ChromeDriver driver = null;
var options = new ChromeOptions();
driver = new ChromeDriver(options);
IWebElement element = driver.FindElementById("myHeader");
IJavaScriptExecutor executor = (IJavaScriptExecutor)driver;
executor.ExecuteScript("arguments[0].click();", element);

Related

Protractor: How to handle with "element is not clickable at point (x,y), Other element would receive the click"

I want to click on the following button, locators:
css div.d-flex > [_ngcontent-c1] > .navbar-toggler
and Xpath //div[#class='container d-flex justify-content-between']/span[1]/a[1]
I also updated the chrome driver using the command:webdriver-manager update
Then, I have: version chromedriver_79.0.3945.36
geckodriver version v0.26.0
Chome Version 79.0.3945.88
When I run the protractor, I got the error:
Failed: element click intercepted: Element ... is not clickable at point (1157, 20). Other
element would receive the click: ...
(Session info: chrome=79.0.3945.88)
(Driver info: chromedriver=79.0.3945.16 (93fcc21110c10dbbd49bbff8f472335360e31d05-refs/branch-heads/3945#{#262}),platform=Windows
NT 10.0.18362 x86_64)
Here is the code I tried:
it('should return to the main menu', function () {
browser.driver.manage().window().setSize(1284, 684);
var until = protractor.ExpectedConditions;
var EC = protractor.ExpectedConditions;
var elem = element(by.css('span:nth-of-type(2)>span>a>svg'));
browser.driver.wait(function () {
browser.wait(EC.visibilityOf(elem), 10000);
return elem;
});
elem.click();
})
The original code (without the wait) is
it('should return to the main menu', function () {
element(by.css('.fa-chevron-left')).click();
});
And then, I got this error:
Failed: element click intercepted: Element ... is not clickable at point (137, 23). Other
element would receive the click: ...
(Session info: chrome=79.0.3945.88)
(Driver info: chromedriver=79.0.3945.16 (93fcc21110c10dbbd49bbff8f472335360e31d05-refs/branch-heads/3945#{#262}),platform=Windows
NT 10.0.18362 x86_64)
The interesting is,the click on this button is working in other parts of the page.
This error doesn't have anything to do with chrome version. The problem is that the element that you are trying to click has another element above it. This might not visually look like it but there can be a container or a web element that is above that element. See if you can find which element would receive the click. You might be able to find it on the error log. See if clicking that element would give you the same result that you require.
Click on the element using javascript executor:
browser.executeScript('arguments[0].click();', elem);

How to stop all JS scripts in Puppeteer

I would like to be able to stop any scripts from being able to run in puppeteer after the page has loaded. The reason for this is to stop carousel images and lazy loading images and essentially get the page to behave as statically as possible to enable screenshots where the images aren't changing etc.
By doing page.evaluate('debugger;') it is possible to pause the whole script, but this does not let you continue with taking screen shots as the a evaluate function does not exit until you exit the debugger (If the gui is enabled)
const page = await browser.newPage()
page.setJavaScriptEnabled(false)
If you would like to disable JavaScript after the page has loaded, you can use debugger:
await page.evaluate(() => {
debugger;
});
I was able to take screenshots after using the debugger.
Alternatively, you can replace each original node with its clone to remove the events attached to each element:
await page.evaluate(() => {
document.querySelectorAll('*').forEach(element => {
element.parentNode.replaceChild(element.cloneNode(true), element);
});
});
You can also use removeEventListener() in a loop similar to the one above to remove specific events attached to a node.
Otherwise, if you can disable JavaScript before the page has loaded, you can use page.setJavaScriptEnabled() before navigating to the page:
await page.setJavaScriptEnabled(false);
A better solution is just to block all requests with the type equals to script:
const puppeteer = require("puppeteer");
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on("request", request => {
if (request.resourceType() === "script") {
request.abort()
} else {
request.continue()
}
})
await page.goto("https://stackoverflow.com/")
await browser.close()
})()
Source: Disabling JavaScript Using Puppeteer
If you want to freeze the page and still be able to call evaluate on it, you can
navigate to the page, wait for it to load (and maybe let its JavaScript make some DOM transformations),
get HTML snapshot of the page,
disable JavaScript,
reload the page statically (no DOM transformations will occur since JavaScript is disabled),
profit (do any amount of evaluate or screenshots on a DOM that is guaranteed to stay the same).
await page.goto('<url>', { waitUntil: 'networkidle0' }); // 1
const html = await page.content(); // 2
page.setJavaScriptEnabled(false); // 3
await page.setContent(html, { waitUntil: 'networkidle0' }); // 4
After phoning a friend the following seems to work:
await page.evaluate('document.body.innerHTML = document.body.innerHTML')

Angular could not be found on the page with angular application while running test for angular app in iFrame

I have an angular application running inside iFrame. I must need to launch parent application URL as it provide some flag which makes angular app working as expected. Now I need to write protractor tests for angular app in iFrame.
Here is the code.
describe('French page', function() {
var IFRAME = "iframe",
TITLE_FR = 'Découverte automatique',
PAGE_URL = '/SAAS/admin/app/page',
pagePaths = browser.params.paths;;
beforeEach(function (done) {
LOGIN_PAGE.goToPageAndLogin().then(function (){
browser.driver.ignoreSynchronization = true;
browser.get(PAGE_URL); // application has angular app in iFrame
browser.sleep(5000);
browser.waitForAngular();
done();
});
});
afterEach(function (done) {
demoPause();
LOGIN_PAGE.logout().then(done);
});
it('should be able to launch with fr-FR locale', function (done) {
browser.driver.switchTo().frame(IFRAME); //Switch to angular app in iFrame
// Check if element text is in french
browser.driver.findElement(by.css('.app-menu li:nth-child(1) p')).then(function (elem) {
elem.getText().then(function (text) {
expect(text).toBe(TITLE_FR); // I can see that both texts are same here while debugging
browser.driver.ignoreSynchronization = true;
done();
});
});
});
});
The test condition passed but it exit with below error.
Message:
Failed: Angular could not be found on the page
https://host/abcd/admin/app/page
retries looking for angular exceeded
The issue got fixed by putting
browser.ignoreSynchronization = true;
before
browser.get(PAGE_URL);
Few things:
The parameter IFRAME passed into:
browser.driver.switchTo().frame(IFRAME); needs to be the ID
property of the element, not the tag name of the element, example:
your iframe element
<iframe id="myIframeId" name="frame3">...</iframe>
you would in this case do
browser.diver.switchTo().frame("myIframeId");
Don't call browser.waitForAngular(); on a non-angular page. Since only your iframe element is Angular, I suggest doing the following to make sure a specific element is present before continuing:
browser.driver.wait(function() {
return browser.driver.isElementPresent(by.css("your_selector")).then(function(present) {
return present;
});
}, 20000);
This will wait for an element to be present for 20 seconds, regardless of the page being Angular or not and then continue.
After you switch to the iframe element, you should call browser.driver.ignoreSynchronization = false; to turn on Angular synchronization back on. Since your code inside your iframe is Angular.

protractor browser.actions().mouseMove() not showing hover effects

I am new to protractor and trying to add tests for a slider panel which is closed by default and hovering mouse over will open it and then there are a list of items on the slider panel to pick.
<div class="slider" [ngClass]="{ closed: state === 1, open: state === 2}" (click)="onClick($event)" (mouseover)="onMouseOver($event)" (mouseleave)="onMouseLeave($event)">
I tried multiple ways, none of them work.
First attempt:(no hover effect, ie, do nothing)
browser.actions().mouseMove(element(by.css('.slider.closed'))).perform();
Second attempt:( got an error: An invalid or illegal selector was specified)
browser.actions().mouseMove(element(by.css('[(mouseover)="onMouseOver($event)"]'))).perform();
Third attempt: (got an error: No element found using locator)
browser.actions().mouseMove(element(by.css('[mouseover="onMouseOver($event)"]'))).perform();
This should work, unless you have multiple elements with class .slider. At which point, you might try including a parent object, or another locator strategy.
browser.actions().mouseMove($('.slider')).perform();
I used webdriver and made it work. browser.executeScript('arguments[0].click()',browser.driver.findElement(By.css('.slider')));
I just have the same problem, after 2 hours, I found this work for me:
src: java mouse over using javascript
let loginElement = await driver.findElement(By.id('header-user'));
let strJavaScript = "var element = arguments[0];"
+ "var mouseEventObj = document.createEvent('MouseEvents');"
+ "mouseEventObj.initEvent( 'mouseover', true, true );"
+ "element.dispatchEvent(mouseEventObj);";
await driver.executeScript(strJavaScript, loginElement);
I got the same issue when run tests with firefox
and find out a solution as below
if (browser.isFirefox) {
var script = `if(document.createEvent) {
var evObj = document.createEvent('MouseEvents');
evObj.initEvent('mouseover', true, false);
arguments[0].dispatchEvent(evObj);
} else if (document.createEventObject) {
arguments[0].fireEvent('onmouseover');
}`;
browser.executeScript(script, elm.getWebElement());
return elm.click();
} else {
return browser.actions()
.mouseMove(elm.getWebElement())
.click()
.perform();
}
Test with:
Protractor: 5.1.1
Selenium: 3.4.0

How to wait the page to test is loaded in non angular site?

I've tried this:
browser.wait(function () {
return browser.executeScript('return document.readyState==="complete" &&' +
' jQuery !== undefined && jQuery.active==0;').then(function (text) {
return text === true;
});
}, 30000);
If jQuery.active==0 then page is completely loaded. This should work for sites with JQuery and non angular pages.
However, I have many problems of instability to test for non angular sites.
How to fix this?
By default protractor waits until the page is loaded completely. If you are facing any error then it is because protractor is waiting for the default time to be completed, that you have specified in your conf.js file to wait until page loads. Change the value to wait a for longer time if you think your app is slow -
// How long to wait for a page to load.
getPageTimeout: 10000, //Increase this time to whatever you think is better
You can also increase the defaultTimeoutInterval to make protractor wait a little longer before the test fails -
jasmineNodeOpts: {
// Default time to wait in ms before a test fails.
defaultTimeoutInterval: 30000
},
If you want to wait for any particular element, then you can do so by using wait() function. Probably waiting for last element to load is the best way to test it. Here's how -
var EC = protractor.ExpectedConditions;
var lastElement = element(LOCATOR_OF_LAST_ELEMENT);
browser.wait(EC.visibilityOf(lastElement), 10000).then(function(){ //Alternatively change the visibilityOf to presenceOf to check for the element's presence only
//Perform operation on the last element
});
Hope it helps.
I use ExpectedConditions to wait for, and verify page loads. I walk through it a bit on my site, and example code on GitHub. Here's the gist...
Base Page: (gets extended by all page objects)
// wait for & verify correct page is loaded
this.at = function() {
var that = this;
return browser.wait(function() {
// call the page's pageLoaded method
return that.pageLoaded();
}, 5000);
};
// navigate to a page
this.to = function() {
browser.get(this.url, 5000);
// wait and verify we're on the expected page
return this.at();
};
...
Page Object:
var QsHomePage = function() {
this.url = 'http://qualityshepherd.com';
// pageLoaded uses Expected Conditions `and()`, that allows us to use
// any number of functions to wait for, and test we're on a given page
this.pageLoaded = this.and(
this.hasText($('h1.site-title'), 'Quality Shepherd')
...
};
QsHomePage.prototype = basePage; // extend basePage
module.exports = new QsHomePage();
The page object may contain a url (if direct access is possible), and a pageLoaded property that returns the ExepectedCondition function that we use to prove the page is loaded (and the right page).
Usage:
describe('Quality Shepherd blog', function() {
beforeEach(function() {
// go to page
qsHomePage.to();
});
it('home link should navigate home', function() {
qsHomePage.homeLink.click();
// wait and verify we're on expected page
expect(qsHomePage.at()).toBe(true);
});
});
Calling at() calls the ExpectedCondidion (which can be be an and() or an or(), etc...).
Hope this helps...