Skip to content

Instantly share code, notes, and snippets.

@marcogrcr
Created December 4, 2024 16:19
Show Gist options
  • Save marcogrcr/08d1b10861992d1c26bf43288341b843 to your computer and use it in GitHub Desktop.
Save marcogrcr/08d1b10861992d1c26bf43288341b843 to your computer and use it in GitHub Desktop.
Vitest mocking basics
import {
afterEach,
beforeEach,
expect,
it,
MockedClass,
MockedFunction,
vi,
} from "vitest";
// import module to mock
import { MyClass, myFunction, myObject } from "./my-module";
// mock the module
vi.mock("./my-module");
// create type-safe mocked versions of classes, functions and objects
const MyClassMock = MyClass as MockedClass<typeof MyClass>;
const myFunctionMock = myFunction as MockedFunction<typeof myFunction>;
const myObjectMock = vi.mocked(myObject);
// if an instance of a mocked class needs to be created in test code
let myClassInstance: MyClass;
beforeEach(async () => {
myClassInstance = new MyClass(
...([] as unknown as ConstructorParameters<typeof MyClass>),
);
});
// mocked fields must be restored manually
const myFieldBackup = myObject.myField;
afterEach(() => {
// @ts-expect-error Field is not optional
delete MyClassMock.prototype.myField;
myObject.myField = myFieldBackup;
});
it("mocks function", () => {
myFunctionMock.mockReturnValue("value");
expect(myFunction()).toBe("value");
});
it("mocks class", () => {
// field
expect(MyClassMock.prototype).not.toHaveProperty("myField");
MyClassMock.prototype.myField = "value";
expect(myClassInstance.myField).toBe("value");
// property
vi.spyOn(MyClassMock.prototype, "myProp", "get").mockReturnValue("value");
expect(myClassInstance.myProp).toBe("value");
// method
MyClassMock.prototype.myMethod.mockReturnValue("value");
expect(myClassInstance.myMethod()).toBe("value");
});
it("mocks object", async () => {
// field
expect(myObject).toHaveProperty("myField");
myObject.myField = "value";
expect(myObject.myField).toBe("value");
// property
vi.spyOn(myObject, "myProp", "get").mockReturnValue("value");
expect(myObject.myProp).toBe("value");
// method
myObjectMock.myMethod.mockReturnValue("value");
expect(myObject.myMethod()).toBe("value");
// async method
myObjectMock.myAsyncMethod.mockResolvedValue("value");
await expect(myObject.myAsyncMethod()).resolves.toBe("value");
});
it("mocks object with original implementations", async () => {
const { myObject: actualMyObject } =
await vi.importActual<typeof import("./my-module")>("./my-module");
// property
vi.spyOn(myObject, "myProp", "get").mockImplementation(
() => actualMyObject.myProp,
);
expect(myObject.myProp).toBe("not implemented");
// method
myObjectMock.myMethod.mockImplementation(
actualMyObject.myMethod.bind(actualMyObject),
);
expect(myObject.myMethod()).toBe("not implemented");
// async method
myObjectMock.myAsyncMethod.mockImplementation(
actualMyObject.myAsyncMethod.bind(actualMyObject),
);
await expect(myObject.myAsyncMethod()).resolves.toBe("not implemented");
});
export interface MyClassOptions {}
export function myFunction(): string {
throw new Error("not implemented");
}
export class MyClass {
myField: string = "not implemented";
constructor(options: MyClassOptions) {}
get myProp(): string {
return "not implemented";
}
myMethod(): string {
return "not implemented";
}
async myAsyncMethod(): Promise<string> {
return "not implemented";
}
}
export const myObject = {
myField: "not implemented",
get myProp(): string {
return "not implemented";
},
myMethod(): string {
return "not implemented";
},
async myAsyncMethod(): Promise<string> {
return "not implemented";
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment