I'm trying to test my Node.js/Express.js application using Mocha and Zombie. I can get simple tests to pass, but as soon as I add the script tags for Twitter Bootstrap to my views, the browser object returns empty HTML.
Here is my test code:
process.env.NODE_ENV = 'test';
var app = require('../app');
var assert = require('assert');
var Browser = require('zombie');
describe('home page', function() {
before(function() {
this.server = app.listen(3000);
this.browser = new Browser({site: 'http://localhost:3000', debug : true});
});
it('should show welcome', function(done) {
var browser = this.browser;
browser
.visit("/")
.then(function() {
console.log(browser.html());
})
.fail(function(error) {
console.log("Error: ", error);
})
.then(done);
});
after(function(done) {
this.server.close(done);
});
});
The view code (my layout.jade file):
doctype 5
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
script(src='/javascripts/jquery-2.0.3.min.js')
script(src='/javascripts/bootstrap.min.js')
body
.navbar.navbar-inverse.navbar-fixed-top
.container
.navbar-header
button.navbar-toggle(type='button', data-toggle='collapse', data-target='.navbar-collapse')
span.icon-bar
span.icon-bar
span.icon-bar
a.navbar-brand(href='/') Contact Database
.collapse.navbar-collapse
ul.nav.navbar-nav
li.active
a(href='/') Home
li.active
a(href='/contacts') Contacts
block content
If I remove the script tags, the HTML is logged to the console as expected. Otherwise, I get empty HTML returned.
The debug output:
home page
◦ should show welcome: Zombie: Opened window http://localhost:3000/
GET / 200 283ms - 1018b
Zombie: GET http://localhost:3000/ => 200
Zombie: Loaded document http://localhost:3000/
GET /javascripts/bootstrap.min.js 200 4ms - 27.08kb
Zombie: GET http://localhost:3000/javascripts/jquery-2.0.3.min.js => 200
Zombie: GET http://localhost:3000/javascripts/bootstrap.min.js => 200
GET /javascripts/jquery-2.0.3.min.js 200 41ms - 81.65kb
<html></html>
Zombie: Event loop is empty
✓ should show welcome (414ms)
It appears that the problem might have to do with timing. The document is loaded, then the Javascript files are loaded. I'm wondering if zombie is executing my callback function before the Javascript is loaded, therefore the DOM is empty at that point. Any ideas?
Update:
This was solved by wprl's suggestion below.
Here is the test that works, after adding a wait function:
it('should show welcome', function(done) {
// Wait until page is loaded
function pageLoaded(window) {
return window.document.querySelector(".container");
}
var browser = this.browser;
browser.visit("/");
browser.wait(pageLoaded, function() {
console.log(browser.html());
});
done();
});
I'll have to rewrite my test logic a bit now, but the key to getting it to work was the wait function.
It does sound like timing might be an issue. On the other hand, Zombie is good about giving you control only after JavaScript events have stopped when using visit.
A good strategy to use is to browser.wait
for a certain DOM element to appear before proceeding with your tests. That way you know e.g. Bootstrap has loaded and shown element #widget-view
.
Might want to adjust maxWait
/waitFor
as well.
At least then you could rule out the timing issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With