How to use Mocha require option in Karma - mocha.js

I've been trying to use the mocha require option:
mocha mytest.js --require myglobals.js
But I don't know how to do it from karma. The idea is to run karma start and it will automatically require myglobals.js.
Is that possible to do it from within karma.conf.js or somehow else?
Maybe I'm not using karma/mocha in the right way.
My idea is:
I want to have unit/integration tests for both the client (react) and the server (node/express)
I want to just run karma start and both client and server tests are tested
I found very useful to have the following file pre-required, in order to avoid requiring some things in all tests:
myglobals.js:
const chai = require('chai');
// Load Chai assertions
global.expect = chai.expect;
global.assert = chai.assert;
chai.should();
// Load Sinon
global.sinon = require('sinon');
// Initialize Chai plugins
chai.use(require('sinon-chai'));
chai.use(require('chai-as-promised'));
chai.use(require('chai-things'));
For the server side I've made it work using the command:
mocha mytest.js --require myglobals.js
But still, I wanted to keep it running under the npm run test (which calls karma start) instead of creating another npm run test:server command.
Furthermore, I wanted to do the same on the client. I'm using webpack there as a preprocessor.
Any ideas if it is possible to accomplish that? Or maybe I'm in the wrong way?

Short Answer
Mocha in the browser does not support an equivalent of the --require option, but you do not need it. You can just load whatever you need ahead of your tests listing the files you want to load in files in front of your test files. Or if you use a loader like RequireJS, write a test-main.js that loads the modules you would load with --require first, and then load your test files.
Long Answer
If you look at Mocha's code you'll see that the only place --require is used is in the bin/_mocha file. This option is not passed further into the Mocha code but is immediately used to load the requested modules:
requires.forEach(function(mod) {
require(mod);
});
When you run Mocha in the browser, none of this code is run, and if you look in the rest of the Mocha code you won't find a similar facility anywhere else. Why?
Because it would serve no purpose. The --require option is very useful at the command line. Without it, the only way to load modules before Mocha loads the test files would be to either write custom code to start Mocha or put the necessary require calls at the start of every single test file.
In the browser, if you do not use a module loader, you can just load the code you'd load using --require by putting the script elements that load them in front of the script elements that load your tests. In Karma, this means putting these files earlier in the list of files you have in your karma.conf.js. Or if you use RequireJS, for instance, you write test-main.js so that the loading is done in two phases: one that loads the modules you'd load through --require on the command-line, and a second that loads your test files. It could be something like:
const allTestFiles = [];
const TEST_REGEXP = /test\/test.*\.js$/i;
Object.keys(window.__karma__.files).forEach((file) => {
if (TEST_REGEXP.test(file)) {
const normalizedTestModule = file.replace(/^\/base\/|\.js$/g, "");
allTestFiles.push(normalizedTestModule);
}
});
require.config({
baseUrl: "/base",
paths: {
...
},
});
// This guarantees that "a", "b", "c" loads before any other module
require(["a", "b", "c", ...], () => {
require(allTestFiles, window.__karma__.start);
});

Related

Is there a way I can run a specified .spec file once all "x" .spec files have been run? Cypress

I want to do some clearing up after all .spec files have been run by Cypress. For this I created another .spec file that does several API calls. I need Cypress to run this .spec file only after all tests form all the other files have ran. One more thing, my .spec files are being run by Cypress in parallel mode, via 4 machines.
I found out there are the "after" hooks I could use, but as far as I read, these hooks apply per only one .spec file, not all of them.
This is not exactly the answer you are looking for, but maybe this information can be useful to you in some way:
One of the antipatterns I have heard multiple times from Cypress gurus is cleaning the application state using after or afterEach hooks.
If I remember correctly, the reasoning was that if the test fails or some step of the after hook fails, it will never get to the end of the script, thus we cannot be sure that the application state is prepared for the future tests.
That's why it is suggested to use before or beforeEach hooks, to prepare application state right before running tests.
If you decide to run some scripts before or after tests in different specs, then the support file can be useful, because it is rendered before each spec:
https://docs.cypress.io/guides/core-concepts/writing-and-organizing-tests#Support-file
As a final thought, if you want something to happen before or after running Cypress, then maybe the best way to accomplish this is to prepare a separate script and run it using whatever you use to run Cypress (node, docker, etc.).
Sorry that this answer got so long :)
To conclude my thoughts:
Better prepare the state for the tests, not clean up after them
Separate scripts can be run before or after tests, and they do not have to be inside Cypress (using node, bash, docker...)
Hope this helps!
To run a single spec out of process, take a look at the Module Api.
With this you can create a node script that can be run after all parallel processes have completed.
./scripts/e2e-run-cleanup.js
const cypress = require('cypress')
cypress
.run({
spec: './cypress/e2e/cleanup.cy.js', // your cleanup spec
})
.then((results) => {
console.log(results)
})
.catch((err) => {
console.error(err)
})
Some configuration:
cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:1234',
excludeSpecPattern: ['cleanup.cy.js'], // exclude this one from the normal run
}
})
package.json
"scripts": {
...
"test:headless": "yarn cypress:run",
...
"cleanup": "yarn ./scripts/e2e-run-cleanup.js", // script to kick off
"posttest:headless": "yarn cleanup", // also after local run
// "post" prefix automatically
// runs this after "test:headless" script
...
}
main.yml
...
jobs:
install:
...
ui-chrome-tests:
...
cleanup:
...
needs: ui-chrome-tests # ensure tests have run
steps:
- run: yarn cleanup
You can use the After Run API for this use case:
module.exports = (on, config) => {
on('after:run', (results) => {
// run some code after the run
})
}
or
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('after:run', (results) => {
// run some code after the run
})
}
}
})

error loading css when running mocha tests with babel-node and babel-istanbul

I am having a problem testing UI components that import .scss with webpack. I am testing the component code directly, not the exported webpack bundle.
In my SUT
I have some code that imports scss:
import '!style!css!sass!postcss-loader!../style.scss'
This code causes an error when I run tests:
Error: Cannot find module '!style!css!sass!postcss-loader!../../stylesheets/parts/Breadcrumbs.scss'
at Function.Module._resolveFilename (module.js:336:15)
at Function.Module._load (module.js:286:25)
at Module.require (module.js:365:17)
at require (module.js:384:17)
Cheap workaround
I've been working around this issue with:
try {
require('!style!css!sass!postcss-loader!../style.scss');
} catch(err) { console.log('Not webpack'); }
But this smells dirty, and I would rather not have this code in my SUT.
Running Tests
I can't figure out how to work in the solutions that I have found for this when using babel-node and babel-istanbul instead of mocha directly. Here is how I am currently running tests:
$ babel-node babel-istanbul cover _mocha -- --require ./test/setup.js --recursive
All of the answers I have found are for mocha directly, but I am not running tests with:
$ mocha --compilers js:babel-core/register --require ./test/setup.js --recursive
?
How can I work in a compiler or setup file to tell mocha to ignore .scss files. I am going to have this problem next with .svg files too I am sure.
What about github.com/css-modules/css-modules-require-hook or if you wanna just ignore the css npmjs.com/package/ignore-styles
EDIT:
If you install ignore-style module and then run:
babel-node babel-istanbul cover _mocha -- --require ./test/setup.js --require node_modules/ignore-styles --recursive
im sure it will work, bare in mind you might need to change the path node_modules/ignore-styles im assuming you have your node_modules in the root of your project.
So I had a similar problem trying to require with a webpack-loader prefix and failing as not in the context of webpack.
prunk was better than rewire etc as covered me for all files as was able to do path matching and replacement.
var prunk = require('prunk');
prunk.alias(/^(your loader prefix)/, '');
Then I modified requires extension handling to replace what was being imported.
require.extensions['.scss'] = function (module, filename) {
module.exports = 'whatever you want';
};
(exactly what style-loader does but style-loader cleans itself up! Also note style loader is misnamed and can handle many extensions))
I added this at the top of my test runner and no unfound modules!
Note I actually went further and used the original loader by itself by reading in the file with fs and passing it to the loader but that may have been over kill and should be using webpack to transpile tests with that sole loader in the first place!

How to get Babel to compile using webpack-style 'modulesDirectories'?

Following this gist here
https://gist.github.com/ryanflorence/daafb1e3cb8ad740b346
I was able to set up a cool folder structure for a pretty complex app using Webpack's 'resolve.modulesDirectories' - I can reference shared components via module-type imports :
import MyModule from 'modules/MyModule';
where the file is in
src/app/modules/Foo/modules/Bar/modules/Baz/component.jsx
and MyModule is in
src/app/shared/modules/MyModule
The trouble is, when I try to run tests
mocha --compilers js:babel-core/register $(find src/app -name *.test.jsx)
the Babel compiler throws saying it can't find anything in 'modules/MyModule'...
Is there an analog to Webpack's 'modulesDirectories' in the Babel compiler config ?
You should be able to use Babel's resolveModuleSource option to essentially rewrite the import paths, but you'd need to use the programmatic API to do it. So instead of using Mocha's --compilers option, use --require to load a script that calls Babel's require hook and passes the resolveModuleSource option. If you're using Babel v6 use the babel-register package and it'd look something like:
require("babel-register")({
resolveModuleSource: function (source, filename) {
return filename.replace(/^modules\/.+/, "/abs/path/to/src/app/shared/$0");
},
});
You'll have to compile your tests using webpack:
https://webpack.github.io/docs/testing.html

Pass argument to jasmine unit test from karma?

I have some unit tests that where I'm using server paths to hit my mock stubs. Currently I'm add the URL into each test. I'd really like to pass this URL from my gulp task into the unit tests. Is this possible?
require('.path_to_my_karma').apply(null, [].concat(args).concat([**host_url**]));
When you run karma you can pass in custom options;
karma start --my-custom-url http://google.com
Then in your karma.conf.js you can access them like so;
module.exports = function(config) {
console.log('URL passed in from command line is %s', config.myCustomUrl);
config.set({
// ...
});
};

How to run mocha tests with webpack when you don't have a single entry point to tests?

I'm trying to convert a project from browserify+mochify to webpack.
The webpack docs demonstrate how to use mocha-loader to run the tests with webpack-dev-server, but assumes a single entry point into the tests.
All the existing tests were designed with mochify in mind which does not require a single entry point as it recursively bundles ./test/*.js.
The setup below sort of works for me. It still uses mochify to run the tests (because it has all the phantomjs interfacing), but doesn't rely on anything from browserify. If you run webpack --watch, it reruns all tests when a file changes.
webpack.config.js:
var path = require("path");
var child_process = require('child_process');
module.exports = {
entry: {
tests: "./tests.js"
},
output: {
filename: "tests.js", // Should be a unique name
path: "/tmp"
},
plugins: [
// Automatically run all tests when webpack is done
function () {
this.plugin("done", function (stats) {
child_process.execSync('mochify /tmp/tests.js', { stdio: 'inherit'});
});
}
],
};
tests.js:
// List all test dirs here if you have multiple
var contexts = [
require.context('./dir1/test', true, /\.js$/),
require.context('./dir2/test', true, /\.js$/)
];
contexts.forEach(function (context) {
context.keys().forEach(context);
});
Another approach is described here: https://stackoverflow.com/a/32386750/675011
This is not exactly an answer, but it solved the problem for me. The reason I wanted to combine mochify and webpack was that I wanted to use the browser console to debug my mocha tests. Since my mocha tests themselves don't rely on a browser, it was enough for me to finally realize I could use a node debugger and it would bring up the Chrome console, (almost) solving my problem. node-inspector is the node debugger, but I'm using babel, so I needed babel-node-debug, but that doesn't yet work with babel6, but there's an unmerged pull request that fixes it: https://github.com/CrabDude/babel-node-debug/pull/12.

Resources