How to determine if JEST is running the code or not? - javascript

I am creating a JS test on my react-native project. I'm specifically using firebase for react native, in which I would like to replace firebase instance with a mockfirebase instance if JS is running the code of my class.
For example I have class setup like below.
import firebase from 'react-native-firebase';
class Database() {
/// use the firebase instance
}
I'd like to have a check if jest is the running environment then I'd replace the import line with appropriate mock class.

jest sets an environment variable called JEST_WORKER_ID so you check if this is set:
function areWeTestingWithJest() {
return process.env.JEST_WORKER_ID !== undefined;
}
I also see that if NODE_ENV is not set the jest CLI sets it to the value 'test'. This might be another way to check.

I usually have NODE_ENV=development set globally on my shell. This works for me:
typeof jest !== 'undefined'
(note that global.jest and 'jest' in global don't work, as this doesn't seem to be a global variable, just a value made available on all modules much like node's require or __filename)

you could add parameter to global for example global.isJest and check on the front end if it is defined

For me best way is checking two things - 0 and undefined:
[0, undefined].includes(process.env.JEST_WORKER_ID)
so it's based on https://stackoverflow.com/a/52231746/3012785

Related

Testing JavaScript without exports using the Jest testing framework

I am in the process of moving an old JS codebase to modern JS. First step though is to add some tests to the current codebase. The current code base is essentially a bunch of individual JS files each wrapped in an IIFE.
This in itself is a problem for tests because, unless something is exposed to the global object, you cannot reach into the IIFE. Some of the code I am refactoring to be simple JS object with properties, which is attached to a namespace(namespace below is just a placeholder name) on the global object, for example:
var namespace = window.namespace || {};
var paymentsHandlerUtils = {
getNewValue: function(selectedAmount) {
'use strict';
return selectedAmount < 1 || isNaN(selectedAmount)
? ''
: '$' + selectedAmount;
},
getSelectedAmount: function(value) {
'use strict';
return value % 1 === 0 ? parseInt(value) : parseFloat(value).toFixed(2);
}
};
namespace.paymentsHandlerUtils = paymentsHandlerUtils;
My question is, how would you go about testing this with Jest? I have tried requiring the above as follows:
const paymentsHandlerUtils = require('../js/components/payments/payments-handler-utils.js');
This runs, but the paymentsHandlerUtils object is just an empty {}. Not surprising, as nothing is being returned by simply executing the JS. However, window.namespace is also undefined. Seems like the code is not being executed in the context of jsDOM, so the global(s) is not created.
Is there a way to get this to work, or is this simply not a use case for Jest? Thanks in advance.
I don’t think there is a way to access module globals when imported as it goes against the principle of encapsulated modules in the first place.
An alternative which would require the least refactoring would be to add the following code to all your modules:
if (typeof exports === "object") {
module.exports = paymentsHandlerUtils;
}
namespace.paymentsHandlerUtils = paymentsHandlerUtils;
It is inspired by the old UMD (Universal Module Definition). The condition detects if you are running in a commonjs environment and exports your variable. You will then be able to require it in your tests:
const paymentsHandlerUtils = require('../js/components/payments/payments-handler-utils.js');
Otherwise you need to use another test suite that works in the browser, because Jest doesn’t.
Good luck to your migrations!
In fact this is now possible with rewire. Here's what you have to do:
install rewire (npm i rewire)
in your jest file,
const rewire = require("'rewire');
const paymentsHandlerUtilsRewire = rewire('../js/components/payments/payments-handler-utils.js');
const namespace = paymentsHandlerUtilsRewire.__get__('namespace');
do what you were planning to do with namespace and namespace.paymentsHandlerUtils
Read more in the rewire repo; there's also babel-plugin-rewire for ES6+ (see, for instance, here).

Mock doesn't work, while reassignment does

I have the following Jest/Enzyme test:
const mockCheckMyFunctionality = jest.fn();
jest.mock('../modules/MyFunctionality', () => ({
checkMyFunctionality: mockCheckMyFunctionality
}));
const wrapper = shallow(
<App initialProps={mockInitialProps} />
);
expect(mockCheckMyFunctionality).toHaveBeenCalledTimes(1);
This will fail with TypeError: Cannot read property 'onNextTick' of undefined. The error message itself is not relevant, but it just shows that the real MyFunctionality.checkMyFunctionality is called instead of mockCheckMyFunctionality.
However, if I replace:
jest.mock('../modules/MyFunctionality', () => ({
checkMyFunctionality: mockCheckMyFunctionality
}));
With:
MyFunctionality.checkMyFunctionality = mockCheckMyFunctionality;
The test will pass, showing that mockCheckMyFunctionality is actually called. However, this is hacky and fails EsLint checking.
The method I am testing is just this:
setupMyFunctionality() {
checkMyFunctionality(this.props.something);
}
How can I modify the mocking such that it is visible inside App?
Reassignment seems to work but mocking doesn't.
Maybe you forgot to create a manual mock for the MyFuncionality module.
As in the documentation for mocking a module:
Manual mocks are defined by writing a module in a __mocks__/
subdirectory immediately adjacent to the module. For example, to mock a module called user in the models directory, create a file called user.js and put it in the models/__mocks__ directory.
...
When a manual mock exists for a given module, Jest's module system will use that module when explicitly calling jest.mock('moduleName').
If that's the case, you can create a folder named __mocks__ adjacent to the MyFunctionality file, then create a MyFunctionality file within that folder, containing the mock implementation as in the code snippet, and explicitly call the mock by calling jest.mock('../modules/MyFunctionality') before the tests.
Another solution, which I started using in my projects, is passing the dependencies as props to the components. To implement that you could change the App component and pass the MyFunctionality as props, thus in the above test you would need just to pass the mock implemented as props, avoiding the necessity of creating __mocks__/ folder to accomplish the test.

Testing URL query string in nodejs

Hey everyone I made a package that can manage and control URL query strings.
I publish it throw npm. and wrote some tests to the core of the package
"parser.js" - that parse the query string to an object
"strigifyer.js" - that make an object to URL query string
I test those files for now with "mocha" and "expect"
there is one main file that manage the above files and the file is also push to query string to URL without refresh. it uses the window.history object.
what should I do to success to test the main file (index.js)?
I need the window and history objects to check if there is a change after I use my api.
here is the package if its help:
https://github.com/nevos12/query-string-manager
thank you.
If I understood correct, the module that exposes your library is src/index.js
From the code style of your index.js, I'd suggest to use sinon to test your code flow.
A unit test could be :
import sinon from 'sinon'
import qs from 'src/index.js'
it('should reset queryStringObject', () => {
const pushToUrlSpy = sinon.spy(qs, 'pushToUrl');
qs.reset(true);
expect(qs.queryStringObject).to.equal({});
expect(pushToUrlSpy.called);
pushToUrlSpy.restore();
})
This code creates a spy on pushToUrl() , invokes reset() and asserts that queryStringObject is an empty object now and pushToUrl() was invoked as least once. In the end it restores the spy, otherwise other tests might act weird.

Using Cucumber.js with Jest

I am using Jest for my unit tests and I'm in the process of integrating Cucumber.js for running specs written in Gherkin.
I have it all set up and it's working, but I am running into one problem: How can I use Jest's expect? I could use chai's, but I'd like to keep the expect syntax the same between my unit tests and my step definitions (I don't want to.equal in my step definitions and toEqual in my unit tests).
How can I do that? After some digging it seems as if Jest relies on the expect npm package. I could depend on that package explicitly in my package.json, but I'd much rather use my existing Jest dependency. Maybe that's not possible, but I hope it is.
Another option would be to somehow execute the Gherkin specs with the Jest test-runner. I'd be open to that option as well. At the moment I'm running them by calling cucumber.js separately from my Jest test-runner.
My react-native environment:
"cucumber": "^4.1.0",
"jest": "22.4.2",
In my steps definition file, I just require it like this
const { Given, Then, When } = require('cucumber');
const expect = require('expect');
Expect is part of Jest, so you can import it as its own object. Then I can use it wherever I need an assertion. Note: newMember is declared and populated elsewhere.
Given('Sara has provided account details', function() {
for (const prop in newMember) {
expect(newMember[prop]).toBeTruthy();
}
});
Hope that helps.
expect is a globally scoped during jest runtime. So as long as you are running jest it will be available. I'm using this package (needs some config to transform correctly to your babel config): gherkin-jest
Here's a feature using the DOM-testing example from the jest docs:
Feature: Using feature files in jest and cucumber
As a developer
I want to write tests in cucumber and jest
So that businesspeople understand tests and I can test React
Scenario: Emoji toggles upon checking and unchecking the checkbox
Given I did not check the checkbox, so the label is "😭"
When I check the box and the emoji toggles to be "😎"
import {cucumber as c} from 'gherkin-jest'
import React from 'react'
import {mount} from 'enzyme'
import {Checkbox} from '../src/components'
c.defineCreateWorld(() => ({
checkbox:null
}))
c.defineRule('I did not check the checkbox so the label is {string}', (world, off) => {
world.checkbox = mount(<Checkbox labelOff={off} />)
expect(world.checkbox.text()).toBe(off)
})
c.defineRule('I checked the box and the emoji toggles to be {string}', (world, on) =>{
world.checkbox = mount(<Checkbox labelOn={on}/>)
world.checkbox.find('TouchableOpacity').props().onPress()
expect(world.checkbox.text()).toBe(on)
})
This issue I posted gives an example of the config.
An alternative would be to use jest-cucumber
https://www.npmjs.com/package/jest-cucumber.
gives you the flexibility of using both frameworks

Sinon and eslint

I am writing unit tests for my angular app with Karma, Jasmine, and Sinon and I run eslint over my code base.
I define global variables that will be used in the beforeEach inject to create a sinon.stub. ESLint keeps complaining that my global variables are defined but never used. For example:
'getListStub' is defined but never used no-unused-vars
but in my code it looks like this
var listService, getListStub;
beforeEach(inject(function(_listService_) {
listService = _listService_;
getListStub = sinon.stub(listService, 'getList').returns(q.when(listResponse));
}
What is the best way to stop ESLint from producing errors?
Is setting /*eslint no-unused-vars: 0*/ at the top of those testing files best?
If you aren't using getListStub anywhere, why are you assigning it to a variable?
The properties of JS closure and memory management (specifically, holding referenced objects) will allow you to use _listService_ directly and you shouldn't need to cache getListStub.
If that does work correctly with sinon, you should be able to rewrite your function as:
beforeEach(inject(function(_listService_) {
sinon.stub(_listService_, 'getList').returns(q.when(listResponse));
}

Categories