typescript - hur man mockar EventSource med jest i TS (försökte de flesta mockningsstrategier)
ville mocka EventSource med jest, men fortsatte få ReferenceError: EventSource är inte definierad.
Vänligen ta en titt på koden. Tack så mycket!
// eventSourceHandler.ts
export default new class A() {
listenEventSource(){
const eventSource = new EventSource(url);
eventSource.addEventListener("something", callSomething);
eventSource.onerror = function() {
console.error();
("Failed to listen EventSource");
};
}
}
Här är testkoden jag vill mocka
// eventSourceHandler.spec.ts
import A from "./eventSourceHandler"
describe("xyz",() =>{
it("eventSourceHandler called", ()=> {
const mEventSourceInstance = {
addEventListener: jest.fn(),
onerror: jest.fn(),
close: jest.fn(),
onmessage: jest.fn(),
onopen: jest.fn(),
url: "test-url",
readyState: 0,
withCredentials: false,
CLOSED: 2,
CONNECTING: 0,
OPEN: 1,
removeEventListener: jest.fn(),
dispatchEvent: jest.fn()
};
jest.mock("EventSource", () => {
return {
EventSource: jest.fn().mockImplementation(() => {
return {
// addEventListener: jest.fn(),
// onerror: jest.fn()
mEventSourceInstance
};
})
};
});
let a = new A()
a.listenEventSource();
// test validation ....
});
});
});
...
Fick hela tiden ReferenceError: EventSource is not defined när jag körde testkoden.
OBS: Jag har läst nästan alla relaterade inlägg från Stack Overflow och försökt mocka global.EventSource men Typescript fortsatte kasta fel och sa EventSource finns inte på typen Global.
Finns det någon som vill dela en bättre strategi för att håna detta? Det skulle uppskattas mycket.
Tack grabbar ...
Svar #1
Tja, jag ser två alternativ som du kan använda.
- Injicera eventSource-instansen i klassen där den används, så att du kan mocka den
- Använd en byggfunktion istället för att anropa konstruktorn direkt i klass A
För det senare kan du sluta upp med något som detta:
utils.ts
export const buildEventSource = (url: string) => {
return new EventSource(url, {});
};
Och sedan i din testklass:
import * as utils from './utils';
const buildEventSourceSpy = jest.spyOn(utils, 'buildEventSource');
buildEventSourceSpy.mockReturnValue({
CLOSED: 0,
CONNECTING: 0,
OPEN: 0,
dispatchEvent(event: Event): boolean {
return false;
},
onerror: jest.fn(),
onmessage: jest.fn(),
onopen: jest.fn(),
readyState: 0,
url: '',
withCredentials: false,
addEventListener(
type: any,
listener: any,
options?: boolean | AddEventListenerOptions
): void {},
close(): void {},
removeEventListener(
type: any,
listener: any,
options?: boolean | EventListenerOptions
): void {}
});
Jag hoppas att det hjälper
Svar #2
Jag hade problem med ReferenceError: EventSource is not defined ett tag. Men det visar sig att den officiella Jest-dokumentationen har en ganska bra förklaring av vad som pågår.
Det är bara det att globala objekt höjs så snart du importerar din kodbit som använder det och sedan kan inte ändras (ungefär som en closure enligt min förståelse).
Så en enkel lösning är att hålla din definition av mockade globala variabler som EventSource i en separat modul och importera den innan någon annan modul som använder globala variabler.
Till exempel har jag en modul mockEventSource.ts med följande innehåll
Object.defineProperty(window, 'EventSource', {
writable: true,
value: jest.fn().mockImplementation(() => ({
close: jest.fn(() => {}),
addEventListener: jest.fn(
(_event: string, _callback: (_message: MessageEvent) => {}) => {},
),
})),
});
Då gör jag i min testfil:
import './mockEventSource.ts';
import { myFunction } from './moduleToTest.ts';
Och nu när jag kallar myFunction bör den ha tillgång till den mockade EventSource
