npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@terminus/fe-testing

v2.0.0

Published

A collection of helpers to facilitate testing UI components

Downloads

4

Readme

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('[email protected]', myEmailInputElement);