Open wernight opened 10 years ago
I found http://redotheweb.com/2013/01/15/functional-testing-for-nodejs-using-mocha-and-zombie-js.html which is not bad but not that good to report errors well.
Instead I found that the Promise version works fine, as long as you don't handle done()
. For example this seems to handles errors well:
describe('something', function() {
it('test', function() {
return browser.visit('/')
.then(function() {
browser.fill(...);
}.then(function() {
assert ....
};
}
}
}
The same written in CoffeeScript is pretty lean. Not as lean as your async example though.
+1
Another good example in here is test/forms_test.coffee in CoffeeScript and some multi-step operations (but no beforeEach
which is required is many tests as you want your tests to be independent).
Previously I used PhantomJS which allows to take screenshot, so I had the screenshot AND source code saved on test errors. That helped a lot! If I get the same working with Mocha (without screenshot) I'll post here a snippet.
I also didn't find any really good debugging system. Zombie probably doesn't have one and there is no way to have it run in Chrome/Firefox during development. One option though is node-inspector
but you won't see the rendered page and that's a big slow down.
After making some tests I found two good patterns and one bad.
Bad pattern IMO is using (done)
callback because it's easy to miss the error callback and then your tests will not correctly fail or may even never end. So I'd keep the function(done) {... done();}
usages to a minimum.
Good patterns:
async
/ await
of Babel experimental (or similar library) like in the test/form_test.jsdescribe()
before()
or beforeEach()
(not in the it()
):describe('Visit home page', function() {
before(function() {
return browser.visit('/');
});
describe('Click link', function() {
before(function() {
return browser.clickLink('a[class"add"]')
.then(function() {
return browser.clickLink('#something-else');
});
});
it('should something', function() {
browser.assert.text('title', 'something');
});
});
});
By design, these two are equivalent and you can use either one to chain multiple action/wait:
// Uses callback, any error will fail the test
before(function(done) {
browser.clickLink('#something-else', done);
});
// Uses promises, any error will fail the test
before(function() {
return browser.clickLink('#something-else');
});
In your example, if you replace the odd then
with another before
, you get code that looks and behaves the same, whether you write it to use callbacks or return promises. I find that easier because it's consistent in using before
to sequence asynchronous steps.
Alternatively, just put everything inside one async
function (which is how I use Zombie).
In that case it is, but for example it's easy for someone to write:
browser.clickLink('#something', function(err, b) {
if (err) {
done(err);
}
brower.clickLink('#something-else', function() {
done();
});
});
This obviously is missing err
check and there is no warning when it doesn't fail. I believe it'll also fail to catch exception in some cases. And in my memory there were function(done_callback, err_callback)
which makes it a lot harder.
Just from the messages I get for Zombie alone, it seems that people are equally good at failing to properly use promises, as they are at failing to properly use callbacks.
Related to #772 , I was looking at examples on https://github.com/assaf/zombie/tree/master/test for a long example doing multiple interactions in a clear manner and I found that node has just so many ways to handle it, like promises, async/await, non-promises with done...
Looking at test/promises_test.js my understanding of promises was that it should avoid having to call done()/error(). Mocha is supposed to handle promises (not sure how yet). The calls to done()/error() puzzle me.
It seems to me the cleanest way to write most tests—so that if something fails it's reported, else my tests just don't report failures!!—is either using
.should.eventually.
of Mocha or async/await like on test/window_test.js.If you have an example doing a few interactions using what you'd consider the recommended way:
Ideally that example would save the source code snapshot of the page where a test or a click/browser operation failed.
Even this may sound like a lot, I believe most people are trying to achieve something like that and that's what I used to do in Java+WebDriver+PhantomJS (with a screenshot), and you can find online, but it's not as fast/lean/clean as Zombie.