diff --git a/.all-contributorsrc b/.all-contributorsrc index 59753c6c8..9bc2e912d 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -2472,7 +2472,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/11414958?v=4", "profile": "https://github.com/StephNathai", "contributions": [ - "code" + "code", + "a11y" ] }, { @@ -2555,6 +2556,250 @@ "contributions": [ "doc" ] + }, + { + "login": "JoyelJohny", + "name": "Joyel Johny", + "avatar_url": "https://avatars.githubusercontent.com/u/81413791?v=4", + "profile": "https://github.com/JoyelJohny", + "contributions": [ + "code" + ] + }, + { + "login": "bsheps", + "name": "bsheps", + "avatar_url": "https://avatars.githubusercontent.com/u/35780702?v=4", + "profile": "https://github.com/bsheps", + "contributions": [ + "doc" + ] + }, + { + "login": "kyle-n", + "name": "Kyle Nazario", + "avatar_url": "https://avatars.githubusercontent.com/u/13384477?v=4", + "profile": "http://www.kylenazario.com/", + "contributions": [ + "doc" + ] + }, + { + "login": "thefalked", + "name": "Giuliano Crivelli", + "avatar_url": "https://avatars.githubusercontent.com/u/28029756?v=4", + "profile": "https://github.com/thefalked", + "contributions": [ + "doc" + ] + }, + { + "login": "mroforolhc", + "name": "mrkv", + "avatar_url": "https://avatars.githubusercontent.com/u/26799398?v=4", + "profile": "https://t.me/markov_ka", + "contributions": [ + "doc" + ] + }, + { + "login": "smk267", + "name": "smk267", + "avatar_url": "https://avatars.githubusercontent.com/u/88115182?v=4", + "profile": "https://github.com/smk267", + "contributions": [ + "infra" + ] + }, + { + "login": "agentdylan", + "name": "Dylan Gordon", + "avatar_url": "https://avatars.githubusercontent.com/u/3656794?v=4", + "profile": "https://www.dylangordon.co.nz/", + "contributions": [ + "doc" + ] + }, + { + "login": "mcous", + "name": "Michael Cousins", + "avatar_url": "https://avatars.githubusercontent.com/u/2963448?v=4", + "profile": "https://michael.cousins.io/", + "contributions": [ + "doc", + "review" + ] + }, + { + "login": "kettanaito", + "name": "Artem Zakharchenko", + "avatar_url": "https://avatars.githubusercontent.com/u/14984911?v=4", + "profile": "https://kettanaito.com/", + "contributions": [ + "doc" + ] + }, + { + "login": "vadimshvetsov", + "name": "Vadim Shvetsov", + "avatar_url": "https://avatars.githubusercontent.com/u/16336572?v=4", + "profile": "https://github.com/vadimshvetsov", + "contributions": [ + "doc" + ] + }, + { + "login": "domnantas", + "name": "Domantas Petrauskas", + "avatar_url": "https://avatars.githubusercontent.com/u/51953549?v=4", + "profile": "https://domnantas.lt/", + "contributions": [ + "doc" + ] + }, + { + "login": "Efim-Kapliy", + "name": "Efim", + "avatar_url": "https://avatars.githubusercontent.com/u/126895483?v=4", + "profile": "https://portfolio.edkt.ru/", + "contributions": [ + "doc" + ] + }, + { + "login": "denisx", + "name": "denisx", + "avatar_url": "https://avatars.githubusercontent.com/u/427776?v=4", + "profile": "https://github.com/denisx", + "contributions": [ + "code" + ] + }, + { + "login": "ggualiato", + "name": "Giovanni Gualiato", + "avatar_url": "https://avatars.githubusercontent.com/u/26698704?v=4", + "profile": "https://github.com/ggualiato", + "contributions": [ + "doc" + ] + }, + { + "login": "saubaig456", + "name": "Saud Baig", + "avatar_url": "https://avatars.githubusercontent.com/u/143418574?v=4", + "profile": "https://github.com/saubaig456", + "contributions": [ + "doc" + ] + }, + { + "login": "moeyashi", + "name": "Ren Adachi", + "avatar_url": "https://avatars.githubusercontent.com/u/49895682?v=4", + "profile": "https://github.com/moeyashi", + "contributions": [ + "doc" + ] + }, + { + "login": "TyMick", + "name": "Ty Mick", + "avatar_url": "https://avatars.githubusercontent.com/u/5317080?v=4", + "profile": "https://tymick.me/", + "contributions": [ + "doc" + ] + }, + { + "login": "enmanuelduran", + "name": "Enmanuel Durán", + "avatar_url": "https://avatars.githubusercontent.com/u/8060530?v=4", + "profile": "https://enmascript.com/", + "contributions": [ + "doc" + ] + }, + { + "login": "gbhasha", + "name": "Galeel Bhasha Satthar", + "avatar_url": "https://avatars.githubusercontent.com/u/501794?v=4", + "profile": "https://github.com/gbhasha", + "contributions": [ + "doc" + ] + }, + { + "login": "ianlet", + "name": "Ian Létourneau", + "avatar_url": "https://avatars.githubusercontent.com/u/6018732?v=4", + "profile": "https://noma.to/", + "contributions": [ + "doc" + ] + }, + { + "login": "brianlu2610", + "name": "brianlu2610", + "avatar_url": "https://avatars.githubusercontent.com/u/68666483?v=4", + "profile": "https://github.com/brianlu2610", + "contributions": [ + "code" + ] + }, + { + "login": "ezzatron", + "name": "Erin", + "avatar_url": "https://avatars.githubusercontent.com/u/100152?v=4", + "profile": "https://github.com/ezzatron", + "contributions": [ + "doc" + ] + }, + { + "login": "nchen000", + "name": "Nan Chen", + "avatar_url": "https://avatars.githubusercontent.com/u/23487984?v=4", + "profile": "https://www.linkedin.com/in/nan-chen-000/", + "contributions": [ + "doc" + ] + }, + { + "login": "aburdiss", + "name": "Alexander Burdiss", + "avatar_url": "https://avatars.githubusercontent.com/u/31200600?v=4", + "profile": "http://alexanderburdiss.com/", + "contributions": [ + "doc" + ] + }, + { + "login": "peterh-capella", + "name": "Peter Hentges", + "avatar_url": "https://avatars.githubusercontent.com/u/1122723?v=4", + "profile": "https://github.com/peterh-capella", + "contributions": [ + "doc" + ] + }, + { + "login": "neknalb", + "name": "neknalb", + "avatar_url": "https://avatars.githubusercontent.com/u/23031302?v=4", + "profile": "https://github.com/neknalb", + "contributions": [ + "doc" + ] + }, + { + "login": "fetsorn", + "name": "fetsorn", + "avatar_url": "https://avatars.githubusercontent.com/u/12858105?v=4", + "profile": "https://github.com/fetsorn", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index a2945dc9d..4ffd940f5 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Documentation site for [React Testing Library](https://github.com/testing-library/react-testing-library), [DOM Testing Library](https://github.com/testing-library/dom-testing-library), +[Angular Testing Library](https://github.com/testing-library/angular-testing-library), and [related projects](https://github.com/testing-library) **https://testing-library.com** @@ -20,7 +21,7 @@ and [related projects](https://github.com/testing-library) https://api.netlify.com/api/v1/badges/24366204-84ca-41e9-b573-2a64f0845e46/deploy-status [build]: https://app.netlify.com/sites/testing-library/deploys [allcontributors-badge]: - https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square + https://img.shields.io/github/all-contributors/testing-library/testing-library-docs?color=ee8449&style=flat-square [coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square [coc]: @@ -484,7 +485,7 @@ Thanks goes to these wonderful people Milan Jaritz
Milan Jaritz

📖 Rokas Brazdžionis
Rokas Brazdžionis

📖 Laforge Thomas
Laforge Thomas

📖 - Steph Nathai
Steph Nathai

💻 + Steph Nathai
Steph Nathai

💻 ️️️️♿️ Frieder Bluemle
Frieder Bluemle

📖 @@ -498,6 +499,41 @@ Thanks goes to these wonderful people Andreas Nordahl
Andreas Nordahl

📖 neaumusic
neaumusic

📖 + Joyel Johny
Joyel Johny

💻 + bsheps
bsheps

📖 + Kyle Nazario
Kyle Nazario

📖 + Giuliano Crivelli
Giuliano Crivelli

📖 + mrkv
mrkv

📖 + + + smk267
smk267

🚇 + Dylan Gordon
Dylan Gordon

📖 + Michael Cousins
Michael Cousins

📖 👀 + Artem Zakharchenko
Artem Zakharchenko

📖 + Vadim Shvetsov
Vadim Shvetsov

📖 + Domantas Petrauskas
Domantas Petrauskas

📖 + Efim
Efim

📖 + + + denisx
denisx

💻 + Giovanni Gualiato
Giovanni Gualiato

📖 + Saud Baig
Saud Baig

📖 + Ren Adachi
Ren Adachi

📖 + Ty Mick
Ty Mick

📖 + Enmanuel Durán
Enmanuel Durán

📖 + Galeel Bhasha Satthar
Galeel Bhasha Satthar

📖 + + + Ian Létourneau
Ian Létourneau

📖 + brianlu2610
brianlu2610

💻 + Erin
Erin

📖 + Nan Chen
Nan Chen

📖 + Alexander Burdiss
Alexander Burdiss

📖 + Peter Hentges
Peter Hentges

📖 + neknalb
neknalb

📖 + + + fetsorn
fetsorn

📖 diff --git a/docs/angular-testing-library/api.mdx b/docs/angular-testing-library/api.mdx index de6b61298..08daa3359 100644 --- a/docs/angular-testing-library/api.mdx +++ b/docs/angular-testing-library/api.mdx @@ -38,7 +38,8 @@ await render(AppComponent) Instead of passing the component's type as first argument, you can also provide a template. This practice is required to render directives but can also be applied to components, it might even be more useful. The directive's (or -component's) type must then be added to the `declarations`. +component's) type must then be added to the `imports` (or `declarations` in case +of non-standalone components). **example with directive**: @@ -76,77 +77,100 @@ export async function render( ## Component RenderOptions -### `componentInputs` -An object to set `@Input` properties of the component. Uses `setInput` to set -the input property. Throws if the component property is not annotated with the -`@Input` attribute. +### `inputs` -**default** : `{}` +An object to set `@Input` or `input()` properties of the component. -**example**: +**default** : `{}` ```typescript await render(AppComponent, { - componentInputs: { + inputs: { counterValue: 10, + // explicitly define aliases using `aliasedInput` + ...aliasedInput('someAlias', 'someValue'), }, }) ``` -### `componentOutputs` +### `on` -An object to set `@Output` properties of the component. +An object with callbacks to subscribe to `EventEmitters` and `Observables` of +the component. **default** : `{}` -**example**: +```ts +// using a manual callback +const sendValue = (value) => { ... } +await render(AppComponent, { + on: { + send: (value) => sendValue(value), + } +}) + +// using a (jest) spy +const sendValueSpy = jest.fn() -```typescript await render(AppComponent, { - componentOutputs: { - clicked: (value) => { ... } + on: { + send: sendValueSpy } }) ``` -### `componentProperties` +### `declarations` -An object to set `@Input` and `@Output` properties of the component. Doesn't -have a fine-grained control as `componentInputs` and `componentOutputs`. +A collection of components, directives and pipes needed to render the component. +For example, nested components of the component. -**default** : `{}` +For more info see the +[Angular docs](https://angular.dev/guide/ngmodules/overview#declarations). + +**default** : `[]` **example**: ```typescript await render(AppComponent, { - componentProperties: { - // an input - counterValue: 10, - // an output - send: (value) => { ... } - // a public property - name: 'Tim' - } + declarations: [CustomerDetailComponent, ButtonComponent], }) ``` -### `declarations` +### `deferBlockBehavior` -A collection of components, directives and pipes needed to render the component. -For example, nested components of the component. +Set the defer blocks behavior. For more info see the -[Angular docs](https://angular.io/api/core/NgModule#declarations). +[Angular docs](https://angular.dev/api/core/testing/DeferBlockBehavior) -**default** : `[]` +**default** : `undefined` (uses `DeferBlockBehavior.Manual`, which is different +from the Angular default of `DeferBlockBehavior.Playthrough`) **example**: ```typescript await render(AppComponent, { - declarations: [CustomerDetailComponent, ButtonComponent], + deferBlockBehavior: DeferBlockBehavior.Playthrough, +}) +``` + +### `deferBlockStates` + +Set the initial state of a deferrable blocks in a component. + +For more info see the +[Angular docs](https://angular.dev/api/core/testing/DeferBlockState) + +**default** : `undefined` (uses the Angular default, which is +`DeferBlockState.Placeholder`) + +**example**: + +```typescript +await render(FixtureComponent, { + deferBlockStates: DeferBlockState.Loading, }) ``` @@ -159,7 +183,7 @@ These will be provided at the component level. To inject dependencies at the module level, use [`providers`](#providers). For more info see the -[Angular docs](https://angular.io/api/core/Directive#providers). +[Angular docs](https://angular.dev/guide/di/hierarchical-dependency-injection#example-providing-services-in-component). **default** : `[]` @@ -255,7 +279,7 @@ modules. Adds `NoopAnimationsModule` by default if `BrowserAnimationsModule` isn't added to the collection For more info see the -[Angular docs](https://angular.io/api/core/NgModule#imports). +[Angular docs](https://angular.dev/guide/components#imports-in-the-component-decorator). **default** : `[NoopAnimationsModule]` @@ -276,7 +300,7 @@ These will be provided at the module level. To inject dependencies at the component level, use [`componentProviders`](#componentProviders). For more info see the -[Angular docs](https://angular.io/api/core/NgModule#providers). +[Angular docs](https://angular.dev/guide/di/dependency-injection-providers#). **default** : `[]` @@ -313,7 +337,7 @@ await render(AppComponent, { The route configuration to set up the router service via `RouterTestingModule.withRoutes`. For more info see the -[Angular Routes docs](https://angular.io/api/router/Routes). +[Angular Routes docs](https://angular.dev/api/router/Routes). **default** : `[]` @@ -342,7 +366,7 @@ A collection of schemas needed to render the component. Allowed values are `NO_ERRORS_SCHEMA` and `CUSTOM_ELEMENTS_SCHEMA`. For more info see the -[Angular docs](https://angular.io/api/core/NgModule#schemas). +[Angular docs](https://angular.dev/guide/components/advanced-configuration#custom-element-schemas). **default** : `[]` @@ -368,6 +392,64 @@ await render(AppComponent, { }) ``` + +### ~~`componentInputs`~~ (deprecated) + +An object to set `@Input` properties of the component. Uses `setInput` to set +the input property. Throws if the component property is not annotated with the +`@Input` attribute. + +**default** : `{}` + +**example**: + +```typescript +await render(AppComponent, { + componentInputs: { + counterValue: 10, + }, +}) +``` + +### ~~`componentOutputs`~~ (deprecated) + +An object to set `@Output` properties of the component. + +**default** : `{}` + +**example**: + +```typescript +await render(AppComponent, { + componentOutputs: { + clicked: (value) => { ... } + } +}) +``` + +### ~~`componentProperties`~~ (deprecated) + +An object to set `@Input` and `@Output` properties of the component. Doesn't +have a fine-grained control as `inputs` and `on`. + +**default** : `{}` + +**example**: + +```typescript +await render(AppComponent, { + componentProperties: { + // an input + counterValue: 10, + // an output + send: (value) => { ... } + // a public property + name: 'Tim' + } +}) +``` + + ## `RenderResult` ### `container` @@ -395,39 +477,60 @@ properties that are not defined are cleared. ```typescript const {rerender} = await render(Counter, { - componentProperties: {count: 4, name: 'Sarah'}, + inputs: {count: 4, name: 'Sarah'}, }) expect(screen.getByTestId('count-value').textContent).toBe('4') expect(screen.getByTestId('name-value').textContent).toBe('Sarah') -await rerender({componentProperties: {count: 7}}) +await rerender({ + inputs: {count: 7} +}) -// count updated to 7 +// count is updated to 7 expect(screen.getByTestId('count-value').textContent).toBe('7') // name is undefined because it's not provided in rerender expect(screen.getByTestId('name-value').textContent).toBeUndefined() ``` +Using `partialUpdate`, only the newly provided properties will be updated. Other +input properties that aren't provided won't be cleared. + +```typescript +const {rerender} = await render(Counter, { + inputs: {count: 4, name: 'Sarah'}, +}) + +expect(screen.getByTestId('count-value').textContent).toBe('4') +expect(screen.getByTestId('name-value').textContent).toBe('Sarah') + +await rerender({inputs: {count: 7}, partialUpdate: true}) + +// count is updated to 7 +expect(screen.getByTestId('count-value').textContent).toBe('7') +// name is still rendered as "Sarah" because of the partial update +expect(screen.getByTestId('name-value').textContent).toBe('Sarah') +``` + ### `detectChanges` Trigger a change detection cycle for the component. For more info see the -[Angular docs](https://angular.io/api/core/testing/ComponentFixture#detectChanges). +[Angular docs](https://angular.dev/api/core/testing/ComponentFixture#detectChanges). ### `debugElement` The Angular `DebugElement` of the component. -For more info see the [Angular docs](https://angular.io/api/core/DebugElement). +For more info see the [Angular docs](https://angular.dev/api/core/DebugElement). ### `fixture` The Angular `ComponentFixture` of the component. For more info see the -[Angular docs](https://angular.io/api/core/testing/ComponentFixture). +[Angular docs](https://angular.dev/api/core/testing/ComponentFixture). ```typescript const {fixture} = await render(AppComponent) @@ -473,3 +576,22 @@ screen.getByRole('heading', { }) queryByLabelText(/First name/i') ``` + +### `renderDeferBlock` + +To test [Deferrable views](https://angular.dev/guide/defer#defer), you can make +use of `renderDeferBlock`. `renderDeferBlock` will set the desired defer state +for a specific deferrable block. The default value of a deferrable view is +`Placeholder`, but you can also set the initial state while rendering the +component. + +```typescript +const {renderDeferBlock} = await render(FixtureComponent, { + deferBlockStates: DeferBlockState.Loading, +}) + +expect(screen.getByText(/loading/i)).toBeInTheDocument() + +await renderDeferBlock(DeferBlockState.Complete) +expect(screen.getByText(/completed/i)).toBeInTheDocument() +``` diff --git a/docs/angular-testing-library/examples.mdx b/docs/angular-testing-library/examples.mdx index b24098ecd..2e44b893c 100644 --- a/docs/angular-testing-library/examples.mdx +++ b/docs/angular-testing-library/examples.mdx @@ -1,6 +1,6 @@ --- id: examples -title: Examples +title: Example --- > Read about @@ -8,124 +8,75 @@ title: Examples > or follow the > [guided example](https://timdeschryver.dev/blog/getting-the-most-value-out-of-your-angular-component-tests) -```ts title="counter.component.ts" -@Component({ - selector: 'counter', - template: ` - - Current Count: {{ counter }} - - `, -}) -export class CounterComponent { - @Input() counter = 0 - - increment() { - this.counter += 1 - } - - decrement() { - this.counter -= 1 - } -} -``` - -```ts title="counter.component.spec.ts" -import {render, screen, fireEvent} from '@testing-library/angular' -import {CounterComponent} from './counter.component.ts' - -describe('Counter', () => { - test('should render counter', async () => { - await render(CounterComponent, { - componentProperties: {counter: 5}, - }) - - expect(screen.getByText('Current Count: 5')).toBeInTheDocument() - }) - - test('should increment the counter on click', async () => { - await render(CounterComponent, { - componentProperties: {counter: 5}, - }) - - fireEvent.click(screen.getByText('+')) - - expect(screen.getByText('Current Count: 6')).toBeInTheDocument() - }) -}) -``` - -## With Standalone Components - -Angular Testing Library can also test your standalone components. -In fact, it even becomes easier because you don't have to set up the whole Angular TestBed. -This was previously only [possible when you used Single Component Angular Modules (SCAMs)](https://timdeschryver.dev/blog/single-component-angular-modules-and-component-tests-go-hand-in-hand). - -Let's migrate the counter component to a standalone component, and let's take a look at how this affects the test. +Angular Testing Library can be used with standalone components and also with Angular components that uses Modules. +The example below shows how to test a standalone component, but the same principles apply to Angular components that uses Modules. +In fact, there should be no difference in how you test both types of components, only the setup might be different. ```ts title="counter.component.ts" @Component({ - selector: 'counter', + selector: 'app-counter', template: ` + {{ hello() }} - Current Count: {{ counter }} + Current Count: {{ counter() }} `, - standalone: true, }) export class CounterComponent { - @Input() counter = 0 + counter = model(0); + hello = input('Hi', { alias: 'greeting' }); increment() { - this.counter += 1 + this.counter.set(this.counter() + 1); } decrement() { - this.counter -= 1 + this.counter.set(this.counter() - 1); } } ``` -Just as you would've expected, this doesn't affect the test cases. -Writing tests for standalone components remains the same as for "regular" components. - -```ts title="counter.component.spec.ts" -import {render, screen, fireEvent} from '@testing-library/angular' -import {CounterComponent} from './counter.component.ts' +```typescript title="counter.component.spec.ts" +import { render, screen, fireEvent, aliasedInput } from '@testing-library/angular'; +import { CounterComponent } from './counter.component'; describe('Counter', () => { - test('should render counter', async () => { - await render(CounterComponent, { - componentProperties: {counter: 5}, - }) - - expect(screen.getByText('Current Count: 5')).toBeInTheDocument() - }) - - test('should increment the counter on click', async () => { + it('should render counter', async () => { await render(CounterComponent, { - componentProperties: {counter: 5}, - }) - - fireEvent.click(screen.getByText('+')) - - expect(screen.getByText('Current Count: 6')).toBeInTheDocument() - }) -}) + inputs: { + counter: 5, + // aliases need to be specified using aliasedInput + ...aliasedInput('greeting', 'Hello Alias!'), + }, + }); + + expect(screen.getByText('Current Count: 5')).toBeVisible(); + expect(screen.getByText('Hello Alias!')).toBeVisible(); + }); + + it('should increment the counter on click', async () => { + await render(CounterComponent, { inputs: { counter: 5 } }); + + const incrementButton = screen.getByRole('button', { name: '+' }); + fireEvent.click(incrementButton); + + expect(screen.getByText('Current Count: 6')).toBeVisible(); + }); +}); ``` -To override an import of a standalone component for your component test, you can use the [`componentImports` property](api.mdx#componentImports). - ## More examples More examples can be found in the [GitHub project](https://github.com/testing-library/angular-testing-library/tree/master/apps/example-app/src/app/examples). These examples include: -- `@Input` and `@Output` properties +- `input` and `output` properties - Forms -- Integration with services -- And [more](https://github.com/testing-library/angular-testing-library/tree/master/apps/example-app/src/app/examples) +- Integration injected services +- And + [more](https://github.com/testing-library/angular-testing-library/tree/master/apps/example-app/src/app/examples) If you're looking for an example that isn't on the list, please feel free to -create a [new issue](https://github.com/testing-library/angular-testing-library/issues/new). +create a +[new issue](https://github.com/testing-library/angular-testing-library/issues/new). diff --git a/docs/angular-testing-library/faq.mdx b/docs/angular-testing-library/faq.mdx index b758c270c..e333db4b3 100644 --- a/docs/angular-testing-library/faq.mdx +++ b/docs/angular-testing-library/faq.mdx @@ -31,7 +31,8 @@ As you write your tests, keep in mind: In general, you should avoid mocking out components (see [the Guiding Principles section](guiding-principles.mdx)). However, if you need -to, then try to use [ng-mocks](https://ng-mocks.sudo.eu/) and its [`MockBuilder`](https://ng-mocks.sudo.eu/extra/with-3rd-party#testing-libraryangular-and-mockbuilder). +to, then try to use [ng-mocks](https://ng-mocks.sudo.eu/) and its +[`MockBuilder`](https://ng-mocks.sudo.eu/extra/with-3rd-party#testing-libraryangular-and-mockbuilder). ```typescript import {Component, NgModule} from '@angular/core' @@ -58,7 +59,7 @@ export class AppModule {} describe('ParentComponent', () => { it('should not render ChildComponent when shallow rendering', async () => { // all imports, declarations and exports of AppModule will be mocked. - const dependencies = MockBuilder(ParentComponent, AppModule).build(); + const dependencies = MockBuilder(ParentComponent, AppModule).build() await render(ParentComponent, dependencies) diff --git a/docs/angular-testing-library/intro.mdx b/docs/angular-testing-library/intro.mdx index 421ebf013..a7820b7f0 100644 --- a/docs/angular-testing-library/intro.mdx +++ b/docs/angular-testing-library/intro.mdx @@ -8,9 +8,17 @@ sidebar_label: Introduction builds on top of [`DOM Testing Library`](https://github.com/testing-library/dom-testing-library) by adding APIs for working with Angular components. +Starting from ATL version 17, you also need to install `@testing-library/dom`: ```bash npm2yarn -npm install --save-dev @testing-library/angular +npm install --save-dev @testing-library/angular @testing-library/dom +``` + +Or, you can use the `ng add` command. +This sets up your project to use Angular Testing Library, which also includes the installation of `@testing-library/dom`. + +```bash +ng add @testing-library/angular ``` - [`@testing-library/angular-testing-library` on GitHub](https://github.com/testing-library/angular-testing-library) diff --git a/docs/angular-testing-library/version-compatibility.mdx b/docs/angular-testing-library/version-compatibility.mdx index 18a72b301..3b64dd5d2 100644 --- a/docs/angular-testing-library/version-compatibility.mdx +++ b/docs/angular-testing-library/version-compatibility.mdx @@ -3,12 +3,16 @@ id: version-compatibility title: Version compatibility --- -An overview of the compatibility between different versions of Angular Testing Library and Angular. - -| Angular | Angular Testing Library | -| ------- | ----------------------- | -| 16.x | 13.x \|\| 14.x | -| >= 15.1 | 13.x \|\| 14.x | -| < 15.1 | 11.x \|\| 12.x | -| 14.x | 11.x \|\| 12.x | +An overview of the compatibility between different versions of Angular Testing +Library and Angular. +| Angular | Angular Testing Library | +| ------- | ---------------------------------- | +| 20.x | 18.x | +| 19.x | 18.x, 17.x, 16.x, 15.x, 14.x, 13.x | +| 18.x | 17.x, 16.x, 15.x, 14.x, 13.x | +| 17.x | 17.x, 16.x, 15.x, 14.x, 13.x | +| 16.x | 14.x, 13.x | +| >= 15.1 | 14.x, 13.x | +| < 15.1 | 12.x, 11.x | +| 14.x | 12.x, 11.x | diff --git a/docs/bs-react-testing-library/examples.mdx b/docs/bs-react-testing-library/examples.mdx index 0fe68d08a..08e96a7c9 100644 --- a/docs/bs-react-testing-library/examples.mdx +++ b/docs/bs-react-testing-library/examples.mdx @@ -1,6 +1,6 @@ --- id: examples -title: Examples +title: Example --- You can find more bs-dom-testing-library examples at diff --git a/docs/bs-react-testing-library/intro.mdx b/docs/bs-react-testing-library/intro.mdx index fec630605..316ccc9b2 100644 --- a/docs/bs-react-testing-library/intro.mdx +++ b/docs/bs-react-testing-library/intro.mdx @@ -15,6 +15,9 @@ Bindings for several testing libraries have been ported to [ReasonML][re]. ```bash npm2yarn npm install --save-dev bs-dom-testing-library +``` + +```bash npm2yarn npm install --save-dev bs-react-testing-library ``` diff --git a/docs/cypress-testing-library/intro.mdx b/docs/cypress-testing-library/intro.mdx index 8121a5be4..3c88d4d2b 100644 --- a/docs/cypress-testing-library/intro.mdx +++ b/docs/cypress-testing-library/intro.mdx @@ -22,8 +22,7 @@ Add this line to your project's `cypress/support/commands.js`: import '@testing-library/cypress/add-commands' ``` -You can now use all of `DOM Testing Library`'s `findBy`, `findAllBy`, `queryBy` -and `queryAllBy` commands off the global `cy` object. +You can now use some of `DOM Testing Library`'s `findBy`, and `findAllBy` commands off the global `cy` object. [See the `About queries` docs for reference](/docs/queries/about). > Note: the `get*` queries are not supported because for reasonable Cypress diff --git a/docs/dom-testing-library/api-configuration.mdx b/docs/dom-testing-library/api-configuration.mdx index d1dd72ca4..72dd2e196 100644 --- a/docs/dom-testing-library/api-configuration.mdx +++ b/docs/dom-testing-library/api-configuration.mdx @@ -90,14 +90,15 @@ second argument. If you're using testing-library in a browser you almost always want to set this to `true`. Only very old browser don't support this property (such as IE 8 and earlier). However, `jsdom` does not support the second argument currently. This includes versions of `jsdom` prior to `16.4.0` and any -version that logs a `not implemented` warning when calling `getComputedStyle` +version that logs a `not implemented` warning when calling +[`getComputedStyle`](https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle) with a second argument e.g. `window.getComputedStyle(document.createElement('div'), '::after')`. Defaults to `false` ### `defaultHidden` -The default value for the `hidden` option used by +The default value for the [`hidden` option](queries/byrole#hidden) used by [`getByRole`](queries/byrole.mdx). Defaults to `false`. ### `defaultIgnore` @@ -110,12 +111,12 @@ Defaults to `script, style`. ### `showOriginalStackTrace` -By default, `waitFor` will ensure that the stack trace for errors thrown by -Testing Library is cleaned up and shortened so it's easier for you to identify -the part of your code that resulted in the error (async stack traces are hard to -debug). If you want to disable this, then set`showOriginalStackTrace` to -`false`. You can also disable this for a specific call in the options you pass -to `waitFor`. +By default, [`waitFor`](api-async#waitfor) will ensure that the stack trace for +errors thrown by Testing Library is cleaned up and shortened so it's easier for +you to identify the part of your code that resulted in the error (async stack +traces are hard to debug). If you want to disable this, then +set`showOriginalStackTrace` to `false`. You can also disable this for a specific +call in the options you pass to `waitFor`. ### `throwSuggestions` (experimental) @@ -130,6 +131,35 @@ option. screen.getByTestId('foo', {suggest: false}) // will not throw a suggestion ``` +:::note + +When this option is enabled, it may provide suggestions that lack an intuitive +implementation. Typically this happens for +[roles which cannot be named](https://w3c.github.io/aria/#namefromprohibited), +most notably paragraphs. For instance, if you attempt to use +[`getByText`](queries/bytext.mdx), you may encounter the following error: + +``` +TestingLibraryElementError: A better query is available, try this: + getByRole('paragraph') +``` + +However, there is no direct way to query paragraphs using the config object +parameter, such as in `getByRole('paragraph', { name: 'Hello World' })`. + +To address this issue, you can leverage a custom function to validate the +element's structure, as shown in the example below. More information can be +found in the +[GitHub issue](https://github.com/testing-library/dom-testing-library/issues/1306) + +```js +getByRole('paragraph', { + name: (_, element) => element.textContent === 'Hello world', +}) +``` + +::: + ### `testIdAttribute` The attribute used by [`getByTestId`](queries/bytestid.mdx) and related queries. @@ -143,5 +173,5 @@ message and container object as arguments. ### `asyncUtilTimeout` -The global timeout value in milliseconds used by `waitFor` utilities. Defaults -to 1000ms. +The global timeout value in milliseconds used by [`waitFor`](api-async#waitfor) +utilities. Defaults to 1000ms. diff --git a/docs/dom-testing-library/api-custom-queries.mdx b/docs/dom-testing-library/api-custom-queries.mdx index 452f518f7..8147ead50 100644 --- a/docs/dom-testing-library/api-custom-queries.mdx +++ b/docs/dom-testing-library/api-custom-queries.mdx @@ -3,9 +3,6 @@ id: api-custom-queries title: Custom Queries --- -import Tabs from '@theme/Tabs' -import TabItem from '@theme/TabItem' - `DOM Testing Library` exposes many of the helper functions that are used to implement the default queries. You can use the helpers to build custom queries. For example, the code below shows a way to override the default `testId` queries diff --git a/docs/dom-testing-library/api-debugging.mdx b/docs/dom-testing-library/api-debugging.mdx index 514a930bc..492542440 100644 --- a/docs/dom-testing-library/api-debugging.mdx +++ b/docs/dom-testing-library/api-debugging.mdx @@ -32,7 +32,7 @@ value is `7000`. You will see `...` in the console, when the DOM content is stripped off, because of the length you have set or due to default size limit. Here's how you might increase this limit when running tests: -``` +```bash npm2yarn DEBUG_PRINT_LIMIT=10000 npm test ``` @@ -42,11 +42,11 @@ you'd like a solution that works for both, see **Note**: The output of the DOM is colorized by default if your tests are running in a node environment. However, you may sometimes want to turn off -colors, such as in cases where the output is written to a log file for -debugging purposes. You can use the environment variable `COLORS` to explicitly -force the colorization off or on. For example: +colors, such as in cases where the output is written to a log file for debugging +purposes. You can use the environment variable `COLORS` to explicitly force the +colorization off or on. For example: -``` +```bash npm2yarn COLORS=false npm test ``` @@ -57,7 +57,7 @@ you'd like a solution that works for both, see ## `prettyDOM` Built on top of -[`pretty-format`](https://github.com/facebook/jest/tree/master/packages/pretty-format), +[`pretty-format`](https://github.com/jestjs/jest/tree/main/packages/pretty-format), this helper function can be used to print out readable representation of the DOM tree of a node. This can be helpful for instance when debugging tests. @@ -79,7 +79,7 @@ It receives the root node to print out, an optional extra parameter to limit the size of the resulting string, for cases when it becomes too large. It has a last parameter which allows you to configure your formatting. In addition to the options listed you can also pass the -[options](https://github.com/facebook/jest/tree/master/packages/pretty-format#usage-with-options) +[options](https://github.com/jestjs/jest/tree/main/packages/pretty-format#usage-with-options) of `pretty-format`. By default, `