Bootstrapping a Mocha test suite - node.js

I have numerous tests spread across multiple files in a Node JS application. I'd like to run bootstrap code prior to Mocha's execution of any of the test files. This is so that I can, for example, set globals to be used in each of the actual tests.
Sample bootstrap code
global.chai = require('chai');
global.expect = chai.expect;
global.sinon = require('sinon');
It seems Mocha loads all files under /test alphabetically, so if I name this bootstrap code "bootstrap.js" and everything else with a starting letter after "B" it "works".
Obviously this is fragile and sucky, but I don't want to put this boilerplate requiring of my supporting libraries at the top of every test file.
How do I tell Mocha to load a bootstrap script first, or create something functionally equivalent?

have you tried mocha --require mymodule.js TESTS_DIR
from the documentation
-r, --require
The --require option is useful for libraries such as should.js, so you
may simply --require should instead of manually invoking
require('should') within each test file. Note that this works well for
should as it augments Object.prototype, however if you wish to access
a module's exports you will have to require them, for example var
should = require('should').
you could also write at the top of each test to load the require("./bootstrap.js") and run tests.

I use mocha's flag --delay
If you need to perform asynchronous operations before any of your
suites are run, you may delay the root suite. Simply run Mocha with
the --delay flag. This will provide a special function, run(), in the
global context.
setTimeout(function() {
// do some setup
describe('my suite', function() {
// ...
});
run();
}, 5000);

If prior to running Mocha you want to first run some bootstrap code in a file that uses ECMAScript 2015 Module syntax (i.e. import instead of require)
Create the following files:
./setupBabel.js (to bootstrap Babel transpiler)
require('babel-polyfill');
require('babel-register');
./setupDependencies.js (to bootstrap Chai and Sinon using ES2015 syntax)
import chai from 'chai';
import sinon from 'sinon';
global.expect = chai.expect;
global.sinon = sinon;
./test/codeSpec.js (example Unit Test using Chai, Sinon Stubs, Spies, and ES2015 syntax such as arrow functions, let, and const)
describe('test suite', () => {
it('does not modify immutable constant value', () => {
const myStub = sinon.stub();
const mySpy = sinon.spy(myStub);
myStub.returns({});
let val = 1;
expect(val).to.not.equal(2);
sinon.assert.notCalled(mySpy);
});
});
Run the following in terminal to install relevant NPM packages:
npm install babel-polyfill babel-register chai sinon mocha
Run the test suite with the following terminal command and flags:
mocha --require ./setupBabel.js --require ./setupDependencies.js ./test/codeSpec.js

describe('异步钩子测试', function () {
const lover = {
bodyname: 'yueyue',
girlname: 'fangfang'
}
const test = 'lihang'
beforeEach('每一个测试之前的钩子', function () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('通过')
})
})
})
it('方方爱张越', function () {
// 是否等于yueuyue
expect(lover.bodyname).to.equal('yueyue')
// 是否是一个字符串
lover.girlname.should.equal('fangfang')
})
})

Related

How to launch a chai test in node?

I have a node/typescript application. I'm trying to test routes with chai and chai-http. I can launch a file when I write an explicit name: yarn test myroute.test.ts, but yarn test at the root does nothing.
Also, the test is never performed. I only receive a Done in 0.06s. in my terminal. No "passed" or "failed".
Here is the test:
import chai from "chai";
import chaiHttp from "chai-http";
import { server } from "../index";
chai.use(chaiHttp);
const chaiApi = chai.request(server);
describe("GET /user/:id", () => {
it("return user information", async () => {
const res = await chaiApi
.get("/user/123")
.set("Cookie", "_id=567;locale=en");
chai.assert.equal(res.status, 200);
});
});
the package.json script is: "test": "test". I assume it's completely wrong, but chai doc says nothing about what to write here.
chai is an assertion library, similar to Node's built-in assert. It does NOT contain a test runner. You need to use mocha to collect and run your declared test suites and test cases.
After adding the mocha test framework, you can declare npm test script like this:
"test": "mocha --require ts-node/register --timeout 5000",
In order to run the TS test file, we need to specify ts-node/register. Use it like this:
yarn test myroute.test.ts

How do you write object literal line coverage in Typescript Mocha unit-test?

Lead:
New to working with typescript and writing unit tests using Mocha and Chai.
Question
Any tips on how I can go about getting 100% line coverage in unit tests with an object literal that isn’t in a class? Trying to avoid going static if at all possible, but unit testing still has to hit 100% to pass.
// constants.ts
export default {
path: “./example”,
name: “Example Name”
}
// constants.spec.ts
// How do I unit test ‘export default’ for 100% line coverage?
// I have tried
import chai from "chai";
import * as constants from “./constants.ts”;
describe(“constants”, () => {
it(“Constants literals should have a length of 2“, () => {
chai.expect(constants.default.length).equal(2);
});
});
// The mocha test succeeds, but the line still says it hasn’t been tested.
I think I found the answer, but I am sure there is an easier way to use and test literals in Typescript.
describe("Constants", async () => {
it("can be created", async () => {
const obj = constants.default;
chai.should().exist(obj);
});
});
Typescript Mocha Chai unit-test 100% line coverage

Mocha (Spectron) suddenly times out on async test scenarios

I wanted to run some Spectron e2e tests I wrote some weeks ago, but to my surprise, suddenly they all stopped working for one and the same reason.
According to the error message, I'm dealing with rejected Promises, but I can't figure out where the problem is coming from. Calling done at the end of my testcase raises the exact same error.
I'm running the following command to launch my test suit: mocha test/e2e
Mocha then executes this index.js before running my tests in ordner to support ES6+ features
'use strict'
//index.js
// Set BABEL_ENV to use proper env config
process.env.BABEL_ENV = 'test'
// Enable use of ES6+ on required files
require('babel-register')({
ignore: /node_modules/
})
// Attach Chai APIs to global scope
const { expect, should, assert } = require('chai')
global.expect = expect
global.should = should
global.assert = assert
// Require all JS files in `./specs` for Mocha to consume
require('require-dir')('./specs')
After that its trying to run this small Login.spec.js which returns the error mentioned above
import utils from '../utils'
import {Application} from "spectron";
import electron from "electron";
describe('🔑 Login', function () {
this.timeout(11000);
it('login form exists', async function (done) {
this.app = new Application({
path: electron,
env: {"SPECTRON_RUNNING":true},
args: ['dist/electron/main.js'],
startTimeout: 10000,
waitTimeout: 10000
})
await this.app.start()
await this.app.client.windowByIndex(1);
done();
})
})

Jest beforeAll() share between multiple test files

I have a Node.js project that I'm testing using Jest. I have several test files that have the same setup requirement. Previously, all these tests were in one file, so I just had a beforeAll(...) that performed the common setup. Now, with the tests split into multiple files, it seems like I have to copy/paste that beforeAll(...) code into each of the files. That seems inelegant - is there a better way to do this, ideally where I can just write my beforeAll(...)/setup logic once, and "require" it from multiple test files? Note that there are other tests in my test suite that don't require this setup functionality, so I don't want to make all my tests run this setup (just a particular subset of test files).
If you're using Jest >=20, you might want to look into creating a custom jest-environment for the tests that require this common setup. This would be a module that extends either jest-environment-node or jest-environment-jsdom, and implements async setup(), async teardown(), and async runScript() to do this setup work.
You can then add a #jest-environment my-custom-env directive to those files that require this setup.
See the Jest config docs for testEnvironment for details on how to set this up; there's a simple example there.
I am using a simple "test hooks" pattern for this:
// This function wraps beforeAll and afterAll into a single RAII-like call.
// That makes the describe code further down easier to read and makes
// sure you don't forget the afterAll part. Can easily be shared between tests.
function useFakeServer() {
let server;
beforeAll(() => server = sinon.fakeServer.create());
afterAll(() => server.restore());
return () => server;
}
describe('Some scenario', () => {
const getServer = useFakeServer();
it('accesses the server', () => {
const server = getServer();
// Test as you normally would..
expect(server.requests[0]. /* ... */);
});
});
If you need a script to run before all your test files, you can use globalSetup
This option allows the use of a custom global setup module which exports an async function that is triggered once before all test suites.
in your jest.config.js
//jest.config.js
module.exports = {
...
testTimeout: 20000,
globalSetup: "./setup.js"
};
then create a file named setup.js
// setup.js
module.exports = async () => {
console.log("I'll be called first before any test cases run");
//add in what you need to do here
};
Docs
You can move your beforeAll logic into one file and reference it in jest.config.js setupFilesAfterEnv section:
module.exports = {
...
setupFilesAfterEnv: ['<rootDir>/testHelper.ts'],
...
}
https://jestjs.io/docs/en/configuration#setupfilesafterenv-array
Create a function somewhere like so:
export function setupBeforeAndAfter(putParamsHereIfYouHaveAny) {
beforeAll(() => shared-before-all-code);
afterAll(() => shared-after-all-code);
beforeEach(() => shared-before-each-code);
afterEach(() => shared-after-each-code);
}
Then just call it wherever you would otherwise have manually written these functions:
describe('My test', () => {
setupBeforeAndAfter(putParamsHereIfYouHaveAny)
it('is amazing', () => {
// Stuff in setupBeforeAndAfter() will run before/after this test as appropriate
})
})

Why are the nightmare.js examples not working?

var Nightmare = require('nightmare');
var expect = require('chai').expect; // jshint ignore:line
describe('test yahoo search results', function() {
it('should find the nightmare github link first', function*() {
var nightmare = Nightmare()
var breadcrumb = yield nightmare
.goto('http://yahoo.com')
.type('input[title="Search"]', 'github nightmare')
.click('.searchsubmit')
.wait('.url.breadcrumb')
.evaluate(function () {
return document.querySelector('.url.breadcrumb').innerText;
});
expect(breadcrumb).to.equal('github.com');
});
});
Why does this test always evaluate to true?
This test evaluates to true even if I change the comparison value. If I add a console.log before the expect, it does not print, which makes me thing the test is never being evaluated and that a null response is true for chai. I am running node v4.2.2, and the latest versions of nightmare and expect. I run the test from the terminal using mocha index.js (the name of this file).
function* and yield is a ES2015 feature called Generators.
There's a additional note after the example on the README:
Please note that the examples are using the mocha-generators package for Mocha, which enables the support for generators.
So you need to install the package and add this to your code:
require('mocha-generators').install();

Resources