Skip to content

Commit

Permalink
feat: expose fireEvent functions via createComponent in order to run …
Browse files Browse the repository at this point in the history
…detectChanges

drop detectChanges function in favor of the exposed events
  • Loading branch information
timdeschryver committed Jun 19, 2018
1 parent cb1593f commit 4a76cf4
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 66 deletions.
20 changes: 4 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ The second parameter in `createComponent` is the `options` parameter, which look

`schemas`: passed to the `TestBed`

The `createComponent` function returns an object consisting all of the query functions from [dom-testing-library][dom-testing-library] and adds the following properties:
The `createComponent` function returns an object consisting all of the query functions from [dom-testing-library][dom-testing-library], all the event functions exposed from `fireEvent`, and adds the following properties:

> Every event runs `detectChanges` on the fixture.
#### `container: HTMLElement`

Expand All @@ -98,10 +100,6 @@ All of the [dom-testing-library][dom-testing-library] query functions are binded

Prints out the container.

#### `detectChanges(checkNoChanges?: boolean) => void`

Runs `detectChanges` on the fixture.

#### `fixture: any`

The Angular fixture.
Expand All @@ -110,16 +108,6 @@ The Angular fixture.

Calls the the Angular `TestBed.get` function.

### `fireEvent`

Exposes the `fireEvent` from [dom-testing-library](dom-testing-library).

```ts
import { fireEvent } from 'ngx-testing-library';

fireEvent.click(buttonNode);
```

## Usage

You can find some examples in the [tests folder](https://github.com/tdeschryver/ngx-testing-library/tree/master/projects/ngx-testing-library/tests).
Expand Down Expand Up @@ -161,7 +149,7 @@ import { AppComponent } from './app.component';
import { createComponent } from 'ngx-testing-library';

it(`should have as title 'my-awesome-app'`, async () => {
const { detectChanges, getByText } = await createComponent('<app-root></app-root>', {
const { getByText } = await createComponent('<app-root></app-root>', {
declarations: [AppComponent],
});
expect(getByText('Welcome to my-awesome-app!')).toBeDefined();
Expand Down
75 changes: 74 additions & 1 deletion projects/ngx-testing-library/src/lib/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ export interface Result<T> {
container: HTMLElement;
getFromTestBed: (token: any, notFoundValue?: any) => any;
debug: () => void;
detectChanges: (checkNoChanges?: boolean) => void;
fixture: ComponentFixture<any>;

// Currently this isn't perfect because the typings from dom-testing-library are for TS 2.8
// dom-testing-library queroes
queryByPlaceholderText: any;
queryAllByPlaceholderText: any;
getByPlaceholderText: any;
Expand Down Expand Up @@ -35,6 +37,77 @@ export interface Result<T> {
queryAllByValue: any;
getByValue: any;
getAllByValue: any;

// dom-testing-library fireEvents
copy: (element: HTMLElement, options?: {}) => boolean;
cut: (element: HTMLElement, options?: {}) => boolean;
paste: (element: HTMLElement, options?: {}) => boolean;
compositionEnd: (element: HTMLElement, options?: {}) => boolean;
compositionStart: (element: HTMLElement, options?: {}) => boolean;
compositionUpdate: (element: HTMLElement, options?: {}) => boolean;
keyDown: (element: HTMLElement, options?: {}) => boolean;
keyPress: (element: HTMLElement, options?: {}) => boolean;
keyUp: (element: HTMLElement, options?: {}) => boolean;
focus: (element: HTMLElement, options?: {}) => boolean;
blur: (element: HTMLElement, options?: {}) => boolean;
change: (element: HTMLElement, options?: {}) => boolean;
input: (element: HTMLElement, options?: {}) => boolean;
invalid: (element: HTMLElement, options?: {}) => boolean;
submit: (element: HTMLElement, options?: {}) => boolean;
click: (element: HTMLElement, options?: {}) => boolean;
contextMenu: (element: HTMLElement, options?: {}) => boolean;
dblClick: (element: HTMLElement, options?: {}) => boolean;
drag: (element: HTMLElement, options?: {}) => boolean;
dragEnd: (element: HTMLElement, options?: {}) => boolean;
dragEnter: (element: HTMLElement, options?: {}) => boolean;
dragExit: (element: HTMLElement, options?: {}) => boolean;
dragLeave: (element: HTMLElement, options?: {}) => boolean;
dragOver: (element: HTMLElement, options?: {}) => boolean;
dragStart: (element: HTMLElement, options?: {}) => boolean;
drop: (element: HTMLElement, options?: {}) => boolean;
mouseDown: (element: HTMLElement, options?: {}) => boolean;
mouseEnter: (element: HTMLElement, options?: {}) => boolean;
mouseLeave: (element: HTMLElement, options?: {}) => boolean;
mouseMove: (element: HTMLElement, options?: {}) => boolean;
mouseOut: (element: HTMLElement, options?: {}) => boolean;
mouseOver: (element: HTMLElement, options?: {}) => boolean;
mouseUp: (element: HTMLElement, options?: {}) => boolean;
select: (element: HTMLElement, options?: {}) => boolean;
touchCancel: (element: HTMLElement, options?: {}) => boolean;
touchEnd: (element: HTMLElement, options?: {}) => boolean;
touchMove: (element: HTMLElement, options?: {}) => boolean;
touchStart: (element: HTMLElement, options?: {}) => boolean;
scroll: (element: HTMLElement, options?: {}) => boolean;
wheel: (element: HTMLElement, options?: {}) => boolean;
abort: (element: HTMLElement, options?: {}) => boolean;
canPlay: (element: HTMLElement, options?: {}) => boolean;
canPlayThrough: (element: HTMLElement, options?: {}) => boolean;
durationChange: (element: HTMLElement, options?: {}) => boolean;
emptied: (element: HTMLElement, options?: {}) => boolean;
encrypted: (element: HTMLElement, options?: {}) => boolean;
ended: (element: HTMLElement, options?: {}) => boolean;
loadedData: (element: HTMLElement, options?: {}) => boolean;
loadedMetadata: (element: HTMLElement, options?: {}) => boolean;
loadStart: (element: HTMLElement, options?: {}) => boolean;
pause: (element: HTMLElement, options?: {}) => boolean;
play: (element: HTMLElement, options?: {}) => boolean;
playing: (element: HTMLElement, options?: {}) => boolean;
progress: (element: HTMLElement, options?: {}) => boolean;
rateChange: (element: HTMLElement, options?: {}) => boolean;
seeked: (element: HTMLElement, options?: {}) => boolean;
seeking: (element: HTMLElement, options?: {}) => boolean;
stalled: (element: HTMLElement, options?: {}) => boolean;
suspend: (element: HTMLElement, options?: {}) => boolean;
timeUpdate: (element: HTMLElement, options?: {}) => boolean;
volumeChange: (element: HTMLElement, options?: {}) => boolean;
waiting: (element: HTMLElement, options?: {}) => boolean;
load: (element: HTMLElement, options?: {}) => boolean;
error: (element: HTMLElement, options?: {}) => boolean;
animationStart: (element: HTMLElement, options?: {}) => boolean;
animationEnd: (element: HTMLElement, options?: {}) => boolean;
animationIteration: (element: HTMLElement, options?: {}) => boolean;
transitionEnd: (element: HTMLElement, options?: {}) => boolean;
doubleClick: (element: HTMLElement, options?: {}) => boolean;
}

export interface Options {
Expand Down
14 changes: 11 additions & 3 deletions projects/ngx-testing-library/src/lib/ngx-testing-library.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, NgModule, Type } from '@angular/core';
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { getQueriesForElement, prettyDOM } from 'dom-testing-library';
import { getQueriesForElement, prettyDOM, fireEvent } from 'dom-testing-library';

import { Options, Result, ComponentInput } from './models';

Expand Down Expand Up @@ -34,13 +34,21 @@ export async function createComponent<T>(
fixture.detectChanges();
}

// Currently this isn't perfect because the typings from dom-testing-library are for TS 2.8
const eventsWithChangeDetection = Object.keys(fireEvent).reduce((events, key) => {
events[key] = (element: HTMLElement, options?: {}) => {
const result = fireEvent[key](element, options);
fixture.detectChanges();
return result;
};
return events;
}, {});

return {
fixture,
container: fixture.nativeElement,
getFromTestBed: TestBed.get,
detectChanges: (checkNoChanges?: boolean) => fixture.detectChanges(checkNoChanges),
debug: () => console.log(prettyDOM(fixture.nativeElement)),
...eventsWithChangeDetection,
...getQueriesForElement(fixture.nativeElement),
};
}
Expand Down
1 change: 0 additions & 1 deletion projects/ngx-testing-library/src/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@

export * from './lib/models';
export * from './lib/ngx-testing-library';
export { fireEvent } from 'dom-testing-library';
26 changes: 10 additions & 16 deletions projects/ngx-testing-library/tests/counter/counter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Input } from '@angular/core';
import { createComponent, fireEvent } from '../../src/public_api';
import { createComponent } from '../../src/public_api';

@Component({
selector: 'counter',
Expand All @@ -20,23 +20,21 @@ export class CounterComponent {
}

test('Counter actions via template syntax', async () => {
const { detectChanges, getByText, getByTestId } = await createComponent('<counter [counter]="10"></counter>', {
const { getByText, getByTestId, click } = await createComponent('<counter [counter]="10"></counter>', {
declarations: [CounterComponent],
});

fireEvent.click(getByText('+'));
detectChanges();
click(getByText('+'));
expect(getByText('Current Count: 11')).toBeTruthy();
expect(getByTestId('count').textContent).toBe('Current Count: 11');

getByText('-').click();
detectChanges();
click(getByText('-'));
expect(getByText('Current Count: 10')).toBeTruthy();
expect(getByTestId('count').textContent).toBe('Current Count: 10');
});

test('Counter actions via component syntax', async () => {
const { getByText, detectChanges, getByTestId } = await createComponent(
const { getByText, getByTestId, click } = await createComponent(
{
component: CounterComponent,
parameters: {
Expand All @@ -48,19 +46,17 @@ test('Counter actions via component syntax', async () => {
},
);

getByText('+').click();
detectChanges();
click(getByText('+'));
expect(getByText('Current Count: 11')).toBeTruthy();
expect(getByTestId('count').textContent).toBe('Current Count: 11');

getByText('-').click();
detectChanges();
click(getByText('-'));
expect(getByText('Current Count: 10')).toBeTruthy();
expect(getByTestId('count').textContent).toBe('Current Count: 10');
});

test('Counter actions via component syntax without parameters', async () => {
const { getByText, detectChanges, getByTestId } = await createComponent(
const { getByText, getByTestId, click } = await createComponent(
{
component: CounterComponent,
},
Expand All @@ -69,13 +65,11 @@ test('Counter actions via component syntax without parameters', async () => {
},
);

getByText('+').click();
detectChanges();
click(getByText('+'));
expect(getByText('Current Count: 1')).toBeTruthy();
expect(getByTestId('count').textContent).toBe('Current Count: 1');

getByText('-').click();
detectChanges();
click(getByText('-'));
expect(getByText('Current Count: 0')).toBeTruthy();
expect(getByTestId('count').textContent).toBe('Current Count: 0');
});
2 changes: 1 addition & 1 deletion projects/ngx-testing-library/tests/debug.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Input } from '@angular/core';
import { createComponent, fireEvent } from '../src/public_api';
import { createComponent } from '../src/public_api';

@Component({
selector: 'fixture',
Expand Down
21 changes: 0 additions & 21 deletions projects/ngx-testing-library/tests/detectChanges.spec.ts

This file was deleted.

10 changes: 5 additions & 5 deletions projects/ngx-testing-library/tests/form/form.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ReactiveFormsModule } from '@angular/forms';
import { createComponent, fireEvent } from '../../src/public_api';
import { createComponent } from '../../src/public_api';
import { LoginFormComponent } from './form.component';

test('login form submits using the component syntax', async () => {
Expand All @@ -8,7 +8,7 @@ test('login form submits using the component syntax', async () => {
emit: jest.fn(),
};

const { container, getByLabelText, getByText } = await createComponent(
const { container, getByLabelText, getByText, input, submit } = await createComponent(
{
component: LoginFormComponent,
parameters: {
Expand All @@ -27,12 +27,12 @@ test('login form submits using the component syntax', async () => {
const formNode = container.querySelector('form');

usernameNode.value = fakeUser.username;
fireEvent.input(usernameNode);
input(usernameNode);

passwordNode.value = fakeUser.password;
fireEvent.input(passwordNode);
input(passwordNode);

fireEvent.submit(formNode);
submit(formNode);

expect(handleLogin.emit).toHaveBeenCalledTimes(1);
expect(handleLogin.emit).toHaveBeenCalledWith(fakeUser);
Expand Down
2 changes: 1 addition & 1 deletion projects/ngx-testing-library/tests/getFromTestBed.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Input, Injectable } from '@angular/core';
import { createComponent, fireEvent } from '../src/public_api';
import { createComponent } from '../src/public_api';

@Component({
selector: 'fixture',
Expand Down
2 changes: 1 addition & 1 deletion src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ test(`matches snapshot`, async () => {
});

test(`should have a title`, async () => {
const { detectChanges, getByText } = await createComponent('<app-root></app-root>', {
const { getByText } = await createComponent('<app-root></app-root>', {
declarations: [AppComponent],
});
expect(getByText('Welcome to app!')).toBeDefined();
Expand Down

0 comments on commit 4a76cf4

Please sign in to comment.