Я попробовал следующие 4 варианта после рассмотрения проблем Jest и SO отвечает, но я получаю либо ошибки TypeScript, либо ошибки времени выполнения. Я бы очень хотел, чтобы вариант 1 (spyOn) работал.

// ------ option 1 -----
// Gives this runtime error: "Cannot spyOn on a primitive value; undefined given"
const writeText = jest.spyOn(navigator.clipboard, 'writeText');

// ------ option 2 -----
Object.defineProperty(navigator, 'clipboard', {
    writeText: jest.fn(),
});

// ------ option 3 -----
// This is from SO answer but gives a TypeScript error
window.__defineGetter__('navigator', function() {
    return {
        clipboard: {
            writeText: jest.fn(x => x)
        }
    }
})

// ------ option 4 -----
const mockClipboard = {
    writeText: jest.fn()
};
global.navigator.clipboard = mockClipboard;
16
Naresh 12 Июн 2020 в 23:22

2 ответа

Лучший ответ

Jest-тесты выполняются в среде JSdom, и не все свойства определены, поэтому вам следует определить функцию, прежде чем шпионить за ней.

Вот пример:

Object.assign(navigator, {
  clipboard: {
    writeText: () => {},
  },
});

describe("Clipboard", () => {
  describe("writeText", () => {
    jest.spyOn(navigator.clipboard, "writeText");
    beforeAll(() => {
      yourImplementationThatWouldInvokeClipboardWriteText();
    });
    it("should call clipboard.writeText", () => {
      expect(navigator.clipboard.writeText).toHaveBeenCalledWith("zxc");
    });
  });
});

Изменить: вы также можете использовать Object.defineProperty, но он принимает объект дескрипторов в качестве третьего параметра.

Object.defineProperty(navigator, "clipboard", {
  value: {
    writeText: () => {},
  },
});
11
Teneff 13 Июн 2020 в 06:31

Я столкнулся с аналогичной ситуацией и использовал следующий метод для имитации буфера обмена в объекте навигатора:

  const originalClipboard = { ...global.navigator.clipboard };
  const mockData = {
     "name": "Test Name",
     "otherKey": "otherValue"
  }

  beforeEach(() => {
    const mockClipboard = {
      writeText: jest.fn(),
    };
    global.navigator.clipboard = mockClipboard;

  });

  afterEach(() => {
    jest.resetAllMocks();
    global.navigator.clipboard = originalClipboard;
  });

  test("copies data to the clipboard", () => {
    copyData(); //my method in the source code which uses the clipboard
    expect(navigator.clipboard.writeText).toBeCalledTimes(1);
    expect(navigator.clipboard.writeText).toHaveBeenCalledWith(
      JSON.stringify(mockData)
    );
  });
1
Parthipan Natkunam 24 Янв 2021 в 11:42