Jest를 사용하여 JavaScript 창 개체를 모의하는 방법은 무엇입니까?


112

브라우저에서 새 탭을 여는 기능을 테스트해야합니다.

openStatementsReport(contactIds) {
  window.open(`a_url_${contactIds}`);
}

open기능 을 모의 하여 올바른 URL이open 함수에 .

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]

테스트 케이스를 어떻게해야합니까? 모든 제안이나 힌트를 주시면 감사하겠습니다.

답변:


91

window사용 대신global

it('correct url is called', () => {
  global.open = jest.fn();
  statementService.openStatementsReport(111);
  expect(global.open).toBeCalled();
});

당신은 또한 시도 할 수 있습니다

const open = jest.fn()
Object.defineProperty(window, 'open', open);

3
이것을 시도했지만 나를 위해 일하지 않았습니다. 내 사건은 이상해, 조롱은 로컬에서 작동하지만 Travis의 PR 합병에는 적용되지 않습니다.
Alex JM

@AlexJM 같은 문제가 있습니까? 창 개체를 어떻게 조롱합니까?
danny

1
난 그냥 내 테스트에서 window.property 정의
maracuja 주스

@ 안드레아스는 정의와 창 조롱 할 수있는 방법이 stackoverflow.com/questions/59173156/...은
의 어플리케이션 개발자 THOMAS

감사! 근무 시간이 지난 후에는 변경이 필요 window했습니다global
SrAxi

70

나를 위해 일한 방법은 다음과 같습니다. 이 세트에 저를이 허용하는이 방법은, 나를 브라우저와 노드 모두에서 작동합니다 몇 가지 코드를 테스트 할 수 windowundefined .

이것은 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();
});

1
Object.defineProperty조롱 할 때 다른 테스트에 영향을주지 않기 때문에 훨씬 낫습니다 .
Sergey

대신 실제 전역 속성 변경의 / 스파이를 조롱 때문에 이것은 허용 대답해야한다
user2490003

10

globalin 을 사용하여 정의 할 수도 있습니다 .setupTests

// setupTests.js
global.open = jest.fn()

그리고 global실제 테스트에서 사용하여 호출하십시오 .

// yourtest.test.js
it('correct url is called', () => {
    statementService.openStatementsReport(111);
    expect(global.open).toBeCalled();
});

7

Jest에서 전역을 조롱하는 몇 가지 방법이 있습니다.

  1. 사용 mockImplementation방법 (방법과 같은 대부분의 농담)하지만에서 제공하는 몇 가지 기본 구현이 그 변수에만 작동합니다은 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();
});
  1. 값을 전역 속성에 직접 할당하십시오. 가장 간단하지만 일부 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;
});
  1. 전역을 직접 사용하지 마십시오 (약간의 리팩토링 필요).

전역 값을 직접 사용하는 대신 다른 파일에서 가져 오는 것이 더 깔끔 할 수 있으므로 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}`);
  }
}

7

쉽게 할 수있는 방법을 찾았습니다 : 삭제 및 바꾸기

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

7

내 구성 요소에서 액세스가 필요합니다 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;
});

5

이것을 시도 할 수 있습니다.

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


4

에 직접 할당 jest.fn()하고 window.open있습니다.

window.open = jest.fn()
// ...code
expect(window.open).toHaveBeenCalledTimes(1)
expect(window.open).toHaveBeenCalledWith('/new-tab','__blank')

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.