-
Notifications
You must be signed in to change notification settings - Fork 3
Testing
Test runner is Jest.
Testing is a part of build process. In case at least one test fail, whole Travis build will be marked as failed.
Test coverage is important metric. Coverage threshold is 90%.
To run tests locally, run:
npm test
Tests located in test directory of each package.
Test file name must end up with .test.ts
.
Specification file name must end up with .spec.ts
.
Test files will be automatically detected and executed by Jest (see configuration in main package.json)
For each class or interface in src
directory there should be test or specification in test
directory with the same path.
packages/
package/
src/
Lifecycle.ts
ChildProcess.ts
test/
Lifecycle.spec.ts
ChildProcess.test.ts
package.json
...
Core difference between them: test files describes test scenarios for classes, specification files describes test scenarios for interfaces. Specifications can be re-used. That's why specifications exported as function.
// src/Lifecycle.ts
export interface Lifecycle {
readonly isRunning: boolean;
public start(): boolean;
public stop(): boolean;
}
// test/Lifecycle.spec.ts
export function testLifecycle(create: () => Lifecycle) {
describe('Lifecycle', () => {
describe('start()', () => {
it('should start lifecycle', () => {
const component: Lifecycle = create();
expect(component.isRunning).toBe(false);
expect(component.start()).toBe(true);
expect(component.isRunning).toBe(true);
}
it('should not take effect when being called more then once in row', () => {
const component: Lifecycle = create();
expect(component.isRunning).toBe(false);
expect(component.start()).toBe(true);
expect(component.isRunning).toBe(true);
expect(component.start()).toBe(false);
expect(component.isRunning).toBe(true);
}
}
}
}
// src/ChildProcess.ts
export class ChildProcess implements Lifecycle {
// implementation omitted
}
// test/ChildProcess.test.ts
import {testLifecycle} from './Lifecycle.spec';
function create(): ChildProcess {
// return new instance of child process
}
describe('ChildProcess', () => {
testLifecycle(create);
// additional tests of child process
});
describe('ClassOrInterfaceName', () => {
// beforeEach() and other hooks at the beginning of 'describe'
// add parentheses to show that it's a test of method
describe('method()', () => {
// start test case with "should", example: "it should start lifecycle"
it('should <description of behavior>', () => {
// PREPARE
// Create or obtain instance
// Check pre-conditions in needed
// ACT
// Do something with instance
// CHECK
// expect(...).toBe(...)
});
});
// describe signature of method, it's especially useful when testing overloads of method
describe('method(string, number)', () => {
it('should <description of behavior>', () => {
// PREPARE
// Create or obtain instance
// Check pre-conditions in needed
// ACT
// Do something with instance
// CHECK
// expect(...).toBe(...)
});
});
describe('propertyName/accessorName', () => {
it('should <description of behavior>', () => {
// PREPARE
// Create or obtain instance
// Check pre-conditions in needed
// ACT
// Do something with instance
// CHECK
// expect(...).toBe(...)
});
});
});