This is more or less a summary of the Jest docs with a focus on code snippets. Take a look there if you miss anything!
- Run the tests with
npm run test. - Unit test are always stored in a .spec.ts file and places along the regular .ts file.
- Both our Frontend and our Backend use the same Testing-Framework.
You may follow the following structure for writing Unit Tests:
// Import statments
// Global const, mocks, etc...
describe('ClassNameGoesHere', () => {
beforeEach(() => {
// Init code
});
describe('FunctionNameOne', () => {
it('should return true on success', () => {
// Run code and check result
});
it('should do XYZ', () => {
// Run code and check result
});
});
describe('FunctionNameTwo', () => {
// ....
});
});This applies to frontend services and most of our backend classes. See below how to test React Components. For this example we want to test a DummyService.
dummyService.ts
export DummyService {
public containsOnlyNumbers(text: string): boolean {
return text.match(/^[0-9]+$/) != null;
}
}dummyService.spec.ts
import DummyService from './DummyService';
describe('ClassNameGoesHere', () => {
let dummyService: DummyService;
beforeEach(() => {
// Create a new and clean instance before each test
dummyService = new DummyService();
});
describe('containsOnlyNumbers', () => {
it('should return true if input only contains', () => {
const result = dummyService.contcontainsOnlyNumbers('012345');
expect(result).toBe(true);
});
it('should return false if input also conains letters', () => {
const result = dummyService.contcontainsOnlyNumbers('012sdfdsf345');
expect(result).toBe(false);
});
});
});You may want to check whether your class correctly calls another function. (Normally you'll call a function of another class. We'll take a loke at that afterwards.)
dummyService.ts
export DummyService {
public containsOnlyNumbers(text: string, containsLetters: () => boolean): boolean {
return !containsLetters(text);
}
}dummyService.spec.ts
// Import
describe('ClassNameGoesHere', () => {
// beforeEach - See above
describe('containsOnlyNumbers', () => {
// ...
it('should call the function containsLetters', () => {
// Create a Spy/Mock function wich always returns true;
const containsLetters = jest.fn().mockReturnValue(true);
// jest.fn() creates a mock, which would return undefined
const result = dummyService.contcontainsOnlyNumbers('abc', containsLetters);
expect(result).toBe(false);
expect(containsLetters).toHaveBeenCalled();
expect(containsLetters).toHaveBeenCalledWith('abc');
});
});
});Since your normally calling functions of a class, you need to mock the whole class. With the method below you may mock any class. You can even mock external dependencies like Expo etc.
dummyService.ts
import TypeHelper from './TypeHelper';
export DummyService {
private typeHelper = new TypeHelper();
public containsOnlyNumbers(text: string): boolean {
return !this.typeHelper.containsLetters(text);
}
}dummyService.spec.ts
// Import
jest.mock('./TypeHelper', () => ({ // Auto mock the class
// specifiy the function Spy
containsLetters: jest.fn().mockReturnValue(true);
}));
describe('ClassNameGoesHere', () => {
// beforeEach
describe('containsOnlyNumbers', () => {
// ...
it('should call the function containsLetters', () => {
const result = dummyService.contcontainsOnlyNumbers('abc');
expect(result).toBe(false);
// Check against the mocked class
expect(TypeHelper.containsLetters).toHaveBeenCalled();
expect(TypeHelper.containsLetters).toHaveBeenCalledWith('abc');
});
});
});Just add the async keyword to the arrow function and you're go to go to use the await keyword.
it('should return true on success', async () => {
const result = await recordingService.askForPermissions();
expect(result).toBe(false);
});