Skip to content

Commit 3a8bb62

Browse files
docs(store): show correct testing snippets (#5124)
Co-authored-by: Marko Stanimirović <markostanimirovic95@gmail.com>
1 parent c0a1f97 commit 3a8bb62

File tree

3 files changed

+91
-111
lines changed

3 files changed

+91
-111
lines changed
Lines changed: 75 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import { provideMockStore, MockStore } from '@ngrx/store/testing';
22
import { TestBed, ComponentFixture } from '@angular/core/testing';
33
import { HttpClientTestingModule } from '@angular/common/http/testing';
4+
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
5+
import { By } from '@angular/platform-browser';
46

57
import { AppState } from './state/app.state';
68
import { AppComponent } from './app.component';
7-
import { addBook, removeBook } from './state/books.actions';
89
import { BookListComponent } from './book-list/book-list.component';
910
import { BookCollectionComponent } from './book-collection/book-collection.component';
10-
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
11-
import { By } from '@angular/platform-browser';
1211
import { selectBooks, selectBookCollection } from './state/books.selectors';
1312

1413
describe('AppComponent', () => {
@@ -18,88 +17,32 @@ describe('AppComponent', () => {
1817
let mockBookCollectionSelector;
1918
let mockBooksSelector;
2019

21-
beforeEach(() => {
22-
TestBed.configureTestingModule({
23-
providers: [provideMockStore()],
24-
imports: [HttpClientTestingModule],
25-
declarations: [BookListComponent, BookCollectionComponent, AppComponent],
26-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
27-
});
28-
29-
store = TestBed.inject(MockStore);
30-
fixture = TestBed.createComponent(AppComponent);
31-
component = fixture.componentInstance;
32-
33-
mockBooksSelector = store.overrideSelector(selectBooks, [
34-
{
35-
id: 'firstId',
36-
volumeInfo: {
37-
title: 'First Title',
38-
authors: ['First Author'],
39-
},
40-
},
41-
{
42-
id: 'secondId',
43-
volumeInfo: {
44-
title: 'Second Title',
45-
authors: ['Second Author'],
46-
},
47-
},
48-
{
49-
id: 'thirdId',
50-
volumeInfo: {
51-
title: 'Third Title',
52-
authors: ['Third Author'],
53-
},
54-
},
55-
{
56-
id: 'fourthId',
57-
volumeInfo: {
58-
title: 'Fourth Title',
59-
authors: ['Fourth Author'],
60-
},
61-
},
62-
]);
63-
64-
mockBookCollectionSelector = store.overrideSelector(selectBookCollection, [
65-
{
66-
id: 'thirdId',
67-
volumeInfo: {
68-
title: 'Third Title',
69-
authors: ['Third Author'],
70-
},
71-
},
72-
]);
73-
74-
fixture.detectChanges();
75-
spyOn(store, 'dispatch').and.callFake(() => {});
20+
TestBed.configureTestingModule({
21+
providers: [provideMockStore()],
22+
imports: [HttpClientTestingModule],
23+
declarations: [BookListComponent, BookCollectionComponent, AppComponent],
24+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
7625
});
7726

78-
afterEach(() => {
79-
TestBed.inject(MockStore)?.resetSelectors();
80-
});
81-
82-
it('add method should dispatch add action', () => {
83-
component.onAdd('firstId');
84-
expect(store.dispatch).toHaveBeenCalledWith(addBook({ bookId: 'firstId' }));
85-
});
27+
store = TestBed.inject(MockStore);
28+
fixture = TestBed.createComponent(AppComponent);
29+
component = fixture.componentInstance;
30+
31+
//#docregion mockSelector
32+
mockBooksSelector = store.overrideSelector(selectBooks, [
33+
{
34+
id: 'firstId',
35+
volumeInfo: {
36+
title: 'First Title',
37+
authors: ['First Author'],
38+
},
39+
},
40+
]);
8641

87-
it('remove method should dispatch remove action', () => {
88-
component.onRemove('thirdId');
89-
expect(store.dispatch).toHaveBeenCalledWith(
90-
removeBook({ bookId: 'thirdId' })
91-
);
92-
});
42+
mockBookCollectionSelector = store.overrideSelector(selectBookCollection, []);
9343

94-
it('should render a book list and a book collection', () => {
95-
expect(
96-
fixture.debugElement.queryAll(By.css('.book-list .book-item')).length
97-
).toBe(4);
98-
expect(
99-
fixture.debugElement.queryAll(By.css('.book-collection .book-item'))
100-
.length
101-
).toBe(1);
102-
});
44+
fixture.detectChanges();
45+
spyOn(store, 'dispatch').and.callFake(() => {});
10346

10447
it('should update the UI when the store changes', () => {
10548
mockBooksSelector.setResult([
@@ -117,13 +60,6 @@ describe('AppComponent', () => {
11760
authors: ['Second Author'],
11861
},
11962
},
120-
{
121-
id: 'thirdId',
122-
volumeInfo: {
123-
title: 'Third Title',
124-
authors: ['Third Author'],
125-
},
126-
},
12763
]);
12864

12965
mockBookCollectionSelector.setResult([
@@ -134,25 +70,67 @@ describe('AppComponent', () => {
13470
authors: ['First Author'],
13571
},
13672
},
137-
{
138-
id: 'secondId',
139-
volumeInfo: {
140-
title: 'Second Title',
141-
authors: ['Second Author'],
142-
},
143-
},
14473
]);
14574

14675
store.refreshState();
14776
fixture.detectChanges();
14877

14978
expect(
15079
fixture.debugElement.queryAll(By.css('.book-list .book-item')).length
151-
).toBe(3);
80+
).toBe(2);
15281

15382
expect(
15483
fixture.debugElement.queryAll(By.css('.book-collection .book-item'))
15584
.length
156-
).toBe(2);
85+
).toBe(1);
86+
});
87+
//#enddocregion mockSelector
88+
});
89+
90+
//#docregion resetMockSelector
91+
describe('AppComponent reset selectors', () => {
92+
let store: MockStore;
93+
94+
afterEach(() => {
95+
store?.resetSelectors();
96+
});
97+
98+
it('should return the mocked value', (done: any) => {
99+
TestBed.configureTestingModule({
100+
providers: [
101+
provideMockStore({
102+
selectors: [
103+
{
104+
selector: selectBooks,
105+
value: [
106+
{
107+
id: 'mockedId',
108+
volumeInfo: {
109+
title: 'Mocked Title',
110+
authors: ['Mocked Author'],
111+
},
112+
},
113+
],
114+
},
115+
],
116+
}),
117+
],
118+
});
119+
120+
store = TestBed.inject(MockStore);
121+
122+
store.select(selectBooks).subscribe((mockBooks) => {
123+
expect(mockBooks).toEqual([
124+
{
125+
id: 'mockedId',
126+
volumeInfo: {
127+
title: 'Mocked Title',
128+
authors: ['Mocked Author'],
129+
},
130+
},
131+
]);
132+
done();
133+
});
157134
});
158135
});
136+
//#enddocregion resetMockSelector

projects/www/src/app/examples/testing-store/src/app/integration.spec.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { TestBed, ComponentFixture, waitForAsync } from '@angular/core/testing';
1+
import { TestBed, ComponentFixture } from '@angular/core/testing';
22
import { By } from '@angular/platform-browser';
33
import { StoreModule } from '@ngrx/store';
44
import {
@@ -16,9 +16,11 @@ import { booksReducer } from './state/books.reducer';
1616
describe('AppComponent Integration Test', () => {
1717
let component: AppComponent;
1818
let fixture: ComponentFixture<AppComponent>;
19+
let booksService: GoogleBooksService;
1920
let httpMock: HttpTestingController;
2021

21-
beforeEach(waitForAsync(() => {
22+
beforeEach(() => {
23+
//#docregion integrate
2224
TestBed.configureTestingModule({
2325
declarations: [AppComponent, BookListComponent, BookCollectionComponent],
2426
imports: [
@@ -31,12 +33,14 @@ describe('AppComponent Integration Test', () => {
3133
providers: [GoogleBooksService],
3234
}).compileComponents();
3335

34-
httpMock = TestBed.inject(HttpTestingController);
35-
3636
fixture = TestBed.createComponent(AppComponent);
3737
component = fixture.debugElement.componentInstance;
3838

3939
fixture.detectChanges();
40+
//#enddocregion integrate
41+
42+
booksService = TestBed.get(GoogleBooksService);
43+
httpMock = TestBed.get(HttpTestingController);
4044

4145
const req = httpMock.expectOne(
4246
'https://www.googleapis.com/books/v1/volumes?maxResults=5&orderBy=relevance&q=oliver%20sacks'
@@ -61,7 +65,7 @@ describe('AppComponent Integration Test', () => {
6165
});
6266

6367
fixture.detectChanges();
64-
}));
68+
});
6569

6670
afterEach(() => {
6771
httpMock.verify();
@@ -70,27 +74,26 @@ describe('AppComponent Integration Test', () => {
7074
it('should create the component', () => {
7175
expect(component).toBeTruthy();
7276
});
73-
77+
//#docregion addTest
7478
describe('buttons should work as expected', () => {
7579
it('should add to collection when add button is clicked and remove from collection when remove button is clicked', () => {
7680
const addButton = getBookList()[1].query(
7781
By.css('[data-test=add-button]')
7882
);
7983

8084
click(addButton);
81-
8285
expect(getBookTitle(getCollection()[0])).toBe('Second Title');
8386

8487
const removeButton = getCollection()[0].query(
8588
By.css('[data-test=remove-button]')
8689
);
87-
8890
click(removeButton);
8991

9092
expect(getCollection().length).toBe(0);
9193
});
9294
});
9395

96+
//functions used in the above test
9497
function getCollection() {
9598
return fixture.debugElement.queryAll(By.css('.book-collection .book-item'));
9699
}
@@ -108,4 +111,5 @@ describe('AppComponent Integration Test', () => {
108111
el.click();
109112
fixture.detectChanges();
110113
}
114+
//#enddocregion addTest
111115
});

projects/www/src/app/pages/guide/store/testing.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,31 +75,29 @@ Usage:
7575

7676
</ngrx-code-example>
7777

78-
<ngrx-code-example header="src/app/app.component.spec.ts (Using Mock Selectors) " path="store-walkthrough/src/app/tests/app.component.1.spec.ts" region="mockSelector">
78+
<ngrx-code-example header="src/app/app.component.spec.ts (Using Mock Selectors)" path="testing-store/src/app/app.component.spec.ts" region="mockSelector">
7979

8080
</ngrx-code-example>
8181

8282
In this example based on the [walkthrough](guide/store/walkthrough), we mock the `selectBooks` selector by using `overrideSelector`, passing in the `selectBooks` selector with a default mocked return value of an array of books. Similarly, we mock the `selectBookCollection` selector and pass the selector together with another array. In the test, we use `setResult()` to update the mock selectors to return new array values, then we use `MockStore.refreshState()` to trigger an emission from the `selectBooks` and `selectBookCollection` selectors.
8383

8484
You can reset selectors by calling the `MockStore.resetSelectors()` method in the `afterEach()` hook.
8585

86-
<ngrx-code-example header="src/app/app.component.spec.ts (Reset Mock Selector) " path="store-walkthrough/src/app/tests/app.component.1.spec.ts" region="resetMockSelector">
86+
<ngrx-code-example header="src/app/app.component.spec.ts (Reset Mock Selector)" path="testing-store/src/app/app.component.spec.ts" region="resetMockSelector">
8787

8888
</ngrx-code-example>
8989

90-
Try the <ngrx-docs-stackblitz name="testing-store"></ngrx-docs-stackblitz>.
91-
9290
### Integration Testing
9391

9492
An integration test should verify that the `Store` coherently works together with our components and services that inject `Store`. An integration test will not mock the store or individual selectors, as unit tests do, but will instead integrate a `Store` by using `StoreModule.forRoot` in your `TestBed` configuration. Here is part of an integration test for the `AppComponent` introduced in the [walkthrough](guide/store/walkthrough).
9593

96-
<ngrx-code-example header="src/app/tests/integration.spec.ts (Integrate Store)" path="store-walkthrough/src/app/tests/integration.spec.ts" region="integrate">
94+
<ngrx-code-example header="src/app/tests/integration.spec.ts (Integrate Store)" path="testing-store/src/app/integration.spec.ts" region="integrate">
9795

9896
</ngrx-code-example>
9997

10098
The integration test sets up the dependent `Store` by importing the `StoreModule`. In this part of the example, we assert that clicking the `add` button dispatches the corresponding action and is correctly emitted by the `collection` selector.
10199

102-
<ngrx-code-example header="src/app/tests/integration.spec.ts (addButton Test)" path="store-walkthrough/src/app/tests/integration.spec.ts" region="addTest">
100+
<ngrx-code-example header="src/app/tests/integration.spec.ts (addButton Test)" path="testing-store/src/app/integration.spec.ts" region="addTest">
103101

104102
</ngrx-code-example>
105103

0 commit comments

Comments
 (0)