Last Updated: February 25, 2016
·
1.791K
· drgorb

Testing Meteor with CucumberJS

Introduction

Now that velocity has been elected the official Meteor testing platform it is worth spending some time to learn the thing.

This is an example about how to test a Meteor app on the client side with CucumberJS and the Zombie headless browser.

Setup

We need a Meteor app to test and the testing framework to execute our tests. Let us set it all up

Creating the app

this is a normal Meteor app created with meteor create myApp

once the app folder exists, we need a tests folder in it with the following structure
+ tests
++ features
+++ step_definitions
+++ support

the cucumber world

the testing environment is setup in a file called world.coffee or world.js which goes into the support folder. Our setup is world.coffee and looks like this:

module.exports = ->
  @World = class MultiWorld extends Cucumber.World
    constructor: ->
      @zombie = new Cucumber.World.Zombie
      @selenium = new Cucumber.World.Selenium if Package.selenium?
      @protractor = new Cucumber.World.Protractor if Package.selenium?
      super

mrt packages

these packages can be installed with mrt add
* velocity
* cucumber
* velocity-html-reporter

The application

The application is the default Meteor one with just a little tweak: we add an input field and handle the change event on it to have something to test.

HTML

<head>
   <link rel="icon" sizes="16x16 32x32" href="/favicon.png?v=2">
   <title>app</title>
</head>

<body>
{{> hello}}
</body>

<template name="hello">
   <h1 id="greeting">Hello {{name}}!</h1>
   <input id="name"/><br>
   {{greeting}}
   <input type="button" value="Click"/>

</template>

Template JavaScript

if (Meteor.isClient) {
   Template.hello.helpers(
      {
         greeting: function () {
            console.log("retunring greeting text")
            return "Welcome to app.";
         },

         name: function() {
            return Session.get("name");
         }
      })

   Template.hello.events(
      {
         'change #name': function () {
            console.log("changing the name");
            Session.set("name", $("#name").val());
         },

         'click input': function () {
            // template data, if any, is available in 'this'
            if (typeof console !== 'undefined')
               console.log("You pressed the button");
         }
      });
}

Tests

Now we need a test. In Cucumber this is a Feature which gets implemented in JavaScript or CoffeeScript.

Feature file

the file containing the description is hello.feature and must be placed in the tests/features folder of the application. The name of the file is meaningful and must be used in the definition and the implementation of the test scenarios. You can read all about it in the CucumberJs documentation.

@zombie
Feature: Display hello world on the home page

  Scenario: Go to the home page and see the hello world message
    Given the application has been created
    When I go to the home page and enter "Micha" in the name field
    Then I should see "Hello Micha!" on the page

Test implementation

In order to have something to execute we need to implement the feature in a javascript file. The file must be called hello.js in our case. The name must be the same as the feature

module.exports = function () {

   this.Given(/^the application has been created$/, function (callback) {
      callback();
   });

   this.When(/^I go to the home page and enter "([^"]*)" in the name field$/, function (name, callback) {
      var z = this.zombie
      z.home(function(){
         z.browser.fill("#name", name)
         z.browser.evaluate("$('#name').change()");
         z.browser.wait(1000, callback);
      })
   });

   this.Then(/^I should see "([^"]*)" on the page$/, function (greeting, callback) {
      var browser = this.zombie.browser;
      var actualGreeting = browser.text("#greeting");
      if(greeting == actualGreeting) {
         callback();
      } else {
         callback.fail(actualGreeting + " not equal to expected " + greeting);
      }
   });
}

If you are familiar with zombieJs, you might have noticed that the change event was not triggered in the usual zombie manner with browser.fire but with the evaluation of some javascript z.browser.evaluate("$('#name').change()") this was necessary as the normal way did not work with meteor. This is probably linked to issue 181 in zombie

Execution

you can clone the repository with all the files from github with clone git@github.com:drgorb/meteor-cucumber-example.git

change to the application's directory and launch with mrt you should see the tests pass