7

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?

raichu
  • 688
  • 2
  • 8
  • 15
  • Could you show us an example of a step where this happens? – RedMage Dec 15 '16 at 23:05
  • I updated it a little. I don't have the exact code anymore, since I worked around it. One of the things that I understand by now is that everything in the support folder is loaded by cucumber automatically. Since I loaded them manually, it probably created two World objects. But I still don't know why it used my own World object in the Given steps, and then the cucumber generated World object in the Then steps. I'd still like too understand the details about the lifecycle and use cases for the World object, if you happen to know. Thanks. – raichu Dec 16 '16 at 13:32
  • 1
    You hit the nail on the head. As soon as I saw your updated code assigning the World variable I thought to myself "This will spell all kinds of trouble". I do not know the specifics, but I will leave you with something potentially more helpful: there is a module called "chimpjs". If you are using cucumber for web interface testing then I cannot recommend it strongly enough. It ties together cucumber, webdriverio, chai, and some other goodies. It managers selenium for you, and it uses fibers, so you can write your tests in sychronous style. – RedMage Dec 18 '16 at 02:29
  • Create an answer saying that it was the duplication of the World object. Then select it as the correct answer. That way the is one less eternally unanswered question. Or just delete the question altogether – RedMage Dec 18 '16 at 17:40

1 Answers1

6

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.

Community
  • 1
  • 1
raichu
  • 688
  • 2
  • 8
  • 15