I have a test that imports a component that in turn imports a helper file that uses the window
object to pull out a query string parameter. I get the following error about window
:
FAIL src/js/components/__tests__/Controls.test.jsx
● Test suite failed to run
ReferenceError: window is not defined
Controls.jsx:
import { Unwrapped as Controls } from '../Controls'
describe('<MyInterestsControls />', () => {
it('should render the component with the fixture data', () => {
const component = shallow(
<UnwrappedMyInterestControls
dashboardData={dashboardData}
loadingFlags={{ controls: false }}
/>
)
expect(component).toMatchSnapshot()
})
})
Controls.jsx imports ./helpers/services.js which contains the following:
import * as queryString from 'query-string'
const flag = queryString.parse(window.location.search).flag || 'off'
^^^^^^ this seems to be the problem
I have attempted to import jsdom
import { JSDOM } from 'jsdom'
And implement the solution presented here at the top of my test file:
const { JSDOM } = require('jsdom');
const jsdom = new JSDOM('<!doctype html><html><body></body></html>');
const { window } = jsdom;
function copyProps(src, target) {
const props = Object.getOwnPropertyNames(src)
.filter(prop => typeof target[prop] === 'undefined')
.map(prop => Object.getOwnPropertyDescriptor(src, prop));
Object.defineProperties(target, props);
}
global.window = window;
global.document = window.document;
global.navigator = {
userAgent: 'node.js',
};
copyProps(window, global);
however I still get the error and it seems JSDOM's window object isn't exposed to the test.
window
or document
to a jest test? "scripts": {
"test:watch": "NODE_ENV=test jest --watch"
},
...
"devDependencies": {
...
"jest": "^20.0.4",
"jest-mock": "^21.2.0",
"jsdom": "^11.0.0",
...
},
...
"jest": {
"verbose": true,
"collectCoverageFrom": [
"src/js/helpers/preparePayload.js",
"src/js/components-ni",
"!**/node_modules/**",
"!**/dist/**"
],
"coverageThreshold": {
"global": {
"statements": 50,
"branches": 50,
"functions": 50,
"lines": 75
}
},
"testEnvironment": "jest-environment-node"
}
To mock the JavaScript window object using Jest, we can use the jest. spyOn method. let windowSpy; beforeEach(() => { windowSpy = jest. spyOn(window, "window", "get"); }); afterEach(() => { windowSpy.
Jest is a JavaScript testing framework built on top of Jasmine and maintained by Meta (formerly Facebook). It was designed and built by Christoph Nakazawa with a focus on simplicity and support for large web applications.
Jest is a JavaScript testing framework designed to ensure correctness of any JavaScript codebase. It allows you to write tests with an approachable, familiar and feature-rich API that gives you results quickly. Jest is well-documented, requires little configuration and can be extended to match your requirements.
By default, jest uses the node testEnvironment. This essentially makes any tests meant for a browser environment invalid. jsdom is an implementation of a browser environment, which supports these types of UI tests.
UPDATE:
As mentioned by @RiZKiT in the comment bellow, since Jest
v.27.0
the default test environment has changed from"jsdom"
to"node"
.
Your problem relies on the configuration.
In the moment you set:
"testEnvironment": "jest-environment-node"
you are changing the default configuration from jest which is browser-like to jest-environment-node
(node-like) meaning that your test will be run under a NodeJs
environment
To solve it either you set your testEnvironment
to jsdom
Or you remove the testEnvironment
from your config so it will take the default value in yourpackage.json
:
...
"jest": {
"verbose": true,
"collectCoverageFrom": [
"src/js/helpers/preparePayload.js",
"src/js/components-ni",
"!**/node_modules/**",
"!**/dist/**"
],
"coverageThreshold": {
"global": {
"statements": 50,
"branches": 50,
"functions": 50,
"lines": 75
}
}
}
testEnvironment
[string] # Default: "jsdom"The test environment that will be used for testing. The default environment in Jest is a browser-like environment through jsdom. If you are building a node service, you can use the node option to use a node-like environment instead.
As I could see, your tests are meant to be run under a browser-like environment.
If you ever need an explicit node environment, better you isolate that case using @jest-environment
:
/**
* @jest-environment node
*/
test('use node in this test file', () => {
expect(true).not.toBeNull();
});
or the other way around if you are meant to run the tests under node
environment
/**
* @jest-environment jsdom
*/
test('use jsdom in this test file', () => {
const element = document.createElement('div');
expect(element).not.toBeNull();
});
With this you can avoid importing jsdom
manually and setting global variables, jsdom
will mock the DOM
implementation automatically.
If you need to change the environment for your tests use the notation @jest-environment
You could try doing
global.window = new jsdom.JSDOM().window;
global.document = window.document;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With