`window`没有暴露给Jest

125*_*748 14 javascript unit-testing reactjs jestjs

我有一个测试导入一个组件,该组件又导入一个帮助文件,该文件使用该window对象来提取查询字符串参数.我收到以下错误window:

 FAIL  src/js/components/__tests__/Controls.test.jsx
  ? Test suite failed to run

    ReferenceError: window is not defined
Run Code Online (Sandbox Code Playgroud)

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()
  })
})
Run Code Online (Sandbox Code Playgroud)

Controls.jsx导入./helpers/services.js,其中包含以下内容:

import * as queryString from 'query-string'
const flag = queryString.parse(window.location.search).flag || 'off'
                               ^^^^^^ this seems to be the problem
Run Code Online (Sandbox Code Playgroud)

我试图导入jsdom

import { JSDOM } from 'jsdom'
Run Code Online (Sandbox Code Playgroud)

并在我的测试文件顶部实现此处提供的解决方案:

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);
Run Code Online (Sandbox Code Playgroud)

但是我仍然得到错误,似乎JSDOM的窗口对象没有暴露在测试中.

我怎样才能正确曝光像全局对象windowdocument一个玩笑测试?

相关的package.json
  "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"
  }
Run Code Online (Sandbox Code Playgroud)

Jos*_*des 17

您的问题依赖于配置.

在你设定的那一刻:

"testEnvironment": "jest-environment-node"
Run Code Online (Sandbox Code Playgroud)

您正在将默认配置从类似浏览器的jest更改为jest-environment-node (类似节点),这意味着您的测试将在NodeJs环境 下运行

要解决此问题,要么将您设置testEnvironmentjsdom
或者testEnvironment从配置中删除它,以便它将采用您的默认值package.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
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

这就是他们在文档中所说的:

testEnvironment [string]#默认:"jsdom"

将用于测试的测试环境.Jest中的默认环境是通过jsdom的类似浏览器的环境.如果要构建节点服务,则可以使用node选项来改为使用类似节点的环境.


你需要`node`环境吗?

正如我所看到的,您的测试应该在类似浏览器的环境中运行.

如果您需要显式节点环境,最好使用@jest-environment以下方法隔离该情况:

/**
 * @jest-environment node
 */

test('use node in this test file', () => {
  expect(true).not.toBeNull();
});
Run Code Online (Sandbox Code Playgroud)

或者反过来,如果你打算在node环境下运行测试

/**
 * @jest-environment jsdom
 */

test('use jsdom in this test file', () => {
  const element = document.createElement('div');
  expect(element).not.toBeNull();
});
Run Code Online (Sandbox Code Playgroud)

结论

有了这个,你可以避免jsdom手动导入和设置全局变量,jsdomDOM自动模拟实现.

如果您需要更改测试环境,请使用表示法 @jest-environment

  • 由于 Jest 27“jsdom”不再是默认值,而是“node”,请参阅 https://github.com/facebook/jest/pull/9874 和此处 https://jestjs.io/blog/2021/05/25 /jest-27#flipping-defaults。所以你现在必须明确设置“jsdom”。 (2认同)

Dem*_*mon 4

你可以尝试做

global.window = new jsdom.JSDOM().window;
global.document = window.document;
Run Code Online (Sandbox Code Playgroud)