Search code examples
javascriptjasminephantomjsjsdomheadless-browser

Load a web page into a headless Jasmine spec running PhantomJS


How do I read in a page from localhost into a headless Jasmine spec so test cases can work on the DOM elements?

My Gulp task is successfully running Jasmine specs for unit testing, and now I need to build integration tests to verify full web pages served from localhost. I'm using the gulp-jasmine-browser plugin to run PhantomJS.

Example:

gulpfile.js

var gulp =           require('gulp');
var jasmineBrowser = require('gulp-jasmine-browser');

function specRunner() {
   gulp.src(['node_modules/jquery/dist/jquery.js', 'src/js/*.js', 'spec/*.js'])
      .pipe(jasmineBrowser.specRunner({ console: true }))
      .pipe(jasmineBrowser.headless());
   }

gulp.task('spec', specRunner);


spec/cart-spec.js

describe('Cart component', function() {

   it('displays on the gateway page', function() {
      var page = loadWebPage('http://localhost/');  //DOES NOT WORK
      var cart = page.find('#cart');
      expect(cart.length).toBe(1);
      });

   });

There is no loadWebPage() function. It's just to illustrate the functionality I believe is needed.


Solution

  • jsdom to the rescue!

    It turns out it's pretty easy to load a web page into a headless Jasmine spec... but you need to swap out PhantomJS for jsdom.

    Strategy:

    1. Use Jasmine's beforeAll() to call a function that will run JSDOM.fromURL() to request the web page.
    2. Once the web page has been loaded into the DOM, expose window and jQuery for use in your test cases.
    3. Finally, call done() to indicate the tests are now ready to run.

    Make sure to close the window after the tests have run.

    spec.js

    const url  = 'http://dnajs.org/';
    const { JSDOM } = require('jsdom');
    let window, $;
    function loadWebPage(done) {
       function handleWebPage(dom) {
          function waitForScripts() {
             window = dom.window;
             $ = dom.window.jQuery;
             done();
             }
          dom.window.onload = waitForScripts;
          }
       const options = { resources: 'usable', runScripts: 'dangerously' };
       JSDOM.fromURL(url, options).then(handleWebPage);
       }
    function closeWebPage() { window.close(); }
    
    describe('The web page', () => {
    
       beforeAll(loadWebPage);
       afterAll(closeWebPage);
    
       it('has the correct URL', () => {
          expect(window.location.href).toBe(url);
          });
    
       it('has exactly one header, main, and footer', () => {
          const actual =   {
              header: $('body >header').length,
              main:   $('body >main').length,
              footer: $('body >footer').length
              };
          const expected = { header: 1, main: 1, footer: 1 };
          expect(actual).toEqual(expected);
          });
    
       });
    


    Test output

    screenshot
    Note: Above screenshot is from a similar Mocha spec since Mocha has a nice default reporter.

    Project

    It's on GitHub if you want try it out yourself:
    https://github.com/dnajs/load-web-page-jsdom-jasmine


    EDITED: Updated for jsdom 11