为什么这个模拟笑话测试失败?

时间:2020-04-21 16:14:23

标签: javascript reactjs jestjs enzyme navigator

我正在尝试模拟document.clipboard。

这是我的代码:

  handleCopyIdToClipboard = () => {
    const el = document.querySelector(`.${CLASS_NAME}`);
    navigator.clipboard.writeText(el.textContent);

    // some extra code
    showPopup();
  };

这是我开玩笑的测试:

describe('handleCopyToClipboard', () => {
const mockQuerySelector = jest.fn();
const mockBoundingClientRect = jest.fn();
const mockClipboard = jest.fn();
const mockWriteText = jest.fn();

mockQuerySelector.mockReturnValue({textContent: 'someText', getBoundingClientRect: mockBoundingClientRect});
mockBoundingClientRect.mockReturnValue({top: 100, left: 100});

Object.defineProperty(document, 'querySelector', {value: mockQuerySelector});
Object.defineProperty(navigator, 'clipboard', {value: mockClipboard});
Object.defineProperty(navigator.clipboard, 'writeText', {value: mockWriteText});

beforeEach(() =>
  [mockQuerySelector, mockClipboard, mockWriteText, mockBoundingClientRect].map(mock =>
    mock.mockClear(),
  ),
);

it('should copy to clipboard', () => {
  const wrapper = buildComponent(DetailsPage, props);
  wrapper.instance().handleCopyIdToClipboard('id');

  expect(mockQuerySelector).toHaveBeenCalled();
  expect(mockClipboard).toHaveBeenCalled();
  expect(mockWriteText).toHaveBeenCalled();
  expect(mockBoundingClientRect).toHaveBeenCalled();
  expect(wrapper.state().showPopup).toEqual(true);
  expect(wrapper.state().top).toEqual(90);
  expect(wrapper.state().left).toEqual(200);
});

});

此行失败expect(mockClipboard).toHaveBeenCalled();,指示从不调用模拟剪贴板。但是,如果我删除此行,expect(mockWriteText).toHaveBeenCalled();不会失败。有想法吗?

编辑:

我已将功能更新为以下内容:

  handleCopyIdToClipboard = () => {
    navigator.clipboard
      .writeText(this.state.urn)
      .then(() => {
        this.setState({showPopup: true});
      })
      .catch(doNothing);
  };

当前的笑话测试:

  describe('handleCopyToClipboard', () => {
    const mockClipboard = jest.fn();
    const mockWriteText = jest.fn();

    Object.defineProperty(navigator, 'clipboard', {value: mockClipboard});
    Object.defineProperty(navigator.clipboard, 'writeText', {value: mockWriteText});

    beforeEach(() => [mockClipboard, mockWriteText].map(mock => mock.mockClear()));

  it('should copy to clipboard', () => {
    const wrapper = buildComponent(ServiceAccountDetailsPage, props);

    mockWriteText.mockReturnValueOnce(true);

    return wrapper
        .instance()
        .handleCopyIdToClipboard()
        .then(() => {
          expect(mockWriteText).toHaveBeenCalled();
          expect(wrapper.state().showPopup).toEqual(true);
        });
  });
});

遇到此错误:navigator.clipboard.writeText(...).then is not a function。我想同时测试.then().catch()

1 个答案:

答案 0 :(得分:0)

Navigator.clipboard不是一个函数,您不应该将它作为一个函数来嘲笑。您应该模拟整个clipboard对象。例如

main.ts

export function handleCopyIdToClipboard() {
  const el = document.querySelector('.class-name');
  const textContent = el ? el.textContent || '' : '';
  return navigator.clipboard.writeText(textContent);
}

main.test.ts

import { handleCopyIdToClipboard } from './main';

describe('61348091', () => {
  it('should pass', async () => {
    const mElement = { textContent: 'hello' };
    const mockQuerySelector = jest.fn().mockReturnValueOnce(mElement);
    const mockWriteText = jest.fn().mockResolvedValueOnce('clipText');
    Object.defineProperty(document, 'querySelector', { value: mockQuerySelector });
    Object.defineProperty(navigator, 'clipboard', {
      value: {
        writeText: mockWriteText,
      },
    });
    const actual = await handleCopyIdToClipboard();
    expect(actual).toBe('clipText');
    expect(mockQuerySelector).toBeCalledWith('.class-name');
    expect(mockWriteText).toBeCalledWith('hello');
  });
});

具有覆盖率报告的单元测试结果:

 PASS  stackoverflow/61348091/main.test.ts (16.222s)
  61348091
    ✓ should pass (6ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |       50 |     100 |     100 |                   
 main.ts  |     100 |       50 |     100 |     100 | 3                 
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        18.23s