Delonous Delonous - 5 months ago 29
Node.js Question

Mocha: using it-each with dependent variables

So I've been having some trouble with the it-each module for loop testing in mocha. I'm using supertest, should and it-each modules.

var hasAccess = [{endpoint: "announcements", send: {"creator": users}}]


users is my varibale which is assigned in this test

it('users', function(done) {
api.get('/users')
.set('Accept', 'application/json')
.set('Authorization', devToken)
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) return done(err)
res.body[0].should.have.property('id')
users = res.body[0].id //<----------
done()
});
});


My it-each

it.each(hasAccess, 'should return 201 perfoming a POST on %s', ['endpoint'], function(element, next) {

console.log(element.send) //prints out "creator": undefined

api.post('/' + element.endpoint)
.set('Accept', 'application/json')
.set('Authorization', userToken)
.expect('Content-Type', /json/)
.send(element.send)
.expect(201)
.end(function(err, res) {
if (err) return next(err)
res.status.should.equal(201)
next()
});
});


Problem is, hasAccess is being passed into the it-each before users is assigned a value. I know it's bad practice to make tests dependent on each other, but there isn't really another way to test this. I need the id to completely test this. So any ideas?
Also there will be more objects in hasAccess, so a loop is the best way to do it. Just shortened it for this.

Answer

You really shouldn't make tests dependent on one another, but if you must...

The problem is not with it.each but with how you are storing the user id you get in your first test. You create your array like this:

var hasAccess = [{endpoint: "announcements", send: {"creator": users}}]

This takes the value from users for the hasAccess[0].send.creator field. It is undefined at that point so the field gets the value undefined. From this point on, the changes you do to users won't affect the values stored in hasAccess. If users were an object, then hasAccess would have a reference to that object and modifying the object would be reflected in hasAccess but it is a primitive value: undefined. So further changes to users have no effect here.

In order for the change to carry forward, your first test could get to the field by going through the hasAccess array.

Here's an illustration of how it could be done. I've simulated the asynchronous processes with setTimeout:

require("it-each")();
var assert = require("assert");

var users;
var hasAccess = [{endpoint: "announcements", send: {"creator": users}}];

it("get users", function (done) {
    setTimeout(function () {
        // Wrong way:
        // users = "foo";

        // Right way:
        hasAccess[0].send.creator = "foo";
        done();
    }, 1000);
});


it.each(hasAccess, 'should return 201 perfoming a POST on %s', ['endpoint'],
        function(element, next) {
            setTimeout(function () {
                assert(element.send.creator === "foo");
                // console.log(element);
                next();
            }, 1000);
        });