From 7f39bf4696a9cb9bb8e9e94e2430c047dbabeff2 Mon Sep 17 00:00:00 2001 From: timdeschryver <28659384+timdeschryver@users.noreply.github.com> Date: Mon, 1 Jun 2020 10:04:07 +0200 Subject: [PATCH 1/3] fix: use types from dom testing library --- package.json | 2 +- projects/testing-library/package.json | 2 +- .../src/lib/testing-library.ts | 58 ++++-------------- yarn.lock | 60 ++++++++----------- 4 files changed, 37 insertions(+), 85 deletions(-) diff --git a/package.json b/package.json index 4445f598..6a455bb8 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "@angular/router": "^9.0.3", "@ngrx/store": "^9.0.0-rc.0", "@phenomnomnominal/tsquery": "^3.0.0", - "@testing-library/dom": "^7.1.1", + "@testing-library/dom": "^7.7.3", "@testing-library/user-event": "^8.1.0", "core-js": "^3.1.3", "rxjs": "^6.5.4", diff --git a/projects/testing-library/package.json b/projects/testing-library/package.json index b0715155..633b5354 100644 --- a/projects/testing-library/package.json +++ b/projects/testing-library/package.json @@ -29,7 +29,7 @@ "@angular/core": "^9.0.0" }, "dependencies": { - "@testing-library/dom": "^7.1.0", + "@testing-library/dom": "^7.7.3", "@testing-library/user-event": "^8.1.0", "@phenomnomnominal/tsquery": "^3.0.0", "tslint": "^5.16.0" diff --git a/projects/testing-library/src/lib/testing-library.ts b/projects/testing-library/src/lib/testing-library.ts index 00231def..f2142940 100644 --- a/projects/testing-library/src/lib/testing-library.ts +++ b/projects/testing-library/src/lib/testing-library.ts @@ -14,6 +14,7 @@ import { fireEvent as dtlFireEvent, screen as dtlScreen, queries as dtlQueries, + waitForOptions, } from '@testing-library/dom'; import { RenderComponentOptions, RenderDirectiveOptions, RenderResult } from './models'; import { createSelectOptions, createType, tab } from './user-events'; @@ -147,26 +148,13 @@ export async function render( return result; }; - function componentWaitFor( - callback, - options: { - container?: HTMLElement; - timeout?: number; - interval?: number; - mutationObserverOptions?: MutationObserverInit; - } = { container: fixture.nativeElement }, - ): Promise { + function componentWaitFor(callback, options: waitForOptions = { container: fixture.nativeElement }): Promise { return waitForWrapper(detectChanges, callback, options); } function componentWaitForElementToBeRemoved( callback: (() => T) | T, - options: { - container?: HTMLElement; - timeout?: number; - interval?: number; - mutationObserverOptions?: MutationObserverInit; - } = { container: fixture.nativeElement }, + options: waitForOptions = { container: fixture.nativeElement }, ): Promise { return waitForElementToBeRemovedWrapper(detectChanges, callback, options); } @@ -255,13 +243,8 @@ function addAutoImports({ imports, routes }: Pick, ' */ async function waitForWrapper( detectChanges: () => void, - callback: () => T, - options?: { - container?: HTMLElement; - timeout?: number; - interval?: number; - mutationObserverOptions?: MutationObserverInit; - }, + callback: () => T extends Promise ? never : T, + options?: waitForOptions, ): Promise { return await dtlWaitFor(() => { detectChanges(); @@ -275,12 +258,7 @@ async function waitForWrapper( async function waitForElementToBeRemovedWrapper( detectChanges: () => void, callback: (() => T) | T, - options?: { - container?: HTMLElement; - timeout?: number; - interval?: number; - mutationObserverOptions?: MutationObserverInit; - }, + options?: waitForOptions, ): Promise { let cb; if (typeof callback !== 'function') { @@ -328,12 +306,12 @@ function replaceFindWithFindAndDetectChanges(container: HTMLElement, original (newQueries, key) => { if (key.startsWith('find')) { const getByQuery = dtlQueries[key.replace('find', 'get')]; - newQueries[key] = async (text, options, waitForOptions) => { + newQueries[key] = async (text, options, waitOptions) => { // original implementation at https://github.com/testing-library/dom-testing-library/blob/master/src/query-helpers.js const result = await waitForWrapper( detectChangesForMountedFixtures, () => getByQuery(container, text, options), - waitForOptions, + waitOptions, ); return result; }; @@ -377,30 +355,14 @@ const screen = replaceFindWithFindAndDetectChanges(document.body, dtlScreen); /** * Re-export waitFor with patched waitFor */ -async function waitFor( - callback: () => T, - options?: { - container?: HTMLElement; - timeout?: number; - interval?: number; - mutationObserverOptions?: MutationObserverInit; - }, -): Promise { +async function waitFor(callback: () => T extends Promise ? never : T, options?: waitForOptions): Promise { return waitForWrapper(detectChangesForMountedFixtures, callback, options); } /** * Re-export waitForElementToBeRemoved with patched waitForElementToBeRemoved */ -async function waitForElementToBeRemoved( - callback: (() => T) | T, - options?: { - container?: HTMLElement; - timeout?: number; - interval?: number; - mutationObserverOptions?: MutationObserverInit; - }, -): Promise { +async function waitForElementToBeRemoved(callback: (() => T) | T, options?: waitForOptions): Promise { return waitForElementToBeRemovedWrapper(detectChangesForMountedFixtures, callback, options); } diff --git a/yarn.lock b/yarn.lock index 4d127519..3f769f0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -998,10 +998,10 @@ dependencies: regenerator-runtime "^0.13.2" -"@babel/runtime@^7.9.2": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" - integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== +"@babel/runtime@^7.9.6": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839" + integrity sha512-6sF3uQw2ivImfVIl62RZ7MXhO2tap69WeWK57vAaimT6AZbE4FbqjdEJIN1UqoD6wI6B+1n9UiagafH1sxjOtg== dependencies: regenerator-runtime "^0.13.4" @@ -1239,10 +1239,10 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" -"@jest/types@^25.1.0": - version "25.1.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.1.0.tgz#b26831916f0d7c381e11dbb5e103a72aed1b4395" - integrity sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA== +"@jest/types@^25.5.0": + version "25.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" + integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^1.1.1" @@ -1545,16 +1545,15 @@ dependencies: defer-to-connect "^1.0.1" -"@testing-library/dom@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.1.1.tgz#bf890c2468bd717ffd8b336a819686907fbe4daa" - integrity sha512-CxspAIntyK2joLUJChOZgnwx7xBxdBC8ugwP+Z49Dd9O3sGVs0wHkOUOsfBVXHgBjmdZk8E3SyHZVrMRd9O1sA== +"@testing-library/dom@^7.7.3": + version "7.7.3" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.7.3.tgz#04fc0881f67ded05a017a2341c78d567c56aad0e" + integrity sha512-TiYhZ2NOg3zyVp7lT1vg1oKdjgVD79l7klu5ysszj6M5ut7DnCTYSFc8eNMfOymnN4c+tzF7aEePMIVomaJOgQ== dependencies: - "@babel/runtime" "^7.9.2" - "@types/testing-library__dom" "^7.0.0" + "@babel/runtime" "^7.9.6" aria-query "^4.0.2" - dom-accessibility-api "^0.4.2" - pretty-format "^25.1.0" + dom-accessibility-api "^0.4.4" + pretty-format "^25.5.0" "@testing-library/jest-dom@^4.1.0": version "4.1.0" @@ -1732,13 +1731,6 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== -"@types/testing-library__dom@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@types/testing-library__dom/-/testing-library__dom-7.0.0.tgz#c0fb7d1c2495a3d26f19342102142d47500f0319" - integrity sha512-1TEPWyqQ6IQ7R1hCegZmFSA3KrBQjdzJW7yC9ybpRcFst5XuPOqBGNr0mTAKbxwI/TrTyc1skeyLJrpcvAf93w== - dependencies: - pretty-format "^25.1.0" - "@types/webpack-sources@^0.1.5": version "0.1.5" resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.5.tgz#be47c10f783d3d6efe1471ff7f042611bd464a92" @@ -3761,7 +3753,7 @@ core-js-compat@^3.6.0: browserslist "^4.8.3" semver "7.0.0" -core-js-pure@^3.0.0, core-js-pure@^3.6.4: +core-js-pure@^3.0.0: version "3.6.4" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.4.tgz#4bf1ba866e25814f149d4e9aaa08c36173506e3a" integrity sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw== @@ -4470,12 +4462,10 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" -dom-accessibility-api@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.4.2.tgz#e19ef39da9a5858f6f9af225113f6ed302ccdf70" - integrity sha512-vKxUcEtM9bVB7eDv7jTAuOLl5L0724Pk6iHxz8KUIgrWl53TTA6MuZ0g/bUrnEx3Gsf9SIJ1LiVtjfo0rg7iMA== - dependencies: - core-js-pure "^3.6.4" +dom-accessibility-api@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.4.4.tgz#c2f9fb8b591bc19581e7ef3e6fe35baf1967c498" + integrity sha512-XBM62jdDc06IXSujkqw6BugEWiDkp6jphtzVJf1kgPQGvfzaU7/jRtRSF/mxc8DBCIm2LS3bN1dCa5Sfxx982A== dom-serializer@0: version "0.2.2" @@ -10252,12 +10242,12 @@ pretty-format@^24.9.0: ansi-styles "^3.2.0" react-is "^16.8.4" -pretty-format@^25.1.0: - version "25.1.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.1.0.tgz#ed869bdaec1356fc5ae45de045e2c8ec7b07b0c8" - integrity sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ== +pretty-format@^25.5.0: + version "25.5.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" + integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ== dependencies: - "@jest/types" "^25.1.0" + "@jest/types" "^25.5.0" ansi-regex "^5.0.0" ansi-styles "^4.0.0" react-is "^16.12.0" From 4f0878f32c4662c982d8391da26bdf0200f7d3b7 Mon Sep 17 00:00:00 2001 From: timdeschryver <28659384+timdeschryver@users.noreply.github.com> Date: Mon, 1 Jun 2020 10:04:43 +0200 Subject: [PATCH 2/3] feat: use a11y queries in selectOptions --- .../src/lib/user-events/selectOptions.ts | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/projects/testing-library/src/lib/user-events/selectOptions.ts b/projects/testing-library/src/lib/user-events/selectOptions.ts index 236f3b09..2f033ae5 100644 --- a/projects/testing-library/src/lib/user-events/selectOptions.ts +++ b/projects/testing-library/src/lib/user-events/selectOptions.ts @@ -1,11 +1,4 @@ -import { - FireFunction, - FireObject, - Matcher, - getByText, - SelectorMatcherOptions, - queryByText, -} from '@testing-library/dom'; +import { FireFunction, FireObject, Matcher, screen, ByRoleOptions } from '@testing-library/dom'; // implementation from https://github.com/testing-library/user-event export function createSelectOptions(fireEvent: FireFunction & FireObject) { @@ -18,10 +11,16 @@ export function createSelectOptions(fireEvent: FireFunction & FireObject) { fireEvent.click(element); } - function selectOption(select: HTMLSelectElement, index: number, matcher: Matcher, options?: SelectorMatcherOptions) { - // fallback to document.body, because libraries as Angular Material will have their custom select component - const option = (queryByText(select, matcher, options) || - getByText(document.body, matcher, options)) as HTMLOptionElement; + function selectOption(select: HTMLSelectElement, index: number, options: Matcher | ByRoleOptions) { + const query = + typeof options === 'string' + ? (({ name: new RegExp(options, 'i') } as unknown) as ByRoleOptions) + : options instanceof RegExp + ? (({ name: options } as unknown) as ByRoleOptions) + : typeof options === 'function' + ? (({ name: options } as unknown) as ByRoleOptions) + : options; + const option = screen.getByRole('option', query) as HTMLOptionElement; fireEvent.mouseOver(option); fireEvent.mouseMove(option); @@ -36,8 +35,7 @@ export function createSelectOptions(fireEvent: FireFunction & FireObject) { return async function selectOptions( element: HTMLElement, - matcher: Matcher | Matcher[], - matcherOptions?: SelectorMatcherOptions, + options: Matcher | ByRoleOptions | ((Matcher | ByRoleOptions)[]), ) { const selectElement = element as HTMLSelectElement; @@ -55,10 +53,10 @@ export function createSelectOptions(fireEvent: FireFunction & FireObject) { clickElement(selectElement); - const values = Array.isArray(matcher) ? matcher : [matcher]; + const values = Array.isArray(options) ? options : [options]; values .filter((_, index) => index === 0 || selectElement.multiple) - .forEach((val, index) => selectOption(selectElement, index, val, matcherOptions)); + .forEach((val, index) => selectOption(selectElement, index, val)); if (wasAnotherElementFocused) { fireEvent.blur(focusedElement); From 8acaebb51ac2093768fad058fc150d63ca667e34 Mon Sep 17 00:00:00 2001 From: timdeschryver <28659384+timdeschryver@users.noreply.github.com> Date: Mon, 1 Jun 2020 10:07:09 +0200 Subject: [PATCH 3/3] docs: update examples with a11y queries --- README.md | 14 +++--- src/app/examples/00-single-component.spec.ts | 4 +- src/app/examples/01-nested-component.spec.ts | 4 +- src/app/examples/02-input-output.spec.ts | 4 +- src/app/examples/03-forms.spec.ts | 8 ++-- src/app/examples/03-forms.ts | 2 +- .../examples/04-forms-with-material.spec.ts | 8 ++-- src/app/examples/04-forms-with-material.ts | 2 +- .../examples/05-component-provider.spec.ts | 12 +++--- src/app/examples/06-with-ngrx-store.spec.ts | 4 +- .../examples/07-with-ngrx-mock-store.spec.ts | 3 +- src/app/examples/07-with-ngrx-mock-store.ts | 2 +- src/app/examples/09-router.spec.ts | 43 ++++++++++--------- src/app/examples/11-ng-content.spec.ts | 2 +- 14 files changed, 57 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 65260e73..ad930ab6 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ counter.component.ts selector: 'counter', template: ` - Current Count: {{ counter }} + Current Count: {{ counter }} `, }) @@ -117,8 +117,8 @@ export class CounterComponent { counter.component.spec.ts ```typescript -import { render, screen } from '@testing-library/angular'; -import CounterComponent from './counter.component.ts'; +import { render, screen, fireEvent } from '@testing-library/angular'; +import { CounterComponent } from './counter.component.ts'; describe('Counter', () => { test('should render counter', async () => { @@ -128,11 +128,12 @@ describe('Counter', () => { }); test('should increment the counter on click', async () => { - const { click } = await render(CounterComponent, { componentProperties: { counter: 5 } }); + await render(CounterComponent, { componentProperties: { counter: 5 } }); - click(screen.getByText('+')); + const incrementButton = screen.getByRole('button', { name: /increment/i }); + fireEvent.click(incrementControl); - expect(getByText('Current Count: 6')); + expect(screen.getByText('Current Count: 6')); }); }); ``` @@ -194,6 +195,7 @@ Thanks goes to these people ([emoji key][emojis]): + This project follows the [all-contributors][all-contributors] specification. diff --git a/src/app/examples/00-single-component.spec.ts b/src/app/examples/00-single-component.spec.ts index d8263f79..460cae16 100644 --- a/src/app/examples/00-single-component.spec.ts +++ b/src/app/examples/00-single-component.spec.ts @@ -5,8 +5,8 @@ import { SingleComponent } from './00-single-component'; test('renders the current value and can increment and decrement', async () => { await render(SingleComponent); - const incrementControl = screen.getByText('Increment'); - const decrementControl = screen.getByText('Decrement'); + const incrementControl = screen.getByRole('button', { name: /increment/i }); + const decrementControl = screen.getByRole('button', { name: /decrement/i }); const valueControl = screen.getByTestId('value'); expect(valueControl.textContent).toBe('0'); diff --git a/src/app/examples/01-nested-component.spec.ts b/src/app/examples/01-nested-component.spec.ts index b7abd3a1..bbaf9c37 100644 --- a/src/app/examples/01-nested-component.spec.ts +++ b/src/app/examples/01-nested-component.spec.ts @@ -7,8 +7,8 @@ test('renders the current value and can increment and decrement', async () => { declarations: [NestedButtonComponent, NestedValueComponent], }); - const incrementControl = screen.getByText('Increment'); - const decrementControl = screen.getByText('Decrement'); + const incrementControl = screen.getByRole('button', { name: /increment/i }); + const decrementControl = screen.getByRole('button', { name: /decrement/i }); const valueControl = screen.getByTestId('value'); expect(valueControl.textContent).toBe('0'); diff --git a/src/app/examples/02-input-output.spec.ts b/src/app/examples/02-input-output.spec.ts index df009356..d2650fd1 100644 --- a/src/app/examples/02-input-output.spec.ts +++ b/src/app/examples/02-input-output.spec.ts @@ -14,9 +14,9 @@ test('is possible to set input and listen for output', async () => { }, }); - const incrementControl = screen.getByText('Increment'); + const incrementControl = screen.getByRole('button', { name: /increment/i }); + const sendControl = screen.getByRole('button', { name: /send/i }); const valueControl = screen.getByTestId('value'); - const sendControl = screen.getByText('Send'); expect(valueControl.textContent).toBe('47'); diff --git a/src/app/examples/03-forms.spec.ts b/src/app/examples/03-forms.spec.ts index 5b0ec79a..7180628f 100644 --- a/src/app/examples/03-forms.spec.ts +++ b/src/app/examples/03-forms.spec.ts @@ -8,9 +8,9 @@ test('is possible to fill in a form and verify error messages (with the help of imports: [ReactiveFormsModule], }); - const nameControl = screen.getByLabelText('Name'); - const scoreControl = screen.getByLabelText(/score/i); - const colorControl = screen.getByLabelText('color', { exact: false }); + const nameControl = screen.getByRole('textbox', { name: /name/i }); + const scoreControl = screen.getByRole('spinbutton', { name: /score/i }); + const colorControl = screen.getByRole('combobox', { name: /color/i }); const errors = screen.getByRole('alert'); expect(errors).toContainElement(screen.queryByText('name is required')); @@ -38,7 +38,7 @@ test('is possible to fill in a form and verify error messages (with the help of expect(scoreControl).toHaveValue(7); expect(colorControl).toHaveValue('G'); - const form = screen.getByTestId('my-form'); + const form = screen.getByRole('form'); expect(form).toHaveFormValues({ name: 'Tim', score: 7, diff --git a/src/app/examples/03-forms.ts b/src/app/examples/03-forms.ts index bb0b56bc..7cff1e71 100644 --- a/src/app/examples/03-forms.ts +++ b/src/app/examples/03-forms.ts @@ -4,7 +4,7 @@ import { FormBuilder, Validators, ReactiveFormsModule, ValidationErrors } from ' @Component({ selector: 'app-fixture', template: ` -
+
diff --git a/src/app/examples/04-forms-with-material.spec.ts b/src/app/examples/04-forms-with-material.spec.ts index fb01eefe..7c7b8a91 100644 --- a/src/app/examples/04-forms-with-material.spec.ts +++ b/src/app/examples/04-forms-with-material.spec.ts @@ -9,9 +9,9 @@ test('is possible to fill in a form and verify error messages (with the help of imports: [ReactiveFormsModule, MaterialModule], }); - const nameControl = screen.getByPlaceholderText('Name'); - const scoreControl = screen.getByPlaceholderText(/score/i); - const colorControl = screen.getByPlaceholderText('color', { exact: false }); + const nameControl = screen.getByLabelText(/name/i); + const scoreControl = screen.getByRole('spinbutton', { name: /score/i }); + const colorControl = screen.getByRole('listbox', { name: /color/i }); const errors = screen.getByRole('alert'); expect(errors).toContainElement(screen.queryByText('name is required')); @@ -35,7 +35,7 @@ test('is possible to fill in a form and verify error messages (with the help of expect(nameControl).toHaveValue('Tim'); expect(scoreControl).toHaveValue(7); - const form = screen.getByTestId('my-form'); + const form = screen.getByRole('form'); expect(form).toHaveFormValues({ name: 'Tim', score: 7, diff --git a/src/app/examples/04-forms-with-material.ts b/src/app/examples/04-forms-with-material.ts index 5b6aa38e..18d4925c 100644 --- a/src/app/examples/04-forms-with-material.ts +++ b/src/app/examples/04-forms-with-material.ts @@ -4,7 +4,7 @@ import { FormBuilder, Validators, ReactiveFormsModule, ValidationErrors } from ' @Component({ selector: 'app-fixture', template: ` - + diff --git a/src/app/examples/05-component-provider.spec.ts b/src/app/examples/05-component-provider.spec.ts index b1a156a8..861eae76 100644 --- a/src/app/examples/05-component-provider.spec.ts +++ b/src/app/examples/05-component-provider.spec.ts @@ -14,8 +14,8 @@ test('renders the current value and can increment and decrement', async () => { ], }); - const incrementControl = screen.getByText('Increment'); - const decrementControl = screen.getByText('Decrement'); + const incrementControl = screen.getByRole('button', { name: /increment/i }); + const decrementControl = screen.getByRole('button', { name: /decrement/i }); const valueControl = screen.getByTestId('value'); expect(valueControl.textContent).toBe('0'); @@ -44,8 +44,8 @@ test('renders the current value and can increment and decrement with a mocked je ], }); - const incrementControl = screen.getByText('Increment'); - const decrementControl = screen.getByText('Decrement'); + const incrementControl = screen.getByRole('button', { name: /increment/i }); + const decrementControl = screen.getByRole('button', { name: /decrement/i }); const valueControl = screen.getByTestId('value'); expect(valueControl.textContent).toBe('50'); @@ -63,8 +63,8 @@ test('renders the current value and can increment and decrement with provideMock componentProviders: [provideMock(CounterService)], }); - const incrementControl = screen.getByText('Increment'); - const decrementControl = screen.getByText('Decrement'); + const incrementControl = screen.getByRole('button', { name: /increment/i }); + const decrementControl = screen.getByRole('button', { name: /decrement/i }); fireEvent.click(incrementControl); fireEvent.click(incrementControl); diff --git a/src/app/examples/06-with-ngrx-store.spec.ts b/src/app/examples/06-with-ngrx-store.spec.ts index fdeb4db9..d8a80d87 100644 --- a/src/app/examples/06-with-ngrx-store.spec.ts +++ b/src/app/examples/06-with-ngrx-store.spec.ts @@ -17,8 +17,8 @@ test('works with ngrx store', async () => { ], }); - const incrementControl = screen.getByText('Increment'); - const decrementControl = screen.getByText('Decrement'); + const incrementControl = screen.getByRole('button', { name: /increment/i }); + const decrementControl = screen.getByRole('button', { name: /decrement/i }); const valueControl = screen.getByTestId('value'); expect(valueControl.textContent).toBe('0'); diff --git a/src/app/examples/07-with-ngrx-mock-store.spec.ts b/src/app/examples/07-with-ngrx-mock-store.spec.ts index 55cde6b9..809dbfb2 100644 --- a/src/app/examples/07-with-ngrx-mock-store.spec.ts +++ b/src/app/examples/07-with-ngrx-mock-store.spec.ts @@ -21,8 +21,7 @@ test('works with provideMockStore', async () => { const store = TestBed.inject(MockStore); store.dispatch = jest.fn(); - screen.getByText('Four'); - fireEvent.click(screen.getByText('Seven')); + fireEvent.click(screen.getByRole('listitem', { name: /seven/i })); expect(store.dispatch).toBeCalledWith({ type: '[Item List] send', item: 'Seven' }); }); diff --git a/src/app/examples/07-with-ngrx-mock-store.ts b/src/app/examples/07-with-ngrx-mock-store.ts index 491ae327..ea88563f 100644 --- a/src/app/examples/07-with-ngrx-mock-store.ts +++ b/src/app/examples/07-with-ngrx-mock-store.ts @@ -10,7 +10,7 @@ export const selectItems = createSelector( selector: 'app-fixture', template: `
    -
  • {{ item }}
  • +
  • {{ item }}
`, }) diff --git a/src/app/examples/09-router.spec.ts b/src/app/examples/09-router.spec.ts index d4eaca73..cb6743fc 100644 --- a/src/app/examples/09-router.spec.ts +++ b/src/app/examples/09-router.spec.ts @@ -24,19 +24,19 @@ test('it can navigate to routes', async () => { expect(screen.queryByText(/Detail one/i)).not.toBeInTheDocument(); - await navigate(screen.getByText(/Load one/)); - expect(screen.queryByText(/Detail one/i)).toBeInTheDocument(); + await navigate(screen.getByRole('link', { name: /load one/i })); + expect(screen.queryByRole('heading', { name: /Detail one/i })).toBeInTheDocument(); - await navigate(screen.getByText(/Load three/)); - expect(screen.queryByText(/Detail one/i)).not.toBeInTheDocument(); - expect(screen.queryByText(/Detail three/i)).toBeInTheDocument(); + await navigate(screen.getByRole('link', { name: /load three/i })); + expect(screen.queryByRole('heading', { name: /Detail one/i })).not.toBeInTheDocument(); + expect(screen.queryByRole('heading', { name: /Detail three/i })).toBeInTheDocument(); - await navigate(screen.getByText(/Back to parent/)); - expect(screen.queryByText(/Detail three/i)).not.toBeInTheDocument(); + await navigate(screen.getByRole('link', { name: /back to parent/i })); + expect(screen.queryByRole('heading', { name: /Detail three/i })).not.toBeInTheDocument(); - await navigate(screen.getByText(/Load two/)); - expect(screen.queryByText(/Detail two/i)).toBeInTheDocument(); - await navigate(screen.getByText(/hidden x/)); + await navigate(screen.getByRole('link', { name: /load two/i })); + expect(screen.queryByRole('heading', { name: /Detail two/i })).toBeInTheDocument(); + await navigate(screen.getByRole('link', { name: /hidden x/i })); expect(screen.queryByText(/You found the treasure!/i)).toBeInTheDocument(); }); @@ -61,21 +61,22 @@ test('it can navigate to routes with a base path', async () => { ], }); - expect(screen.queryByText(/Detail one/i)).not.toBeInTheDocument(); + expect(screen.queryByRole('heading', { name: /Detail one/i })).not.toBeInTheDocument(); - await navigate(screen.getByText(/Load one/), basePath); - expect(screen.queryByText(/Detail one/i)).toBeInTheDocument(); + await navigate(screen.getByRole('link', { name: /load one/i }), basePath); + expect(screen.queryByRole('heading', { name: /Detail one/i })).toBeInTheDocument(); - await navigate(screen.getByText(/Load three/), basePath); - expect(screen.queryByText(/Detail one/i)).not.toBeInTheDocument(); - expect(screen.queryByText(/Detail three/i)).toBeInTheDocument(); + await navigate(screen.getByRole('link', { name: /load three/i }), basePath); + expect(screen.queryByRole('heading', { name: /Detail one/i })).not.toBeInTheDocument(); + expect(screen.queryByRole('heading', { name: /Detail three/i })).toBeInTheDocument(); - await navigate(screen.getByText(/Back to parent/)); - expect(screen.queryByText(/Detail three/i)).not.toBeInTheDocument(); + await navigate(screen.getByRole('link', { name: /back to parent/i })); + expect(screen.queryByRole('heading', { name: /Detail three/i })).not.toBeInTheDocument(); - await navigate('base/detail/two?text=Hello&subtext=World'); // possible to just use strings - expect(screen.queryByText(/Detail two/i)).toBeInTheDocument(); - expect(screen.queryByText(/Hello World/i)).toBeInTheDocument(); + // It's possible to just use strings + await navigate('base/detail/two?text=Hello&subtext=World'); + expect(screen.queryByRole('heading', { name: /Detail two/i })).toBeInTheDocument(); + expect(screen.getByText(/Hello World/i)).toBeInTheDocument(); await navigate('/hidden-detail', basePath); expect(screen.queryByText(/You found the treasure!/i)).toBeInTheDocument(); diff --git a/src/app/examples/11-ng-content.spec.ts b/src/app/examples/11-ng-content.spec.ts index 85f2a49f..14a1630c 100644 --- a/src/app/examples/11-ng-content.spec.ts +++ b/src/app/examples/11-ng-content.spec.ts @@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/angular'; import { CellComponent } from './11-ng-content'; -test('it is posible to test ng-content without selector', async () => { +test('it is possible to test ng-content without selector', async () => { const projection = 'it should be showed into a p element!'; TestBed.overrideComponent(CellComponent, { set: { selector: 'cell' } });