Michal Zimmermann Michal Zimmermann - 4 months ago 14
Node.js Question

Node.js es6 module export async variable

I've implemented tests with

supertest
that are run after the user logs in:

// ../prepare.login
"use strict";

import {default as request} from "supertest";
import {default as app} from "../../server.js";

const postUrl = "/api/v1/login";
const postData = {
"username": "user",
"password": "pass"
};

module.exports = {
prepare: function(done) {
request(app.listen())
.post(postUrl)
.send(postData)
.end((err, res) => {
if (err) {
throw err;
}
module.exports.token = res.body.token;
done();
});
}
}


Until now I was using es5 and used that
module.exports.token
as sort of ugly hack to send the token to the actual test:

// users.js
...
var login = require("../prepare.login");

describe("authenticated /api/v1/users", function() {
beforeEach(function(done) {
login.prepare(done);
});
});

...

it("On GET /api/v1/users I want to get all the users in an array", function(done) {
request(app.listen())
.get("/api/v1/users")
.set("X-Access-Token", login.token)
.expect(200)
...


I switched to es6 that doesn't allow
import
and
export
statements anywhere else than the top level of the module. Thus, I'm not really sure how this should be implemented. Should I wait asynchronously for the result? Is it even possible? Is there any other way?

Answer

es6 doesn't allow import and export statemens anywhere else than the top level of the module

Yes, but that's only where the variable declarations need to be. You still can assign to them whereever you want.

import {default as request} from "supertest";
import {default as app} from "../../server.js";

const postUrl = "/api/v1/login";
const postData = {
    "username": "user",
    "password": "pass"
};

export let token = null;
export function prepare(done) {
    request(app.listen())
        .post(postUrl)
        .send(postData)
        .end((err, res) => {
            if (err) return done(err);
            token = res.body.token;
            done();
        });
}

import {prepare, token} from "prepare.login";
…

Is there any other way?

Yes. Instead of mutating global variables (despised since ages), you should rather pass the token to the callback:

…
.end((err, res) => {
    if (err) done(err);
    else done(null, res.body.token);
});

so that you can extract it where you need it:

let token = null;
describe("authenticated /api/v1/users", function() {
    beforeEach(function(done) {
        login.prepare(function(err, t) {
            if (err) return done(err);
            token = t;
            done();
        });
    });
});

Is there an even better way?

Like in the second approach, don't use an exported variable; but instead of calling cumbersome callbacks just return a promise for the token.

Comments