From c1ccbe87cd30628977f2ffa58ce0864f31ee7175 Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Thu, 20 Jan 2022 21:38:22 +0100 Subject: [PATCH] docs(angular): Update docs to reflect v11 of ATL --- docs/angular-testing-library/api.mdx | 141 ++++++++++++++-------- docs/angular-testing-library/examples.mdx | 14 ++- 2 files changed, 99 insertions(+), 56 deletions(-) diff --git a/docs/angular-testing-library/api.mdx b/docs/angular-testing-library/api.mdx index d3f6565bb..e30c42729 100644 --- a/docs/angular-testing-library/api.mdx +++ b/docs/angular-testing-library/api.mdx @@ -5,12 +5,9 @@ sidebar_label: API --- `Angular Testing Library` re-exports everything from `DOM Testing Library` as -well as these methods: +well as the `render` method. -- [`render`](#render) - -Some of the `DOM Testing Library` re-exports are patched to work easier with -Angular: +The following re-exports are patched to make them easier to use with Angular: - The events on `fireEvent` automatically invoke a change detection cycle after the event has been fired @@ -21,15 +18,61 @@ Angular: ## `render` +With Angular Testing Library, the component can be rendered in two ways, via the +component's type or with a template. + +> By default, `render` also imports the `NoopAnimationsModule`. + +## `Type` + +To render a component, you need to pass component's type to the `render` method. +For components that don't use other parts of your application (for example +design modules or services), rendering a component can be as simple as the +following example. + +```typescript +await render(AppComponent) +``` + +## `template` + +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`. + +**example with directive**: + +```typescript +await render('
', { + declarations: [SpoilerDirective], +}) +``` + +**example with component**: + +```typescript +await render( + '', + { + declarations: [AppComponent], + componentProperties: { + anotherValue: 'valueOfAnotherProperty', + sendValue: jest.fn(), + }, + }, +) +``` + ```typescript -async function render( +export async function render( component: Type, renderOptions?: RenderComponentOptions, ): Promise> -async function render( - component: Type, - renderOptions?: RenderDirectiveOptions, -): Promise> +export async function render( + template: string, + renderOptions?: RenderTemplateOptions, +): Promise> ``` ## Component RenderOptions @@ -105,7 +148,8 @@ await render(AppComponent, {detectChanges: false}) ### `excludeComponentDeclaration` Exclude the component to be automatically be added as a declaration. This is -needed when the component is declared in an imported module. +needed when the component is declared in an imported module, for example with +SCAMs. **default** : `false` @@ -238,39 +282,6 @@ await render(AppComponent, { }) ``` -## Directive RenderOptions - -To test a directive, the render API is a bit different. The API has the same -options as the Component RenderOptions, but has more options: - -### `template` - -The template to render the directive. - -**example**: - -```typescript -await render(SpoilerDirective, { - template: `
`, -}) -``` - -### `wrapper` - -An Angular component to wrap the directive in. - -**default**: `WrapperComponent` , an empty component that strips the -`ng-version` attribute. - -**example**: - -```typescript -await render(SpoilerDirective, { - template: `
` - wrapper: CustomWrapperComponent -}) -``` - ## `RenderResult` ### `container` @@ -290,19 +301,46 @@ const {debug} = await render(AppComponent) debug() ``` +### `change` + +Change the input of the component. This calls `detectChanges` after the props +are updated. + +```typescript +const {change} = await render(Counter, { + componentProperties: {count: 4, name: 'Sarah'}, +}) + +expect(screen.getByTestId('count-value').textContent).toBe('4') +expect(screen.getByTestId('name-value').textContent).toBe('Sarah') + +change({count: 7}) + +// count updated to 7 +expect(screen.getByTestId('count-value').textContent).toBe('7') +// name keeps the same value +expect(screen.getByTestId('name-value').textContent).toBe('Sarah') +``` + ### `rerender` -Re-render the same component with different props. Will call `detectChanges` -after props has been updated. +Re-render the same component with different props. Input properties that are not +defined are cleared. This calls `detectChanges` after the props are updated. ```typescript -const {rerender} = await render(Counter, {componentProperties: {count: 4}}) +const {rerender} = await render(Counter, { + componentProperties: {count: 4, name: 'Sarah'}, +}) expect(screen.getByTestId('count-value').textContent).toBe('4') +expect(screen.getByTestId('name-value').textContent).toBe('Sarah') rerender({count: 7}) +// count 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() ``` ### `detectChanges` @@ -328,7 +366,8 @@ For more info see the ```typescript const {fixture} = await render(AppComponent) -const componentInstance = fixture.componentInstance as AppComponent +// componentInstance is typed as AppComponent +const componentInstance = fixture.componentInstance ``` > 🚨 If you find yourself using `fixture` to access the component's internal @@ -363,6 +402,8 @@ See [Queries](queries/about.mdx) for a complete list. ```typescript const {getByText, queryByLabelText} = await render(AppComponent) -getByText('Hello world') -queryByLabelText('First name:') +screen.getByRole('heading', { + name: /api/i, +}) +queryByLabelText(/First name/i') ``` diff --git a/docs/angular-testing-library/examples.mdx b/docs/angular-testing-library/examples.mdx index 5bddb7a48..265565d64 100644 --- a/docs/angular-testing-library/examples.mdx +++ b/docs/angular-testing-library/examples.mdx @@ -4,9 +4,10 @@ title: Examples sidebar_label: Examples --- -> Read -> [Good testing practices with 🦔 Angular Testing Library](https://timdeschryver.dev/posts/good-testing-practices-with-angular-testing-library) -> for a guided example +> Read about +> [best practices](https://timdeschryver.dev/blog/good-testing-practices-with-angular-testing-library), +> or follow the +> [guided example](https://timdeschryver.dev/blog/getting-the-most-value-out-of-your-angular-component-tests) counter.component.ts @@ -44,7 +45,7 @@ describe('Counter', () => { componentProperties: {counter: 5}, }) - expect(screen.getByText('Current Count: 5')) + expect(screen.getByText('Current Count: 5')).toBeInTheDocument() }) test('should increment the counter on click', async () => { @@ -54,7 +55,7 @@ describe('Counter', () => { fireEvent.click(screen.getByText('+')) - expect(screen.getByText('Current Count: 6')) + expect(screen.getByText('Current Count: 6')).toBeInTheDocument() }) }) ``` @@ -66,7 +67,8 @@ These examples include: - `@Input` and `@Output` properties - (Reactive) Forms - Integration with NgRx (mock) Store -- And more +- 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