Babel won't ignore my module regex - node.js

I'm using Mocha to run tests on my React components, so I need Babel in my Mocha bootstrap to transpile the jsx requires. In my bootstrap.js I start with
global.babel = require("babel/register")({
ignore: [/node_modules/, '**/scss*', /sinon/, /foo/]
});
According to the docs, ignore accepts "A glob, regex, or mixed array of both" But its weird because the /node_modules/, /sinon/ regexes work, but the **/scss* and /foo/ don't.
For example, here's the top of the component that fails the require:
var React = require('react');
var Router = require('react-router');
var Link = Router.Link;
var foo = require('foo');
var StyleSheet = require('../../scss/core/Linker');
Fails with:
1) app/core/Linker.jsx "before each" hook:
Error: Cannot find module 'foo'
at Object.<anonymous> (app/core/Linker.jsx:4:11)
at Context.<anonymous> (test/app/helpers/linker-test.js:10:23)
I start the tests like so:
mocha test --recursive --reporter spec --timeout 30000
Am I doing it wrong, or losing the babel ignore by the time the required component test is loaded up?

Related

Jest can not deal with insertAdjacentElement?

I want to test a quite simple JS function
export function displaySpinner() {
const loadingOverlayDOM = document.createElement('DIV');
const spinner = document.createElement('IMG');
loadingOverlayDOM.id = 'overlay-spinner';
loadingOverlayDOM.className = 'content-overlay';
spinner.className = 'is-spinning';
spinner.setAttribute('src', '/assets/img/svg/icons/spinner.svg');
l loadingOverlayDOM.insertAdjacentElement('beforeend', spinner);
document.body.insertAdjacentElement('beforeend', loadingOverlayDOM);
}
with this (for the purpose of this issue stripped down) Jest test code:
test('displaySpinner displays the spinner overlay in the current page', () => {
utils.displaySpinner();
});
But the test run yells at me:
FAIL app/helper/utils.test.js
● utils › displaySpinner displays the spinner overlay in the current page
TypeError: loadingOverlayDOM.insertAdjacentElement is not a function
at Object.displaySpinner (app/helper/utils.js:185:439)
at Object.<anonymous> (app/helper/utils.test.js:87:15)
at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
at process._tickCallback (internal/process/next_tick.js:109:7)
Is this an error in Jest or am I missing something here?
I finally found the answer myself:
Jest uses jsdom which does not yet support the DOM function insertAdjacentElement (see this issue on GitHub and it's references). So I'll have to wait until jsdom implements it or use another method in my JS.
You can replace the default version of jsdom with an up-to-date version (e.g. 14) by installing the corresponding module:
npm install --save-dev jest-environment-jsdom-fourteen
or using yarn:
yarn add jest-environment-jsdom-fourteen --dev
and then using the jest testEnvironment config parameter:
{
"testEnvironment": "jest-environment-jsdom-fourteen"
}
Note that if you launch jest with the --env=jsdom argument, this will override the config file, so you need to remove it.

babelify pipe results in: The code generator has deoptimised the styling of "/.../jquery.js" as it exceeds the max of "100KB"

I'm trying to create a single js file containing jquery, bootstrap and reactjs components using a gulp task:
app.jsx:
var React = require('react');
var ReactDOM = require('react-dom');
var HelloWorld = require('./Application.jsx');
var $, jQuery = require('../../libraries/jquery/dist/jquery');
var bootstrap = require('../../libraries/bootstrap-sass/assets/javascripts/bootstrap');
ReactDOM.render(
<Application />,
document.getElementById('example')
);
gulp task:
gulp.task('js', function () {
browserify('./public/javascripts/src/app.jsx')
.transform(babelify, {presets: ["es2015", "react"]})
.bundle()
.pipe(source('app.js'))
.pipe(gulp.dest('public/javascripts/build/'));
});
When running gulp, I get the following message:
[BABEL] Note: The code generator has deoptimised the styling of "/Users/.../jquery/dist/jquery.js" as it exceeds the max of "100KB".
How I design the gulp task, so that jquery and bootstrap does not pass the babelify pipe?
One possible solution is to add an ignore key to your babelify configuration so that it looks like something along the lines of:
.transform(babelify, {ignore: ['./libraries/**/*'], presets:["es2015", "react"]})
This should keep bableify from messing with your lib files that are already es5/minified/production ready.
(You may need to adjust the path a little bit... not 100% of your project structure)

Bootstrapping a Mocha test suite

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')
})
})

Mocha tests with extra options or parameters

I am writing test cases for my Node.js application using Mocha. The test cases need an API key as an extra input option or parameter. The API key is private, so I don't want to include it directly in the test files as everyone then can see it on GitHub. I know there are some options available for Mocha at:
http://mochajs.org/#usage
But is it possible to include some parameters to let testers specify their own API key for the test in the commandline? Such as:
./node_modules/mocha/bin/mocha test/*.js --key YOUR_KEY
I don't think Mocha itself supports passing extra parameters to your tests, but you could use environment variables:
env KEY=YOUR_KEY mocha test/*.js # assumes some sort of Unix-type OS.
And read them in your test files:
var key = process.env.KEY;
One of the easiest ways to pass parameters similar to the process.argv[index] method mentioned in this thread is using the npm config variables. This allows you to see the variable name a little more clearly:
test command:
npm --somevariable=myvalue run mytest
package.json:
"scripts": {
"mytest": "mocha ./test.js" }
test.js
console.log(process.env.npm_config_somevariable) // should evaluate to "myvalue"
Take a look at the optimist module by Substack and nconf from flatiron. A lot of my tests depend on external parameters and the optimist and nconf modules makes it easy to load configuration options from a json file
In your test command pass the path to the config.json file
test command
mocha test/api-test.js --config=/path/to/config.json --reporter spec
api-test.js
var path = require('path')
var fs = require('fs')
var assert = require('assert')
var argv = require('optimist').demand('config').argv
var configFilePath = argv.config
assert.ok(fs.existsSync(configFilePath), 'config file not found at path: ' + configFilePath)
var config = require('nconf').env().argv().file({file: configFilePath})
var apiConfig = config.get('api')
var apiKey = apiConfig.key
config.json
{
"api": {
"key": "fooKey",
"host": "example.com",
"port": 9000
}
}
Alternative
Another pattern I have been using recently is the config module. You can specify a ./config/default.yml file for running regularly and a ./config/test.yml file for tests.
When running your test suite, export NODE_ENV=test and the config module will load test.yml
In your code it is easy to access the configuration object
var config = require('config')
// config now contains your actual configuration values as determined by the process.env.NODE_ENV
var apiKey = config.api.key
An easy way to set NODE_ENV=test is by running your tests with a makefile. Run all your tests via make test. To run a single test execute make one NAME=test/unit/sample-test.js
Sample makefile
MOCHA?=node_modules/.bin/mocha
REPORTER?=spec
GROWL?=--growl
FLAGS=$(GROWL) --reporter $(REPORTER) --colors --bail
test:
#NODE_ENV="test" \
$(MOCHA) $(shell find test -name "*-test.js") $(FLAGS)
one:
#NODE_ENV="test" \
$(MOCHA) $(NAME) $(FLAGS)
unit:
#NODE_ENV="test" \
$(MOCHA) $(shell find test/unit -name "*-test.js") $(FLAGS)
integration:
#NODE_ENV="test" \
$(MOCHA) $(shell find test/integration -name "*-test.js") $(FLAGS)
acceptance:
#NODE_ENV="test" \
$(MOCHA) $(shell find test/acceptance -name "*-test.js") $(FLAGS)
.PHONY: test
The other answers are limited in that they do not support code execution prior to running your test suite. They only support passing parameters.
This answer supports code execution BEFORE your test suite is executed and is fully documented by mocha
mocha docs: http://unitjs.com/guide/mocha.html#mocha-opts
create ./test/mocha.opts
--recursive
--reporter spec
--require ./server.bootstrap
--require ./test/test.bootstrap
create ./server.bootstrap.js
global.appRoot = require('app-root-path');
// any more server init code
create ./test/test.bootstrap.js
process.env.NODE_ENV='test';
// any more test specific init code
finally in your server.js:
require('./server.bootstrap');
DONE!
The code in the server bootstrap will be executed prior to testing and server execution (npm start and npm test)
The code in the test bootstrap will only be executed prior to testing (npm test)
Thanks to #damianfabian for this one - see How to initialise a global variable in unit test runs?
There's no supported way to do this with Mocha. the suggested way is to use a file (for instance config.json), require it, and let other people change it.
That being said, if you pass your key at the end of the commandline (after the file to test) and use -- it should be available using process.argv (if you don't use -- or it's not after a regular file name, then mocha will fail).
if you run ./node_modules/mocha/bin/mocha --reporter spec test.js --apiKey=someKey , and test.js contains the code:
var assert = require("assert")
describe("testy", function () {
it("shouldy", function (done) {
var value;
for (var index in process.argv) {
var str = process.argv[index];
if (str.indexOf("--apiKey") == 0) {
value = str.substr(9);
}
}
assert.equal(value,"someKey")
done();
})
})
the test should pass
You can pass an argument to mocha test script using 'minimist' module.
Install with npm install minimist
Terminal:
mocha test.js --config=VALUE
Mocha node script:
var argv = require('minimist')(process.argv.slice(2));
console.log('config', argv.config);
A simple way, using process.argv that contain the command line args
$ mocha -w test/*.js --KEY=YOUR_VALUE
Later, you can get YOUR_VALUE in your code:
let LAST_PARAM = process.argv[process.argv.length-1]
let PARAM_NAME = LAST_PARAM.split("=")[0].replace("--","")
let PARAM_VALUE = LAST_PARAM.split("=")[1]
console.log("KEY: ", PARAM_VALUE)
To see all process.argv:
process.argv.forEach((value, index) => {
console.log(`process.argv[${index}]: ${value}`);
})
Output:
$ mocha -w test/*.js --KEY=YOUR_VALUE
KEY: YOUR_VALUE
process.argv[0]: /usr/local/bin/node
process.argv[1]: /Users/pabloin/.npm-packages/lib/node_modules/mocha/bin/_mocha
process.argv[2]: -w
process.argv[3]: test/tt.js
process.argv[4]: test/tt2.js
process.argv[5]: --KEY=YOUR_VALUE
KEY: YOUR_VALUE
process.argv[0]: /usr/local/bin/node
process.argv[1]: /Users/pabloin/.npm-packages/lib/node_modules/mocha/bin/_mocha
process.argv[2]: -w
process.argv[3]: test/tt.js
process.argv[4]: test/tt2.js
process.argv[5]: --KEY=YOUR_VALUE
I could send parameter thought mochaStream (require('spawn-mocha-parallel').mochaStream).
like:
var mochaStream = require('spawn-mocha-parallel').mochaStream;
var mocha = mochaStream({
env: function(){
return {yourParam: 'value'}
}
});
return gulp.src('test/**/*-specs.js', {read: false})
.pipe(mochaStream)
.on('error', console.warn.bind(console));
Inside ..spec.js file
var yourParam = process.env.yourParam;
I have been reading quite some answers, most of them more complex than the actual solution has to be.
Let's say I have config.yml or config.json. In my case it's a YAML file.
First of all I install the yamljs dependency. It has a function called load.
Basically what I do:
const YAML = require('yamljs');
const ymlConfig = YAML.load('./config.yml');
Then I go for:
process.env.setting1 = ymlConfig.setting1;
process.env.setting2 = ymlConfig.setting2;
And of course - this is all done in your test file.
if you are debugging/testing with Mocha sidebar (VS Code extension), just put it:
{
"mocha.env": {
"KEY": "YOUR_KEY",
"MY_VARIABLE": "MY VALUE"
}
}
at .vscode/settings.json

Can't get a file required before every test

I try to setup mocha in combination with coffeescript and chai. Before every file containing the tests, I want to include the following file:
test/_helper.coffee
path = require 'path'
AppDir = path.resolve("#{__dirname}/../src/app")
chai = require('chai')
should = chai.should()
factories = require('chai-factories')
chai.use(factories)
This is so that I have access to the AppDir variabel. So that I don't have to specify the complete path to the app directory when I want to require a file.
test/app/setup-test.coffee
describe 'Setup instance', ->
it 'should be a object', ->
setup = require "#{AppDir}/setup"
setup.should.be.a('object')
I tried the following setups:
Added _hellper.coffee to mocha commandline options like so:
./node_modules/.bin/mocha --require coffee-script --require test/_helper.coffee --compilers coffee:coffee-script --recursive --reporter spec test
and so:
./node_modules/.bin/mocha --require coffee-script --compilers coffee:coffee-script --recursive --reporter spec test/_helper.coffee test
And I tried a normal require in setup-test.coffee:
require '../_helper.coffee'
What ever method I use, I get the following error if I run the test:
Setup instance
1) should be a object
✖ 1 of 1 test failed:
1) Setup instance should be a object:
ReferenceError: AppDir is not defined
at Context.<anonymous> (/Users/ivotrompert/Dropbox/projects/nodejs/getWallpapers/test/app/setup-test.coffee:8:28)
at Test.Runnable.run (/Users/ivotrompert/Dropbox/projects/nodejs/getWallpapers/node_modules/mocha/lib/runnable.js:184:32)
at Runner.runTest (/Users/ivotrompert/Dropbox/projects/nodejs/getWallpapers/node_modules/mocha/lib/runner.js:300:10)
at Runner.runTests.next (/Users/ivotrompert/Dropbox/projects/nodejs/getWallpapers/node_modules/mocha/lib/runner.js:346:12)
at next (/Users/ivotrompert/Dropbox/projects/nodejs/getWallpapers/node_modules/mocha/lib/runner.js:228:14)
at Runner.hooks (/Users/ivotrompert/Dropbox/projects/nodejs/getWallpapers/node_modules/mocha/lib/runner.js:237:7)
at next (/Users/ivotrompert/Dropbox/projects/nodejs/getWallpapers/node_modules/mocha/lib/runner.js:185:23)
at Runner.hook (/Users/ivotrompert/Dropbox/projects/nodejs/getWallpapers/node_modules/mocha/lib/runner.js:205:5)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
And here is my MAKE file if someone want to know how I run the tests:
Makefile
REPORTER = spec
DEFAULT_COMMAND = ./node_modules/.bin/mocha --require coffee-script --ui bdd --compilers coffee:coffee-script --recursive --growl --reporter
check: test
test:
#NODE_ENV=test $(DEFAULT_COMMAND) $(REPORTER)
test-watch:
#clear
#NODE_ENV=test $(DEFAULT_COMMAND) $(REPORTER) --watch
coverage:
#jscoverage --no-highlight src src-cov
#SRC_COV=1 $(DEFAULT_COMMAND) html-cov > coverage.html
#rm -rf src-cov
ifeq ($(shell uname), Darwin)
#open coverage.html
else
#xdg-open coverage.html &> /dev/null &
endif
.PHONY: test
Can someone please help me, thank you.
Here is one Solution.
_helper.coffee
path = require 'path'
exports.AppDir = path.resolve("#{__dirname}/../src/app")
chai = require('chai')
should = chai.should()
factories = require('chai-factories')
chai.use(factories)
your test coffee
{AppDir} = require "../helpers"
describe 'Setup instance', ->
it 'should be a object', ->
setup = require "#{AppDir}/setup"
setup.should.be.a('object')
What I have done is use exports and require returns multiple objects you can separate them by comma if you have more exports in your _helper.coffee. The Order is relevant.
Side note:
But why would your require a file in your test? I wouldn't like to have some hidden setup in a external file for one test. That doesn't make it easy to understand the test later or for others.

Resources