Nightwatch Abort Test on Pass - javascript

I'm writing a script in Nightwatch that tests a specific element on a page. It's possible that the script could be testing a URL in which the element is not present on the page, in which case I want the script to end the test without any failures being logged.
I cannot seem to find a way to abort the test early without invoking a failure, however. Is there any way to have a Nightwatch test abort on a pass?
Here's a part of the code I'm working with for reference:
//End test if pagination is not present
'Pagination Present' : function (browser) {
browser
.execute(function() {
return document.querySelectorAll("ul[class='pagination']").length;
},
function(count){
if (count.value == 0) {
browser.assert.equal(count.value, 0, "There is no pagination on this page.");
browser.end();
}
})
},
Invoking browser.end(); closes the browser, but it reopens immediately after and the tests continue. Every single case fails, since the pagination does not exist on the given page. I'd like to end the test immediately after browser.assert.equal passes. Is there any way to do so?

You can use try/catch.
I had the same issue with some tests and i've got it to skip that assertion like this: you try to check something, but if you don't find the element, instead of failing the test, i just display a message in the console and exit the whole test:
'Test product\'s UPSs' : function (browser) {
try {
browser.assert.elementPresent('#someElement');
}
catch(err) {
console.log('this product has no Special features! Skipping');
process.exit();
}
}
In case you have further tests that you know they wouldn't fail and you'd like to continue with them, just leave out the process.exit() function. While it might not be the safest way to do it, at least it gets the job done.

Related

Why does execution of program stop - I caught the exception?

I'm writing a unit test framework. I noticed Mocha purports to handle exceptions in your test code gracefully, mapping the exception to the correct test in the log output. I'm attempting to do the same thing here. Let's ignore mapping the exception to the correct test for now (I'll def take a suggestion though, I'm stumped on how I'll do that for now)
I add all the test functions into the testmap, iterate over the keys in the testmap, and call each test's function one by one. I stall till the tests report back completed. I wrap around this a try-catch block to catch any exceptions that happen in any of the tests. It works - I can catch exceptions generated in the tests but even though I catch them, the program terminates. I do not want the program to terminate, and I don't think it's supposed to if you catch the exception... what gives?
Here is the try-catch in my library code
this.runtests = () => {
try {
Object.keys(this.testmap).forEach((test) => {
performance.mark(test)
this.testmap[test].testfunc();
});
this.stalltillgood(() => {
this.finallog();
});
}
catch (e) {
console.log('UNHANDLED EXCEPTION IN TEST');
console.log(e.stack);
}
};
Here is the client code which generates the exception - it is ENOENT - no such file or directory - hello.htm doesn't exist (on purpose)
expected('<fuck>&<fuck>');
testinfo('A Hello World Test', //the name of the test [MUST PASS TO ACTUAL AS WELL]
'This is the hello world test doc lol'); //the doc
comparator(cmp.equals); //you can use the pre built compare functions or your own
test(() => { //pass your test function to test
const file = fs.readFileSync('./hello.htm');
actual('A Hello World Test', file.toString());//make a call to actual in your test code
}); //to pass it your test result
//write more tests with the same sequence of commands
I think my problem is that this.runtests is the last method called, and after continuing on from my catch block, the program literally never has anything to output to me again, everything should be logged by then. The program just terminates after the catch block. I think I will have an extra var in test 'started' and just restart this.runtests, which will now check to see if a test has been started before trying to start it! Hooray! Still don't know how to map the exception to the proper test, maybe e.stack? Actually yeah that should be easy I guess lol.
I think my problem is that this.runtests is the last method called, and after continuing on from my catch block, the program literally never has anything to output to me again, everything should be logged by then. The program just terminates after the catch block. I think I will have an extra var in test 'started' and just restart this.runtests, which will now check to see if a test has been started before trying to start it! Hooray! Still don't know how to map the exception to the proper test, maybe e.stack? Actually yeah that should be easy I guess lol.

Why does timer for waits start before the steps are actually executed in a protractor test? Eventloop wrangling

tl;dr: When I run my test case, steps executed seem to work, but the test bails out early on a failure to find an element that hasn't even loaded yet. It seems like the waits I have around locating certain elements are loaded/launched as soon as the test is launched, not when the lines should actually be executed in the test case. I think this is happening because the page is barely (correctly) loaded before the "search" for the element to verify the page has loaded bails out. How do I wrangle the event loop?
This is probably a promise question, which is fine, but I don't understand what's going on. How do I implement my below code to work as expected? I'm working on creating automated E2E test cases using Jasmine2 and Protractor 5.3.0 in an Angular2 web app.
describe('hardware sets', () => {
it('TC3780:My_Test', async function() {
const testLogger = new CustomLogger('TC3780');
const PROJECT_ID = '65';
// Test Setup
browser.waitForAngularEnabled(false); // due to nature of angular project, the app never leaves zones, leaving a macrotask constantly running, thus protractor's niceness with angular is not working on our web app
// Navigate via URL to planviewer page for PROJECT_ID
await planListingPage.navigateTo(PROJECT_ID); // go to listing page for particular project
await planListingPage.clickIntoFirstRowPlans(); // go to first plan on listing page
await planViewerPage.clickOnSetItem('100'); // click on item id 100 in the plan
});
});
planViewerPage.po.ts function:
clickOnSetItem(id: string) {
element(by.id(id)).click();
browser.wait(until.visibilityOf(element(by.css('app-side-bar .card .info-content'))), 30000); // verify element I want to verify is present and visible
return expect(element(by.css('app-side-bar .card .info-content')).getText).toEqual(id); //Verify values match, This line specifically is failing.
}
This is the test case so far. I need more verification, but it is mostly done. I switched to using async function and awaits instead of the typical (done) and '.then(()=>{' statement chaining because I prefer not having to do a bunch of nesting to get things to execute in the right order. I come from a java background, so this insanity of having to force things to run in the order you write them is a bit much for me sometimes. I've been pointed to information like Mozilla's on event loop, but this line just confuses me more:
whenever a function runs, it cannot be pre-empted and will run entirely before any other code
runs (and can modify data the function manipulates).
Thus, why does it seem like test case is pre-evaluated and the timer's set off before any of the pages have been clicked on/loaded? I've implemented the solution here: tell Protractor to wait for the page before executing expect pretty much verbatim and it still doesn't wait.
Bonus question: Is there a way to output the event-loop's expected event execution and timestamps? Maybe then I could understand what it's doing.
The behavior
The code in your function is running asynchronously
clickOnSetItem(id: string) {
element(by.id(id)).click().then(function(){
return browser.wait(until.visibilityOf(element(by.css('app-side-bar .card .info-content'))), 30000);
}).then(function(){
expect(element(by.css('app-side-bar .card .info-content')).getText).toEqual(id);
}).catch(function(err){
console.log('Error: ' + err);
})
}

How to handle UnexpectedAlertOpenError in Protractor

I'm working on the automation of a website and i ran into a particular problem.
I'm using protractor over gulp to run the automated tests and also a report generator included in the gulp task.
The issue at hand is the following:
Whenever an alert is triggered by chrome, protractor stops and throws the "UnexpectedAlertOpenError" in the console, stopping the test run and canceling the report generation.
I would like to know if there is a way to make the spec fail and continue running the rest of the suite.
I know you can do this:
browser.get(url).catch(function () {
return browser.switchTo().alert().then(function (alert) {
alert.accept();
return browser.get(url);
});
});
But i don't want protractor to close the alert and continue, I would like to fail the test where it came up, and return an error message to continue with the run.
Is there any way to do that? Is it possible to pass an exception to the catch function and return a message? I could not find any documentation about that catch method.
Thank you!
EDIT: After going over the stack trace on the console, I've found that protractor detects as if the spec failed, and the exception comes from the reporter when it tries to take a screenshot (I'm using protractor-jasmine2-html-reporter)
I'm going to paste a bit of the stack trace in case someone can figure out something, I'm lost really.
E/launcher - UnexpectedAlertOpenError: unexpected alert open: {Alert text : You have pending changes}
From: Task: WebDriver.takeScreenshot()
EDIT2: I found the real problem with my implementation. The npm plugin protractor-jasmine2-html-reporter (which i'm using) was trying to take a screenshot when the alert was open, causing the webdriver to break and the kept the report from being generated.
What i did to fix this was to fork from their repository and before trying to take a screenshot confirm if the alert was open and avoid taking the screenshot if it was:
function alertIsPresent() {
return browser.driver.switchTo().alert()
.then(function (alert) {
alert.accept();
return true;
}, function (err) {
return false;
});
};
In case it was open, i would close it and continue without taking the screenshot, otherwise take the screenshot.
By doing this the report generates correctly and it documents that on the next spec report that there was an alert open.
Hope this is helpful to someone.
I've had a similar problem. Searched for hours and finally found this:
unexpectedAlertBehaviour: 'accept'
See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities#read-write-capabilities for more information. You basically create a capabilities object and pass the desired values into it:
capabilities: {
browserName: "chrome",
unexpectedAlertBehaviour: 'accept',
chromeOptions: {
args: ["--window-size=1920,1080", "--disable-gpu"],
},
},
Hope this helps!
You should be able to check for these Error codes and force a failure via the jasmine fail function
browser.switchTo().alert().then(function(alert) {
alert.accept();
}, function(err) {
if (err.code == webdriver.error.ErrorCode.UNEXPECTED_ALERT_OPEN) {
fail('Fail this spec');
}
});
This is odd that your test Protractor test completely fails and Protractor stops working. If this is the case, please feel free to open up a Protractor issue.
My guess is that you have an it spec that fails, and it puts up an alert causing other tests to not work. There are a couple of things you could do:
Restart the browser after each test (see the config). This quits the driver session and creates a new browser instance. As you can imagine, this will slow down your test. In your config set:
restartBrowserBetweenTests: true
Try using the postTest plugin. Use postTest to check if the test failed, and maybe check if there is an alert and close it.
postTest: function(passed, testInfo) {
if (!passed) {
// should check to see if there is an alert
// close the alert
return browser.switchTo().alert().then(function (alert) {
return alert.accept();
});
}
}

Protractor - need to find a happy meduim between the default behavour and jasmine-bail-fast

I can share frustration with a lot of professionals about default protractor behavior on test failure - it just keeps running the tests and you have to wait until it finishes to fix the error.
I read the related posts and came across jasmine-bail-fast solution. Link to related post is provided here: Exit Protractor e2e test on fail?
However, this solution puts me on the other side of the pickle. I do NOT want to terminate the testing suite when it failed to close the confirmation message or ran into similar minor issues.
I would like to have the ability to control when to exit the script via exitonfailure() function or something similar. For instance, if had this block of code:
> browser.wait(function()
> return browser.isElementPresent(acceptBudgetButton);
> }, 30000, 'Error - Unable to save budget changes because Accept Budget button is not visible. Terminating test run.');
and put exitonfailure() after this block, I want my test run to exit immediately. However, I want to test keep on running if exitonfailure() is not there.
Is there a feasible way to achieve this goal and take control of my own destiny?
Thank you for your help!
You can handle the browser.wait() success and failure cases appropriately:
var EC = protractor.ExpectedConditions;
browser.wait(EC.presenceOf(acceptBudgetButton), 30000).then(
function () {
// success
},
function () {
// failure
console.log('Error - Unable to save budget changes because Accept Budget button is not visible. Terminating test run.');
jasmine.getEnv().bailFast();
}
});
Also, look into using fail() function which fails a test.

Continue test if a click error occurs

I'm running CasperJS with PhantomJS. I have it going to a url and clicking on an element based on XPath. This could happen several times without a problem, until, I suspect there is a delay in the page loading, it can't find the XPath, it throws an error and stops the test. I would like it to continue through the error. I don't want to wait+click any longer than I already am, as there are many clicks going on, and an error can be at a random click, waiting on every click is counter productive.
I have tried putting the whole test into a try catch, it wouldn't catch.
The only handling I could find just gave out more information on the error, still stopped the test.
I would wait for the selector you want to run, with a short timeout. In the success function do your click, in the timeout function report the problem (or do nothing at all).
For instance:
casper.waitForSelector('a.some-class', function() {
this.click('a.some-class');
}, function onTimeout(){
this.echo("No a.some-class found, skipping it.");
},
100); //Only wait 0.1s, as we expect it to already be there
});
(If you were already doing a casper.wait() just before this, then replace that with the above code, and increase the timeout accordingly.)
You cannot catch an error in something that is executed asynchronously. All then* and wait* functions are step functions which are asynchronous.
Darren Cook provides a good reliable solution. Here are two more which may work for you.
casper.options.exitOnError
CasperJS provides an option to disable exiting on error. It work reliably. The complete error with stacktrace is printed in the console, but the script execution continues. Although, this might have adverse effects when you also have other errors on which you may want to stop execution.
try-catch
Using a try-catch block works in CasperJS, but only on synchronous code. The following code shows an example where only the error message is printed without stacktrace:
casper.then(function() {
try {
this.click(selector);
} catch(e){
console.log("Caught", e);
}
});
or more integrated:
// at the beginning of the script
casper.errorClick = function(selector) {
try {
this.click(selector);
} catch(e){
console.log("Caught", e);
return false;
}
return true;
};
// in the test
casper.then(function() {
this.errorClick("someSelector");
});

Categories