如何使用Jest模拟JavaScript中的'window'对象?

234

我需要测试一个在浏览器中打开新标签页的函数

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

我希望模拟 windowopen函数,以便验证正确的URL被传递给open函数。

使用Jest,我不知道如何模拟window。我尝试使用模拟函数设置window.open,但是这种方法不起作用。以下是测试案例:

it('the 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]

我该怎么处理这个测试用例?


请参见 https://dev59.com/5VYO5IYBdhLWcg3wI-Vw#9TEzoYgBc1ULPQZFwCd7。 - Michael Freidgeim
17个回答

4

尝试简单地:

let windowOpenSpy: jest.SpyInstance;
beforeEach(() => {
    windowOpenSpy = jest.spyOn(window, 'open');
});

it('should open window with dashboard url', () => {
    expect(windowOpenSpy).toBeCalledWith('your URL', '_blank');
});

需要解释一下。 - Peter Mortensen
这就是我想象中的答案,我可以说这种方法对我很有效。 - Harleyz

2
在您的Jest配置中,添加setupFilesAfterEnv: ["./setupTests.js"],创建该文件,并添加您想在测试之前运行的代码:
// setupTests.js
window.crypto = {
   .....
};

Reference: setupFilesAfterEnv [array]


1
你可以测试它:

describe('TableItem Components', () => {
    let open_url = ""
    const { open } = window;
    beforeAll(() => {
        delete window.open;
        window.open = (url) => { open_url = url };
    });
    afterAll(() => {
        window.open = open;
    });
    test('string type', async () => {
        wrapper.vm.openNewTab('http://example.com')
        expect(open_url).toBe('http://example.com')
    })
})

需要解释一下。 - Peter Mortensen

1
我有一个实用函数,可以模拟窗口上的任何方法,如下所示:
  function givenMockWindowMethods(methods: Partial<{ [key in keyof Window]: jest.Mock<any, any> }>): () => void {
    const mocks = Object.values(methods);

    Object.entries(methods).forEach(([key, value]) => {
      Object.defineProperty(window, key, { value });
    });

    return (): void => mocks.forEach((mock) => mock?.mockClear());
  }

如果我需要模拟窗口上的open方法(或其他任何东西),我可以这样做:

      const cleanupMocks = givenMockWindowMethods({ open: jest.fn() });
      // expect(...).toBe(...)

      //at the end of the test, clean it up
      cleanupMocks()


0
const windowSpy = jest.spyOn(iFrame, "contentWindow", "get");
windowSpy.mockImplementation(() => ({
  location: {
    origin: "https://test.com",
    href: "href",
    hash: "hash"
  }
}));

需要解释一下。 - Peter Mortensen

0

我尝试了类似的测试,它对我起作用了...

我的代码:

export const Blah = () => {
        const BLAH = 'https://www.google.com/'
        const handleBlah = () => {
            window.open(BLAH, '_blank')
        }

    return (
        <button onClick={handleBlah}> BLAHBLAH </button>
    )
}

我的Jest测试:

it('should be able to render "BLAHBLAH " button ', () => {
    window.open = jest.fn();
    const BLAH = 'https://www.google.com/'
    const { getByText } = render(<Blah/>) // Get text by my page Blah
    const buttonGoToBlah = getByText('BLAHBLAH') // Get button by text
    fireEvent.click(buttonGoToBlah) // Simulate the click event

    expect(window.open).toHaveBeenCalledTimes(1) // Expect the window.open have to been called at least once.
    expect(window.open).toHaveBeenCalledWith(BLAH, '_blank'); // And the page should be the same called in my BLAH page
})

0

日期:2023年7月

Jest版本:28.1.3

此版本通过全局变量open来监视window.open,然后在所有测试完成后恢复window.open。

const realOpen = global.open; // store real window.open

describe('Given [thing you are testing]', () => {
  beforeAll(() => {
    jest.spyOn(global, 'open'); // create spy in beforeAll hook
  });

  afterAll(() => {
    global.open = realOpen; // after all the tests are completed restore window.open in afterAll hook
  });

  it('the correct URL is called', () => {
    jest.clearAllMocks(); // clear all mocks before running statementService.openStatementsReport
    statementService.openStatementsReport(111);
    expect(global.open).toBeCalled();
  });
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接