diff --git a/README.md b/README.md index 07795269..84b80616 100644 --- a/README.md +++ b/README.md @@ -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` @@ -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. @@ -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). @@ -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('', { + const { getByText } = await createComponent('', { declarations: [AppComponent], }); expect(getByText('Welcome to my-awesome-app!')).toBeDefined(); diff --git a/projects/ngx-testing-library/src/lib/models.ts b/projects/ngx-testing-library/src/lib/models.ts index 50e9143f..958accc0 100644 --- a/projects/ngx-testing-library/src/lib/models.ts +++ b/projects/ngx-testing-library/src/lib/models.ts @@ -5,8 +5,10 @@ export interface Result { container: HTMLElement; getFromTestBed: (token: any, notFoundValue?: any) => any; debug: () => void; - detectChanges: (checkNoChanges?: boolean) => void; fixture: ComponentFixture; + + // 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; @@ -35,6 +37,77 @@ export interface Result { 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 { diff --git a/projects/ngx-testing-library/src/lib/ngx-testing-library.ts b/projects/ngx-testing-library/src/lib/ngx-testing-library.ts index 0dd7e1c2..a3585a24 100644 --- a/projects/ngx-testing-library/src/lib/ngx-testing-library.ts +++ b/projects/ngx-testing-library/src/lib/ngx-testing-library.ts @@ -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'; @@ -34,13 +34,21 @@ export async function createComponent( 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), }; } diff --git a/projects/ngx-testing-library/src/public_api.ts b/projects/ngx-testing-library/src/public_api.ts index 919dbcff..e00dc79e 100644 --- a/projects/ngx-testing-library/src/public_api.ts +++ b/projects/ngx-testing-library/src/public_api.ts @@ -4,4 +4,3 @@ export * from './lib/models'; export * from './lib/ngx-testing-library'; -export { fireEvent } from 'dom-testing-library'; diff --git a/projects/ngx-testing-library/tests/counter/counter.spec.ts b/projects/ngx-testing-library/tests/counter/counter.spec.ts index d2552efd..21f4def4 100644 --- a/projects/ngx-testing-library/tests/counter/counter.spec.ts +++ b/projects/ngx-testing-library/tests/counter/counter.spec.ts @@ -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', @@ -20,23 +20,21 @@ export class CounterComponent { } test('Counter actions via template syntax', async () => { - const { detectChanges, getByText, getByTestId } = await createComponent('', { + const { getByText, getByTestId, click } = await createComponent('', { 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: { @@ -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, }, @@ -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'); }); diff --git a/projects/ngx-testing-library/tests/debug.spec.ts b/projects/ngx-testing-library/tests/debug.spec.ts index 893d4a46..b818d7a9 100644 --- a/projects/ngx-testing-library/tests/debug.spec.ts +++ b/projects/ngx-testing-library/tests/debug.spec.ts @@ -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', diff --git a/projects/ngx-testing-library/tests/detectChanges.spec.ts b/projects/ngx-testing-library/tests/detectChanges.spec.ts deleted file mode 100644 index febde168..00000000 --- a/projects/ngx-testing-library/tests/detectChanges.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { createComponent, fireEvent } from '../src/public_api'; - -@Component({ - selector: 'fixture', - template: `

rawr

`, -}) -class FixtureComponent {} - -test('calls detect changes on the fixture', async () => { - const { fixture, detectChanges } = await createComponent('', { - declarations: [FixtureComponent], - }); - fixture.detectChanges = jest.fn(); - - detectChanges(); - expect(fixture.detectChanges).toBeCalledWith(undefined); - - detectChanges(true); - expect(fixture.detectChanges).toBeCalledWith(true); -}); diff --git a/projects/ngx-testing-library/tests/form/form.spec.ts b/projects/ngx-testing-library/tests/form/form.spec.ts index ab073642..79100962 100644 --- a/projects/ngx-testing-library/tests/form/form.spec.ts +++ b/projects/ngx-testing-library/tests/form/form.spec.ts @@ -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 () => { @@ -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: { @@ -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); diff --git a/projects/ngx-testing-library/tests/getFromTestBed.spec.ts b/projects/ngx-testing-library/tests/getFromTestBed.spec.ts index 40a01512..684c564d 100644 --- a/projects/ngx-testing-library/tests/getFromTestBed.spec.ts +++ b/projects/ngx-testing-library/tests/getFromTestBed.spec.ts @@ -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', diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index a25bc927..624db6b6 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -9,7 +9,7 @@ test(`matches snapshot`, async () => { }); test(`should have a title`, async () => { - const { detectChanges, getByText } = await createComponent('', { + const { getByText } = await createComponent('', { declarations: [AppComponent], }); expect(getByText('Welcome to app!')).toBeDefined();