I'm working on a project that has a method defined in the script tag of the index.html file. For some reason, that causes Jest to fail when it runs.
index.html
<script>
var getCookie = function(cookieVal) { return cookieVal; }
</script>
To fix this, I've tried defining the 'getCookie' variable inside of Jest globals like:
package.json
"jest": {
"globals": {
"getCookie": "someString"
}
}
This does define getCookie, but when I run my tests I get this error:
Error in data(): "TypeError: getCookie is not a function"
which makes sense, but I'm not sure how I can define it as a function in the globals object.
How can I mock my getCookie function in Jest?
Even though the Jest docs indicate that globals cannot contain functions, I verified that global functions could still be defined with a function expression or arrow function:
{
jest: {
globals: {
getCookie() { return 'someCookie' }, // function expression
getCookie: () => 'someCookie', // arrow function
}
}
}
Alternatively, you could define a setupFiles that sets global.getCookie:
// package.json
{
jest: {
setupFiles: ['./jest.setup.js']
}
}
// jest.setup.js
global.getCookie = () => 'someCookie'
Related
My mocked utilFunction isn't being used and adding logging to the factory function shows that it's never called. I've already tried searching for jest.mock not working with relative paths and jest.mock not being called for Typescript thinking that it might be related to the mix of JS tests and TS source code or to the different module paths used in the source vs test code.
Code being tested:
// src/foo/fooModule.ts
import { utilFunction } from '../util'
export const foo = () => {
return utilFunction()
}
Test code:
// test/fooModule.test.js
const { foo } = require('../src/foo/fooModule')
jest.mock('../src/util', () => {
return { utilFunction: () => 'mocked' };
});
describe('fooModule tests', () => ...)
The jest.mock call needs to be moved above the imports:
// test/fooModule.test.js
jest.mock('../src/util', () => {
return { utilFunction: () => 'mocked' };
});
const { foo } = require('../src/foo/fooModule')
describe('fooModule tests', () => ...)
My last experience working with Jest prior to this was in a project where the tests were also written in Typescript and babel-jest was used. babel-jest includes babel-jest-hoist which hoists the jest mocks above any imports automatically, so I didn't previously have to worry about the ordering.
I have code that I am writing tests for to refactor later, as such I cannot change the code or any of the dependencies. Here is the problem:
// foo.js
Knex = require('knex')
module.exports ={func}
// calling this inside func will
// have the expected {a:4}
client = Knex()
async function func(){
console.log(client)
return true
}
// foo.spec.js
const foo = require('./foo')
const Knex = require('knex')
jest.mock('knex', ()=>jest.fn())
describe('jest.mockImplementation',()=>{
it('should mock knex',async ()=>{
Knex.mockImplementation(()=>({a:4}))
// alternative, I can put
// const foo = require('./foo')
// here
await foo.func()
})
})
// jest.config.js
module.exports={
"verbose": true,
"testEnvironment": "node",
}
//package.json
{
"dependencies": {
"jest": "^26.6.3",
"knex": "0.19.3"
}
}
I run:
$ jest --config jest.config.js --runInBand foo.spec.js and I expect there to be a console log of { a : 4}, but it is undefined. Note however, if I move the client inside func then it will log {a : 4}
alternatively, if I leave the client where it is and require foo in spec.js after mockImplementation, it will again have the expected console log.
I would have expected to see the correct behavior with the client being created outside of func and without needing to require foo after mockImplementation.
Why is this happening and how can I have the desired behavior without moving the client? also requireing inside the function is not the best.
I created this repl.it for experimentation; please don't update it for others' use:
https://replit.com/join/xmlwttzl-eminarakelian1
The code of the module scope will be executed immediately when the module is required, so it is too late to provide the mock implementation in the test case.
jest.mock() will be hoisted to the top of the test file. It will be executed before the require statement, so when the module is required, the mock implementation provided in jest.mock() will be used.
Provide a mock implementation inside jest.mock() like this:
const foo = require('./foo');
jest.mock('knex', () => jest.fn(() => ({ a: 4 })));
describe('jest.mockImplementation', () => {
it('should mock knex', async () => {
await foo.func();
});
});
test result:
PASS examples/66881537/foo.spec.js (6.347 s)
jest.mockImplementation
✓ should mock knex (15 ms)
console.log
{ a: 4 }
at Object.<anonymous> (examples/66881537/foo.js:8:11)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 6.789 s
I am running into a strange issue.
xxx.testFunction(); statement when executed errors out: TypeError: Cannot read property 'testFunction' of undefined, but works when executed with pre-condition if(xxx)..
Issue can be recreated in the following setup
index.js
const { Module1 } = require("./Module1"); //Commenting out this line fixes the issue
const { Module3 } = require("./Module3");
Module3.testFunction();
Module1.js
const { Module2 } = require("./Module2");
class Module1 {
static testFunction() {
console.log("testFunction")
}
}
module.exports = { Module1 };
Module2.js
const { Module3 } = require("./Module3"); //Commenting out this line also fixes the issue
class Module2 {
}
module.exports = { Module2 };
Module3.js
const { Module1 } = require("./Module1");
class Module3 {
static testFunction() {
//if(Module1) //If we merely check this first it works, but directly it doesn't
Module1.testFunction();
}
}
module.exports = { Module3 };
Moreover, if some of the require statements are removed, the function gets executed..
It also gets fixed when order of requires in index.js is changed.
If you're wondering why the extra requires, the reason is that they were needed for other code in the modules.. The above code is a stripped down version of the production code we found the issue in.
As per my understanding variables in nodejs modules are scoped to the module, and should not have any effect on other modules..
Can someone explain this behavior..
It seems that you have a circular dependency. to solve it you can require in the function itself as if you make Module3.js looks like:
class Module3 {
static testFunction() {
const { Module1 } = require("./Module1");
Module1.testFunction();
}
}
module.exports = { Module3 };
I'm trying to define a module in requirejs and use it in another script.
I've tried a lot of things, but I cannot achieve what I want.
At the moment this is what I have.
define([],{
return {
functionOne: function(){etc, etc...}
functionTwo: function(){etc, etc...}
}
})
Then I put this in the configuration file:
requirejs.config({
paths: {myModule: pathToMyModule}
})
And then, this in the script where I want to use this module
requirejs(["myModule"], function(){
//Some code
})
But I'm still getting this errors when I try to use the defined module:
myModule is not defined.
functionOne is not defined.
functionTwo is not defined.
Am I missing something?
Thank you.
To declare your module, you need to use a function, so the first line in myModule.js should look like this:
define([], function () { // ...
When you're invoking the module, you need to declare it as an argument, so your requirejs call should look like this:
requirejs(["myModule"], function (myModule) {
// ^^^^^^^^
// Notice the argument declaration
The following worked for me:
// myModule.js
define([], function () {
return {
functionOne: function(){
console.log("Hello, world. I'm functionOne.");
},
functionTwo: function(){
console.log("Hello, world. I'm functionTwo.");
}
}
});
// require.config.js
requirejs.config({
paths: { myModule: './myModule' }
});
// index.js
requirejs(["myModule"], function (myModule) {
myModule.functionOne();
myModule.functionTwo();
})
I'm new at unit testing but I've tried many methods of getting my script (require module) loaded for use with my mocha test script. No matter what I do I always get undefined when I try to read a property or function or anything. Can anyone help point out what may be causing this?
rmq.js (script to test)
define(['bx_slider/1/bx_slider'], {
...
ansrTotal: 0,
...
init: function(settings) {
var self = this;
// do some stuff
return self;
}
});
test-bootstrap.js
require.config({
paths: {
'chai': '/node_modules/chai/chai',
'bx_slider/1/bx_slider': '/test/lib/bx_slider'
},
baseUrl: '/',
nodeRequire: require
});
mocha.setup({
ui: 'bdd'
});
require(['test/test'], function() {
if (window.mochaPhantomJS) {
mochaPhantomJS.run();
} else {
mocha.run();
}
});
test.js
define(['chai'], function(chai) {
var expect = chai.expect;
var rmq = require(['../src/js/rmq']);
describe('rmq test suite', function() {
before(function() {
return rmq.init();
});
it('should blah', function() {
expect(rmq.ansrTotal).to.equal(0);
});
});
});
If it helps, my directory structure is
.
/node_modules
/src
/js
rmq.js
/test
/lib
bx_slider.js
require.js
test-bootstrap.js
test.js
The exact error (for what I have currently written and posted here) in my CLI is
Testing: test/test.js
rmq test suite
"before all" hook
'undefined' is not a function (evaluating 'rmq.init()')
As Mathletics mentioned in a comment, you could do:
define(['chai', '../src/js/rmq'], function(chai, rmq) {
If, for some reason, you cannot do that, there's an alternative. (Maybe you simplified your code so much in your question that the reason is no longer apparent.)
define(['chai'], function(chai) {
var expect = chai.expect;
describe('rmq test suite', function() {
var rmq;
before(function (done) {
require(['../src/js/rmq'], function (_rmq) {
// Save the module we got to the `rmq` variable.
rmq = _rmq;
// Init and call `done` when finished.
rmq.init().then(done);
});
});
it('should blah', function() {
expect(rmq.ansrTotal).to.equal(0);
});
});
});
I have assumed that rmq.init() returns a promise since you did return rmq.init() in your code, and doing this does not make sense unless rmq.init() returns a promise. If that's not the case then you'd have to call rmq.init() and then call done() after it.
The code you had cannot work because require(['../src/js/rmq']) gets the module asynchronously so it does not return the module. You have to use it like I've shown above.