@terminus/fe-testing v2.0.0
A collection of helpers to facilitate testing UI components.
Import from: @terminus/fe-testing
Table of Contents
Installation
yarn add @terminus/fe-testing -D
yarn add @terminus/fe-utilities rxjs date-fns @angular/{forms,platform-browser}Mocks
ChangeDetectorRefMock
A mock of the Angular ChangeDetectorRefMock class.
// my.component.ts
import { ChangeDetectorRef } from '@angular/core';
@Component({...})
export class MyComponent {
constructor(private changeDetectorRef: ChangeDetectorRef) {}
}// my.component.spec.ts
import { ChangeDetectorRefMock } from '@terminus/fe-testing';
import { MyComponent } from './my.component';
let component: MyComponent;
beforeEach(() => {
component = new MyComponent(
new ChangeDetectorRefMock(),
);
});ElementRefMock
A mock of the Angular ElementRef class.
// my.component.ts
import { ElementRef } from '@angular/core';
@Component({...})
export class MyComponent {
constructor(private elementRef: ElementRef) {}
}// my.component.spec.ts
import { ElementRefMock } from '@terminus/fe-testing';
import { MyComponent } from './my.component';
let component: MyComponent;
beforeEach(() => {
component = new MyComponent(
new ElementRefMock(),
);
});rendererMock
A mock of the Angular Renderer with properties initialized with noop function.
// my.component.ts
import { Renderer } from '@angular/core';
@Component({...})
export class MyComponent {
constructor(private renderer: Renderer) {}
}// my.component.spec.ts
import { rendererMock } from '@terminus/fe-testing';
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MyNeededModule],
providers: [
// rendererMock is a value:
{
provide: Renderer,
useValue: rendererMock,
},
],
declarations: [MyComponent],
}).compileComponents();
}));renderer2Mock
A mock of the Angular Renderer2 with all properties stubbed.
// my.component.ts
import { Renderer2 } from '@angular/core';
@Component({...})
export class MyComponent {
constructor(private renderer2: Renderer2) {}
}// my.component.spec.ts
import { Renderer2Mock } from '@terminus/fe-testing';
beforeEach(async(() => {
TestBed.configureTestingModule({
...
providers: [
// Renderer2Mock is a class:
{
provide: Renderer,
useClass: Renderer2Mock,
},
],
declarations: [MyComponent],
}).compileComponents();
}));Or for newed classes:
import { Renderer2Mock } from '@terminus/fe-testing';
let component: MyComponent;
beforeEach(() => {
component = new MyComponent(
new Renderer2Mock(),
);
});TokenEscalatorMock
TODO
TokenExtractorMock
TODO
TsDocumentServiceMock
// my.component.ts
import { TsDocumentService } from '@terminus/fe-utilities';
@Component({...})
export class MyComponent {
constructor(
private documentService: TsDocumentService,
) {}
}// my.component.spec.ts
import { TsDocumentServiceMock } from '@terminus/fe-testing';
import { MyComponent } from './my.component';
let component: MyComponent;
beforeEach(() => {
component = new MyComponent(
new TsDocumentServiceMock(),
);
});TsWindowServiceMock
// my.component.ts
import { TsWindowService } from '@terminus/fe-utilities';
@Component({...})
export class MyComponent {
constructor(
private windowService: TsWindowService,
) {}
}// my.component.spec.ts
import { TsWindowServiceMock } from '@terminus/fe-testing';
import { MyComponent } from './my.component';
let component: MyComponent;
beforeEach(() => {
component = new MyComponent(
new TsWindowServiceMock(),
);
});Events
Creating Events
createFakeEvent
Creates a fake event object with any desired event type.
import { createFakeEvent } from '@terminus/fe-testing';
const focusEvent = createFakeEvent('focus');| Param | Type | Default |
|---|---|---|
type | string | |
canBubble | boolean | true |
cancelable | boolean | true |
createKeyboardEvent
Creates a browser KeyboardEvent from an element.
import { KEYCODES } from '@terminus/fe-utilities';
import { createKeyboardEvent } from '@terminus/fe-testing';
const keyboardEvent = createKeyboardEvent('keydown', KEYCODES.ENTER.keyCode, myInputNativeElement);| Param | Type | Default |
|---|---|---|
type | string | |
keyCode | number | |
target? | Element | |
key? | string |
createMouseEvent
Creates a browser MouseEvent with the specified options.
import { createMouseEvent } from '@terminus/fe-testing';
const mouseEvent = createMouseEvent('click');
const mouseEventAtLocation = createMouseEvent('click', 212, 433);| Param | Type | Default |
|---|---|---|
type | string | |
x | number | 0 |
y | number | 0 |
createTouchEvent
Creates a browser TouchEvent with the specified pointer coordinates.
import { createTouchEvent } from '@terminus/fe-testing';
const touchEvent = createTouchEvent('touchstart');
const touchEventAtLocation = createTouchEvent('touchstart', 212, 433);| Param | Type | Default |
|---|---|---|
type | string | |
pageX | number | 0 |
pageY | number | 0 |
Dispatching Events
dispatchEvent
Utility to dispatch any event on a Node.
import { dispatchEvent } from '@terminus/fe-testing';
dispatchEvent(myNativeElement, 'blur');| Param | Type | Default |
|---|---|---|
node | Node|Window | |
event | Event |
dispatchFakeEvent
Shorthand to dispatch a fake event on a specified node.
import { dispatchFakeEvent } from '@terminus/fe-testing';
dispatchFakeEvent(myNativeElement, 'mousedown');| Param | Type | Default |
|---|---|---|
node | Node|Window | |
type | string | |
canBubble? | boolean |
dispatchKeyboardEvent
Shorthand to dispatch a keyboard event with a specified key code.
import { dispatchKeyboardEvent } from '@terminus/fe-testing';
dispatchKeyboardEvent(myNativeElement, 'keyup', ENTER);| Param | Type | Default |
|---|---|---|
node | Node | |
type | string | |
keyCode | number | |
target? | Element |
dispatchMouseEvent
Shorthand to dispatch a mouse event on the specified coordinates.
import { dispatchMouseEvent } from '@terminus/fe-testing';
dispatchMouseEvent(myNativeElement, 'mousedown');| Param | Type | Default |
|---|---|---|
node | Node | |
type | string | |
x | number | 0 |
y | number | 0 |
event | MouseEvent | createMouseEvent(type, x, y) |
dispatchTouchEvent
Shorthand to dispatch a touch event on the specified coordinates.
import { dispatchTouchEvent } from '@terminus/fe-testing';
dispatchTouchEvent(myNativeElement, 'touchstart');| Param | Type | Default |
|---|---|---|
node | Node | |
type | string | |
x | number | 0 |
y | number | 0 |
Angular Test Helpers
configureTestBedWhitespace
By default, Angular does not strip out any white space when compiling templates for the TestBed. This
can make snapshot testing more difficult to visually parse. This helper will configure the TestBed
and compile the components with extra white space stripped.
import {
ConfigureTestBedFn,
configureTestBed,
} from '@terminus/fe-testing';
describe(`MyComponentSnapshot`, () => {
let fixture: ComponentFixture<MyComponent>;
let component: MyComponent;
beforeEach(async(() => {
// Define your configuration just as you would using the standard TestBed,
// except now it's inside a `ConfigureTestBedFn` function:
const configure: ConfigureTestBedFn = (testBed) => {
testBed.configureTestingModule({
...
declarations: [
MyComponent,
],
...
});
};
// Pass the configuration in and receive a TestBed instance:
configureTestBedWhitespace(configure).then((testBed) => {
fixture = testBed.createComponent(MyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
}));
test(`should match the snapshot`, () => {
expect(fixture).toMatchSnapshot();
});
});configureTestBedWithoutReset
By default, Angular resets the TestBed between each test. While this can be useful if
components or services have shared state or create side-effects, it can slow down tests quite a bit.
When the TestBed doesn't need to be reset, we can improve testing time by disabling this reset
functionality.
NOTE: This function makes use of
beforeAllandafterAllso it must be called inside your outermostdescribeblock.
import { TestModuleMetadata } from '@angular/core/testing';
import { configureTestBedWithoutReset } from '@terminus/fe-testing';
describe(`MyComponent`, () => {
let fixture: ComponentFixture<MyComponent>;
let component: MyComponent;
const moduleDefinition: TestModuleMetadata = {
imports: [
...
],
declarations: [
...
],
};
setUpTestBed(moduleDefinition);
test(`should...`, () => {
...
});
});createComponent
Helper function to quickly generate a TestBed fixture with a single component.
import { createComponent } from '@terminus/fe-testing';
@Component({template: ``})
export class TestComponent {
foo = 'bar';
}
test(`should do something`, () => {
const fixture = createComponent<TestComponent>(TestComponent);
expect(fixture.componentInstance.foo).toEqual('bar');
});expectNativeEl
Reusable expect statement to check for the nativeElement.
import { expectNativeEl } from '@terminus/fe-testing';
let fixture: ComponentFixture<TestHostComponent>;
let testHost: TestHostComponent;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [...],
declarations: [
MyComponent,
TestHostComponent,
],
providers: [...],
}).compileComponents();
fixture = TestBed.createComponent(TestHostComponent);
testHost = fixture.componentInstance;
fixture.detectChanges();
}));
test(`should have a native element`, () => {
expectNativeEl(fixture).toBeTruthy();
})getChildComponentInstanceFromFixture
Returns a component instance from a TestBed fixture:
import { getChildComponentInstanceFromFixture } from '@terminus/fe-testing';
import { Component } from '@angular/core';
import {
async,
ComponentFixture,
TestBed,
} from '@angular/core/testing';
// The component we will want a reference too:
@Component({
selector: `my-test`,
template: `<h1>foo</h1>`,
})
class TestComponent {
myString = 'foo';
}
// The parent component (fixture):
@Component({
template: `<my-test></my-test>`,
})
class TestHostComponent {}
describe(`my test`, () => {
let fixture: ComponentFixture<TestHostComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
TestComponent,
TestHostComponent,
],
});
// Create the fixture:
fixture = TestBed.createComponent(TestHostComponent);
});
test(`should ...`, () => {
// Get the instance:
const instance: TestComponent = getChildComponentInstanceFromFixture(fixture, TestComponent);
console.log(instance.myString); // logs out: `foo`
});
});getDomAttribute
A helper to return the value of a DOM attribute.
import { getDomAttribute } from '@terminus/fe-testing';
getDomAttribute(myElement, 'aria-label');queryFor
Helper to query a fixture for a selector.
import { queryFor } from '@terminus/fe-testing';
let fixture: ComponentFixture<TestHostComponent>;
let testHost: TestHostComponent;
let nestedElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [...],
declarations: [
MyComponent,
TestHostComponent,
],
providers: [...],
}).compileComponents();
fixture = TestBed.createComponent(TestHostComponent);
testHost = fixture.componentInstance;
fixture.detectChanges();
nestedElement = queryFor(fixture, '.my-class');
}));wrappedErrorMessage
Gets a RegExp used to detect an Angular wrapped error message. This allows testing for specific thrown errors in tests.
import { wrappedErrorMessage } from '@terminus/fe-testing';
expect(myFunc).toThrowError(wrappedErrorMessage(mySpecificError()));See https://github.com/angular/angular/issues/8348 for more information.
typeInElement
Focuses an input, sets it's value and dispatches the input event, simulating user typing.
import { typeInElement } from '@terminus/fe-testing';
typeInElement('test@test.com', myEmailInputElement);