- 
                Notifications
    You must be signed in to change notification settings 
- Fork 1
Quick start guide
interface FoodPlant {
    process(ingredient: 'potato' | 'tomato'): number;
}
import { mock, instance, when } from 'omnimock';
// Step 1: Create a mock
const plantMock = mock<FoodPlant>('plantMock');
// Step 2: Define behaviors
when(plantMock.process('potato')).return(2);
// Step 3: Use your mock
const foodPlant = instance(plantMock);
foodPlant.process('potato') === 2; // true
foodPlant.process('tomato');       // Error: No behavior defined for <plantMock>.process('tomato')This method works best for classes which belong to the C in MVC (services, controllers, ...). Check out mockInstance for mocking DTOs and other data objects.
Long call chains can be matched just as easily:
interface ProcessResult {
    getQuantityOf(ingredient: string): number;
}
interface FoodPlant {
    process(...ingredients: Array<string>): ProcessResult;
}
// ...
when(plantMock.process('potato', 'tomato').getQuantityOf('tomato')).return(4);
foodPlant.process('potato', 'tomato').getQuantityOf('tomato') === 4; // trueUse argument matchers to capture a large subset of possible calls at once:
import { anyOf } from 'omnimock';
when(plantMock.process(anyOf('potato', 'tomato'))).return(4);
foodPlant.process('tomato') === foodPlant.process('potato'); // true ( === 4)See the full list of available matchers.
Using a custom function is a powerful way to customize the behavior of a mock.
import { anyString } from 'omnimock';
when(plantMock.process(anyString())).call(i => i.charAt(0) === 'p' ? 4 : 0);
foodPlant.process('potato') // 4
foodPlant.process('tomato') // 0The documentation shows all possible ways to define the result of a call.
mockInstance(...) is a shorthand for instance(mock(...)).
interface Vegetable {
    type: string;
    edible: boolean;
}
import { mockInstance } from 'omnimock';
const edibleMock = mockInstance<Vegetable>('edibleMock', { edible: true });
expect(edibleMock.edible).toBe(true);This technique is convenient for working with DTOs and other simple data objects.
Nested objects can be mocked with nested calls.
interface Vitamin {
    letter: string;
}
interface Vegetable {
    // ...
    vitamins: Array<Vitamin>;
}
    
const ascorbic = mockInstance<Vegetable>('ascorbic', {
    edible: true,
    vitamins: [
        mockInstance<Vitamin>('vitamin', { letter: 'c' })
    ]
});If what you are mocking is an actual class, then you may pass that class as the first argument to mock or mockInstance.
Note: This does not work with abstract classes or interfaces.
// The regular usage: Specify the type and the name of the mock
const edibleMock = mockInstance<Vegetable>('edibleMock', { edible: true });
// Shorthand: the type and name of the mock are inferred.
const edibleMock = mockInstance(Vegetable, { edible: true });
// Works with `mock` too
const edibleMock = mock(Vegetable);The nested example from the previous section can be rewritten like this:
const ascorbic = mockInstance(Vegetable, {
    edible: true,
    vitamins: [
        mockInstance(Vitamin, { letter: 'c' })
    ]
});In order for instanceof to work properly, you need to use the constructor shorthand syntax:
const edibleMock = mock<Vegetable>('edibleMock', { edible: true });
instance(edibleMock) instanceof Vegetable // false
const edibleMock = mock(Vegetable, { edible: true });
instance(edibleMock) instanceof Vegetable // trueIf you find yourself having to do a type cast, then most likely you are doing something wrong. Omnimock is designed to eliminate the need for casts.
const myVegetable: Vegetable = {
    edible: true
} as Partial<Vegetable> as Vegetable; // A bad type cast!
// Instead, do:
const myVegetable = mockInstance<Vegetable>('myVegetable', {
    edible: true
});Why is the later better than the former? Omnimock's cast from Partial<T> to T is type-safe because it guarantees that no undefined behavior may occur. See Why use a mocking library for more details.
Type arguments of functions are lost when the function is mocked. This is due to a limitation in TypeScript's generics.
function myGeneric<T extends string>(t: T): T { return t; }
const dict = { hello: 'world' };
const mockGeneric = mock<typeof myGeneric>('myGeneric');
// Error: s should be of type 'hello' but it is instead of type 'string' 
when(mockGeneric('hello')).call(s => dict[s]);
// You need an explicit cast to fix this
when(mockGeneric('hello')).call(s => dict[s as 'hello']);Keep this in mind when dealing with generic methods or functions.