How to use should.js as global variable: - javascript

I am trying to write some unit test that using mocha and should.js since I would like to keep format for each of my unit test the same and each unit test require should.js to verify proerpty of object. How can I make it as globally variable so I do not need to require should.js on each test file so far I have tried
global.should = require('should');
describe('try gloabl'), () => {
it('should work'), () => {
let user = { name: 'test'};
global.should(user).have.property('name', 'test');
});
});
#error, global.should is not a function
and if i use this. it works
const should = require('should');
should = require('should');
describe('try gloabl'), () => {
it('should work'), () => {
let user = { name: 'test'};
global.should(user).have.property('name', 'test');
});
});

First of all, I'm tired of writing "require" is the worst reason to use the GLOBAL variable. There is a reason that using require is the conventional way of doing things, and it is not different from any other language where you have to import or type using in each and every file. It just makes it easier to understand what the code is doing later on.
See this for further explanation.
Now, that said, when requiring should, the module actually attaches itself to the GLOBAL variable, and makes describe, it and should accessible methods.
index.js
require('should');
describe('try global', () => {
it('should work with global', () => {
let user = { name: 'test' };
global.should(user).have.property('name', 'test');
});
it('should work without global', () => {
let user = { name: 'test' };
should(user).have.property('name', 'test');
});
});
//////
mocha ./index.js
try global
√ should work with global
√ should work without global
2 passing (11ms)
I fixed the typos in your code (eg. Removing the extra ) from describe and it function), and this code works just fine when running with mocha ./index.js. Make sure you have install mocha with npm i -g mocha to make the module available in the CLI.

Related

Running a test with Mocha also launches the main program

I'm trying to use Mocha to test a CLI app. The tests are running fine but, when I launch the testing procedure, it also launches the main app:
$ npm run test
> standardize-js#0.2.2 test C:\Users\Gaspard\Documents\Code\standardize-js
> mocha "./source/**/*.spec.js"
? Choose your project language or framework (Use arrow keys) //<-- THIS IS THE PROGRAM
> Javascript
Typescript
AngularJS
Main function //<-- THIS IS THE TEST
ask if the configuration is valid
Configuration is not valid, terminating program.
√ should return false if the configuration is not accepted
1 passing (29ms)
I'm kind of new to the testing world and I'm really struggling to understand what I'm doing wrong.
Here is the NPM script used to launch mocha :
"test": "mocha \"./source/**/*.spec.js\""
Here is my testing method:
/* eslint-disable func-names */
const { expect } = require("chai");
const main = require("./index").test;
describe("Main function", function() {
describe("ask if the configuration is valid", function() {
it("should return false if the configuration is not accepted", function() {
const fakeAnswer = false;
expect(main.validateConfiguration(fakeAnswer)).to.equal(false);
});
});
});
And here is my index.js file:
function validateConfiguration(answer) {
if (answer === false) {
console.log(chalk.red("Configuration is not valid, terminating program."));
return false;
}
return true;
}
const run = async () => {
//MAIN FUNCTION
};
run();
// Export functions and variables to be able to test
exports.test = {
validateConfiguration
};
It's not a problem with mocha. It is simply now node.js modules work.
When you do this:
const main = require("./index").test;
Node.js will execute index.js and then check the value of module.exports. If the module (index.js) sets or modifies module.exports then node will export it for use by require(). But note, in order for node to know that the module has exported anything it must execute the javascript file.
Node.js does not have any ability to parse and analyze javascript syntax (that's V8's job). Unlike other languages such as C or Java, modules in node.js are not implemented at the syntax level. Therefore the javascript language does not need to be modified (eg. ES6 modules) for node.js to support modules. Modules are simply implemented as a design pattern.
In your index.js file you call run:
run();
When require() loads index.js it will therefore also cause run() to be called.
Test libraries, not main
The solution to this is to implement your own logic as modules and test that, not test index.js:
mylib.js:
function validateConfiguration(answer) {
if (answer === false) {
console.log(chalk.red("Configuration is not valid, terminating program."));
return false;
}
return true;
}
// Export functions and variables to be able to test
exports.test = { validateConfiguration };
index.js:
const validateConfiguration = require("./mylib").test;
const run = async () => {
//MAIN FUNCTION
};
run();
You can now use your test script as written.
How can you not test code??
The strategy to keep index.js bug free without testing is to remove all logic from it except for the minimum amount of code to wire all your other code up together to run the app. The code should be as simple as "Hello World". That way, the code in main is so small and so simple that you can test it for bugs using your eyeballs.
Any code in index.js that causes a bug should be refactored into its own library so that it can be tested separately. There are a small handful of corner cases, such as loading environment variables or opening port 80 where you can't really separate into a library because they literally are wiring logic. For such cases you just have to be really careful.
It's calling run because you are telling it to right after defining the method.

jest.setMock not working for installed dependencies

I am having trouble using jest.setMock with installed dependencies
So, I have a feature to test which requires my-module dependency:
// my-module/index.js
import { hello } from 'my-dep';
export const doSomething = () => {
return hello();
};
// my-dep
// location: my-module/node_modules/my-dep/index.js
export const hello = () => {
return 'dude';
};
I have "npm linked" the my-module in my app:
cd my-module
npm link
cd app
npm link my-module
I wrote a test file as follows:
// app/feature.test.js
jest.setMock('my-dep', {
hello: () => 'world'
});
const { doSomething } = require('my-module');
it('should return dude', () => {
expect(doSomething()).toBe('dude');
});
I don't understand why mocking my-dep did not work and called the actual hello() function.
When I tried using the my-module file as relative import & installed my-dep dependency, the mocking worked:
// app/feature.test.js
jest.setMock('my-dep', {
hello: () => 'world'
});
const { doSomething } = require('./my-module');
it('should return world', () => {
expect(doSomething()).toBe('world');
});
What am I missing here?
Environment:
Binaries:
Node: 8.9.4
Yarn: 1.3.2
npm: 5.6.0
npmPackages:
jest: ^22.4.3 => 22.4.3
Some related issues:
https://github.com/facebook/jest/issues/701
https://github.com/facebook/jest/issues/796
Your problem is likely caused by the module loading order, but I'm not sure how changing from my-module to ./my-module changes it. I'd love to see the console output after adding console.log(require('path').join(__dirname, __filename)) to the top of my-module and my-dep.
This comment in the Jest issue you shared indicates that jest.setMock isn't hoisted before your import statements. If you switch it to use jest.mock that is hoisted, does it work?
jest.mock('my-dep', () => ({
hello: () => 'world'
}));
The Jest docs on manual mocks mention hoisting in this note:
If you're using ES module imports then you'll normally be inclined to put your import statements at the top of the test file. But often you need to instruct Jest to use a mock before modules use it. For this reason, Jest will automatically hoist jest.mock calls to the top of the module (before any imports).
For more about hoisting in JavaScript, refer to You Don't Know JS: Scope & Closures - Chapter 4: Hoisting

Running javascript e2e tests on a local appium server

I'm wanting to run e2e tests written in javascript with mocha on an Appium server instance running a local android emulator. The app on test is an apk originally written in react-native.
On Windows I have the server up and running with an Android Studio emulator through using the Appium desktop app. The server all looks good and has the apk of the native app I want to test working fine. I also have a basic describe/assert test written in mocha that I want to apply to the app.
My question is what do I need to include (presumably in the test file) to make the tests actually test the emulator application? I'm finding the documentation pretty confusing and the sample code seems pretty specific to a different use case.
Many thanks for your help!
There are at least 2 good js client libraries to use for Appium based project: webdriverio and wd. Personally, I'm using the second one so I can advice you how write tests with it and mocha:
my test file looks like this:
'use strict'
require(path.resolve('hooks', 'hooks'))
describe('Suite name', function () {
before('Start new auction', async function () {
//do before all the tests in this file, e.g. generate test data
})
after('Cancel auction', async function () {
//do after all the tests in this file, e.g. remove test data
})
it('test1', async () => {
// test steps and checks are here
})
it('test2', async () => {
// test steps and checks are here
})
it('test3', async () => {
// test steps and checks are here
})
})
where hooks.js contains global before/after for all the tests:
const hooks = {}
before(async () => {
// before all the tests, e.g. start Appium session
})
after(async () => {
// after all the tests, e.g. close session
})
beforeEach(async () => {
// before each test, e.g. restart app
})
afterEach(async function () {
// e.g. take screenshot if test failed
})
module.exports = hooks
I'm not saying its the best practice of designing tests, but its one of multiple ways.
Cool so I managed to get it working to a degree. I was checking through the Appium console logs as I was trying to run stuff and noticed that the session id was missing from my requests. All that was needed was to attach the driver using the session id. My code looks a bit like this:
"use strict";
var wd = require("wd")
var assert = require("assert")
var serverConfig = {
host: "localhost",
port: 4723,
}
var driver = wd.remote(serverConfig)
driver.attach("0864a299-dd7a-4b2d-b3a0-e66226817761", function() {
it("should be true", function() {
const action = new wd.TouchAction()
action
.press({x: 210, y: 130})
.wait(3000)
.release()
driver.performTouchAction(action)
assert.equal(true, true)
})
})
The equals true assert is just there as a placeholder sanity check. The only problem with this currently is that I'm copy-pasting the alpha-numeric session id inside the attach method each time I restart the Appium server so I need to find a way to automate that.

Chai assertions not executed inside JSDOM Env block

I've just started writing my front-end unit tests with mocha, chai and jsdom. When I try to follow the tutorials based on those - I'm getting passing tests even when I set them to fail. Everything else is setup and works as expected jQuery, setup.js, window etc. The only issue is that my Assertions are not getting executed at all inside the jsdom env block.
This is my test:
var chai = require('chai'),
expect = chai.expect,
jsdom = require('jsdom'),
fs = require('fs'),
jquery = fs.readFileSync('./js/vendor/jquery-3.0.0.min.js', 'utf-8');
describe('UI DOM tests', function () {
it('should fail', function () {
// simple html
var htmlFragment = fs.readFileSync('./test/runner.html');
jsdom.env({
html: htmlFragment,
src: [jquery, '../node_modules/chai/chai.js'],
done: function (err, window) {
var $ = window.$;
expect(true).eql(false); // nothing happens
done();
}
});
expect(true).eql(false); // assert fails as expected
});
});
Any help is greatly appreciated.
it seems you're missing the done argument in your it:
it('should fail', function (done) {
otherwise mocha will think your it is synchronous and finish before your jsdom env is created.

babel generated code breaking istanbul coverage

I'm using babel to enable ES6 imports in a node project. Also using mocha for testing, and istanbul for coverage. I end up with less than full coverage because babel generates code something like the following:
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _koa = require('koa');
var _koa2 = _interopRequireDefault(_koa);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Specifically, the generated function _interopRequireDefault is copied into every code file, and the branches are not necessarily always executed, which skews the branch coverage number emitted for istanbul. Is there any way around this issue?
If you're using gulp, I have a gist with a gulpfile here that sets up the necessary hooks and filters. The relevant chunk is to load isparta, hook require, and let the tests run:
gulp.task('test:cover', (cb) => {
gulp.src('src/main/**/*.js')
.pipe(istanbul({
instrumenter: require('isparta').Instrumenter,
includeUntested: true
}))
.pipe(babel())
.pipe(gulp.dest('target/cover'))
.pipe(istanbul.hookRequire())
.on('finish', cb);
});
gulp.task('test:mocha', (cb) => {
gulp.src('target/test/**/Test*')
.pipe(mocha())
.pipe(istanbul.writeReports())
.on('end', cb);
});
gulp.task('test', (cb) => {
return runSequence('test:cover', 'test:mocha', cb);
});
The only frustrating part is that your tests must use the covered code:
import {
LinearInterpolator,
CosineInterpolator
} from '../../cover/random/Interpolators';
I haven't found a way to work around that yet without also covering the test scripts and skewing coverage, although you should be able to do that by merging streams:
gulp.task('test:cover', (cb) => {
const src = gulp.src('src/main/**/*.js')
.pipe(istanbul({
instrumenter: require('isparta').Instrumenter,
includeUntested: true
}));
const test = gulp.src('src/test/**/*.js');
merge(src, test)
.pipe(babel())
.pipe(gulp.dest('target/cover'))
.pipe(istanbul.hookRequire())
.on('finish', cb);
});
You need to combine it with isparta - https://github.com/douglasduteil/isparta - to get the coverage working correctly. I warn you its a bit trial and error at the moment! My npm script looks like -
"coverage": "node_modules/.bin/babel-node node_modules/.bin/isparta cover --include-all-sources --report html node_modules/.bin/_mocha -- --reporter $npm_package_config_bdd_reporter",
We've run into this and I finally got fed up and looked into what causes this line. It turns out that every time to use an import like:
import chai from 'chai';
this babel fill gets added to allow sane interaction with older export styles. The trouble is that none of the common libraries exhibit the "true" branch of the ternary. I build the following file coverInterrop.js that artificially trips the first branch using old-school exports:
module.exports = {
__esModule: true
};
and I include in any file where I want to use an undestructured import:
// eslint-disable-next-line no-unused-vars
import coverInterrop from 'coverInterrop';
Note that it has to assign to a variable to trip the coverage and good eslint rules won't like that

Categories