Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 91 additions & 50 deletions docs/angular-testing-library/api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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('<div appSpoiler></div>', {
declarations: [SpoilerDirective],
})
```

**example with component**:

```typescript
await render(
'<app-component [value]="47" [otherValue]="anotherValue" (sendValue)="sendValue($event)"></app-component>',
{
declarations: [AppComponent],
componentProperties: {
anotherValue: 'valueOfAnotherProperty',
sendValue: jest.fn(),
},
},
)
```

```typescript
async function render<ComponentType>(
export async function render<ComponentType>(
component: Type<ComponentType>,
renderOptions?: RenderComponentOptions<ComponentType>,
): Promise<RenderResult<ComponentType, ComponentType>>
async function render<DirectiveType, WrapperType = WrapperComponent>(
component: Type<DirectiveType>,
renderOptions?: RenderDirectiveOptions<DirectiveType, WrapperType>,
): Promise<RenderResult<DirectiveType, WrapperType>>
export async function render<WrapperType = WrapperComponent>(
template: string,
renderOptions?: RenderTemplateOptions<WrapperType>,
): Promise<RenderResult<WrapperType>>
```

## Component RenderOptions
Expand Down Expand Up @@ -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`

Expand Down Expand Up @@ -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: `<div spoiler message='SPOILER'></div>`,
})
```

### `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: `<div spoiler message='SPOILER'></div>`
wrapper: CustomWrapperComponent
})
```

## `RenderResult`

### `container`
Expand All @@ -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`
Expand All @@ -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
Expand Down Expand Up @@ -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')
```
14 changes: 8 additions & 6 deletions docs/angular-testing-library/examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 () => {
Expand All @@ -54,7 +55,7 @@ describe('Counter', () => {

fireEvent.click(screen.getByText('+'))

expect(screen.getByText('Current Count: 6'))
expect(screen.getByText('Current Count: 6')).toBeInTheDocument()
})
})
```
Expand All @@ -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
Expand Down