Подтвердить что ты не робот

`window` не подвергается Jest

У меня есть тест, который импортирует компонент, который, в свою очередь, импортирует вспомогательный файл, который использует объект window, чтобы вытащить параметр строки запроса. Я получаю следующую ошибку: 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 импортирует. /helpers/services.js, который содержит следующее:

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

Я попытался импортировать jsdom

import { JSDOM } from 'jsdom'

И реализуем представленное решение здесь в верхней части тестового файла:

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);

однако я все равно получаю сообщение об ошибке, и кажется, что объект окна JSDOM не подвергается тестированию.

Как я могу правильно открыть глобальные объекты, такие как window или document, для теста jest?

Соответствующий пакет .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"
  }
4b9b3361

Ответ 1

Ваша проблема зависит от конфигурации.

В тот момент, когда вы установили:

"testEnvironment": "jest-environment-node"

вы меняете конфигурацию по умолчанию из jest, которая похожа на браузер, на jest-environment-node (node -like), что означает, что ваш тест будет запущен в среде NodeJs

Чтобы решить эту проблему, либо установите testEnvironment на jsdom
Или вы удалите 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
      }
    }
  }

Это то, что они говорят в документации:

testEnvironment [string] # По умолчанию: "jsdom"

Условия тестирования, которые будет использоваться для тестирования. Стандартная среда в Jest - это браузером через jsdom. Если вы создаете nodeслужбы, вы можете использовать опцию node для использования среды nodeвместо этого.


Вам нужна среда ` node?

Как я мог видеть, ваши тесты предназначены для запуска в среде, подобной браузерам.

Если вам понадобится явная среда node, лучше изолируйте этот случай, используя @jest-environment:

/**
 * @jest-environment node
 */

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

или наоборот, если вы предназначены для запуска тестов в node среде

/**
 * @jest-environment jsdom
 */

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

Заключение

С этим вы можете избежать импорта jsdom вручную и установки глобальных переменных, jsdom будет издеваться над реализацией DOM автоматически.

Если вам нужно изменить среду для ваших тестов, используйте обозначение @jest-environment

Ответ 2

Вы можете попробовать сделать

global.window = new jsdom.JSDOM().window;
global.document = window.document;

Ответ 3

Вы можете просто высмеять location:

global.location = {search: 'someSearchString'}

Также обратите внимание, что global в вашем тесте - это глобальный контекст для тестируемого файла (global === window)

Обратите внимание, что это будет работать, только если ваш модуль сделает вызов window.location после завершения теста для импорта всех модулей.

export default () => window.location

Итак, если ваш модуль выглядит так:

const  l = window.location
export default l 

это не сработает. В этом случае вы можете издеваться над модулем, используя jest.mock.

Ответ 4

https://github.com/facebook/jest/issues/2460#issuecomment-324630534

Похоже, что один из участников объявил, что он не планирует подвергать jsdom глобальному в среде шутов.

Однако вы можете использовать API Object.defineProperty(window, 'location', {value: '…'} для его приближения, как это делает разработчик в Facebook. В вашем случае это может быть как:

    Object.defineProperty(window, 'location', {
      value: {
        search: ...
      },
    })

Удачи!

Ответ 5

Здесь вы можете найти примеры того, как это сделать:

https://www.codementor.io/pkodmad/dom-testing-react-application-jest-k4ll4f8sd

Например:

import {jsdom} from 'jsdom';

const documentHTML = '<!doctype html><html><body><div id="root"></div></body></html>';
global.document = jsdom(documentHTML);
global.window = document.parentWindow;

Ответ 6

Не уверен, но я думаю, что вы могли бы сделать это с помощью jest.fn()

global.window = jest.fn(() => {
  location: { ... }
})

может быть даже как window = jest.fn(...)