Мне нужно протестировать функцию, которая открывает новую вкладку в браузере
openStatementsReport(contactIds) {
window.open(`a_url_${contactIds}`);
}
Я хотел бы поиздеваться над open
функцией окна, чтобы я мог убедиться, что в open
функцию передается правильный URL-адрес .
Используя Jest, я не знаю, как издеваться над window
. Я пытался установить window.open
фиктивную функцию, но этот способ не работает. Ниже представлен тестовый пример
it('correct url is called', () => {
window.open = jest.fn();
statementService.openStatementsReport(111);
expect(window.open).toBeCalled();
});
но это дает мне ошибку
expect(jest.fn())[.not].toBeCalled()
jest.fn() value must be a mock function or spy.
Received:
function: [Function anonymous]
Что мне делать с тестовым примером? Любые предложения или подсказки приветствуются.
javascript
mocking
jestjs
Дэнни
источник
источник
window
дляglobal
У меня сработал следующий метод. Такой подход позволил мне протестировать код, который должен работать как в браузере, так и в Node, поскольку он позволил мне установить
window
значениеundefined
.Это было с Jest 24.8 (я думаю):
let windowSpy; beforeEach(() => { windowSpy = jest.spyOn(window, "window", "get"); }); afterEach(() => { windowSpy.mockRestore(); }); it('should return https://example.com', () => { windowSpy.mockImplementation(() => ({ location: { origin: "https://example.com" } })); expect(window.location.origin).toEqual("https://example.com"); }); it('should be undefined.', () => { windowSpy.mockImplementation(() => undefined); expect(window).toBeUndefined(); });
источник
Object.defineProperty
поскольку это позволяет не влиять на другие тесты при насмешке.Мы также можем определить его, используя
global
вsetupTests
// setupTests.js global.open = jest.fn()
И назовите это using
global
в реальном тесте:// yourtest.test.js it('correct url is called', () => { statementService.openStatementsReport(111); expect(global.open).toBeCalled(); });
источник
В Jest есть несколько способов имитировать глобальные объекты:
mockImplementation
подход (наиболее похожий на Jest), но он будет работать только для тех переменных, которые имеют некоторую реализацию по умолчаниюjsdom
,window.open
одну из них:test('it works', () => { // setup const mockedOpen = jest.fn(); // without making a copy you will have a circular dependency problem const originalWindow = { ...window }; const windowSpy = jest.spyOn(global, "window", "get"); windowSpy.mockImplementation(() => ({ ...originalWindow, // in case you need other window properties to be in place open: mockedOpen })); // tests statementService.openStatementsReport(111) expect(mockedOpen).toBeCalled(); // cleanup windowSpy.mockRestore(); });
window
переменных, напримерwindow.href
.test('it works', () => { // setup const mockedOpen = jest.fn(); const originalOpen = window.open; window.open = mockedOpen; // tests statementService.openStatementsReport(111) expect(mockedOpen).toBeCalled(); // cleanup window.open = originalOpen; });
Вместо того, чтобы напрямую использовать глобальное значение, было бы проще импортировать его из другого файла, поэтому насмешки с Jest станут тривиальными.
./test.js
jest.mock('./fileWithGlobalValueExported.js'); import { windowOpen } from './fileWithGlobalValueExported.js'; import { statementService } from './testedFile.js'; // tests test('it works', () => { statementService.openStatementsReport(111) expect(windowOpen).toBeCalled(); });
./fileWithGlobalValueExported.js
export const windowOpen = window.open;
./testedFile.js
import { windowOpen } from './fileWithGlobalValueExported.js'; export const statementService = { openStatementsReport(contactIds) { windowOpen(`a_url_${contactIds}`); } }
источник
Вы можете попробовать это:
import * as _Window from "jsdom/lib/jsdom/browser/Window"; window.open = jest.fn().mockImplementationOnce(() => { return new _Window({ parsingMode: "html" }); }); it("correct url is called", () => { statementService.openStatementsReport(111); expect(window.open).toHaveBeenCalled(); });
источник
Я нашел простой способ: удалить и заменить
describe('Test case', () => { const { open } = window; beforeAll(() => { // Delete the existing delete window.open; // Replace with the custom value window.open = jest.fn(); // Works for `location` too, eg: // window.location = { origin: 'http://localhost:3100' }; }); afterAll(() => { // Restore original window.open = open; }); it('correct url is called', () => { statementService.openStatementsReport(111); expect(window.open).toBeCalled(); // Happy happy, joy joy }); });
источник
Если это похоже на проблему с расположением окон на https://github.com/facebook/jest/issues/890 , вы можете попробовать [скорректировано]
delete global.window.open; global.window = Object.create(window); global.window.open = jest.fn();
источник
В моем компоненте мне нужен доступ
window.location.search
, вот что я сделал в шутливом тесте:Object.defineProperty(global, "window", { value: { location: { search: "test" } } });
В случае, если свойства окна должны отличаться в разных тестах, мы можем поместить имитацию окна в функцию и сделать ее доступной для записи, чтобы переопределить для разных тестов:
function mockWindow(search, pathname) { Object.defineProperty(global, "window", { value: { location: { search, pathname } }, writable: true }); }
И сбрасывать после каждого теста
afterEach(() => { delete global.window.location; });
источник
Я непосредственно назначая
jest.fn()
кwindow.open
.window.open = jest.fn() // ...code expect(window.open).toHaveBeenCalledTimes(1) expect(window.open).toHaveBeenCalledWith('/new-tab','__blank')
источник
В вашей конфигурации jest добавьте setupFilesAfterEnv: ["./setupTests.js"], создайте этот файл и добавьте код, который хотите запустить перед тестами.
//setupTests.js window.crypto = { ..... };
Ссылка: https://jestjs.io/docs/en/configuration#setupfilesafterenv-array
источник