Online Lectures/JavaScript Unit Testing - The Practical
Section8: More on Mocking & Diving Deeper
Nomad Kim
2023. 4. 5. 06:43
- Mocking Global Objects & Functions
- Mocking Frontend Features
- Examples
Case1. fetch is a globally available function which is not imported.
Thus, cannot use vi.mock to replace a module in this case. SubGlobal method allows us to replace globally available objects and functions with implementations. Then, Production codes are not effected!
sendDataRequest function
export async function sendDataRequest(data) {
const response = await fetch("https://dummy-site.dev/posts", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
// body: data,
});
const responseData = await response.json();
if (!response.ok) {
throw new HttpError(
response.status,
"Sending the request failed.",
responseData
);
}
return responseData;
}
https.test.js
const testResponseData = {
testKey: "testData",
};
// await fetch('https://dummy-site.dev/posts', { method: 'POST',...in sendDataRequest function
const testFetch = vi.fn((url, options) => {
return new Promise((resolve, reject) => {
/**
* @description test JSON.stringify(required data conversion) works or not
*/
if (typeof options.body !== "string") return reject("Not a string.");
const testResponse = {
//if (!response.ok) { ... in sendDataRequest function
ok: true,
//const responseData = await response.json(); ... in sendDataRequest function
json() {
return new Promise((resolve, reject) => {
resolve(testResponseData);
});
},
};
resolve(testResponse);
});
});
// SubGlobal method allows us to replace globally available objects
// and functions with implementations
vi.stubGlobal("fetch", testFetch);
it("should convert the provided data to JSON before sending the request", async () => {
const testData = { key: "test" };
let errorMessage;
try {
await sendDataRequest(testData);
} catch (error) {
errorMessage = error;
}
expect(errorMessage).not.toBe("Not a string.");
});
Case2. non-ok response. use mockImplementationOnce method
In case of difference on the arguments in response.
it("should throw and httpError in case of non-ok responses", () => {
testFetch.mockImplementationOnce((url, options) => {
return new Promise((resolve, reject) => {
const testResponse = {
ok: false,
json() {
return new Promise((resolve, reject) => {
resolve(testResponseData);
});
},
};
resolve(testResponse);
});
});
const testData = { key: "test" };
return expect(sendDataRequest(testData)).rejects.toBeInstanceOf(HttpError);
});
Case3. local mock values
const testTitle = "Test title";
const testContent = "Test content";
let testFormData;
describe("extractPostData()", () => {
beforeEach(() => {
// usage of local mock values!
testFormData = {
title: testTitle,
content: testContent,
get(identifier) {
return this[identifier];
},
};
});
it("should extract title and content from the provided form data", () => {
const data = extractPostData(testFormData);
expect(data.title).toBe(testTitle);
expect(data.content).toBe(testContent);
});
});