@terminus/fe-testing
TypeScript icon, indicating that this package has built-in type declarations

2.0.0 • Public • Published

Testing Utilities

CI/CD Status MIT License
NPM version Library size

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 beforeAll and afterAll so it must be called inside your outermost describe block.

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);

Readme

Keywords

none

Package Sidebar

Install

npm i @terminus/fe-testing

Weekly Downloads

1

Version

2.0.0

License

MIT

Unpacked Size

285 kB

Total Files

149

Last publish

Collaborators

  • bmalinconico-terminus
  • atlwendy
  • terminus_devops