Integrating Jest and Rewire - javascript

Working on getting a project transitioned over from Mocha to Jest to take advantage of the speed in running tests as well as the Jest framework itself and running into an issue. Rewire is used pretty extensively in the codebase and I'm having an issue when running the gulp-jest task and only for those files that use rewire. I assume it has something to do with modules loading or not loading, but I'm stumped. Here's the really bare-bones gulp task, doesn't have much to it. I've already run through an extensive codemod on the codebase and many tests pass, just not those that use rewire.
gulp.task('jest', function() {
process.env.NODE_ENV = 'test';
return gulp.src('name/path').pipe(
jest({
preprocessorIgnorePatterns: ['<rootDir>/node_modules/'],
automock: false,
resetModules: true,
setupFiles: ['./jestsetup.js']
})
);
});
gulp.task('newtest', function(callback) {
runSequence('env', 'jest', callback);
});
Any time the rewire-related files are run, they complain about the file not being found. Am I missing anything here? I'm certain the modules themselves have the correct path set for the require.
Here's the actual error from jest/rewire:
FAIL path/to/folder/file/app.test.js
● Test suite failed to run
Cannot find module '../../../../path/to/folder/file/app'
at Function.Module._resolveFilename (module.js:469:15)
at internalRewire (node_modules/rewire/lib/rewire.js:23:25)
at rewire (node_modules/rewire/lib/index.js:11:12)
at Object.<anonymous (path/to/folder/file/app.test.js:10:14)
at process._tickCallback (internal/process/next_tick.js:109:7)
Using node 6.X, jest 20.x
Thanks in advance!

Jest has its own mechanism of mocking import, it's called jest.mock.
You will need to switch to using that instead of rewire.
Example
// banana.js
module.exports = () => 'banana';
// __tests__/test.js
jest.mock('../banana');
const banana = require('../banana'); // banana will be explicitly mocked.
banana(); // will return 'undefined' because the function is auto-mocked.
example was taken from here

To my surpise, Proxyquire was not compatible with jest. To mock a dependency you would need to utilize a mocking library, like rewiremock.
Please have a look at this answer and this REPL example on how to successfully mock dependent packages.

Related

Mocha / Webpack: Cannot use import statement outside a module

I'm new to Node and JS Testing. I have a web applications w/ Webpack as a bundler. I have some entry point JS's which are included into the page. The entry points are using module files like this:
export default function() {
...
}
Now I would like to Unit test this module. I have picked up Mocha but it is not critical to me. Could be Jest or anything else.
I wrote a very simple test.js like this. It it not doing anything but tests if the entire setup works:
import foo from '../js/someModuleOfMine'
const assert = require('assert')
describe('Test Suite', () => {
it('should at least run', () => {
assert.equal(true, true)
})
})
executing mocha from CLI gives me this error:
import foo from '../js/someModuleOfMine'
^^^^^^
SyntaxError: Cannot use import statement outside a module
Adhering to some advises I have tired to add "type": "module" to my package.json but it only changed error to something even more obscure:
Error: Not supported
I am definitely missing something obvious but I cannot comprehend what.
Not sure if it will help the OP, but I had the same problem and it was due to typescript. I solved in this way:
install ts-node:
npm install ts-node --save-dev
add the require line in the mocha config (I have it in the package.json, but one can also have it in the .mocharc.json file):
"mocha": {
"spec": "./**/*test.ts",
"ignore": "./node_modules/**",
"require": "ts-node/register/files",
"timeout": 20000
}

How to get Jest to see the functions I am writing for MongoDB Stitch?

I am trying out Stitch, a serverless/hosted JavaScript environment from MongoDB. My main purpose is to help me learn modern JavaScript, but I am trying to write a useful app as well.
I have written the following function, and saved it in my Stitch app. I believe this follows the documented way to write functions in Stitch, and I have tested it from the Stitch administration console:
exports = function(query){
const http = context.services.get("HTTP");
const urlBase = context.values.get("stackOverflowApiUrl");
const options = [
'order=desc',
'sort=activity',
'site=stackoverflow',
'q=' + encodeURIComponent(query),
'user=472495',
'filter=!--uPQ.wqQ0zW'
];
return http
.get({ url: urlBase + '?' + options.join('&') })
.then(response => {
// The response body is encoded as raw BSON.Binary. Parse it to JSON.
const ejson_body = EJSON.parse(response.body.text());
return ejson_body.total;
});
};
This code is pretty simple - it obtains an http object for making external API fetches, and obtains a configuration value for a URL urlBase to contact (resolving to https://api.stackexchange.com/2.2/search/excerpts) and then makes a call to the Stack Overflow Data API. This runs a search query against my user and returns the number of results.
So far so good. Now, I want to call this function locally, in Jest. To do this, I have installed Node and Jest in a local Docker container, and have written the following test function:
const callApi = require('./source');
test('Simple fetch with no user', () => {
expect(callApi('hello')).toBe(123);
});
This fails, with the following error:
~ # jest
FAIL functions/callApi/source.test.js
✕ Simple fetch with no user (3ms)
● Simple fetch with no user
TypeError: callApi is not a function
2 |
3 | test('Simple fetch with no user', () => {
> 4 | expect(callApi('hello')).toBe(123);
| ^
5 | });
6 |
at Object.<anonymous>.test (functions/callApi/source.test.js:4:12)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.418s
Ran all test suites.
(In fact I was expecting it to fail, since it contains a global object context that Jest does not have access to. I will work out how to mock that later, but for now Jest cannot even see the function at all).
I suspect I can see the reason - in the Jest introduction docs, one has to do this for the SUT:
module.exports = function() { ... }
However the Stitch docs seem to require functions to be defined as:
exports = function() { ... }
I do not have a background in JavaScript to understand the difference. I could try module.exports in Stitch, but I would rather not, since this would either not work now, or cause a breakage in the future. Can Jest be instructed to "see" bare exports without the module prefix?
Incidentally, I have picked Jest because it is popular, and because some of my JavaScript colleagues vouch for it. However, I am not wedded to it, and would be happy to use something else if it is known to be better for Stitch development.
Update
Following the useful answer from jperl below, I find that the following construction is not possible in Stitch:
module.exports = exports = function() {}
I also cannot do this:
exports = function() {}
module.exports = exports
If I try either, I get the following error:
runtime error during function validation
So it looks like I have to get Jest to work without module.exports, or create a glue file that imports the exports version into module.exports, with the main file being used by Stitch, and the glue importer being used by Jest.
I suggest you to read this thread. And you're right in thinking it has to do with modules.exports vs exports. The thing is that module.exports and exports first point to the same thing. So something like this works:
//modify the same object that modules.exports is pointing to
exports.a = {}
exports.b = {}
but this won't:
exports = {}
Why? Because now exports points to something else than module.exports so what you're doing has no effect at all.
Update
Following some updates in the comments, we came to the view that Stitch does not seem to support the export format that Jest requires.
This is an addendum to jperl's answer, to show how I got Jest working while respecting Stitch's limitations.
Firstly, it is worth noting how a Stitch application is laid out. This is determined by the import/export format.
auth_providers/
functions/
function_name_1/
config.json
source.js
function_name_2/
config.json
source.js
...
services/
values/
The config.json file is created by Stitch remotely, and is obtained through a export. This contains ID information to uniquely identify the function in the same folder.
I believe it is common JavaScript practice to mix tests with source code, so I am following that style (I am new to modern JS, and I confess I find this style untidy, but I am running with it nevertheless). Thus I add a source.test.js file in each function folder.
Finally, since there is a discrepancy between what Stitch requires and what Jest requires, I have written a script to create a source code file under _source.js in each function folder.
So, each folder will contain these files (the underscore files will probably be ignored by Git, as they will always be generated):
_source.js
config.json
source.js
source.test.js
In order to create the underscored copies, I am using this shell script:
#!/bin/bash
# Copy all source.js files as _source.js
for f in $(find functions/ -name source.js); do cp -- "$f" "$(dirname $f)/_$(basename $f)"; done
# Search and replace in all _source.js files
for f in $(find functions/ -name _source.js); do sed -i -e 's/exports =/module.exports =/g' $f; done
A bit hacky perhaps, but it works!

protractor 3.0.0 and cucumber automated testing

I am currently using protractor, cucumber and chai/chai-as-promised for my automated tests. My current code is using protractor 1.8.0 and I would like to update it to the most recent version. The problem is that the most recent version of protractor doesn't support cucumber.
To use cucumber as your framework, protractor (http://angular.github.io/protractor/#/frameworks) points you to using protractor-cucumber-framework (https://github.com/mattfritz/protractor-cucumber-framework). I have tried integrating this with my current code and some smaller example projects with no luck at getting them working. The main error I get is:
Error: Step timed out after 5000 milliseconds at Timer.listOnTimeout
(timers.js:92:15)
I have tried changing the default timeout globally as cucumber suggests by:// features/support/env.js
var configure = function () {
this.setDefaultTimeout(60 * 1000);
};
module.exports = configure;
But I seem to be missing something with my setup.
So, does anyone know of a good example that can show me the proper setup for the new protractor/cucumber framework? If not, does anyone know of an example that shows how to change the default timeout globally?
You should add
this.setDefaultTimeout(60000);
to one of your step_def files. For example:
module.exports = function () {
this.setDefaultTimeout(60000);
this.After(function (callback) { ... }
}
Or you should add //features/support/env.js to
cucumberOpts:{require: ['//features/support/env.js']}
to array with your stepDefinition files
thx to #Ivan,
with cucumber-protractor-framework and typescript:
in protractor.conf.js
cucumberOpts: {
compiler: "ts:ts-node/register",
require: [
'./src/env.ts', //<- added
'./src/**/*.steps.ts'
]
},
in src/env.ts:
import {setDefaultTimeout} from 'cucumber';
setDefaultTimeout(9001);

Why does using Mongo in package tests fail when the package has api.use('mongo')?

I'm developing a custom package. Its package.js is :
Package.describe({
name: 'adigiovanni:one-way-accounts',
version: '0.0.1',
summary: 'One Way Accounts',
git: '',
documentation: 'README.md',
});
Package.onUse(function (api) {
api.versionsFrom('1.2.0.2');
api.use('ecmascript');
api.use('mongo');
// api.imply('mongo');
api.addFiles([
'lib/collections/Accounts.js',
'lib/methods.js',
'lib/OneWayAccounts.js',
]);
api.export('OneWayAccounts');
});
Package.onTest(function (api) {
api.use([
'ecmascript',
'sanjo:jasmine#0.20.2',
'velocity:html-reporter',
]);
api.use('adigiovanni:one-way-accounts');
api.addFiles('tests/client/OneWayAccounts.js', 'client');
api.addFiles('tests/server/OneWayAccounts.js', 'server');
});
As you can see, package makes use of 'mongo'.
Tests fail with :
Reference error: Mongo is not defined
But if I uncomment the line api.imply('mongo') then tests succeed.
Same odd behavior applies to ecmascript dependency, if I don't api.use('ecmascript') in Package.onTest, tests fail.
Meteor version is 1.2.0.2.
Test runner is velocity.
Test framework is jasmine.
I am using Mongo and ES6 syntax and features in my tests.
What is happening and how can I fix it?
Using a package with api.use('other-package') in Package.onUse does not make 'other-package' available in your test codes in the same way it doesn't make it available for other packages that use('my-package') or in applications that meteor add my-package. To solve this issue there is two solutions depending on the need for other-package :
Allowing users of the package (including your tests) to access 'other-package' with api.imply
Package.onUse(function (api) {
//...
api.imply('other-package')
//...
})
This makes sense if and only if the package you imply is necessary to use your own package. Do not imply everything willy-nilly for scope convenience. See more in this question.
If it does not fall into that category,
Simply use the package in your tests
Package.onTest(function (api) {
//...
api.use('my-package')
api.use('other-package')
//...
})
This will allow you to use other-package in your tests too, without polluting scopes.

Mocha + RequireJS in the browser - cannot instantiate _ui

I am having a hard time trying to run tests with Mocha and RequireJS in the browser.
My attempt is based on https://gist.github.com/michaelcox/3800736
I had to diverge from that example, because my main issue is that require('mocha') always errors with "Module name "lib/mocha" has not been loaded yet for context".
But somehow magically I see that global Mocha is instantiated. I invoke it as a constructor, but the run of new Mocha() does not prepare the interface (describe, etc.)
I see that the problem is that an inner call to
this._ui = this._ui(this.suite);
leaves this._ui undefined, apparently because array this.suite.tests is empty, which is explainable as I still have to read the test suite file.
Here are the details. If anyone can shed some light, I'll be very grateful.
I start from a single HTML tag loading require.js with a data-main.
<script data-main="./js_modular/spec-runner" src="./js_modular/lib/require.js"></script>
My data-main file (not working!) is the following:
require.config({
'paths': {
'mocha': './lib/mocha',
'chai': './lib/chai',
'sinon': './lib/sinon-1.11.1'
}
});
define(['require', 'exports', 'mocha'], (function(require, exports, mocha) {
// mocha is undefined, but Mocha is not
var mocha = new Mocha({ ui: 'bdd' }); // mocha misses the characteristic methods of the bdd interface, though...
require([
'./geiesadts_test', // load of test file fails because describe is undefined
], function(require) {
mocha.run(); // never got till here :-(
});
}));
Thank you for your attention.

Categories

Resources