867MS

MS

19

Suites

39

Tests

39

Passed

0

Failed

0

Pending

0% Pending
100% Passing

Unit suite - The `errorHandler` function

/test/unit/lib/error-handler.js
  • 4 ms
  • 3
  • 3
  • 0
  • 0

Tests

should send the custom error if it's an instance of MWError

2 ms
var res = getResponse();
                        errorHandler(res, new MWError(400, "Message"));
                        res.status.calledWith(400).should.equal(true);
                        res.send.calledWith({error: "Message"}).should.equal(true);

should send a 500 if the error is not an instance of MWError

1 ms
var res = getResponse();
                        errorHandler(res, new Error("Message"));
                        res.status.calledWith(500).should.equal(true);
                        res.send.calledWith({error: "Internal server error"}).should.equal(true);

should log an error if the error is not an instance of MWError

1 ms
var error = new Error("Message");
                        var res = getResponse();
                        errorHandler(res, error);
                        console.error.calledWith(error).should.equal(true);

Unit suite - The `getLastValidDate` function

/test/unit/lib/get-last-valid-date.js
  • 0 ms
  • 1
  • 1
  • 0
  • 0

Tests

should get the last valid date from now

0 ms
var EIGHTYNINE_DAYS_AGO_IN_MS = Date.now() - (89 * 24 * 60 * 60 * 1000);
                        var ret = getLastValidDate();
                        (ret.getTime() < EIGHTYNINE_DAYS_AGO_IN_MS).should.equal(true);

Unit suite - The `getUserFromToken` function

/test/unit/lib/get-user-from-token.js
  • 2 ms
  • 1
  • 1
  • 0
  • 0

Tests

should return a thenable

2 ms
var mwInstance = {
                            db: {
                                collection: function () {
                                    return {
                                        findOne: R.always(null)
                                    };
                                }
                            }
                        };
                        var ret = getUserFromToken(mwInstance, "loginToken");
                        ret.then.should.be.of.type("function");

Unit suite - The `hashLoginToken` function

/test/unit/lib/hash-login-token.js
  • 0 ms
  • 1
  • 1
  • 0
  • 0

Tests

should hash with sha256 the passed in string and return it as a base64 string

0 ms
var ret = hashLoginToken("hello");
                        ret.should.equal("LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=");

Unit suite - The `resultHandler` function

/test/unit/lib/result-handler.js
  • 1 ms
  • 1
  • 1
  • 0
  • 0

Tests

should send the provided response with a 200 HTTP code

1 ms
var res_0 = getResponse();
                                resultHandler(res_0, {});
                                res_0.status.calledWith(200).should.equal(true);
                                res_0.send.calledWith({result: {}}).should.equal(true);
                                var res_1 = getResponse();
                                resultHandler(res_1, undefined);
                                res_1.status.calledWith(200).should.equal(true);
                                res_1.send.calledWith({result: null}).should.equal(true);

Unit suite - The `_runMethod` method

/test/unit/methods/_runMethod.js
  • 5 ms
  • 3
  • 3
  • 0
  • 0

Tests

should return a thenable

2 ms
var ret = methods._runMethod({}, "", []);
                        ret.catch(R.identity);
                        ret.then.should.be.of.type("function");

should actually call the method

1 ms
var ctx = {
                            _methods: {
                                method: {
                                    fn: sinon.spy(),
                                    context: {}
                                }
                            }
                        };
                        methods._runMethod.call(ctx, {}, "method", [])
                            .then(function () {
                                try {
                                    ctx._methods.method.fn.called.should.equal(true);
                                } catch (e) {
                                    return done(e);
                                }
                                done();
                            })
                            .catch(done);

should call the method with the additional context we provide when registering it

2 ms
var ctx = {
                            _methods: {
                                method: {
                                    fn: sinon.spy(),
                                    context: {
                                        prop: "value"
                                    }
                                }
                            }
                        };
                        methods._runMethod.call(ctx, {userId: null}, "method", [])
                            .then(function () {
                                try {
                                    ctx._methods.method.fn.firstCall.thisValue.should.eql({
                                        userId: null,
                                        prop: "value"
                                    });
                                } catch (e) {
                                    return done(e);
                                }
                                done();
                            })
                            .catch(done);

Unit suite - The promise returned by `_runMethod`

/test/unit/methods/_runMethod.js
  • 2 ms
  • 3
  • 3
  • 0
  • 0

Tests

should be rejected if the method does not exist

0 ms
var ctx = {
                            _methods: {}
                        };
                        methods._runMethod.call(ctx, {}, "method", [])
                            .then(function () {
                                done("The promise should have been rejected");
                            })
                            .catch(function (err) {
                                try {
                                    err.code.should.equal(404);
                                    err.message.should.equal("Method not found");
                                } catch (e) {
                                    return done(e);
                                }
                                done();
                            });

should be rejected if the method throws

1 ms
var error = {};
                        var ctx = {
                            _methods: {
                                method: {
                                    fn: sinon.stub().throws(error),
                                    context: {}
                                }
                            }
                        };
                        methods._runMethod.call(ctx, {}, "method", [])
                            .then(function () {
                                done("The promise should have been rejected");
                            })
                            .catch(function (err) {
                                try {
                                    err.should.equal(error);
                                } catch (e) {
                                    return done(e);
                                }
                                done();
                            });

should be resolved with the value returned by the method

1 ms
var value = {};
                        var ctx = {
                            _methods: {
                                method: {
                                    fn: sinon.stub().returns(value),
                                    context: {}
                                }
                            }
                        };
                        methods._runMethod.call(ctx, {}, "method", [])
                            .then(function (val) {
                                try {
                                    val.should.equal(value);
                                } catch (e) {
                                    return done(e);
                                }
                                done();
                            })
                            .catch(done);

Unit suite - The `getRouter` method

/test/unit/methods/getRouter.js
  • 17 ms
  • 1
  • 1
  • 0
  • 0

Tests

should return an express.Router

17 ms
/*
                        *   express routers are not instances of any class, therefore we can't
                        *   use `instanceOf` for this test. Instead we test it against the
                        *   current implementation, where a router is a function which has,
                        *   according to its API, a `use` property (which is a function too).
                        */
                        var router = methods.getRouter();
                        router.should.be.of.type("function");
                        router.use.should.be.of.type("function");

Unit suite - The function returned by `getRouter`

/test/unit/methods/getRouter.js
  • 3 ms
  • 1
  • 1
  • 0
  • 0

Tests

should call the `_runMethod` method

3 ms
var ctx = {
                            _runMethod: sinon.spy(function () {
                                return new BPromise(R.identity);
                            })
                        };
                        var route = methods.getRouter.call(ctx);
                        /*
                        *   Mock the request "only as much as needed" to make it pass through
                        *   the router. We accept this poor compromise since this part is also
                        *   thoroughly tested with integration tests.
                        */
                        var req = {
                            url: "/",
                            method: "POST",
                            context: {},
                            /*
                            *   If the bodyParser middleware finds a _body property on the
                            *   request, it lets it through.
                            */
                            _body: "notUndefined",
                            body: {
                                method: "method",
                                params: []
                            }
                        };
                        var res = {};
                        var next = R.identity;
                        route(req, res, next);
                        ctx._runMethod.calledWith(req.context, req.body.method, req.body.params).should.equal(true);

Unit suite - The `methods` method

/test/unit/methods/methods.js
  • 2 ms
  • 2
  • 2
  • 0
  • 0

Tests

should register methods

1 ms
var ctx = {
                            _methods: {}
                        };
                        var optionalContext = {};
                        methods.methods.call(ctx, {
                            name: R.identity
                        }, optionalContext);
                        ctx._methods.name.fn.should.equal(R.identity);
                        ctx._methods.name.context.should.equal(optionalContext);

should type-check its arguments (throwing in case of mismatches)

1 ms
var ctx = {
                            _methods: {}
                        };
                        var troublemaker_0 = function () {
                            methods.methods.call(ctx, {
                                name: "notAFunction"
                            });
                        };
                        troublemaker_0.should.throw();
                        var troublemaker_1 = function () {
                            methods.methods.call(ctx, {
                                name: R.identity
                            }, "notAnObject");
                        };
                        troublemaker_1.should.throw();

Unit suite - The `bodyValidation` middleware getter

/test/unit/middleware/bodyValidation.js
  • 0 ms
  • 1
  • 1
  • 0
  • 0

Tests

should return a middleware function

0 ms
var bodyValidationMiddleware = middleware.bodyValidation();
                        bodyValidationMiddleware.should.be.of.type("function");
                        bodyValidationMiddleware.length.should.equal(3);

Unit suite - The middleware function returned by the `bodyValidation` middleware getter

/test/unit/middleware/bodyValidation.js
  • 2 ms
  • 2
  • 2
  • 0
  • 0

Tests

should stop the request with an error if the body is malformed

1 ms
var req = {
                            body: "malformed body"
                        };
                        var res = {
                            status: sinon.spy(function () {
                                return res;
                            }),
                            send: sinon.spy()
                        };
                        var next = sinon.spy();
                        var bodyValidationMiddleware = middleware.bodyValidation();
                        bodyValidationMiddleware(req, res, next);
                        res.status.called.should.equal(true);
                        res.send.called.should.equal(true);

should let the request through if the body is well-formed

1 ms
var req = {
                            body: {
                                method: "method",
                                params: []
                            }
                        };
                        var res = {};
                        var next = sinon.spy();
                        var bodyValidationMiddleware = middleware.bodyValidation();
                        bodyValidationMiddleware(req, res, next);
                        next.called.should.equal(true);

Unit suite - The `context` middleware getter

/test/unit/middleware/context.js
  • 0 ms
  • 1
  • 1
  • 0
  • 0

Tests

should return a middleware function

0 ms
var contextMiddleware = middleware.context();
                        contextMiddleware.should.be.of.type("function");
                        contextMiddleware.length.should.equal(3);

Unit suite - The middleware function returned by the `context` middleware getter

/test/unit/middleware/context.js
  • 0 ms
  • 1
  • 1
  • 0
  • 0

Tests

should attach a default context to the request

0 ms
var req = {};
                        var res = {};
                        var next = sinon.spy();
                        var contextMiddleware = middleware.context();
                        contextMiddleware(req, res, next);
                        req.context.should.eql({userId: null});
                        next.called.should.equal(true);

Unit suite - The `user` middleware getter

/test/unit/middleware/user.js
  • 0 ms
  • 1
  • 1
  • 0
  • 0

Tests

should return a middleware function

0 ms
var userMiddleware = middleware.user();
                        userMiddleware.should.be.of.type("function");
                        userMiddleware.length.should.equal(3);

Unit suite - The middleware function returned by the `user` middleware getter

/test/unit/middleware/user.js
  • 1 ms
  • 3
  • 3
  • 0
  • 0

Tests

should let the request through if it doesn't have a `loginToken`

0 ms
var userMiddleware = middleware.user();
                        var req = {body: {}};
                        var res = {};
                        var next = sinon.spy();
                        userMiddleware(req, res, next);
                        next.called.should.equal(true);

should 401 if there's an invalid `loginToken` (which doesn't match any user)

1 ms
var userMiddleware = middleware.user({
                            db: {
                                collection: R.always({
                                    findOne: function (selector, cb) {
                                        cb(null, undefined);
                                    }
                                })
                            }
                        });
                        var req = {
                            body: {
                                loginToken: "invalid"
                            }
                        };
                        var res = {
                            status: sinon.spy(function () {
                                return res;
                            }),
                            send: sinon.spy(function () {
                                var err;
                                try {
                                    res.status.calledWith(401).should.equal(true);
                                    res.send.called.should.equal(true);
                                    res.send.calledWith({error: "Invalid loginToken"}).should.equal(true);
                                } catch (e) {
                                    err = e;
                                }
                                done(err);
                            })
                        };
                        var next = sinon.spy();
                        userMiddleware(req, res, next);

should let the request through and attach the user object to the context

0 ms
var userMiddleware = middleware.user({
                            db: {
                                collection: R.always({
                                    findOne: function (selector, cb) {
                                        cb(null, {_id: "userId"});
                                    }
                                })
                            }
                        });
                        var req = {
                            body: {
                                loginToken: "valid"
                            },
                            context: {}
                        };
                        var res = {};
                        var next = sinon.spy(function () {
                            var err;
                            try {
                                req.context.userId.should.equal("userId");
                                req.context.user.should.eql({_id: "userId"});
                                next.called.should.equal(true);
                            } catch (e) {
                                err = e;
                            }
                            done(err);
                        });
                        userMiddleware(req, res, next);

Integration suite - Bad requests

/test/integration/bad-requests.js
  • 28 ms
  • 1
  • 1
  • 0
  • 0

Tests

the server should reply a 400 on malformed body

28 ms
var mw = new MW(db);
                        var app = express().use("/", mw.getRouter());
                        return request(app)
                            .post("/")
                            .send({unexpectedProp: "unexpectedValue"})
                            .expect("Content-Type", /json/)
                            .expect(400);

Integration suite - Methods

/test/integration/methods.js
  • 74 ms
  • 8
  • 8
  • 0
  • 0

Tests

that do not exist

10 ms
var mw = new MW(db);
                        var app = express().use("/", mw.getRouter());
                        return request(app)
                            .post("/")
                            .send({method: "nonexistentMethod", params: []})
                            .expect("Content-Type", /json/)
                            .expect(404)
                            .expect({error: "Method not found"});

that return undefined

3 ms
var mw = new MW(db);
                        mw.methods({
                            "return:value": function () {
                            }
                        });
                        var app = express().use("/", mw.getRouter());
                        return request(app)
                            .post("/")
                            .send({method: "return:value", params: []})
                            .expect("Content-Type", /json/)
                            .expect(200)
                            .expect({result: null});

that return a value

3 ms
var mw = new MW(db);
                        mw.methods({
                            "return:value": function () {
                                return "return:value";
                            }
                        });
                        var app = express().use("/", mw.getRouter());
                        return request(app)
                            .post("/")
                            .send({method: "return:value", params: []})
                            .expect("Content-Type", /json/)
                            .expect(200)
                            .expect({result: "return:value"});

that throw a MW.Error

3 ms
var mw = new MW(db);
                        mw.methods({
                            "throw:mw-error": function () {
                                throw new MW.Error(499, "MW.Error");
                            }
                        });
                        var app = express().use("/", mw.getRouter());
                        return request(app)
                            .post("/")
                            .send({method: "throw:mw-error", params: []})
                            .expect("Content-Type", /json/)
                            .expect(499)
                            .expect({error: "MW.Error"});

that throw a generic error

4 ms
var mw = new MW(db);
                        mw.methods({
                            "throw:generic-error": function () {
                                throw new Error("Generic error");
                            }
                        });
                        var app = express().use("/", mw.getRouter());
                        return request(app)
                            .post("/")
                            .send({method: "throw:generic-error", params: []})
                            .expect("Content-Type", /json/)
                            .expect(500)
                            .expect({error: "Internal server error"});

that return a promise which is eventually resolved

17 ms
var mw = new MW(db);
                        mw.methods({
                            "return:promise:resolved": function () {
                                return new BPromise(function (resolve, reject) {
                                    setTimeout(function () {
                                        resolve("return:promise:resolved");
                                    }, 10);
                                });
                            }
                        });
                        var app = express().use("/", mw.getRouter());
                        return request(app)
                            .post("/")
                            .send({method: "return:promise:resolved", params: []})
                            .expect("Content-Type", /json/)
                            .expect(200)
                            .expect({result: "return:promise:resolved"});

that return a promise which is eventually rejected with an MW.Error

17 ms
var mw = new MW(db);
                        mw.methods({
                            "return:promise:rejected:mw-error": function () {
                                return new BPromise(function (resolve, reject) {
                                    setTimeout(function () {
                                        reject(new MW.Error(499, "MW.Error"));
                                    }, 10);
                                });
                            }
                        });
                        var app = express().use("/", mw.getRouter());
                        return request(app)
                            .post("/")
                            .send({method: "return:promise:rejected:mw-error", params: []})
                            .expect("Content-Type", /json/)
                            .expect(499)
                            .expect({error: "MW.Error"});

that return a promise which is eventually rejected with a generic error

17 ms
var mw = new MW(db);
                        mw.methods({
                            "return:promise:rejected:generic-error": function () {
                                return new BPromise(function (resolve, reject) {
                                    setTimeout(function () {
                                        reject(new Error("Generic error"));
                                    }, 10);
                                });
                            }
                        });
                        var app = express().use("/", mw.getRouter());
                        return request(app)
                            .post("/")
                            .send({method: "return:promise:rejected:generic-error", params: []})
                            .expect("Content-Type", /json/)
                            .expect(500)
                            .expect({error: "Internal server error"});

Integration suite - User auth

/test/integration/user-auth.js
  • 16 ms
  • 4
  • 4
  • 0
  • 0

Tests

the server should auth the user if the loginToken is valid

7 ms
var mw = new MW(db);
                        mw.methods({
                            getUserId: function () {
                                return this.userId;
                            }
                        });
                        var app = express().use("/", mw.getRouter());
                        return request(app)
                            .post("/")
                            .send({method: "getUserId", params: [], loginToken: "loginToken"})
                            .expect("Content-Type", /json/)
                            .expect(200)
                            .expect({result: "userId"});

if the user is authenticated, methods should have available `this.userId` and `this.user`

1 ms
db.collection("users").findOne({_id: "userId"}, function (err, user) {
                            // Stringify and parse to convert the Date object at `services.resume.loginTokens.when`
                            user = JSON.parse(JSON.stringify(user));
                            var mw = new MW(db);
                            mw.methods({
                                getUserIdAndUser: function () {
                                    return [this.userId, this.user];
                                }
                            });
                            var app = express().use("/", mw.getRouter());
                            return request(app)
                                .post("/")
                                .send({method: "getUserIdAndUser", params: [], loginToken: "loginToken"})
                                .expect("Content-Type", /json/)
                                .expect(200)
                                .expect({result: ["userId", user]});
                        });

the server should reply 403 if the loginToken is invalid

5 ms
var mw = new MW(db);
                        mw.methods({
                            getUserId: function () {
                                return this.userId;
                            }
                        });
                        var app = express().use("/", mw.getRouter());
                        return request(app)
                            .post("/")
                            .send({method: "getUserId", params: [], loginToken: "invalidLoginToken"})
                            .expect("Content-Type", /json/)
                            .expect(401)
                            .expect({error: "Invalid loginToken"});

the server should let requests without loginToken through

3 ms
var mw = new MW(db);
                        mw.methods({
                            getUserId: function () {
                                return this.userId;
                            }
                        });
                        var app = express().use("/", mw.getRouter());
                        return request(app)
                            .post("/")
                            .send({method: "getUserId", params: []})
                            .expect("Content-Type", /json/)
                            .expect(200)
                            .expect({result: null});