Customizing wdio test errors by using the browser.on - javascript

According to wdio's documentation found here I should be allowed to handle an error using
browser.on('error', (err)=>{ console.log('do something') })
However, when I do this, nothing happens it isn't executed when the test fails, which from my understanding should have happened.
Am I doing this wrong? If so, how can I use the .on function to handle the test fails or errors my own way? I do know I can use try/catch blocks, but I would like something cleaner that is just called every time tests fail or there is an error.
Edit: as requested, added some code to show the error
browser.on('error', () => {
console.log('do something about the error')
})
it('should do something', function () {
const nonExistingElement = browser.getText('.idontexist')
assert.deepStrictEqual(nonExistingElement, 'Say something that isnt there')
})
What I would like to do is for the callback function of browser.on be executed whenever an error or failed test occur, in this case, I am trying to get the text of an element that doesn't exist, so naturally I will get the whole
element (".idontexist") still not existing after 500ms
But before that, as it happens I would also like to get the:
do something about the error
So far, the alternative to this, would be to put a try and catch block in my it block and do a browser.emit('error', 'Error'), which I would like to avoid so that I don't have to repeat it every single test.

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.

Nightwatch Abort Test on Pass

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.

Requiring timeouts when testing Meteor with Velocity and Jasmine

Pretty new to meteor, velocity and jasmine so not sure if I am doing something wrong, using Jasmine for something it's not designed for, or this is just the way it works.
I am finding I need to set timeouts for pretty much all of my tests in order to get them to pass. Should this be the case or am I doing something incorrectly?
For example some tests I am running to check validation messages:
describe("add quote validation", function() {
beforeEach(function (done) {
Router.go('addQuote');
Tracker.afterFlush(function(){
done();
});
});
beforeEach(waitForRouter);
it("should show validation when Quote is missing", function(done) {
$('#quote').val('');
$('#author').val('Some author');
Meteor.setTimeout(function(){
$('#addQuoteBtn').click();
}, 500);
Meteor.setTimeout(function(){
expect($('.parsley-custom-error-message').text()).toEqual("Quote can't be empty.");
done();
}, 500);
});
}
OK, we've had this exact same problem and devised a pretty elegant solution to it, that doesn't require timeouts and is the fastest way to run your tests. Basically, we use one of two strategies, depending on what screen elements you're waiting for.
All code goes into tests/mocha/client/lib.coffee, not 100% what the Jasmine equivalent is, but it should be available to all client test code. I've left it in Coffeescript, but you can compile it on coffeescript.org into Javascript, it should work fine as well.
If whatever you do (routing or something else like changing a reactive variable) causes a Template to (re)render, you can use the Template.<your_template>.rendered hook to detect when it is finished rendering. So, we've added the following function in lib.coffee:
#afterRendered = (template,f)->
cb = template.rendered
template.rendered = ->
cb?()
template.rendered = cb
f?()
return
return
What does it do? It basically "remembers" the original rendered callback and temporarily replaces it with one that calls an extra function after the template is rendered and the original callback is called. It needs to do this sort of housekeeping to avoid breaking any code that may have depended on the rendered callback, as you're basically messing with the Meteor code directly.
In your test, you can then do something like this:
it.only "should check stuff after routing", (done)->
try
Router.go "<somewhere>"
afterRendered Template.<expected_template>, ->
<your tests here>
done()
catch e
done(e)
I'd recommend the try-catch as well, as I've noticed asynchronous errors don't always make it into the velocity system, merely giving you a timeout failure.
OK, then there are things that don't actually re-render, but are generated with JS or by some kind of "show/hide" mechanism. For that, you do need some kind of timeout, but you can reduce the "time cost" of the timeout by using a polling mechanism.
# evaluates if a JQuery element is visible or not
$.fn.visible = -> this.length > 0 and this.css('display') isnt 'none'
# This superduper JQuery helper function will trigger a function when an element becomes visible (display != none). If the element is already visible, it triggers immediately.
$.fn.onVisible = (fn,it)->
sel = this.selector
if this.visible()
console.log "Found immediately"
fn?(this)
else
counter = 0
timer = setInterval ->
counter++
el = $(sel)
if el.visible()
fn?(el)
clearInterval timer
console.log "Found on iteration #{counter}"
else
it?(el)
, 50
You can remove the console logging and secondary it iterator function if you like, they're not important. This allows you to do something like this in your test:
$('#modalId').onVisible (el)->
<tests here>
done()
, (el)->
console.log "Waiting for #{el.selector}"
You can remove the second function if you want, it is the it iterator function mentioned above. However, do note that this particular code works with "display: hidden" as the marker for invisibility (Bootstrap does this). Change it if your code uses another mechanism to hide/show parts.
Works like a charm for us!

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");
});

Why "fail" in promise does not catch errors?

I'm trying to access a file, that might not exist:
var localFolder = Windows.Storage.ApplicationData.current.localFolder;
localFolder.getFileAsync(stateFile).then(function (file) {
Windows.Storage.FileIO.readTextAsync(file).then(function (text) {
// do something with the text
});
}, function (err) {
// log error, load dummy data
});
if the file is not there, the "fail" method does get called, BUT it happens only AFTER my application halts with an exception "file not found". only when I press "continue" for the debugger does it continue to the "fail" method..
what am i doing wrong? should i check for existence beforehand?
You're seeing a first-chance exception. The debugger is breaking at the point of throw. If you hit the "continue" button on the debugger dialog, the app will keep running and the exception handler will run.
You can change this by using the "Debug|Exceptions" menu to turn off first chance exceptions.
I have been struggling with this same problem for two or three days and finally came to the following solution: I use getFilesAsync function to get the list of all files in a folder, and then look through this list to know if the needed file exists. After that I can call getFileAsyns without throwing. Not very pretty, but works for me. I agree that assuming that a developer can turn exceptions off is not the best advice... In my opinion this issue should be considered as a bug in RT implementation.

Categories