Skip to content

Commit 9f9e8c3

Browse files
docs: add inline docs (#43)
1 parent 5d623f3 commit 9f9e8c3

File tree

8 files changed

+270
-27
lines changed

8 files changed

+270
-27
lines changed

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export class CounterComponent {
116116

117117
counter.component.spec.ts
118118

119-
```javascript
119+
```typescript
120120
import { render } from '@testing-library/angular';
121121
import CounterComponent from './counter.component.ts';
122122

@@ -137,6 +137,8 @@ describe('Counter', () => {
137137
});
138138
```
139139

140+
[See more examples](https://github.com/testing-library/angular-testing-library/tree/master/src/app/examples)
141+
140142
## Installation
141143

142144
This module is distributed via [npm][npm] which is bundled with [node][node] and

projects/jest-utils/src/lib/create-mock.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ export function createMock<T>(type: Type<T>): Mock<T> {
3232
export function provideMock<T>(type: Type<T>): Provider {
3333
return {
3434
provide: type,
35-
useFactory: () => createMock(type),
35+
useValue: createMock(type),
3636
};
3737
}

projects/testing-library/src/lib/models.ts

+162-2
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,184 @@ import { UserEvents } from './user-events';
66
export type RenderResultQueries<Q extends Queries = typeof queries> = { [P in keyof Q]: BoundFunction<Q[P]> };
77

88
export interface RenderResult extends RenderResultQueries, FireObject, UserEvents {
9+
/**
10+
* @description
11+
* The HTML of the rendered component
12+
*/
913
container: HTMLElement;
14+
/**
15+
* @description
16+
* Prints out the component's HTML with syntax highlighting
17+
*
18+
* @param
19+
* element: The to be printed HTML element, if not provided it will log the whole component's HTML
20+
*/
1021
debug: (element?: HTMLElement) => void;
22+
/**
23+
* @description
24+
* The Angular `ComponentFixture` of the component
25+
* For more info see https://angular.io/api/core/testing/ComponentFixture
26+
*/
1127
fixture: ComponentFixture<any>;
1228
}
1329

1430
export interface RenderOptions<C, Q extends Queries = typeof queries> {
31+
/**
32+
* @description
33+
* Will call detectChanges when the component is compiled
34+
*
35+
* @default
36+
* true
37+
*
38+
* @example
39+
* const component = render(AppComponent, {
40+
* detectChanges: false
41+
* })
42+
*/
1543
detectChanges?: boolean;
44+
/**
45+
* @description
46+
* A collection of components, directives and pipes needed to render the component, for example, nested components of the component
47+
* For more info see https://angular.io/api/core/NgModule#declarations
48+
*
49+
* @default
50+
* []
51+
*
52+
* @example
53+
* const component = render(AppComponent, {
54+
* declarations: [ CustomerDetailComponent, ButtonComponent ]
55+
* })
56+
*/
1657
declarations?: any[];
58+
/**
59+
* @description
60+
* A collection of providers needed to render the component via Dependency Injection, for example, injectable services or tokens
61+
* For more info see https://angular.io/api/core/NgModule#providers
62+
*
63+
* @default
64+
* []
65+
*
66+
* @example
67+
* const component = render(AppComponent, {
68+
* providers: [
69+
* CustomersService,
70+
* {
71+
* provide: MAX_CUSTOMERS_TOKEN,
72+
* useValue: 10
73+
* }
74+
* ]
75+
* })
76+
*/
1777
providers?: any[];
78+
/**
79+
* @description
80+
* A collection of imports needed to render the component, for example, shared modules
81+
* For more info see https://angular.io/api/core/NgModule#imports
82+
*
83+
* @default
84+
* Adds `NoopAnimationsModule` by default if `BrowserAnimationsModule` isn't added to the collection:
85+
* `[NoopAnimationsModule]`
86+
*
87+
* @example
88+
* const component = render(AppComponent, {
89+
* providers: [
90+
* AppSharedModule,
91+
* MaterialModule,
92+
* ]
93+
* })
94+
*/
1895
imports?: any[];
96+
/**
97+
* @description
98+
* A collection of schemas needed to render the component.
99+
* Allowed value are `NO_ERRORS_SCHEMA` and `CUSTOM_ELEMENTS_SCHEMA`.
100+
* For more info see https://angular.io/api/core/NgModule#schemas
101+
*
102+
* @default
103+
* []
104+
*
105+
* @example
106+
* const component = render(AppComponent, {
107+
* imports: [
108+
* NO_ERRORS_SCHEMA,
109+
* ]
110+
* })
111+
*/
19112
schemas?: any[];
113+
/**
114+
* @description
115+
* An object to set `@Input` and `@Output` properties of the component
116+
*
117+
* @default
118+
* {}
119+
*
120+
* @example
121+
* const component = render(AppComponent, {
122+
* componentProperties: {
123+
* counterValue: 10,
124+
* send: (value) => { ... }
125+
* }
126+
* })
127+
*/
20128
componentProperties?: Partial<C>;
129+
/**
130+
* @description
131+
* A collection of providers to inject dependencies of the component
132+
* For more info see https://angular.io/api/core/Directive#providers
133+
*
134+
* @default
135+
* []
136+
*
137+
* @example
138+
* const component = render(AppComponent, {
139+
* componentProviders: [
140+
* AppComponentService
141+
* ]
142+
* })
143+
*/
21144
componentProviders?: any[];
145+
/**
146+
* @description
147+
* Queries to bind. Overrides the default set from DOM Testing Library unless merged.
148+
*
149+
* @default
150+
* undefined
151+
*
152+
* @example
153+
* import * as customQueries from 'custom-queries'
154+
* import { queries } from '@testing-library/angular'
155+
*
156+
* const component = render(AppComponent, {
157+
* queries: { ...queries, ...customQueries }
158+
* })
159+
*/
22160
queries?: Q;
161+
/**
162+
* @description
163+
* An Angular component to wrap the component in
164+
*
165+
* @default
166+
* `WrapperComponent`, an empty component that strips the `ng-version` attribute
167+
*
168+
* @example
169+
* const component = render(AppComponent, {
170+
* wrapper: CustomWrapperComponent
171+
* })
172+
*/
23173
wrapper?: Type<any>;
24174
/**
25-
* Exclude the component to be automatically be added as a declaration
26-
* This is needed when the component is declared in an imported module
175+
* @description
176+
* Exclude the component to be automatically be added as a declaration.
177+
* This is needed when the component is declared in an imported module.
178+
*
179+
* @default
180+
* false
181+
*
182+
* @example
183+
* const component = render(AppComponent, {
184+
* imports: [AppModule], // a module that includes AppComponent
185+
* excludeComponentDeclaration: true
186+
* })
27187
*/
28188
excludeComponentDeclaration?: boolean;
29189
}

projects/testing-library/src/lib/user-events/index.ts

+26
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,33 @@ import { createType } from './type';
33
import { createSelectOptions } from './selectOptions';
44

55
export interface UserEvents {
6+
/**
7+
* @description
8+
* Types a value in an input field just like the user would do
9+
*
10+
* @argument
11+
* element: HTMLElement - the form field to type in
12+
* value: string - the value to type in
13+
*
14+
* @example
15+
* component.type(component.getByLabelText('Firstname'), 'Tim')
16+
* component.type(component.getByLabelText('Firstname'), 'Tim', { delay: 100 })
17+
* component.type(component.getByLabelText('Firstname'), 'Tim', { allAtOnce: true })
18+
*/
619
type: ReturnType<typeof createType>;
20+
21+
/**
22+
* @description
23+
* Select an option(s) from a select just like the user would do
24+
*
25+
* @argument
26+
* element: HTMLElement - the select box to select an option in
27+
* matcher: Matcher | Matcher[] - the value(s) to select
28+
*
29+
* @example
30+
* component.selectOptions(component.getByLabelText('Fruit'), 'Blueberry')
31+
* component.selectOptions(component.getByLabelText('Fruit'), ['Blueberry'. 'Grape'])
32+
*/
733
selectOptions: ReturnType<typeof createSelectOptions>;
834
}
935

projects/testing-library/src/lib/user-events/type.ts

+21-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,25 @@ function wait(time) {
66
});
77
}
88

9+
export interface TypeOptions {
10+
/**
11+
* @description
12+
* Write the text at once rather than on character at a time
13+
*
14+
* @default
15+
* false
16+
*/
17+
allAtOnce?: boolean;
18+
/**
19+
* @description
20+
* Number of milliseconds until the next character is typed
21+
*
22+
* @default
23+
* 0
24+
*/
25+
delay?: number;
26+
}
27+
928
// implementation from https://github.com/testing-library/user-event
1029
export function createType(fireEvent: FireFunction & FireObject) {
1130
function createFireChangeEvent(value: string) {
@@ -17,7 +36,8 @@ export function createType(fireEvent: FireFunction & FireObject) {
1736
};
1837
}
1938

20-
return async function type(element: HTMLElement, value: string, { allAtOnce = false, delay = 0 } = {}) {
39+
return async function type(element: HTMLElement, value: string, options?: TypeOptions) {
40+
const { allAtOnce = false, delay = 0 } = options || {};
2141
const initialValue = (element as HTMLInputElement).value;
2242

2343
if (allAtOnce) {

src/app/examples/05-component-provider.spec.ts

+43-19
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { TestBed } from '@angular/core/testing';
12
import { render } from '@testing-library/angular';
3+
import { provideMock, Mock, createMock } from '@testing-library/angular/jest-utils';
24

35
import { ComponentWithProviderComponent, CounterService } from './05-component-provider';
46

@@ -26,27 +28,49 @@ test('renders the current value and can increment and decrement', async () => {
2628
expect(valueControl.textContent).toBe('1');
2729
});
2830

29-
// test('renders the current value and can increment and decrement with a mocked jest-utils service', async () => {
30-
// const component = await render(FixtureComponent, {
31-
// componentProviders: [provideMock(CounterService)],
32-
// });
31+
test('renders the current value and can increment and decrement with a mocked jest-utils service', async () => {
32+
const counter = createMock(CounterService);
33+
let fakeCounterValue = 50;
34+
counter.increment.mockImplementation(() => (fakeCounterValue += 10));
35+
counter.decrement.mockImplementation(() => (fakeCounterValue -= 10));
36+
counter.value.mockImplementation(() => fakeCounterValue);
3337

34-
// const counter = TestBed.get<CounterService>(CounterService) as Mock<CounterService>;
35-
// let fakeCounter = 50;
36-
// counter.increment.mockImplementation(() => (fakeCounter += 10));
37-
// counter.decrement.mockImplementation(() => (fakeCounter -= 10));
38-
// counter.value.mockImplementation(() => fakeCounter);
38+
const component = await render(ComponentWithProviderComponent, {
39+
componentProviders: [
40+
{
41+
provide: CounterService,
42+
useValue: counter,
43+
},
44+
],
45+
});
46+
47+
const incrementControl = component.getByText('Increment');
48+
const decrementControl = component.getByText('Decrement');
49+
const valueControl = component.getByTestId('value');
50+
51+
expect(valueControl.textContent).toBe('50');
52+
53+
component.click(incrementControl);
54+
component.click(incrementControl);
55+
expect(valueControl.textContent).toBe('70');
3956

40-
// const incrementControl = component.getByText('Increment');
41-
// const decrementControl = component.getByText('Decrement');
42-
// const valueControl = component.getByTestId('value');
57+
component.click(decrementControl);
58+
expect(valueControl.textContent).toBe('60');
59+
});
4360

44-
// expect(valueControl.textContent).toBe('50');
61+
test('renders the current value and can increment and decrement with provideMocked from jest-utils', async () => {
62+
const component = await render(ComponentWithProviderComponent, {
63+
componentProviders: [provideMock(CounterService)],
64+
});
4565

46-
// component.click(incrementControl);
47-
// component.click(incrementControl);
48-
// expect(valueControl.textContent).toBe('70');
66+
const incrementControl = component.getByText('Increment');
67+
const decrementControl = component.getByText('Decrement');
68+
69+
component.click(incrementControl);
70+
component.click(incrementControl);
71+
component.click(decrementControl);
4972

50-
// component.click(decrementControl);
51-
// expect(valueControl.textContent).toBe('60');
52-
// });
73+
const counterService = TestBed.get<CounterService>(CounterService) as Mock<CounterService>;
74+
expect(counterService.increment).toHaveBeenCalledTimes(2);
75+
expect(counterService.decrement).toHaveBeenCalledTimes(1);
76+
});

src/app/examples/07-with-ngrx-mock-store.spec.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { render } from '@testing-library/angular';
2-
import { provideMockStore } from '@ngrx/store/testing';
2+
import { provideMockStore, MockStore } from '@ngrx/store/testing';
33

44
import { WithNgRxMockStoreComponent, selectItems } from './07-with-ngrx-mock-store';
5+
import { TestBed } from '@angular/core/testing';
6+
import { Store } from '@ngrx/store';
57

68
test('works with provideMockStore', async () => {
79
const component = await render(WithNgRxMockStoreComponent, {
@@ -17,6 +19,11 @@ test('works with provideMockStore', async () => {
1719
],
1820
});
1921

22+
const store = TestBed.get(Store) as MockStore<any>;
23+
store.dispatch = jest.fn();
24+
2025
component.getByText('Four');
21-
component.getByText('Seven');
26+
component.click(component.getByText('Seven'));
27+
28+
expect(store.dispatch).toBeCalledWith({ type: '[Item List] send', item: 'Seven' });
2229
});

src/app/examples/07-with-ngrx-mock-store.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ export const selectItems = createSelector(
1010
selector: 'app-fixture',
1111
template: `
1212
<ul>
13-
<li *ngFor="let item of items | async">{{ item }}</li>
13+
<li *ngFor="let item of items | async" (click)="send(item)">{{ item }}</li>
1414
</ul>
1515
`,
1616
})
1717
export class WithNgRxMockStoreComponent {
1818
items = this.store.pipe(select(selectItems));
1919
constructor(private store: Store<any>) {}
20+
21+
send(item: string) {
22+
this.store.dispatch({ type: '[Item List] send', item });
23+
}
2024
}

0 commit comments

Comments
 (0)