Context in mocha test is undefined - node.js

So I'm using mocha and node to test some apis. I have a test that goes
import { describe, before, it, xit } from 'mocha';
describe('test my scenarios dude', () => {
before('do all my pre-test stuff', () => {
const blah = blah;
});
it('tests my really useful test', () => {
const testName = this.test.ctx.currentTest.fullTitle();
});
});
The 'this' is undefined though. How can I get the test name?

https://mochajs.org/#arrow-functions
as docs says Passing arrow functions (“lambdas”) to Mocha is discouraged
use function instead
describe('test my scenarios dude', function() {
before('do all my pre-test stuff', function() {
const blah = blah;
});
it('tests my really useful test', function() {
const testName = this.test.ctx.currentTest.fullTitle();
});
});
also you can read more about arrow functions here. they don't have this

Related

Nodejs, Serverless expected stub function to be called once but was called 0 times

I have been the said error when trying to create a stub from sinon in my test function. I am trying to test a function responsible to make http calls to other endpoints. I am trying to understand why Its not resolving to the output provided.
const sinon = require('sinon');
const sandbox = sinon.createSandbox();
describe('test endpoint', () => {
it('should be test function', async () => {
const stub = sinon.stub(someServiceMock.POST, '/funcName').resolves({ status: 204 });
sinon.assert.calledOnce(stub);
});
});
});
and getting AssertError: expected '/funcName' to be called once but was called 0 times
The object i pass in the stub is
const someServiceMock = {
POST: {
'/funcName': () => {},
},
};
The stubbed function is never called in the code-sample you provided. If you actually call the funtion with
describe('test endpoint', () => {
it('should be test function', async () => {
const stub = sinon.stub(someServiceMock.POST, '/funcName').resolves({ status: 204 });
someServiceMock.POST["/funcName"]();
sinon.assert.calledOnce(stub);
});
});
the test should pass as expected.

How to use resetMocks:true with module factory mocks

I would like to mock imported modules while keeping my unit tests independent of each other.
Setting resetMocks:true in my Jest config file means that behaviour set up using module factory mocking is lost (issue). Setting up module mocks in any other way doesn't work (issue).
Changing to resetMocks:false couples the unit tests and makes the order they are executed matter, which goes against unit testing best practices.
I have tried calling jest.mock('./a', () => {/* implementation */}) inside beforeEach() and at the top of test(). I have also tried to use a reference to a jest.fn() inside the module factory mock and then call .mockImplementation() on that reference.
Minimum demonstration:
// greeter.ts
export class Greeter {
sayHello(): string {
return 'hello world!';
}
}
// module-mocking.spec.ts
import { Greeter } from "./greeter";
jest.mock('./greeter', () => ({
Greeter: jest.fn(() => ({ sayHello: () => 'goodbye world!' }))
}));
test('mocked module behaviour should exist', () => {
const result = new Greeter().sayHello();
expect(result).toEqual('goodbye world!');
});
This test fails with the error:
TypeError: (intermediate value).sayHello is not a function
Moving the jest.mock() inside beforeEach() or into test() results in:
Expected: "goodbye world!" Received: "hello world!"
Edit
I managed to work around this by using require instead of import. The question still remains for ES6 imports.
// module-mocking.spec.ts
const greeter = require("./greeter");
let mockGreeter: any;
beforeEach(() => {
mockGreeter = { sayHello: () => 'goodbye world!' };
greeter.Greeter = jest.fn(() => mockGreeter);
});
test('mocked module behaviour should exist', () => {
const result = new Greeter().sayHello();
expect(result).toEqual('goodbye world!');
});

Why won't these chai tests fail?

We have some simple "is this really working" chai tests of an electron app using spectron and WebdriverIO. The example code we started with is from
https://github.com/jwood803/ElectronSpectronDemo as reported in https://github.com/jwood803/ElectronSpectronDemo/issues/2, the chai-as-promised tests are not catching mismatches, so I thought I would add some additional tests to find out why Chai is not failing tests where the electron app has text that doesn't match the expected unit test text.
Let's start with something really simple, the rest of the code is at https://github.com/drjasonharrison/ElectronSpectronDemo
describe('Test Example', function () {
beforeEach(function (done) {
app.start().then(function() { done(); } );
});
afterEach(function (done) {
app.stop().then(function() { done(); });
});
it('yes == no should fail', function () {
chai.expect("yes").to.equal("no");
});
it('yes == yes should succeed', function () {
chai.expect("yes").to.equal("yes");
});
The first unit test fails, the second succeeds.
And when we put the assertion into a function this still detects the failure:
it('should fail, but succeeds!?', function () {
function fn() {
var yes = 'yes';
yes.should.equal('no');
};
fn();
});
So now into the world of electron, webdriverio, and spectron, the application title is supposed to be "Hello World!", so this should fail, but it passes:
it('tests the page title', function () {
page.getApplicationTitle().should.eventually.equal("NO WAY");
});
Hmm, let's try a more familiar test:
it('should fail, waitUntilWindowLoaded, yes != no', function () {
app.client.waitUntilWindowLoaded().getTitle().then(
function (txt) {
console.log('txt = ' + txt);
var yes = 'yes';
yes.should.equal('no');
}
);
});
Output:
✓ should fail, waitUntilWindowLoaded, yes != no
txt = Hello World!
It succeeds? What? Why? How?
Found it! If you look at https://github.com/webdriverio/webdriverio/blob/master/examples/standalone/webdriverio.with.mocha.and.chai.js
you will see that you need to return the promise from each of the tests. This is typical for async chai/mocha tests:
it('tests the page title', function () {
return page.getApplicationTitle().should.eventually.equal("NO WAY");
});
If you do that, then the chai test is actually correctly evaluated.

Testing method signatures in Node.js

I'm relatively new to Unit-testing and TDD specificly and am about to start my first project with TDD using mocha and chai.
Am I supposed to test the existence and parameter length of the methods?
And if so, is there any better way of doing it than I currently am? It feels extremly verbose, especially when repeating this for most of my classes.
For understand I've set up some dummy test.
test/index.js
'use strict';
const assert = require('chai').assert;
const Test = require('../lib/index.js');
describe('Test', function() {
it('should be a function without parameters', function() {
assert.isFunction(Test);
assert.lengthOf(Test, 0);
});
let test;
beforeEach(function() {
test = new Test();
});
describe('static#method1', function() {
it('should have static method method1 with 1 parameter', function() {
assert.property(Test, 'method1');
assert.isFunction(Test.method1);
assert.lengthOf(Test.method1, 1);
});
it('should assert on non-string parameters', function() {
const params = [
123,
{},
[],
function() {}
];
params.forEach(function(param) {
assert.throws(function() {
Test.method1(param)
});
});
});
it('should return "some value"', function() {
assert.equal(Test.method1('param'), 'some value')
});
});
describe('method2', function() {
it('should have method method2 with 2 parameters', function() {
assert.property(test, 'method2');
assert.isFunction(test.method2);
assert.lengthOf(test.method2, 2);
});
it('should assert on non-number parameters', function() {
const params = [
'some string',
{},
[],
function() {}
];
params.forEach(function(param) {
assert.throws(function() {
test.method2(param)
});
});
});
it('should add the parameters', function() {
assert.equal(test.method2(1, 2), 3);
assert.equal(test.method2(9, -2), 7);
assert.equal(test.method2(3, -12), -9);
assert.equal(test.method2(-7, -5), -12);
})
});
});
And the tested implementation.
lib/index.js
'use strict';
const assert = require('chai').assert;
exports = module.exports = (function() {
class Test {
static method1(param0) {
assert.typeOf(param0, 'string');
return 'some value';
}
method2(param0, param1) {
assert.typeOf(param0, 'number');
assert.typeOf(param1, 'number');
return param0 + param1;
}
}
return Test;
}());
No, such detailed tests are not necessary. What is the value of them? What do they help you to achieve?
Usually when testing functions we test behavior of a function, not its implementation. Implementation can completely change without changing the observable behavior: for example, you can find more readable way to rewrite your code or a more performant algorithm.
You test the call signature of your function by the whole set of tests for it, indirectly. Every test provides an example of how to use your function, thus ensuring its call signature and return parameters.

How can I stub a Promise such that my test can be run synchronously?

I am trying to unit test a module by stubbing one of its dependencies, in this case the UserManager
A simplified version of the module is as follows:
// CodeHandler
module.exports = function(UserManager) {
return {
oAuthCallback: function(req, res) {
var incomingCode = req.query.code;
var clientKey = req.query.key;
UserManager.saveCode(clientKey, incomingCode)
.then(function(){
res.redirect('https://test.tes');
}).catch(function(err){
res.redirect('back');
}
);
}
};
};
I'm stubbing the UserManager's saveCode function which returns a Promise such that it returns a resolved Promise, but when I assert that res.redirect has been called, alas at the time of the assertion res.redirect has not yet been called.
A simplified version of the unit test is:
// test
describe('CodeHandler', function() {
var req = {
query: {
code: 'test-code',
key: 'test-state'
}
};
var res = {
redirect: function() {}
};
var expectedUrl = 'https://test.tes';
var ch;
beforeEach(function() {
sinon.stub(UserManager, 'saveCode').returns(
new RSVP.Promise(function(resolve, reject){
resolve();
})
);
sinon.stub(res, 'redirect');
ch = CodeHandler(UserManager);
});
afterEach(function() {
UserManager.saveCode.restore();
res.redirect.restore();
});
it('redirects to the expected URL', function(){
ch.oAuthCallback(req, res);
assert(res.redirect.calledWith(expectedUrl));
})
});
How can I properly stub the promise such that the method under test behaves synchronously?
I've worked out a solution using sinon-stub-promise.
describe('CodeHandler', function() {
var req = {
query: {
code: 'test-code',
key: 'test-state'
}
};
var ch;
var promise;
var res = {
redirect: function() {}
};
beforeEach(function() {
promise = sinon.stub(UserManager, 'saveCode').returnsPromise();
ch = CodeHandler(UserManager);
sinon.stub(res, 'redirect');
});
afterEach(function() {
UserManager.saveCode.restore();
res.redirect.restore();
});
describe('can save code', function() {
var expectedUrl = 'https://test.tes';
beforeEach(function() {
promise.resolves();
});
it('redirects to the expected URL', function(){
ch.oAuthCallback(req, res);
assert(res.redirect.calledWith(expectedUrl));
});
});
describe('can not save code', function() {
var expectedUrl = 'back';
beforeEach(function() {
promise.rejects();
});
it('redirects to the expected URL', function(){
ch.oAuthCallback(req, res);
assert(res.redirect.calledWith(expectedUrl));
})
})
});
This works perfectly.
Well, the easiest thing would be not to stub it to run synchronously at all since that might change execution order and use Mocha's built in promises support (or jasmine-as-promised if using jasmine).
The reason is there can be cases like:
somePromise.then(function(){
doB();
});
doA();
If you cause promises to resolve synchronously the execution order - and thus output of the program changes, making the test worthless.
On the contrary, you can use the test syntax:
describe("the test", () => { // use arrow functions, node has them and they're short
it("does something", () => {
return methodThatReturnsPromise().then(x => {
// assert things about x, throws will be rejections here
// which will cause a test failure, so can use `assert`
});
});
});
You can use the even lighter arrow syntax for single lines which makes the test even less verbose:
describe("the test", () => { // use arrow functions, node has them and they're short
it("does something", () =>
methodThatReturnsPromise().then(x => {
// assert things about x, throws will be rejections here
// which will cause a test failure, so can use `assert`
});
);
});
In RSVP, you can't set the scheduler as far as I know so it's quite impossible to test things synchronously anyway, other libraries like bluebird let you do it at your own risk, but even in libraries that let you do it it's probably not the best idea.

Resources