World object in cucumber.js or where to put state in cucumber tests

raichu picture raichu · Dec 13, 2016 · Viewed 8.7k times · Source

I'm trying to save the current navigation state in one step (the page on a platform with multiple websites) in cucumber.js so the following steps of a scenario can deal with it. I thought using the World object for it, but mysterious things are happening.

I have a navigation state object like this:

module.exports = {
    pageName:null,
    siteName: null,
    isLoggedIn: false
}

Then I have a NavigationStateManager like this

function NavigationStateManager() {
    var state
    this.setState = function(stateP) {
       state = stateP
    }
    this.setPage = function(pageNameP, siteNameP, isLoggedInP) {
        // among other things do something link this:
        state.pageName = pageNameP
        state.siteName = siteNameP
        state.isLoggedIn = isLoggedInP
    }
}

And I have a World object

var navState = require('./navigation-state')
var NavigationStateManager = require('./navigation-state-manager')

var navigationStateManager = new NavigationStateManager()

function World() {
    this.navState = simpleCopy(navState)
    navigationStateManager.setState(this.navState)
}

function simpleCopy(objectToCopy) {
    var copy = {}
    for(var key in objectToCopy) {
       copy[key] = objectToCopy[key]
    }
    return copy
}

In my steps file I do this

var World = require('../support/world')

module.exports = function() {
   this.World = World

   this.Given(...)
   this.Then(...)
}

For some reason the state becomes undefined in the NavigationStateManager when the Given steps have been executed and the Then steps are being executed. When I log I can't see setState being called with an 'undefined' argument. I've had a different setup, putting the NavigationStateManager on the World object, but it gave me similar issues. Apparently the World object doesn't remain the same through all steps of a scenario, but how does it behave. The error seems to go against all JavaScript knowledge I have. Where do I put state in my tests?

Answer

raichu picture raichu · Dec 18, 2016

All support files that export a function will be called with a context that exposes the following methods:

source: https://github.com/cucumber/cucumber-js/blob/master/docs/support_files/api_reference.md

I hadn't read this (and probably wouldn't have understood). I also confused the this reference to the context object and the this reference to a world object.

With context they mean the object that is exposed as this in the functions you export. It is the interface to interact with the Cucumber API.

This so called context object shouldn't be confused, with the world object. The world object is the this reference inside your steps, and is created by Cucumber from the World constructor you set on the context object (or the default if you don't set one) for every scenario.

Lastly you should not require and create new instances of any constructor exported in the support folder as I did. Since Cucumber automatically calls these constructors, you'll end up with two instances of the same object. Put your own helper objects, like a PageObject, in an separate folder.