Issue
I have tried the following 4 options after looking at Jest issues and SO answers, but I am either getting TypeScript errors or runtime errors. I would really like to get option 1 (spyOn) working.
// ------ 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;
Solution
Jest tests are running in JSdom environment and not all of the properties are defined, but so you should define the function before spying on it.
Here is an example:
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");
});
});
});
Edit: you can also use Object.defineProperty, but it accepts descriptors object as third parameter
Object.defineProperty(navigator, "clipboard", {
value: {
writeText: () => {},
},
});
Answered By - Teneff