Issue
I'm trying to test a call to a function defined on the global window object. I have looked at multiple examples but am still not able to run a simple test case.
Api.ts
import "./global.d";
const verifier = window.Verifier;
export class Api {
constructor(private readonly id: string) {}
public fetchData() {
return new Promise<object>((resolve, reject) => {
verifier.request({
request: {
id: this.id
},
onSuccess: (data: object) => {
resolve(data);
},
onFailure: () => {
reject("Error!");
}
});
});
}
}
Api.test.ts
import { Api } from "./Api";
let windowSpy: any;
describe("Test Apis", () => {
beforeEach(() => {
windowSpy = jest.spyOn(window, "window", "get");
});
afterEach(() => {
windowSpy.mockRestore();
});
it("should call the function", () => {
const mockedReplace = jest.fn();
windowSpy.mockImplementation(() => ({
Verifier: {
request: mockedReplace
}
}));
const api = new Api("123");
api.fetchData();
expect(mockedReplace).toHaveBeenCalled();
});
});
global.d.ts
import { Verifier } from "./verifier";
declare global {
interface Window {
Verifier: Verifier;
}
}
verifier.d.ts
type RequestPayload = {
request: {
id: string;
};
onSuccess: (data: object) => void;
onFailure: () => void;
};
type verifyCode = number;
export interface Verifier {
request: (requestPayload: RequestPayload) => verifyCode;
}
I have also created a codesandbox example for easy reference https://codesandbox.io/s/cranky-mccarthy-2jj622?file=/src/verifier.d.ts
Solution
The problem here is your import order.
When you import { Api } from "./api";
, you run const verifier = window.Verifier;
, which, at the time, is undefined
.
If you change the order of the imports and spies it should work as expected:
import { RequestPayload } from "./verifier";
const mockRequest = jest
.fn()
.mockImplementation((requestPayload: RequestPayload) => 1);
jest.spyOn(window, "window", "get").mockImplementation(() => {
return {
Verifier: {
request: mockRequest,
},
} as unknown as Window & typeof globalThis;
});
// // // // //
import { Api } from "./api";
// // // // //
describe("Test Apis", () => {
let api: Api;
beforeEach(() => {
jest.clearAllMocks();
});
beforeEach(() => {
api = new Api("123");
});
it("should have valid function", () => {
expect(typeof api.fetchData).toBe("function");
});
it("should call the function", () => {
api.fetchData();
expect(mockRequest).toHaveBeenCalled();
});
});
You could also think about using window.Verifier
directly, making the tests a bit cleaner:
export class Api {
constructor(private readonly id: string) {}
public fetchData() {
return new Promise<object>((resolve, reject) => {
window.Verifier.request({
request: {
id: this.id,
},
onSuccess: (data: object) => {
resolve(data);
},
onFailure: () => {
reject("Error!");
},
});
});
}
}
describe("Test Apis", () => {
let api: Api, mockRequest: jest.Mock;
beforeEach(() => {
jest.clearAllMocks();
mockRequest = jest
.fn()
.mockImplementation((requestPayload: RequestPayload) => 1);
jest.spyOn(global, "window", "get").mockImplementation(() => {
return {
Verifier: {
request: mockRequest,
},
} as unknown as Window & typeof globalThis;
});
});
beforeEach(() => {
api = new Api("123");
});
it("should have valid function", () => {
expect(typeof api.fetchData).toBe("function");
});
it("should call the function", () => {
api.fetchData();
expect(mockRequest).toHaveBeenCalled();
});
});
Answered By - doublethink
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.