Nightwatch: wait for element without pass/fail result - selenium

Related questions:
wait for element present without error
Nightwatchjs: how to check if element exists without creating an error/failure/exception
Selenium WebDriver : Wait for complex page with JavaScript(JS) to load
Whenever I load my web-page, I need to wait for ajax calls to complete. I currently do this with:
browser.waitForElementNotPresent(
"cssSelector_For_HTML_afterAJAXComplete",
10000 //timeout
);
This adds an extra assertion to my test though, and makes the test-count for the report artificially larger than necessary.
Any ideas?

Ok, I hacked something together. I'm basically sending javascript to the console in selenium using browser.execute(function, params, callback)
function waitForElement_NoPassFail(selector, timeout){
browser.execute(function(selector, timeout, done){
let intervalId;
var p1 = new Promise(function(resolve, reject){
intervalId = setInterval(function(){
let itemArray = document.querySelectorAll(selector);
if(itemArray.length == 1){
clearInterval(intervalId);
resolve(true); //element found
} else if(itemArray.length>1){
reject(false); //too many elements found, because of ambiguous selector
}
}, 100);
});
var p2 = new Promise(function(resolve, reject){
setTimeout(reject,timeout, false); //timeout reached
});
return Promise.race([p1, p2]).then(function(result){
done(result);
});
},
[selector, timeout],
function(result){
if(!result){
throw "Element: " + selector + " wasn't found after " + timout + " ms.";
} else {
console.log("Element found within timeout limits.") //doesn't trigger assert=ok
}
});
};
waitForElement_NoPassFail(
"cssSelector_that_Is_Valid_after_AjaxIsComplete",
10000 //timeout
);
This can be extended in various ways, for example to support xPath. You could use the nightwatch global variable for element checking frequency when waiting. Write a comment if you need the help.

Related

Protractor how to wait until browser.get to a url

await browser.wait(function() {
return browser.getCurrentUrl().then(function(url) {
return `cars/detail.aspx${browser.baseUrl}`;
});
}, 5000, "url err");
How do I make protractor wait until cars/detail.aspx${browser.baseUrl} is loaded?
I think you can use the urlContains expected condition in protractor to wait until the url contains something specific. You can refer to the documentation here.
I'm using this method, maybe it will be helpful
export function waitForUrlContains(url: string, customTimeout: number = E2E_TIMEOUT) {
return browser.getCurrentUrl().then(myUrl => {
return browser.wait(protractor.ExpectedConditions.urlContains(url), customTimeout, `URL do not contain: ${url}, and is: ${myUrl}`);
});
}
You can read the Protractor's API documentation for further information on different ways of waiting for an element (url in this case) https://www.protractortest.org/#/api
You have 2 ways actually:
const EC = protractor.ExpectedConditions;
const myUrl = 'cars/detail.aspx${browser.baseUrl}';
then:
return browser.wait(EC.urlIs(myUrl));
OR
return browser.wait(EC.urlContains(myUrl));

Ionic 3 infinite-scroll simulate in e2e test jasmine/protractor

If you go here: http://ionicframework.com/docs/api/components/infinite-scroll/InfiniteScroll/
Inspect the demo and click the last item on the list:
Then in the console type: $0.scrollIntoView()
Infinite Scroll is never triggered.
Is there a way to programmatically trigger infinite-scroll in protractor context?
The implementation of the scroll in your example rely on the speed/velocity of the scroll which I guess falls far from the expected range when scrollIntoView is called.
One workaround is to simulates a smooth scroll by emitting multiple scroll events over a reasonable time. The idea is to reproduce as close as possible the behavior of a real user.
Some browsers already provides the option via scrollIntoView (supported by Chrome 62) :
$0.scrollIntoView({behavior: "smooth", block: "end"});
Using the accepted answer, in my case, I used ion-infinite-scroll as the argument.
Complete test to check if more content is loaded in Ionic:
describe('Scroll', () => {
it('should load more when reached end', async () => {
let list = getList();
let currentCount = await list.count();
const refresher = element(by.tagName('ion-infinite-scroll')).getWebElement();
let count = 0;
while(true){
browser.executeScript(`arguments[0].scrollIntoView({behavior: "smooth", block: "end"});`, refresher);
browser.sleep(1000); // wait for data to be loaded from api
list = getList();
let newCount = await list.count();
expect(newCount).toBeGreaterThanOrEqual(currentCount)
expect(newCount).toBeLessThanOrEqual(currentCount * 2)
if(newCount === currentCount){
break;
}
currentCount = newCount;
count++;
}
expect(count).toBeGreaterThan(0);
})
});
function getList() {
return element(by.className(pageId + ' list')).all(by.tagName('ion-item'));
}

Casperjs Unsafe JavaScript attempt to access frame with URL about:blank from frame with URL

casper.on("page.initialized", function(casp){
this.echo("Initialized...");
casper.evaluate(function(){ window.sessionStorage.setItem('authorization','xxxxxxx');
window.sessionStorage.setItem('_USER','xxxxx');
window.sessionStorage.setItem('USERNAME','xxxxx');
window.sessionStorage.setItem('INTERNAL','xxxx');
});
};
casper.test.begin('1: Asserting casperjs is working', 2, function suite(test) {
test.assertEquals(true, true);
test.assert(true);
test.done();
});
casper.test.begin('starting at /', 5, function suite(test
var starting = Date.now();
casper.start();
casper.open("xxxxx",function() {
test.assertHttpStatus(200);
var session = this.evaluate(function(){
return JSON.stringify(window.sessionStorage);
});
this.echo("SESSION: ", session);
});
casper.then(function(){
this.wait(10000, function(){this.echo("WAITED!");});
this.echo(this.getHTML('body'));
try{
casper.waitFor(function check() {
return this.evaluate(function() {
var quotes = document.getElementById('quoteBody').children.length > 1;
this.echo("QUOTES", quotes);
return true;
});
}, function then() {
// ending timer
var ending = Date.now();
var totalt = (ending - start) / 3600;
test.assertFalsy(function(){
return totalt >= 10.0;
}, "loading asserting total time passed");
this.echo("total time: ", totalt);
// tests
test.assertEval(function(){
return document.querySelectorAll('#quotesBody tr').length > 1;
});
//this.echo(this.getHTML('body'));
this.assertTitle("xxxxx", "title match");
});
} catch (e){
this.echo(e);
}
});
casper.run(function() {
test.done();
});
});
I've tried wrapping the test.done() in a timeout but I can't get passed the endless Unsafe JavaScript attempt to access frame with URL about:blank from frame with URL... warnings. The document.getElementById('quoteBody').children.length > 1; works in the browser, but is not returning true and triggering the waitTimeout event. It is after this event is emitted that I get the warnings. I tried waiting much longer than 10000 for loading to no avail. I was able to get some good advice from #Artjom B to get my script off the ground, but this seemingly perennial phantom bug is adding noise to my logs and the waitFor if returned falsy should not present any Unsafe errors.
edit
I think I can fix my script if the warnings weren't completely polluting my output. I've tried web-security=no flags -- didn't work. downgrade to phantom 1.9.2 from 1.9.8? I understand 1.9.8 is a little buggy and many people are having this issue. I'm much more concerned about how to get rid of the noise for now.
still looking for solution
"phantomjs": "^1.9.9"
for casperJs
casperjs --ssl-protocol=tlsv1 test run.js

Phantomjs dump dom object

I'm new to Phantomjs. For debugging on a remote server, I often want to dump a DOM object to look at the structure (similar to Data::Dumper in Perl). This currently is for scraping a couple of sites.
I've thought JSON.stringify may help with this, but it still displays an object name like "[object HTMLDocument]"
Edit: I have also looked at JavaScript: how to serialize a DOM element as a string to be used later? , but I can't seem to inject jquery in phantomjs (still looking for a solution to that, and would prefer no depencencies), and the other answer doesn't seem to work. As I assume it would be a common case for Phantom to analyse the DOM, I thought it would be common for phantom users to have a solution to this.
var page = require('webpage').create();
var system = require('system');
page.onConsoleMessage = function(msg) {
console.log( msg );
}
page.open('http://www.test.com', function(status) {
if(status !== "success") {
console.log( status );
} else {
page.evaluate(function() {
var headline = document.querySelectorAll('div');
console.log( JSON.stringify( headline ) ); // HERE???
});
}
phantom.exit();
});
Is there any way to do this, or am I approaching this wrong ?
in page.evaluate(), you can use XMLSerializer.serializeToString() to convert whatever DOM node you want to string.
page.evaluate(function() {
var s = new XMLSerializer();
return s.serializeToString(document.getElementById('div'));
});
I haven't tried it with "querySelectorAll", since it may return array instead of standalone DOM node, but it definitely works for DOM nodes.
MDN Link

How to run a server url in a Dojo DOH test

The Dojo DOH examples and tutorials do not seem to cover this case. I have a server url for which I want to write tests. I want the target page to show in the TestPage tab and then have multiple tests run against it. The closest example I could find is an html file that defines some tests and then a widget in the body, but I can't do that with a url over which I do not have control. I have done it with a page that fires the robot.init function, but I would like to use the test runner page.
I finally came up with this:
...
doh.register("login tests", [
{
name: "load",
timeout: 20000,
runTest: function(){
var d = new doh.Deferred();
testPage = dom.byId("testBody");
console.log("in load, testPage: " + testPage);
doh.showTestPage();
testPage.src = path;
robot.sequence(function() {
console.log("in load, sequence: ");
testpageBody = testPage.contentDocument.getElementsByTagName("body")[0];
console.log("in load, testpageBody: " + testpageBody);
var bdy = query(".headerFooterLoaded", testpageBody)[0];
console.log("in load, headerFooterLoaded: " + bdy);
if (!!bdy) {
d.callback(true);
} else {
d.errback(new Error("Node with class 'headerFooterLoaded' not found."));
}
}, 8000);
return d;
}
},
...
I tried to catch an iframe onload event, but had no luck.
Hope this helps someone