ng-mocks 11.2.7 → 11.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +41 -3174
  3. package/dist/lib/common/core.helpers.d.ts +2 -2
  4. package/dist/lib/common/core.helpers.js +55 -27
  5. package/dist/lib/common/{core.reflect.body.d.ts → core.reflect.body-catch.d.ts} +0 -0
  6. package/dist/lib/common/core.reflect.body-catch.js +12 -0
  7. package/dist/lib/common/core.reflect.body-global.d.ts +3 -0
  8. package/dist/lib/common/core.reflect.body-global.js +11 -0
  9. package/dist/lib/common/core.reflect.directive-resolve.js +6 -4
  10. package/dist/lib/common/core.reflect.jit.d.ts +3 -0
  11. package/dist/lib/common/core.reflect.jit.js +11 -0
  12. package/dist/lib/common/core.reflect.module-resolve.js +6 -4
  13. package/dist/lib/common/core.reflect.pipe-resolve.js +6 -4
  14. package/dist/lib/common/core.tokens.d.ts +2 -2
  15. package/dist/lib/common/core.tokens.js +1 -1
  16. package/dist/lib/common/decorate.inputs.js +2 -2
  17. package/dist/lib/common/decorate.mock.d.ts +3 -0
  18. package/dist/lib/common/decorate.mock.js +13 -0
  19. package/dist/lib/common/decorate.outputs.js +2 -2
  20. package/dist/lib/common/decorate.queries.js +2 -2
  21. package/dist/lib/common/func.is-mock-control-value-accessor.js +2 -3
  22. package/dist/lib/common/func.is-mock-validator.js +2 -3
  23. package/dist/lib/common/func.is-ng-def.d.ts +7 -1
  24. package/dist/lib/common/func.is-ng-def.js +5 -1
  25. package/dist/lib/common/func.is-ng-injection-token.js +2 -3
  26. package/dist/lib/common/func.is-ng-module-def-with-providers.js +2 -3
  27. package/dist/lib/common/func.is-ng-type.d.ts +2 -2
  28. package/dist/lib/common/func.is-ng-type.js +6 -5
  29. package/dist/lib/common/mock-control-value-accessor.d.ts +3 -3
  30. package/dist/lib/common/mock-control-value-accessor.js +1 -1
  31. package/dist/lib/common/mock.js +31 -26
  32. package/dist/lib/common/ng-mocks-universe.d.ts +5 -0
  33. package/dist/lib/common/ng-mocks-universe.js +65 -7
  34. package/dist/lib/mock/clone-providers.js +23 -6
  35. package/dist/lib/mock/decorate-declaration.js +6 -6
  36. package/dist/lib/mock/to-existing-provider.d.ts +1 -1
  37. package/dist/lib/mock/to-factory-provider.d.ts +1 -1
  38. package/dist/lib/mock-builder/mock-builder-stash.js +3 -1
  39. package/dist/lib/mock-builder/mock-builder.js +2 -2
  40. package/dist/lib/mock-builder/mock-builder.performance.js +2 -2
  41. package/dist/lib/mock-builder/mock-builder.promise.js +4 -1
  42. package/dist/lib/mock-builder/promise/create-ng-mocks-overrides-token.js +2 -2
  43. package/dist/lib/mock-builder/promise/create-ng-mocks-touches-token.js +2 -2
  44. package/dist/lib/mock-builder/promise/get-override-meta.js +4 -4
  45. package/dist/lib/mock-builder/promise/get-root-provider-parameters.js +3 -3
  46. package/dist/lib/mock-builder/promise/init-module.js +2 -2
  47. package/dist/lib/mock-builder/promise/init-ng-modules.js +2 -2
  48. package/dist/lib/mock-component/mock-component.d.ts +1 -1
  49. package/dist/lib/mock-component/mock-component.js +9 -17
  50. package/dist/lib/mock-directive/mock-directive.d.ts +1 -1
  51. package/dist/lib/mock-directive/mock-directive.js +10 -23
  52. package/dist/lib/mock-helper/func.global-prepare.d.ts +2 -0
  53. package/dist/lib/mock-helper/func.global-prepare.js +9 -0
  54. package/dist/lib/mock-helper/mock-helper.auto-spy.js +2 -2
  55. package/dist/lib/mock-helper/mock-helper.d.ts +38 -0
  56. package/dist/lib/mock-helper/mock-helper.global-exclude.d.ts +4 -0
  57. package/dist/lib/mock-helper/mock-helper.global-exclude.js +9 -0
  58. package/dist/lib/mock-helper/mock-helper.global-keep.d.ts +4 -0
  59. package/dist/lib/mock-helper/mock-helper.global-keep.js +9 -0
  60. package/dist/lib/mock-helper/mock-helper.global-mock.d.ts +4 -0
  61. package/dist/lib/mock-helper/mock-helper.global-mock.js +9 -0
  62. package/dist/lib/mock-helper/mock-helper.global-replace.d.ts +3 -0
  63. package/dist/lib/mock-helper/mock-helper.global-replace.js +26 -0
  64. package/dist/lib/mock-helper/mock-helper.global-wipe.d.ts +4 -0
  65. package/dist/lib/mock-helper/mock-helper.global-wipe.js +11 -0
  66. package/dist/lib/mock-helper/mock-helper.guts.js +100 -37
  67. package/dist/lib/mock-helper/mock-helper.js +15 -1
  68. package/dist/lib/mock-helper/mock-helper.reset.js +2 -1
  69. package/dist/lib/mock-helper/mock-helper.stub-member.d.ts +2 -0
  70. package/dist/lib/mock-helper/mock-helper.stub-member.js +25 -0
  71. package/dist/lib/mock-helper/mock-helper.stub.js +2 -1
  72. package/dist/lib/mock-helper/mock-helper.throw-on-console.d.ts +2 -0
  73. package/dist/lib/mock-helper/mock-helper.throw-on-console.js +25 -0
  74. package/dist/lib/mock-instance/mock-instance.js +11 -7
  75. package/dist/lib/mock-module/mock-module.d.ts +2 -2
  76. package/dist/lib/mock-module/mock-module.js +7 -9
  77. package/dist/lib/mock-module/mock-ng-def.js +29 -12
  78. package/dist/lib/mock-pipe/mock-pipe.d.ts +2 -2
  79. package/dist/lib/mock-pipe/mock-pipe.js +18 -44
  80. package/dist/lib/mock-provider/mock-provider.d.ts +3 -3
  81. package/dist/lib/mock-provider/mock-provider.js +1 -1
  82. package/dist/lib/mock-render/func.generate-template.d.ts +2 -0
  83. package/dist/lib/mock-render/func.generate-template.js +87 -0
  84. package/dist/lib/mock-render/func.install-prop-reader.d.ts +2 -0
  85. package/dist/lib/mock-render/func.install-prop-reader.js +80 -0
  86. package/dist/lib/mock-render/mock-render.d.ts +16 -2
  87. package/dist/lib/mock-render/mock-render.js +111 -132
  88. package/dist/lib/mock-service/helper.resolve-provider.js +9 -12
  89. package/dist/lib/mock-service/helper.use-factory.js +3 -3
  90. package/dist/lib/mock-service/mock-provider.js +2 -1
  91. package/dist/lib/mock-service/mock-service.d.ts +4 -4
  92. package/dist/lib/mock-service/mock-service.js +1 -1
  93. package/examples/MockBuilder/test.deep.spec.ts +1 -1
  94. package/examples/MockBuilder/test.ng-mocks.spec.ts +1 -1
  95. package/examples/MockForms/test.spec.ts +2 -2
  96. package/examples/MockInstance/test.spec.ts +1 -1
  97. package/examples/MockObservable/test.spec.ts +7 -4
  98. package/examples/MockPipe/test.spec.ts +1 -1
  99. package/examples/MockProvider/test.spec.ts +5 -6
  100. package/examples/MockReactiveForms/test.spec.ts +2 -2
  101. package/examples/MockViewChild/test.spec.ts +3 -3
  102. package/examples/TestAttributeDirective/test.spec.ts +1 -1
  103. package/examples/TestHttpInterceptor/test.spec.ts +10 -4
  104. package/examples/TestHttpRequest/test.spec.ts +6 -4
  105. package/examples/TestLifecycleHooks/test.spec.ts +6 -2
  106. package/examples/TestLifecycleHooks/test.string.spec.ts +3 -2
  107. package/examples/TestLifecycleHooks/test.type-without-params.spec.ts +3 -2
  108. package/examples/TestMultiToken/test.spec.ts +3 -3
  109. package/examples/TestProvider/test.spec.ts +2 -3
  110. package/examples/TestProviderWithDependencies/test.spec.ts +7 -3
  111. package/examples/TestProviderWithUseClass/test.spec.ts +9 -3
  112. package/examples/TestProviderWithUseExisting/test.spec.ts +9 -3
  113. package/examples/TestProviderWithUseFactory/test.spec.ts +2 -3
  114. package/examples/TestProviderWithUseValue/test.spec.ts +4 -4
  115. package/examples/TestRoute/test.spec.ts +7 -7
  116. package/examples/TestRoutingGuard/test.spec.ts +8 -6
  117. package/examples/TestRoutingResolver/test.spec.ts +6 -4
  118. package/examples/TestToken/test.spec.ts +7 -6
  119. package/examples/main/test.spec.ts +2 -2
  120. package/examples/ngMocksFaster/test.spec.ts +2 -2
  121. package/package.json +2 -3
  122. package/dist/lib/common/core.reflect.body.js +0 -12
  123. package/dist/lib/common/core.reflect.d.ts +0 -6
  124. package/dist/lib/common/core.reflect.js +0 -10
  125. package/dist/lib/common/mock-of.d.ts +0 -3
  126. package/dist/lib/common/mock-of.js +0 -23
package/README.md CHANGED
@@ -6,3199 +6,66 @@
6
6
 
7
7
  # Mock components, services and more out of annoying dependencies in Angular tests
8
8
 
9
- `ng-mocks` is a testing library which helps with
10
- **mocking [services](#how-to-mock-services),
11
- [components](#how-to-mock-components)**,
12
- [directives](#how-to-mock-directives),
13
- [pipes](#how-to-mock-pipes) and
14
- [modules](#how-to-mock-modules)
15
- in tests for Angular applications.
16
- When you have [a noisy child component](#how-to-mock-components),
17
- or any other [annoying dependency](#how-to-turn-annoying-declarations-into-mocks-in-an-angular-application),
18
- `ng-mocks` has tools to turn these declarations into their mocks,
19
- keeping interfaces as they are, but suppressing their implementation.
9
+ `ng-mocks` helps to:
20
10
 
21
- The current version of the library has been tested and can be used with:
11
+ - mock Components, Directives, Pipes, Modules, Services and Tokens
12
+ - facilitate boilerplate in tests
13
+ - access declarations via simple interface
22
14
 
23
- - Angular 5 (Jasmine, Jest, es5, es2015)
24
- - Angular 6 (Jasmine, Jest, es5, es2015)
25
- - Angular 7 (Jasmine, Jest, es5, es2015)
26
- - Angular 8 (Jasmine, Jest, es5, es2015)
27
- - Angular 9 (Jasmine, Jest, Ivy, es5, es2015)
28
- - Angular 10 (Jasmine, Jest, Ivy, es5, es2015)
29
- - Angular 11 (Jasmine, Jest, Ivy, es5, es2015)
30
-
31
- There are preconfigured sandboxes on
32
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/test.spec.ts)
33
- and
34
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/test.spec.ts)
35
- where you might check all the features. To focus on a particular one, simply prefix it with `fdescribe` or `fit`.
36
-
37
- There is a brief summary of the latest changes in [CHANGELOG](https://github.com/ike18t/ng-mocks/blob/master/CHANGELOG.md).
38
-
39
- ### Find an issue or have a question or a request?
40
-
41
- We are open to contributions.
42
-
43
- - [ask a question on gitter](https://gitter.im/ng-mocks/community)
44
- - [report it as an issue on github](https://github.com/ike18t/ng-mocks/issues/new)
45
- - or submit a PR
46
-
47
- ## Table of contents
48
-
49
- - [How to read this](#how-to-read-this)
50
- - [Motivation and easy start](#motivation-and-easy-start)
51
- - [How to install](#install)
52
-
53
- * [Mocking in Angular tests](#how-to-turn-annoying-declarations-into-mocks-in-an-angular-application)
54
- - [How to mock components](#how-to-mock-components)
55
- - [How to mock directives](#how-to-mock-directives)
56
- - [How to mock pipes](#how-to-mock-pipes)
57
- - [How to mock services](#how-to-mock-services)
58
- - [How to mock providers](#how-to-mock-providers)
59
- - [How to mock modules](#how-to-mock-modules)
60
- - [How to mock observables](#how-to-mock-observables)
61
- - [How to mock form controls](#how-to-mock-form-controls)
62
-
63
- - [Example of mocking with `ng-mocks`](#extensive-example-of-mocks-in-angular-tests)
64
-
65
- * [`MockBuilder` in details](#mockbuilder)
66
- * [`MockRender` in details](#mockrender)
67
- * [`MockInstance` in details](#mockinstance)
68
- * [`ngMocks` in details](#ngmocks)
69
- * [Helper functions](#helper-functions)
70
-
71
- - [Usage with 3rd-party libraries](#usage-with-3rd-party-libraries)
72
- - [Making Angular tests faster](#making-angular-tests-faster)
73
- - [Auto spies in Angular tests](#auto-spy)
74
-
75
- * [How to fix](#how-to-fix-an-error-in-angular-tests)
76
- - [`TypeError: Cannot read property 'subscribe' of undefined`](#how-to-fix-typeerror-cannot-read-property-subscribe-of-undefined)
77
- - [`Error: Type is part of the declarations of 2 modules`](#how-to-fix-error-type-is-part-of-the-declarations-of-2-modules)
78
- - [`Error: Directive has no selector, please add it!`](#how-to-fix-error-directive-has-no-selector-please-add-it)
79
- - [`Template parse errors: <component> is not a known element`](#how-to-fix-template-parse-errors-component-is-not-a-known-element)
80
-
81
- ### External resources
82
-
83
- - [How to test Angular applications](https://ng-mocks.github.io/)
84
- - [How to configure CI to execute Angular tests automatically](https://satantime.github.io/puppeteer-node/)
85
-
86
- ### How to read this?
87
-
88
- **Essential**
89
-
90
- 1. Read titles from [TOC](#table-of-contents)
91
- 1. Start with [Motivation and easy start](#motivation-and-easy-start)
92
- 1. Check an [extensive example](#extensive-example-of-mocks-in-angular-tests)
93
- 1. Search keywords you need on this page: `NgModel`, `ViewChild`, `mock service` etc
94
-
95
- **Additional**
96
-
97
- - Don't hesitate to [ask questions on gitter](https://gitter.im/ng-mocks/community)
98
- - Try one of the online sandboxes:
99
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/test.spec.ts),
100
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/test.spec.ts)
101
-
102
- **TL;DR**
103
-
104
- - Read about [`MockRender`](#mockrender), [`MockInstance`](#mockinstance), [`ngMocks`](#ngmocks)
105
- - Read about [`MockBuilder`](#mockbuilder)
106
- - Check [guides and examples how to test Angular applications](https://ng-mocks.github.io/)
107
-
108
- ## Motivation and easy start
109
-
110
- Angular testing is fun and easy until you've met complex dependencies,
111
- and setting up the `TestBed` becomes really annoying and time-consuming.
112
-
113
- `ng-mocks` helps to bring fun and ease back allowing developers
114
- **to create [mock child components](#how-to-mock-components)**
115
- and stub dependencies via a few lines of code with help of
116
- [`MockService`](#how-to-mock-services),
117
- [`MockComponent`](#how-to-mock-components),
118
- [`MockDirective`](#how-to-mock-directives),
119
- [`MockPipe`](#how-to-mock-pipes),
120
- [`MockProvider`](#how-to-mock-providers),
121
- [`MockModule`](#how-to-mock-modules),
122
- or with pro tools such as
123
- [`MockBuilder`](#mockbuilder) with
124
- [`MockRender`](#mockrender).
125
-
126
- Let's imagine that in our Angular application we have a base component,
127
- and its template looks like that:
128
-
129
- ```html
130
- <app-header [menu]="items">
131
- <app-search (search)="search($event)" [results]="search$ | async">
132
- <ng-template #item let-item>
133
- <strong>{{ item }}</strong>
134
- </ng-template>
135
- </app-search>
136
- {{ title | translate }}
137
- </app-header>
138
- <app-body appDark>
139
- <router-outlet></router-outlet>
140
- </app-body>
141
- <app-footer></app-footer>
142
- ```
143
-
144
- This means that our base component depends on the next child components, services and declarations:
145
- `AppHeaderComponent`,
146
- `AppSearchComponent`,
147
- `AppBodyComponent`,
148
- `AppFooterComponent`,
149
- `SearchService`,
150
- `TranslatePipe`
151
- etc.
152
-
153
- We could easily test it with `schemas: [NO_ERRORS_SCHEMA]`
154
- to avoid
155
- [`Template parse errors: <component> is not a known element`](#how-to-fix-template-parse-errors-component-is-not-a-known-element),
156
- and it would work, but in this case we have zero guarantee, that our tests will fail
157
- if an interface of a dependency has been changed and requires
158
- code updates. Therefore, we have to avoid `NO_ERRORS_SCHEMA`.
159
-
160
- However, it forces us putting all dependencies in the `TestBed` like that:
161
-
162
- ```typescript
163
- TestBed.configureTestingModule({
164
- declarations: [
165
- AppBaseComponent, // <- the only declaration we care about.
166
- AppHeaderComponent,
167
- AppDarkDirective,
168
- TranslatePipe,
169
- // ...
170
- ],
171
- imports: [
172
- CommonModule,
173
- AppSearchModule,
174
- // ...
175
- ],
176
- providers: [
177
- LoginService,
178
- DataService,
179
- // ...
180
- ],
181
- });
182
- ```
183
-
184
- And... nobody knows which dependencies the dependencies have.
185
- Although, we definitely know that we do not want to worry about them.
186
-
187
- That's where `ng-mocks` comes for help. Simply pass all the dependencies
188
- into **[helper functions](#how-to-turn-annoying-declarations-into-mocks-in-an-angular-application) to get their mock versions**
189
- and to avoid a dependency hassle.
190
-
191
- ```typescript
192
- TestBed.configureTestingModule({
193
- declarations: [
194
- AppBaseComponent, // <- the only declaration we care about.
195
- MockComponent(AppHeaderComponent),
196
- MockDirective(AppDarkDirective),
197
- MockPipe(TranslatePipe),
198
- // ...
199
- ],
200
- imports: [
201
- MockModule(CommonModule),
202
- MockModule(AppSearchModule),
203
- // ...
204
- ],
205
- providers: [
206
- MockProvider(LoginService),
207
- MockProvider(DataService),
208
- // ...
209
- ],
210
- });
211
- ```
212
-
213
- Profit. Now we can forget about noise of child dependencies.
214
-
215
- Nevertheless, if we count lines of mock declarations,
216
- we see that there are a lot of them, and looks like here might be dozens more for big
217
- components. Also, what happens if someone deletes `AppSearchModule`
218
- from `AppBaseModule`? Doesn't look like the test will fail due to
219
- a missed dependency.
220
-
221
- Right, we need a tool that would extract declarations of the module
222
- `AppBaseComponent` belongs to, and create mocks out of them like the code above.
223
- Then, if someone deletes `AppSearchModule` the test fails too.
224
-
225
- [`ngMocks.guts`](#ngmocksguts) is the tool for that.
226
- Its first parameter accepts things we want to test (avoid mocks),
227
- the second parameter accepts things out of which we want to create mocks, if it is a module,
228
- its declarations (guts) will be turned into mocks, except the things
229
- from the first parameter, and the third parameter accepts things we want
230
- to exclude at all from the final meta. Any parameter can be `null` if
231
- we need to skip it, or an array if we want to pass several more than one.
232
-
233
- ```typescript
234
- const testModuleMeta = ngMocks.guts(AppBaseComponent, AppBaseModule);
235
- // feel free to add extra stuff
236
- // testModuleMeta.providers.push({
237
- // provide: SearchService,
238
- // useValue: SpiedSearchService,
239
- // });
240
- TestBed.configureTestingModule(testModuleMeta);
241
- ```
242
-
243
- Profit, but what about lazy loaded modules?
244
-
245
- If we have a lazy module, then it alone might be not sufficient, and
246
- we need to add its parent module, for example `AppModule`.
247
- In such a case, simply pass an array of modules as the second
248
- parameter.
249
-
250
- ```typescript
251
- TestBed.configureTestingModule(
252
- ngMocks.guts(
253
- AppBaseComponent, // <- kept as it is.
254
- [AppBaseModule, AppModule],
255
- ),
256
- );
257
- ```
258
-
259
- Profit. That should be enough for the start.
260
-
261
- The functions above help with an easy start, but they do not cover all
262
- possible cases and do not provide tools for customizing behavior.
263
- Consider reading [`MockBuilder`](#mockbuilder) and [`MockRender`](#mockrender)
264
- if you want **to create [mock child dependencies](#how-to-turn-annoying-declarations-into-mocks-in-an-angular-application) like a pro**
265
- in writing Angular tests.
266
-
267
- For example, if we needed `TranslatePipe` to prefix its strings instead of
268
- translating them, and to create a stub `SearchService` with an empty result that would not cause
269
- an error during execution due to a missed observable in its mock object,
270
- the code would look like:
271
-
272
- ```typescript
273
- beforeEach(() => {
274
- return MockBuilder(AppBaseComponent, AppBaseModule)
275
- .mock(TranslatePipe, v => `translated:${v}`)
276
- .mock(SearchService, {
277
- search: of([]),
278
- });
279
- });
280
- ```
281
-
282
- Profit.
283
- [Subscribe](https://github.com/ike18t/ng-mocks),
284
- [like](https://github.com/ike18t/ng-mocks),
285
- [share](https://twitter.com/intent/tweet?text=Check+ng-mocks+package&url=https%3A%2F%2Fgithub.com%2Fike18t%2Fng-mocks)!
286
-
287
- Have a question still? Don't hesitate to [contact us](#find-an-issue-or-have-a-question-or-a-request).
288
-
289
- [to the top](#table-of-contents).
290
-
291
- Below more detailed documentation begins, please bear with us.
292
-
293
- ## Install
294
-
295
- For any Angular project you can use the latest version of the library.
296
-
297
- NPM
298
-
299
- > npm install ng-mocks --save-dev
300
-
301
- Yarn
302
-
303
- > yarn add ng-mocks --dev
304
-
305
- ## How to turn annoying declarations into mocks in an Angular application
306
-
307
- This section provides vast **information how to create mock dependencies in angular** with real examples and detailed explanations
308
- of all aspects might be useful in writing fully isolated unit tests.
309
-
310
- - [mock components](#how-to-mock-components)
311
- - [mock directives](#how-to-mock-directives)
312
- - [mock pipes](#how-to-mock-pipes)
313
- - [mock services](#how-to-mock-services)
314
- - [mock providers](#how-to-mock-providers)
315
- - [mock modules](#how-to-mock-modules)
316
- - [mock observables](#how-to-mock-observables)
317
- - [mock form controls](#how-to-mock-form-controls)
318
-
319
- ### How to mock components
320
-
321
- **A mock component in Angular tests** can be created by `MockComponent` function.
322
-
323
- - `MockComponent( Component )` - returns a mock class of `Component` component.
324
- - `MockComponents( Component1, Component2, ... )` - returns an array of mocks.
325
-
326
- > **NOTE**: Information about [form control and their mocks](#how-to-mock-form-controls)
327
- > is in a different section.
328
-
329
- **A mock component** respects the interface of its original component as
330
- a type of `MockedComponent<T>` and provides:
331
-
332
- - the same `selector`
333
- - the same `Inputs` and `Outputs` with alias support
334
- - templates are pure `ng-content` tags to allow transclusion
335
- - supports `@ContentChild` with an `$implicit` context
336
- - `__render('id', $implicit, variables)` - renders a template
337
- - `__hide('id')` - hides a rendered template
338
- - supports [`FormsModule`, `ReactiveFormsModule` and `ControlValueAccessor`](#how-to-mock-form-controls)
339
- - `__simulateChange()` - calls `onChanged` on the mock component bound to a `FormControl`
340
- - `__simulateTouch()` - calls `onTouched` on the mock component bound to a `FormControl`
341
- - supports `exportAs`
342
-
343
- Let's pretend that in our Angular application `TargetComponent` depends on a child component of `DependencyComponent`
344
- and we want to use its mock object in a test.
345
-
346
- Usually `beforeEach` looks like:
347
-
348
- ```typescript
349
- describe('Test', () => {
350
- let component: TargetComponent;
351
- let fixture: ComponentFixture<TargetComponent>;
352
-
353
- beforeEach(() => {
354
- TestBed.configureTestingModule({
355
- declarations: [
356
- TargetComponent,
357
- DependencyComponent, // <- annoying dependency
358
- ],
359
- });
360
-
361
- fixture = TestBed.createComponent(TargetComponent);
362
- component = fixture.componentInstance;
363
- });
364
- });
365
- ```
366
-
367
- To **create a mock child component** simply pass its class into `MockComponent`:
368
-
369
- ```typescript
370
- TestBed.configureTestingModule({
371
- declarations: [
372
- TargetComponent,
373
- MockComponent(DependencyComponent), // <- profit
374
- ],
375
- });
376
- ```
377
-
378
- Or be like a pro and use [`MockBuilder`](#mockbuilder), its [`.mock`](#mockbuildermock) method
379
- and [`MockRender`](#mockrender):
380
-
381
- ```typescript
382
- describe('Test', () => {
383
- beforeEach(() => {
384
- return MockBuilder(TargetComponent).mock(DependencyComponent);
385
- });
386
-
387
- it('should create', () => {
388
- const fixture = MockRender(TargetComponent);
389
- expect(fixture.point.componentInstance).toBeDefined();
390
- });
391
- });
392
- ```
393
-
394
- <details><summary>Click to see <strong>a usage example of mock components in Angular tests</strong></summary>
395
- <p>
396
-
397
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/MockComponent/test.spec.ts),
398
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/MockComponent/test.spec.ts&initialpath=%3Fspec%3DMockComponent),
399
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/MockComponent/test.spec.ts&initialpath=%3Fspec%3DMockComponent).
400
-
401
- ```typescript
402
- describe('MockComponent', () => {
403
- beforeEach(() => {
404
- return MockBuilder(TestedComponent).mock(DependencyComponent);
405
- });
406
-
407
- it('sends the correct value to the child input', () => {
408
- const fixture = MockRender(TestedComponent);
409
- const component = fixture.point.componentInstance;
410
-
411
- // The same as
412
- // fixture.debugElement.query(
413
- // By.css('app-child')
414
- // ).componentInstance
415
- // but properly typed.
416
- const mockComponent = ngMocks.find<DependencyComponent>(
417
- 'app-child',
418
- ).componentInstance;
419
-
420
- // Let's pretend that DependencyComponent has 'someInput' as
421
- // an input. TestedComponent sets its value via
422
- // `[someInput]="value"`. The input's value will be passed into
423
- // the mock component so you can assert on it.
424
- component.value = 'foo';
425
- fixture.detectChanges();
426
-
427
- // Thanks to ng-mocks, this is type safe.
428
- expect(mockComponent.someInput).toEqual('foo');
429
- });
430
-
431
- it('does something on an emit of the child component', () => {
432
- const fixture = MockRender(TestedComponent);
433
- const component = fixture.point.componentInstance;
434
-
435
- // The same as
436
- // fixture.debugElement.query(
437
- // By.directive(DependencyComponent)
438
- // ).componentInstance
439
- // but properly typed.
440
- const mockComponent = ngMocks.findInstance(DependencyComponent);
441
-
442
- // Again, let's pretend DependencyComponent has an output
443
- // called 'someOutput'. TestedComponent listens on the output via
444
- // `(someOutput)="trigger($event)"`.
445
- // Let's install a spy and trigger the output.
446
- spyOn(component, 'trigger');
447
- mockComponent.someOutput.emit({
448
- payload: 'foo',
449
- });
450
-
451
- // Assert on the effect.
452
- expect(component.trigger).toHaveBeenCalledWith({
453
- payload: 'foo',
454
- });
455
- });
456
-
457
- it('renders something inside of the child component', () => {
458
- const localFixture = MockRender<DependencyComponent>(`
459
- <app-child>
460
- <p>inside content</p>
461
- </app-child>
462
- `);
463
-
464
- // We can access html directly asserting on some side effect.
465
- const mockNgContent = localFixture.point.nativeElement.innerHTML;
466
- expect(mockNgContent).toContain('<p>inside content</p>');
467
- });
468
-
469
- it('renders ContentChild of the child component', () => {
470
- const fixture = MockRender<DependencyComponent>(`
471
- <app-child>
472
- <ng-template #something>
473
- <p>inside template</p>
474
- </ng-template>
475
- <p>inside content</p>
476
- </app-child>
477
- `);
478
-
479
- // Injected ng-content rendered everything except templates.
480
- const mockNgContent = fixture.point.nativeElement.innerHTML;
481
- expect(mockNgContent).toContain('<p>inside content</p>');
482
- expect(mockNgContent).not.toContain('<p>inside template</p>');
483
-
484
- // Let's render the template. First, we need to assert that
485
- // componentInstance is a MockedComponent<T> to access
486
- // its `__render` method. `isMockOf` function helps here.
487
- const mockComponent = fixture.point.componentInstance;
488
- if (isMockOf(mockComponent, DependencyComponent, 'c')) {
489
- mockComponent.__render('something');
490
- fixture.detectChanges();
491
- }
492
-
493
- // The rendered template is wrapped by <div data-key="something">.
494
- // We can use this selector to assert exactly its content.
495
- const mockNgTemplate = ngMocks.find('[data-key="something"]')
496
- .nativeElement.innerHTML;
497
- expect(mockNgTemplate).toContain('<p>inside template</p>');
498
- });
499
- });
500
- ```
501
-
502
- </p>
503
- </details>
504
-
505
- [to the top](#table-of-contents)
506
-
507
- ### How to mock directives
15
+ The current version of the library **has been tested** and **can be used** with:
508
16
 
509
- **A mock directive in Angular tests** can be created by `MockDirective` function.
510
-
511
- - `MockDirective( Directive )` - returns a mock class of `Directive` directive.
512
- - `MockDirectives( Directive1, Directive2, ... )` - returns an array of mocks.
513
-
514
- > **NOTE**: Information about [form control and their mocks](#how-to-mock-form-controls)
515
- > is in a different section.
516
-
517
- **A mock directive** respects the interface of its original directive as
518
- a type of `MockedDirective<T>` and provides:
519
-
520
- - the same `selector`
521
- - the same `Inputs` and `Outputs` with alias support
522
- - supports structural directives
523
- - `__render($implicit, variables)` - renders content
524
- - supports [`FormsModule`, `ReactiveFormsModule` and `ControlValueAccessor`](#how-to-mock-form-controls)
525
- - `__simulateChange()` - calls `onChanged` on the mock component bound to a `FormControl`
526
- - `__simulateTouch()` - calls `onTouched` on the mock component bound to a `FormControl`
527
- - supports `exportAs`
528
-
529
- Let's assume that an Angular application has `TargetComponent` that depends on a directive of `DependencyDirective` and
530
- we need to use its mock object for facilitating unit tests.
531
-
532
- Usually a test looks like:
533
-
534
- ```typescript
535
- describe('Test', () => {
536
- let component: TargetComponent;
537
- let fixture: ComponentFixture<TargetComponent>;
538
-
539
- beforeEach(() => {
540
- TestBed.configureTestingModule({
541
- declarations: [
542
- TargetComponent,
543
- DependencyDirective, // <- annoying dependency
544
- ],
545
- });
546
-
547
- fixture = TestBed.createComponent(TargetComponent);
548
- component = fixture.componentInstance;
549
- });
550
- });
551
- ```
552
-
553
- To **create a mock child directive** simply pass its class into `MockDirective`:
554
-
555
- ```typescript
556
- TestBed.configureTestingModule({
557
- declarations: [
558
- TargetComponent,
559
- MockDirective(DependencyDirective), // <- profit
560
- ],
561
- });
562
- ```
563
-
564
- Or be like a pro and use [`MockBuilder`](#mockbuilder), its [`.mock`](#mockbuildermock) method
565
- and [`MockRender`](#mockrender):
566
-
567
- ```typescript
568
- describe('Test', () => {
569
- beforeEach(() => {
570
- return MockBuilder(TargetComponent).mock(DependencyDirective);
571
- });
572
-
573
- it('should create', () => {
574
- const fixture = MockRender(TargetComponent);
575
- expect(fixture.point.componentInstance).toBeDefined();
576
- });
577
- });
578
- ```
579
-
580
- <details><summary>Click to see <strong>a usage example of mock attribute directives in Angular tests</strong></summary>
581
- <p>
582
-
583
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/MockDirective-Attribute/test.spec.ts),
584
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/MockDirective-Attribute/test.spec.ts&initialpath=%3Fspec%3DMockDirective%3AAttribute),
585
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/MockDirective-Attribute/test.spec.ts&initialpath=%3Fspec%3DMockDirective%3AAttribute).
586
-
587
- ```typescript
588
- describe('MockDirective:Attribute', () => {
589
- beforeEach(() => {
590
- return MockBuilder(TestedComponent).mock(DependencyDirective);
591
- });
592
-
593
- it('sends the correct value to the input', () => {
594
- const fixture = MockRender(TestedComponent);
595
- const component = fixture.point.componentInstance;
596
-
597
- // The same as
598
- // fixture.debugElement.query(
599
- // By.css('span')
600
- // ).injector.get(DependencyDirective)
601
- // but easier and more precise.
602
- const mockDirective = ngMocks.get(
603
- ngMocks.find('span'),
604
- DependencyDirective,
605
- );
606
-
607
- // Let's pretend DependencyDirective has 'someInput'
608
- // as an input. TestedComponent sets its value via
609
- // `[someInput]="value"`. The input's value will be passed into
610
- // the mock directive so you can assert on it.
611
- component.value = 'foo';
612
- fixture.detectChanges();
613
-
614
- // Thanks to ng-mocks, this is type safe.
615
- expect(mockDirective.someInput).toEqual('foo');
616
- });
617
-
618
- it('does something on an emit of the child directive', () => {
619
- const fixture = MockRender(TestedComponent);
620
- const component = fixture.point.componentInstance;
621
-
622
- // The same as
623
- // fixture.debugElement.query(
624
- // By.css('span')
625
- // ).injector.get(DependencyDirective)
626
- // but easier and more precise.
627
- const mockDirective = ngMocks.get(
628
- ngMocks.find('span'),
629
- DependencyDirective,
630
- );
631
-
632
- // Again, let's pretend DependencyDirective has an output called
633
- // 'someOutput'. TestedComponent listens on the output via
634
- // `(someOutput)="trigger($event)"`.
635
- // Let's install a spy and trigger the output.
636
- spyOn(component, 'trigger');
637
- mockDirective.someOutput.emit();
638
-
639
- // Assert on the effect.
640
- expect(component.trigger).toHaveBeenCalled();
641
- });
642
- });
643
- ```
644
-
645
- </p>
646
- </details>
647
-
648
- <details><summary>Click to see <strong>a usage example of mock structural directives in Angular tests</strong></summary>
649
- <p>
650
-
651
- It's important to render a structural directive with the right context first,
652
- if you want to assert on its nested elements.
653
-
654
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/MockDirective-Structural/test.spec.ts),
655
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/MockDirective-Structural/test.spec.ts&initialpath=%3Fspec%3DMockDirective%3AStructural),
656
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/MockDirective-Structural/test.spec.ts&initialpath=%3Fspec%3DMockDirective%3AStructural).
657
-
658
- ```typescript
659
- describe('MockDirective:Structural', () => {
660
- // IMPORTANT: by default structural directives are not rendered.
661
- // Because they might require a context which should be provided.
662
- // Usually a developer knows the context and can render it
663
- // manually with proper setup.
664
- beforeEach(() => {
665
- return MockBuilder(TestedComponent).mock(DependencyDirective, {
666
- // render: true, // <-- a flag to render the directive by default
667
- });
668
- });
669
-
670
- it('renders content of the child structural directive', () => {
671
- const fixture = MockRender(TestedComponent);
672
-
673
- // Let's assert that nothing has been rendered inside of
674
- // the structural directive by default.
675
- expect(fixture.nativeElement.innerHTML).not.toContain(
676
- '>content<',
677
- );
678
-
679
- // And let's render it manually now.
680
- const mockDirective = ngMocks.findInstance(DependencyDirective);
681
- if (isMockOf(mockDirective, DependencyDirective, 'd')) {
682
- mockDirective.__render();
683
- fixture.detectChanges();
684
- }
685
-
686
- // The content of the structural directive should be rendered.
687
- expect(fixture.nativeElement.innerHTML).toContain('>content<');
688
- });
689
- });
690
- ```
691
-
692
- </p>
693
- </details>
694
-
695
- [to the top](#table-of-contents)
696
-
697
- ### How to mock pipes
698
-
699
- **A mock pipe in Angular tests** can be created by `MockPipe` function.
700
- The second parameter of the function accepts a custom transform callback.
701
-
702
- - `MockPipe( Pipe )` - returns a mock class of `Pipe` pipe that always transforms to `undefined`.
703
- - `MockPipe( Pipe, value => 'fake' )` - returns a mock class of `Pipe` pipe that transforms to `fake`.
704
- - `MockPipes( Pipe1, Pipe2, ... )` - returns an array of mocks.
705
-
706
- **A mock pipe** respects the interface of its original pipe as
707
- a type of `MockedPipe<T>` and provides:
708
-
709
- - the same `name`
710
- - ability to override the transform function with a type-safe function
711
- - default transform is `() => undefined` to prevent problems with chaining
712
-
713
- Let's imagine that in an Angular application `TargetComponent` depends on a pipe of `DependencyPipe` and
714
- we would like to replace it with its mock pipe in a test.
715
-
716
- Usually a test looks like:
17
+ - Angular 11 (Jasmine, Jest, Ivy, es5, es2015)
18
+ - Angular 10 (Jasmine, Jest, Ivy, es5, es2015)
19
+ - Angular 9 (Jasmine, Jest, Ivy, es5, es2015)
20
+ - Angular 8 (Jasmine, Jest, es5, es2015)
21
+ - Angular 7 (Jasmine, Jest, es5, es2015)
22
+ - Angular 6 (Jasmine, Jest, es5, es2015)
23
+ - Angular 5 (Jasmine, Jest, es5, es2015)
717
24
 
718
- ```typescript
719
- describe('Test', () => {
720
- let component: TargetComponent;
721
- let fixture: ComponentFixture<TargetComponent>;
25
+ **Important links**
722
26
 
723
- beforeEach(() => {
724
- TestBed.configureTestingModule({
725
- declarations: [
726
- TargetComponent,
727
- DependencyPipe, // <- annoying dependency
728
- ],
729
- });
27
+ - [**Documentation with examples**](https://ng-mocks.sudo.eu)
28
+ - [GitHub repo](https://github.com/ike18t/ng-mocks)
29
+ - [NPM package](https://www.npmjs.com/package/ng-mocks)
730
30
 
731
- fixture = TestBed.createComponent(TargetComponent);
732
- component = fixture.componentInstance;
733
- });
734
- });
735
- ```
31
+ * Live [example on StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/test.spec.ts)
32
+ * Live [example on CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/test.spec.ts)
736
33
 
737
- To **create a mock pipe** simply pass its class into `MockPipe`:
34
+ - [chat on gitter](https://gitter.im/ng-mocks/community)
35
+ - [**ask a question on Stackoverflow**](https://stackoverflow.com/questions/ask?tags=ng-mocks%20angular%20testing%20mocking)
36
+ - [report an issue on GitHub](https://github.com/ike18t/ng-mocks/issues/new)
738
37
 
739
- ```typescript
740
- TestBed.configureTestingModule({
741
- declarations: [
742
- TargetComponent,
743
- MockPipe(DependencyPipe, value => `mock:${value}`), // <- profit
744
- ],
745
- });
746
- ```
38
+ ## Very short introduction
747
39
 
748
- Or if you want to be like a pro, use [`MockBuilder`](#mockbuilder), its [`.mock`](#mockbuildermock) method
749
- and call [`MockRender`](#mockrender):
40
+ ```ts title="src/app.component.spec.ts"
41
+ describe('app-component', () => {
42
+ // Mocking everything in AppModule except AppComponent
43
+ beforeEach(() => MockBuilder(AppComponent, AppModule));
750
44
 
751
- ```typescript
752
- describe('Test', () => {
753
- beforeEach(() => {
754
- return MockBuilder(TargetComponent).mock(
755
- DependencyPipe,
756
- value => `mock:${value}`,
757
- );
758
- });
45
+ // Mocking observables in dependencies
46
+ beforeEach(() =>
47
+ MockInstance(AuthService, () => ({
48
+ isLoggedIn$: EMPTY,
49
+ currentUser$: EMPTY,
50
+ })),
51
+ );
759
52
 
760
- it('should create', () => {
761
- const fixture = MockRender(TargetComponent);
53
+ it('should be created', () => {
54
+ const fixture = MockRender(AppComponent);
762
55
  expect(fixture.point.componentInstance).toBeDefined();
763
- expect(fixture.nativeElement.innerHTML).toContain('mock:foo');
764
-
765
- // An instance of DependencyPipe from the fixture if we need it.
766
- const pipe = ngMocks.findInstance(DependencyPipe);
767
- expect(pipe).toBeDefined();
768
- });
769
- });
770
- ```
771
-
772
- <details><summary>Click to see <strong>a usage example of mock pipes in Angular tests</strong></summary>
773
- <p>
774
-
775
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/MockPipe/test.spec.ts),
776
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/MockPipe/test.spec.ts&initialpath=%3Fspec%3DMockPipe),
777
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/MockPipe/test.spec.ts&initialpath=%3Fspec%3DMockPipe).
778
-
779
- ```typescript
780
- describe('MockPipe', () => {
781
- // A fake transform function.
782
- const fakeTransform = (...args: string[]) => JSON.stringify(args);
783
-
784
- // A spy, just in case if we want to verify
785
- // how the pipe has been called.
786
- const spy = jasmine
787
- .createSpy('transform')
788
- .and.callFake(fakeTransform);
789
- // in case of jest
790
- // const spy = jest.fn().mockImplementation(fakeTransform);
791
-
792
- beforeEach(() => {
793
- return MockBuilder(TestedComponent).mock(DependencyPipe, spy);
794
- });
795
-
796
- it('transforms values to json', () => {
797
- const fixture = MockRender(TestedComponent);
798
-
799
- expect(fixture.nativeElement.innerHTML).toEqual(
800
- '<component>["foo"]</component>',
801
- );
802
-
803
- // Also we can find an instance of the pipe in
804
- // the fixture if it's needed.
805
- const pipe = ngMocks.findInstance(DependencyPipe);
806
- expect(pipe.transform).toHaveBeenCalledWith('foo');
807
- expect(pipe.transform).toHaveBeenCalledTimes(1);
808
- });
809
- });
810
- ```
811
-
812
- </p>
813
- </details>
814
-
815
- [to the top](#table-of-contents)
816
-
817
- ### How to mock services
818
-
819
- **A mock service in Angular tests** can be created by `MockService` function.
820
-
821
- It tends to avoid a hassle of providing customized mock objects for huge services.
822
- Simply pass a class into it and its result will be a mock instance that respects the class,
823
- but all methods and properties are customizable dummies.
824
-
825
- - `MockService( Service, overrides? )` - returns a mock instance of `Service` class.
826
- - `MockService( Obj )` - returns a mock object of `Obj` object.
827
-
828
- > **NOTE**: Information about [mocking provides](#how-to-mock-providers)
829
- > is in the next section, and about [mocking observables](#how-to-mock-observables) after it.
830
-
831
- **A mock service instance** is based on its original class, and provides:
832
-
833
- - all methods are dummies like `() => undefined`
834
- - all properties have been linked via getters and setters <small>(might not work in some cases, use [`ngMocks.stub`](#ngmocks) then)</small>
835
- - respects [auto spy](#auto-spy) environment
836
-
837
- A class with dozens of methods, where we want to change behavior of
838
- a single method, can be handled like that:
839
-
840
- ```typescript
841
- const instance = MockService(MyClass);
842
- // instance.method() returns undefined
843
- instance.method = () => 'My Custom Behavior';
844
- ```
845
-
846
- ```typescript
847
- const instance = MockService(MyClass, {
848
- method: () => 'My Custom Behavior',
849
- });
850
- // instance.method() returns 'My Custom Behavior'
851
- ```
852
-
853
- It also supports objects. All properties that are not objects or functions will be omitted,
854
- the functions will become dummy functions.
855
-
856
- ```typescript
857
- const instance = MockService({
858
- nested: {
859
- prop: true,
860
- func: () => 'hello',
861
- },
862
- });
863
- // instance.nested.prop is undefined
864
- // instance.nested.func() returns undefined
865
- instance.nested.func = () => 'My Custom Behavior';
866
- ```
867
-
868
- [to the top](#table-of-contents)
869
-
870
- ### How to mock providers
871
-
872
- **A mock provider in Angular tests** can be created by `MockProvider` function.
873
-
874
- - `MockProvider( Service, overrides? )` - creates a factory provider with `MockService(Service)` under the hood.
875
- - `MockProvider( TOKEN, useValue? )` - creates a factory provider that returns `undefined`.
876
- - `MockProvider( Service, {mock: true} )` - creates a factory provider that extends the mock instance with the passed value.
877
- - `MockProvider( TOKEN, 'fake' )` - creates a factory provider that returns the specified value.
878
- - `MockProviders( Service, TOKEN, ... )` - returns an array of mocks.
879
-
880
- Now let's pretend that in an Angular application `TargetComponent` depends on a service of `DependencyService`,
881
- and, in favor of avoiding overhead, its mock object should be used.
882
-
883
- Usually a test looks like:
884
-
885
- ```typescript
886
- describe('Test', () => {
887
- let component: TargetComponent;
888
- let fixture: ComponentFixture<TargetComponent>;
889
-
890
- beforeEach(() => {
891
- TestBed.configureTestingModule({
892
- declarations: [TargetComponent],
893
- providers: [
894
- // Annoying dependencies.
895
- DependencyService,
896
- ObservableService,
897
- ],
898
- });
899
-
900
- fixture = TestBed.createComponent(TargetComponent);
901
- component = fixture.componentInstance;
902
56
  });
903
57
  });
904
58
  ```
905
59
 
906
- To **create a mock provider** simply pass its class into `MockProvider`:
907
-
908
- ```typescript
909
- TestBed.configureTestingModule({
910
- declarations: [TargetComponent],
911
- providers: [
912
- // Profit.
913
- MockProvider(DependencyService),
914
- MockProvider(ObservableService, {
915
- prop$: EMPTY,
916
- getStream$: () => EMPTY,
917
- }),
918
- ],
919
- });
920
- ```
921
-
922
- Or, to be like a pro, use [`MockBuilder`](#mockbuilder), [`.mock`](#mockbuildermock) method
923
- and call [`MockRender`](#mockrender):
924
-
925
- ```typescript
926
- describe('Test', () => {
927
- beforeEach(() => {
928
- return MockBuilder(TargetComponent)
929
- .mock(DependencyService)
930
- .mock(ObservableService, {
931
- prop$: EMPTY,
932
- getStream$: () => EMPTY,
933
- });
934
- });
935
-
936
- it('should create', () => {
937
- const fixture = MockRender(TargetComponent);
938
- expect(component).toBeDefined();
939
- });
940
- });
941
- ```
942
-
943
- **Please note**: The most common error developers meet, when they create mock services, is "**TypeError: Cannot read property 'subscribe' of undefined**".
944
- If you are encountering it too, please read a section called [How to fix `TypeError: Cannot read property 'subscribe' of undefined`](#how-to-fix-typeerror-cannot-read-property-subscribe-of-undefined).
945
-
946
- <details><summary>Click to see <strong>a usage example of mock providers in Angular tests</strong></summary>
947
- <p>
948
-
949
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/MockProvider/test.spec.ts),
950
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/MockProvider/test.spec.ts&initialpath=%3Fspec%3DMockProvider),
951
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/MockProvider/test.spec.ts&initialpath=%3Fspec%3DMockProvider).
952
-
953
- ```typescript
954
- describe('MockProvider', () => {
955
- const mockObj = { value: 123 };
956
-
957
- beforeEach(() =>
958
- TestBed.configureTestingModule({
959
- declarations: [TargetComponent],
960
- imports: [CommonModule],
961
- providers: [
962
- MockProvider(Dependency1Service),
963
- MockProvider(Dependency2Service, { name: 'd2:mock' }),
964
- MockProvider(UNK_TOKEN, 'mock token'),
965
- MockProvider(STR_TOKEN, 'mock'),
966
- MockProvider(OBJ_TOKEN, mockObj),
967
- MockProvider('pri', 'pri'),
968
- ],
969
- }).compileComponents(),
970
- );
971
-
972
- it('uses mock providers', () => {
973
- // overriding the token's data that does affect the provided token.
974
- mockObj.value = 321;
975
- const fixture = TestBed.createComponent(TargetComponent);
976
- fixture.detectChanges();
977
- expect(
978
- fixture.debugElement.injector.get(Dependency1Service).echo(),
979
- ).toBeUndefined();
980
- expect(
981
- fixture.debugElement.injector.get(Dependency2Service).echo(),
982
- ).toBeUndefined();
983
- expect(fixture.debugElement.injector.get(OBJ_TOKEN)).toBe(
984
- mockObj,
985
- );
986
- expect(fixture.nativeElement.innerHTML).not.toContain('"target"');
987
- expect(fixture.nativeElement.innerHTML).toContain('"d2:mock"');
988
- expect(fixture.nativeElement.innerHTML).toContain('"mock token"');
989
- expect(fixture.nativeElement.innerHTML).toContain('"mock"');
990
- expect(fixture.nativeElement.innerHTML).toContain('"value": 321');
991
- expect(fixture.nativeElement.innerHTML).toContain('"pri"');
992
- });
993
- });
994
- ```
995
-
996
- </p>
997
- </details>
998
-
999
- [to the top](#table-of-contents)
1000
-
1001
- ### How to mock modules
1002
-
1003
- **A mock module in Angular tests** can be created by `MockModule`.
1004
-
1005
- A mock module is processed recursively. Mocks for all imports, exports and declarations will be created.
1006
-
1007
- - `MockModule( Module )` - returns a mock class of `Module` module.
1008
- - `MockModule( Module.forRoots() )` - additionally to a mock class of `Module` module returns mock providers.
1009
-
1010
- **A mock module** respects the interface of its original module as
1011
- a type of `MockedModule<T>` and provides:
1012
-
1013
- - mocks of all components, directives, pipes and providers
1014
- - mocks of all imports and exports
1015
- - dummy clones of all services
1016
- - dummy abstract methods for services with a `useClass` definition
1017
- - mocks of tokens with a `useClass` definition
1018
- - respect of tokens with a `useExisting` definition
1019
- - empty objects instead of tokens with a `helperUseFactory` definition
1020
- - base primitives instead of tokens with a `useValue` definition
1021
- - mocks of tokens with a `useValue` definition
1022
-
1023
- If you get an error like: "**Type is part of the declarations of 2 modules**",
1024
- then consider usage of [`MockBuilder`](#mockbuilder).
1025
- More detailed information about its cause and a solution you can read in a section called [How to fix `Type is part of the declarations of 2 modules`](#how-to-fix-error-type-is-part-of-the-declarations-of-2-modules).
1026
-
1027
- Let's imagine an Angular application where `TargetComponent` depends on a module of `DependencyModule`
1028
- and we would like to use its mock object in a test.
1029
-
1030
- Usually `beforeEach` looks like:
1031
-
1032
- ```typescript
1033
- describe('Test', () => {
1034
- let component: TargetComponent;
1035
- let fixture: ComponentFixture<TargetComponent>;
1036
-
1037
- beforeEach(() => {
1038
- TestBed.configureTestingModule({
1039
- imports: [DependencyModule], // <- annoying dependency
1040
- declarations: [TargetComponent],
1041
- });
1042
-
1043
- fixture = TestBed.createComponent(TargetComponent);
1044
- component = fixture.componentInstance;
1045
- });
1046
- });
1047
- ```
1048
-
1049
- To **create a mock module** simply pass its class into `MockModule`:
1050
-
1051
- ```typescript
1052
- TestBed.configureTestingModule({
1053
- imports: [
1054
- MockModule(DependencyModule), // <- profit
1055
- ],
1056
- declarations: [TargetComponent],
1057
- });
1058
- ```
1059
-
1060
- Or be like a pro and use [`MockBuilder`](#mockbuilder), its [`.mock`](#mockbuildermock) method
1061
- and [`MockRender`](#mockrender):
1062
-
1063
- ```typescript
1064
- describe('Test', () => {
1065
- beforeEach(() => {
1066
- return MockBuilder(TargetComponent).mock(DependencyModule);
1067
- });
1068
-
1069
- it('should create', () => {
1070
- const fixture = MockRender(TargetComponent);
1071
- expect(fixture.point.componentInstance).toBeDefined();
1072
- });
1073
- });
1074
- ```
1075
-
1076
- There is a trick to avoid specifying all dependencies of the `TargetComponent` in the chain:
1077
- simply pass its module as the second parameter of [`MockBuilder`](#mockbuilder).
1078
- Everything in `TargetModule` will be replaced with their mocks, but not `TargetComponent`, it will stay as it is:
1079
-
1080
- ```typescript
1081
- // Do not forget to return the promise of MockBuilder.
1082
- beforeEach(() => MockBuilder(TargetComponent, TargetModule));
1083
- ```
1084
-
1085
- <details><summary>Click to see <strong>a usage example of mock modules in Angular tests</strong></summary>
1086
- <p>
1087
-
1088
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/MockModule/test.spec.ts),
1089
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/MockModule/test.spec.ts&initialpath=%3Fspec%3DMockModule),
1090
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/MockModule/test.spec.ts&initialpath=%3Fspec%3DMockModule).
1091
-
1092
- ```typescript
1093
- describe('MockModule', () => {
1094
- beforeEach(() => {
1095
- return MockBuilder(TestedComponent).mock(DependencyModule);
1096
- });
1097
-
1098
- it('renders TestedComponent with its dependencies', () => {
1099
- const fixture = MockRender(TestedComponent);
1100
- const component = fixture.point.componentInstance;
1101
-
1102
- expect(component).toBeTruthy();
1103
- });
1104
- });
1105
- ```
1106
-
1107
- </p>
1108
- </details>
1109
-
1110
- [to the top](#table-of-contents)
1111
-
1112
- ### How to mock observables
1113
-
1114
- **A mock observable in Angular tests** can be created by
1115
- [`MockProvider`](#how-to-mock-providers),
1116
- [`MockInstance`](#mockinstance) or
1117
- [`ngMocks.defaultMock`](#ngmocksdefaultmock).
1118
-
1119
- For example, if we have `TodoService.list$()`,
1120
- that returns a type of `Observable<Array<Todo>>`,
1121
- and a component,
1122
- that fetches the list in `OnInit` via `subscribe` method:
1123
-
1124
- ```typescript
1125
- class TodoComponent implements OnInit {
1126
- public list: Observable<Array<Todo>>;
1127
-
1128
- constructor(protected service: TodoService) {}
1129
-
1130
- ngOnInit(): void {
1131
- // Never do like that.
1132
- // It is just for the demonstration purposes.
1133
- this.service.list$().subscribe(list => (this.list = list));
1134
- }
1135
- }
1136
- ```
1137
-
1138
- If we wanted to test the component, we would like to replace its dependencies with their mocks.
1139
- In our case it is `TodoService`.
1140
-
1141
- ```typescript
1142
- TestBed.configureTestingModule({
1143
- declarations: [TodoComponent],
1144
- providers: [MockProvider(TodoService)],
1145
- });
1146
- ```
1147
-
1148
- If we created a fixture, we would face an error about reading properties of `undefined`. This happens because a mock object of `TodoService.list$`
1149
- returns a spy, if [auto spy](#auto-spy) has been configured, or `undefined`. Therefore, neither has the `subscribe` property.
1150
-
1151
- Obviously, to solve this, we need to get the method to return an observable stream.
1152
- For that, we could extend the mock object via passing overrides as the second parameter into [`MockProvider`](#how-to-mock-providers).
1153
-
1154
- ```typescript
1155
- TestBed.configureTestingModule({
1156
- declarations: [TodoComponent],
1157
- providers: [
1158
- MockProvider(TodoService, {
1159
- list$: () => EMPTY,
1160
- }),
1161
- ],
1162
- });
1163
- ```
1164
-
1165
- Profit, now initialization of the component does not throw the error anymore.
1166
-
1167
- If we want to do it for all tests globally, we might use [`ngMocks.defaultMock`](#ngmocksdefaultmock).
1168
-
1169
- ```typescript
1170
- ngMocks.defaultMock(TodoService, () => ({
1171
- list$: () => EMPTY,
1172
- }));
1173
- ```
1174
-
1175
- Then, every time tests need a mock object of `TodoService`, its `list$()` will return `EMPTY`.
1176
-
1177
- Nevertheless, usually, we want not only to return a stub result as `EMPTY` observable stream,
1178
- but also to provide a fake subject, that would simulate its calls.
1179
-
1180
- A possible solution is to create a context variable of `Subject` type for that.
1181
-
1182
- ```typescript
1183
- let todoServiceList$: Subject<any>; // <- a context variable.
1184
-
1185
- beforeEach(() => {
1186
- todoServiceList$ = new Subject(); // <- create the subject.
1187
-
1188
- TestBed.configureTestingModule({
1189
- declarations: [TodoComponent],
1190
- providers: [
1191
- MockProvider(TodoService, {
1192
- list$: () => todoServiceList$,
1193
- }),
1194
- ],
1195
- });
1196
- });
1197
-
1198
- it('test', () => {
1199
- const fixture = TestBed.createComponent(TodoComponent);
1200
- // Let's simulate emits.
1201
- todoServiceList$.next([]);
1202
- // Here we can do some assertions.
1203
- });
1204
- ```
1205
-
1206
- A solution for [`MockBuilder`](#mockbuilder) is quite similar.
1207
-
1208
- ```typescript
1209
- let todoServiceList$: Subject<any>; // <- a context variable.
1210
-
1211
- beforeEach(() => {
1212
- todoServiceList$ = new Subject(); // <- create the subject.
1213
-
1214
- return MockBuilder(TodoComponent).mock(TodoService, {
1215
- list$: () => todoServiceList$,
1216
- });
1217
- });
1218
-
1219
- it('test', () => {
1220
- const fixture = MockRender(TodoComponent);
1221
- todoServiceList$.next([]);
1222
- // some assertions.
1223
- });
1224
- ```
1225
-
1226
- This all might be implemented with [`MockInstance`](#mockinstance) too,
1227
- but it goes beyond the topic.
1228
-
1229
- <details><summary>Click to see <strong>a usage example of a mock observable in Angular tests</strong></summary>
1230
- <p>
1231
-
1232
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/MockObservable/test.spec.ts),
1233
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/MockObservable/test.spec.ts&initialpath=%3Fspec%3DMockObservable),
1234
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/MockObservable/test.spec.ts&initialpath=%3Fspec%3DMockObservable).
1235
-
1236
- ```typescript
1237
- describe('MockObservable', () => {
1238
- // Because we want to test the component, we pass it as the first
1239
- // parameter of MockBuilder. To create its mock dependencies
1240
- // we pass its module as the second parameter.
1241
- // Do not forget to return the promise of MockBuilder.
1242
- beforeEach(() => MockBuilder(TargetComponent, TargetModule));
1243
-
1244
- // Now we need to customize the mock object of the service.
1245
- // value$ is our access point to the stream.
1246
- const value$: Subject<number[]> = new Subject();
1247
- beforeAll(() => {
1248
- // MockInstance helps to override mock instances.
1249
- MockInstance(TargetService, instance =>
1250
- ngMocks.stub(instance, {
1251
- value$, // even it is a read-only property we can override.
1252
- }),
1253
- );
1254
- });
1255
-
1256
- // Cleanup after tests.
1257
- afterAll(() => {
1258
- value$.complete();
1259
- MockInstance(TargetService);
1260
- });
1261
-
1262
- it('listens on emits of an injected subject', () => {
1263
- // Let's render the component.
1264
- const fixture = MockRender(TargetComponent);
1265
-
1266
- // We haven't emitted anything yet, let's check the template.
1267
- expect(fixture.nativeElement.innerHTML).not.toContain('1');
1268
- expect(fixture.nativeElement.innerHTML).not.toContain('2');
1269
- expect(fixture.nativeElement.innerHTML).not.toContain('3');
1270
-
1271
- // Let's simulate an emit.
1272
- value$.next([1, 2, 3]);
1273
- fixture.detectChanges();
1274
-
1275
- // The template should contain the emitted numbers.
1276
- expect(fixture.nativeElement.innerHTML).toContain('1');
1277
- expect(fixture.nativeElement.innerHTML).toContain('2');
1278
- expect(fixture.nativeElement.innerHTML).toContain('3');
1279
-
1280
- // Let's simulate an emit.
1281
- value$.next([]);
1282
- fixture.detectChanges();
1283
-
1284
- // The numbers should disappear.
1285
- expect(fixture.nativeElement.innerHTML).not.toContain('1');
1286
- expect(fixture.nativeElement.innerHTML).not.toContain('2');
1287
- expect(fixture.nativeElement.innerHTML).not.toContain('3');
1288
-
1289
- // Checking that a sibling method has been replaced
1290
- // with a mock object too.
1291
- expect(TestBed.inject(TargetService).getValue$).toBeDefined();
1292
- expect(TestBed.inject(TargetService).getValue$()).toBeUndefined();
1293
- });
1294
- });
1295
- ```
1296
-
1297
- </p>
1298
- </details>
1299
-
1300
- [to the top](#table-of-contents)
1301
-
1302
- ### How to mock form controls
1303
-
1304
- `ng-mocks` respects `ControlValueAccessor` interface if [a directive](#how-to-mock-directives),
1305
- or [a component](#how-to-mock-components) implements it.
1306
- Apart from that, `ng-mocks` provides helper functions to emit changes and touches.
1307
-
1308
- it supports both `FormsModule` and `ReactiveFormsModule`:
1309
-
1310
- - `ngModel`
1311
- - `ngModelChange`
1312
- - `formControl`
1313
- - `formControlName`
1314
-
1315
- * `NG_VALUE_ACCESSOR`
1316
- * `ControlValueAccessor`
1317
- * `writeValue`
1318
- * `registerOnChange`
1319
- * `registerOnTouched`
1320
-
1321
- - `NG_VALIDATORS`
1322
- - `Validator`
1323
- - `NG_ASYNC_VALIDATORS`
1324
- - `AsyncValidator`
1325
- - `registerOnValidatorChange`
1326
- - `validate`
1327
-
1328
- A mock object of `ControlValueAccessor` additionally implements `MockControlValueAccessor` and provides:
1329
-
1330
- - `__simulateChange(value: any)` - calls `onChanged` on the mock component bound to a `FormControl`
1331
- - `__simulateTouch()` - calls `onTouched` on the mock component bound to a `FormControl`
1332
-
1333
- * [`isMockControlValueAccessor( instance )`](#ismockcontrolvalueaccessor) - to verify `MockControlValueAccessor`
1334
-
1335
- A mock object of `Validator` or `AsyncValidator` additionally implements `MockValidator` and provides:
1336
-
1337
- - `__simulateValidatorChange()` - calls `updateValueAndValidity` on the mock component bound to a `FormControl`
1338
-
1339
- * [`isMockValidator( instance )`](#ismockvalidator) - to verify `MockValidator`
1340
-
1341
- <details><summary>Click to see <strong>a usage example of a mock FormControl with ReactiveForms in Angular tests</strong></summary>
1342
- <p>
1343
-
1344
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/MockReactiveForms/test.spec.ts),
1345
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/MockReactiveForms/test.spec.ts&initialpath=%3Fspec%3DMockReactiveForms),
1346
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/MockReactiveForms/test.spec.ts&initialpath=%3Fspec%3DMockReactiveForms).
1347
-
1348
- ```typescript
1349
- describe('MockReactiveForms', () => {
1350
- // That's our spy on writeValue calls.
1351
- // With auto spy this code isn't needed.
1352
- const writeValue = jasmine.createSpy('writeValue');
1353
- // in case of jest
1354
- // const writeValue = jest.fn();
1355
-
1356
- // Because of early calls of writeValue, we need to install
1357
- // the spy in the ctor call.
1358
- beforeEach(() =>
1359
- MockInstance(DependencyComponent, () => ({
1360
- writeValue,
1361
- })),
1362
- );
1363
-
1364
- beforeEach(() => {
1365
- return MockBuilder(TestedComponent)
1366
- .mock(DependencyComponent)
1367
- .keep(ReactiveFormsModule);
1368
- });
1369
-
1370
- it('sends the correct value to the mock form component', () => {
1371
- const fixture = MockRender(TestedComponent);
1372
- const component = fixture.point.componentInstance;
1373
-
1374
- // Let's find the mock form component.
1375
- const mockControl = ngMocks.find(DependencyComponent)
1376
- .componentInstance;
1377
-
1378
- // During initialization it should be called
1379
- // with null.
1380
- expect(writeValue).toHaveBeenCalledWith(null);
1381
-
1382
- // Let's simulate its change, like a user does it.
1383
- if (isMockControlValueAccessor(mockControl)) {
1384
- mockControl.__simulateChange('foo');
1385
- }
1386
- expect(component.formControl.value).toBe('foo');
1387
-
1388
- // Let's check that change on existing formControl
1389
- // causes calls of `writeValue` on the mock component.
1390
- component.formControl.setValue('bar');
1391
- expect(writeValue).toHaveBeenCalledWith('bar');
1392
- });
1393
- });
1394
- ```
1395
-
1396
- </p>
1397
- </details>
1398
-
1399
- <details><summary>Click to see <strong>a usage example of mock FormControl with ngModel in Angular tests</strong></summary>
1400
- <p>
1401
-
1402
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/MockForms/test.spec.ts),
1403
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/MockForms/test.spec.ts&initialpath=%3Fspec%3DMockForms),
1404
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/MockForms/test.spec.ts&initialpath=%3Fspec%3DMockForms).
1405
-
1406
- ```typescript
1407
- describe('MockForms', () => {
1408
- // That's our spy on writeValue calls.
1409
- // With auto spy this code isn't needed.
1410
- const writeValue = jasmine.createSpy('writeValue');
1411
- // in case of jest
1412
- // const writeValue = jest.fn();
1413
-
1414
- // Because of early calls of writeValue, we need to install
1415
- // the spy in the ctor call.
1416
- beforeEach(() =>
1417
- MockInstance(DependencyComponent, () => ({
1418
- writeValue,
1419
- })),
1420
- );
1421
-
1422
- beforeEach(() => {
1423
- return MockBuilder(TestedComponent)
1424
- .mock(DependencyComponent)
1425
- .keep(FormsModule);
1426
- });
1427
-
1428
- it('sends the correct value to the mock form component', async () => {
1429
- const fixture = MockRender(TestedComponent);
1430
- const component = fixture.point.componentInstance;
1431
-
1432
- // Let's find the mock form component.
1433
- const mockControl = ngMocks.find(DependencyComponent)
1434
- .componentInstance;
1435
-
1436
- // During initialization it should be called
1437
- // with null.
1438
- expect(writeValue).toHaveBeenCalledWith(null);
1439
-
1440
- // Let's simulate its change, like a user does it.
1441
- if (isMockControlValueAccessor(mockControl)) {
1442
- mockControl.__simulateChange('foo');
1443
- fixture.detectChanges();
1444
- await fixture.whenStable();
1445
- }
1446
- expect(component.value).toBe('foo');
1447
-
1448
- // Let's check that change on existing value
1449
- // causes calls of `writeValue` on the mock component.
1450
- component.value = 'bar';
1451
- fixture.detectChanges();
1452
- await fixture.whenStable();
1453
- expect(writeValue).toHaveBeenCalledWith('bar');
1454
- });
1455
- });
1456
- ```
1457
-
1458
- </p>
1459
- </details>
1460
-
1461
- [to the top](#table-of-contents)
1462
-
1463
- ## Extensive example of mocks in Angular tests
1464
-
1465
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/main/test.spec.ts),
1466
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/main/test.spec.ts&initialpath=%3Fspec%3Dmain),
1467
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/main/test.spec.ts&initialpath=%3Fspec%3Dmain).
1468
-
1469
- ```typescript
1470
- @Pipe({
1471
- name: 'translate',
1472
- })
1473
- class TranslatePipe implements PipeTransform {
1474
- public transform(value: string): string {
1475
- // Just for the test purpose
1476
- // we don't use any translation services.
1477
- return `translated:${value}`;
1478
- }
1479
- }
1480
-
1481
- // Our main component that we want to test.
1482
- @Component({
1483
- selector: 'app-root',
1484
- template: `
1485
- <app-header
1486
- [showLogo]="true"
1487
- [title]="title"
1488
- (logo)="logoClick.emit()"
1489
- >
1490
- <ng-template #menu>
1491
- <ul>
1492
- <li>
1493
- <a [routerLink]="['/home']">{{ 'Home' | translate }}</a>
1494
- </li>
1495
- <li>
1496
- <a [routerLink]="['/about']">{{ 'About' | translate }}</a>
1497
- </li>
1498
- </ul>
1499
- </ng-template>
1500
- </app-header>
1501
- <router-outlet></router-outlet>
1502
- `,
1503
- })
1504
- class AppComponent {
1505
- @Output() public logoClick = new EventEmitter<void>();
1506
- @Input() public title = 'My Application';
1507
- }
1508
-
1509
- // A dependency component out of which we want to create a mock
1510
- // component with a respect of its inputs, outputs and ContentChild.
1511
- @Component({
1512
- selector: 'app-header',
1513
- template: `
1514
- <a (click)="logo.emit()">
1515
- <img src="assets/logo.png" *ngIf="showLogo" />
1516
- </a>
1517
- {{ title }}
1518
- <template [ngTemplateOutlet]="menu"></template>
1519
- `,
1520
- })
1521
- class AppHeaderComponent {
1522
- @Output() public readonly logo = new EventEmitter<void>();
1523
- @ContentChild('menu') public menu?: TemplateRef<ElementRef>;
1524
- @Input() public showLogo = false;
1525
- @Input() public title = '';
1526
- }
1527
-
1528
- // The module where our components are declared.
1529
- @NgModule({
1530
- declarations: [AppComponent, AppHeaderComponent, TranslatePipe],
1531
- imports: [CommonModule, RouterModule.forRoot([])],
1532
- })
1533
- class AppModule {}
1534
-
1535
- describe('main', () => {
1536
- // Usually, we would have something like that.
1537
- // beforeEach(() => {
1538
- // TestBed.configureTestingModule({
1539
- // imports: [
1540
- // CommonModule,
1541
- // RouterModule.forRoot([]),
1542
- // ],
1543
- // declarations: [
1544
- // AppComponent,
1545
- // AppHeaderComponent,
1546
- // TranslatePipe,
1547
- // ],
1548
- // });
1549
- //
1550
- // fixture = TestBed.createComponent(AppComponent);
1551
- // fixture.detectChanges();
1552
- // });
1553
- // But, usually, instead of AppHeaderComponent and TranslatePipe
1554
- // we want to have mocks.
1555
-
1556
- // With ng-mocks it can be defined in the next way.
1557
- beforeEach(() => {
1558
- // AppComponent will stay as it is,
1559
- // everything in AppModule will be replaced with their mocks.
1560
- return (
1561
- MockBuilder(AppComponent, AppModule)
1562
- // Adding a special config how to create
1563
- // a mock AppHeaderComponent.
1564
- .mock(AppHeaderComponent, {
1565
- render: {
1566
- // #menu template will be rendered simultaneously
1567
- // with the mock AppHeaderComponent.
1568
- menu: true,
1569
- },
1570
- })
1571
- // a fake transform handler.
1572
- .mock(TranslatePipe, v => `fake:${v}`)
1573
- );
1574
- // the same as
1575
- // TestBed.configureTestingModule({
1576
- // imports: [
1577
- // MockModule(CommonModule),
1578
- // MockModule(RouterModule.forRoot([])),
1579
- // ],
1580
- // declarations: [
1581
- // AppComponent, // <- keeping it as it is.
1582
- // MockComponent(AppHeaderComponent),
1583
- // MockPipe(TranslatePipe, v => `fake:${v}`),
1584
- // ],
1585
- // });
1586
- // return testBed.compileComponents();
1587
- //
1588
- // of if we used ngMocks.guts
1589
- // TestBed.configureTestingModule(ngMocks.guts(
1590
- // AppComponent, // <- keeping it as it is.
1591
- // AppModule,
1592
- // ));
1593
- // return testBed.compileComponents();
1594
- // But in this case TranslatePipe will return undefined,
1595
- // if we don't customize it via MockInstance or defaultMock.
1596
- });
1597
-
1598
- it('asserts behavior of AppComponent', () => {
1599
- const logoClickSpy = jasmine.createSpy();
1600
- // in case of jest
1601
- // const logoClickSpy = jest.fn();
1602
-
1603
- // Instead of TestBed.createComponent(AppComponent) in beforeEach
1604
- // MockRender might be used directly in tests.
1605
- const fixture = MockRender(AppComponent, {
1606
- logoClick: logoClickSpy,
1607
- title: 'Fake Application',
1608
- });
1609
- // It creates a helper component
1610
- // with the next template:
1611
- // <app-root
1612
- // [title]="'Fake Application'"
1613
- // (logoClick)="logoClickSpy($event)"
1614
- // ></app-root>
1615
- // and renders it via TestBed.createComponent(HelperComponent).
1616
- // AppComponent is accessible via fixture.point.
1617
-
1618
- // The same as fixture.debugElement.query(
1619
- // By.directive(AppHeaderComponent)
1620
- // );
1621
- // but type safe and fails if nothing has been found.
1622
- const header = ngMocks.find(AppHeaderComponent);
1623
-
1624
- // Verifies how AppComponent uses AppHeaderComponent.
1625
- expect(header.componentInstance.showLogo).toBe(true);
1626
- expect(header.componentInstance.title).toBe('Fake Application');
1627
-
1628
- // Checking that AppComponents updates AppHeaderComponent.
1629
- fixture.componentInstance.title = 'Updated Application';
1630
- fixture.detectChanges();
1631
- expect(header.componentInstance.title).toBe(
1632
- 'Updated Application',
1633
- );
1634
-
1635
- // Checking that AppComponent listens on outputs of
1636
- // AppHeaderComponent.
1637
- expect(logoClickSpy).not.toHaveBeenCalled();
1638
- header.componentInstance.logo.emit();
1639
- expect(logoClickSpy).toHaveBeenCalled();
1640
-
1641
- // Verifies that AppComponent passes the right menu into
1642
- // AppHeaderComponent.
1643
- const links = ngMocks.findAll(header, 'a');
1644
- expect(links.length).toBe(2);
1645
- const [link1, link2] = links;
1646
-
1647
- // Checking that TranslatePipe has been used.
1648
- expect(link1.nativeElement.innerHTML).toEqual('fake:Home');
1649
- // An easy way to get a value of an input. The same as
1650
- // links[0].injector.get(RouterLinkWithHref).routerLink
1651
- expect(ngMocks.input(link1, 'routerLink')).toEqual(['/home']);
1652
-
1653
- expect(link2.nativeElement.innerHTML).toEqual('fake:About');
1654
- expect(ngMocks.input(link2, 'routerLink')).toEqual(['/about']);
1655
- });
1656
- });
1657
- ```
1658
-
1659
- Our tests:
1660
-
1661
- - [sandbox on StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/e2e.ts)
1662
- - [sandbox on CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/e2e.ts)
1663
- - [examples from the doc](https://github.com/ike18t/ng-mocks/tree/master/examples)
1664
- - [current e2e tests](https://github.com/ike18t/ng-mocks/tree/master/tests)
1665
-
1666
- [to the top](#table-of-contents)
1667
-
1668
- ## Functions for easy builds of mocks and template rendering
1669
-
1670
- The section provides information about essential functions for creating mocks with minimum coding.
1671
-
1672
- - [`MockBuilder`](#mockbuilder) - creates meta for the testing module where declarations are their mocks
1673
- - [`MockRender`](#mockrender) - renders custom templates
1674
- - [`MockInstance`](#mockinstance) - extends mocks on an early stage
1675
- - [`ngMocks`](#ngmocks) - facilitates work with fixtures
1676
-
1677
- ### MockBuilder
1678
-
1679
- `MockBuilder` is the simplest way to create mocks out of everything.
1680
- It provides a rich toolkit of functions to manipulate the mocks in the way your test requires,
1681
- but with minimum overhead.
1682
-
1683
- Usually, we have something simple to test, but time to time, the simplicity is killed by nightmarish dependencies.
1684
- The good thing here is that commonly the dependencies have been declared or imported in the same module, where our
1685
- tested thing is. Therefore, with help of `MockBuilder` we can quite easily define a testing module,
1686
- where everything in the module will be replaced with their mocks, except the tested thing: `MockBuilder( TheThing, ItsModule )`.
1687
-
1688
- MockBuilder tends to provide **a simple instrument to turn Angular dependencies into their mocks**,
1689
- does it in isolated scopes,
1690
- and has a rich toolkit that supports:
1691
-
1692
- - detection and creation of mocks for root providers
1693
- - replacement of modules and declarations in any depth
1694
- - exclusion of modules, declarations and providers in any depth
1695
-
1696
- * [Factory function](#mockbuilder-factory)
1697
- * [`.keep()`](#mockbuilderkeep)
1698
- * [`.mock()`](#mockbuildermock)
1699
- * [`.exclude()`](#mockbuilderexclude)
1700
- * [`.replace()`](#mockbuilderreplace)
1701
- * [`.provide()`](#mockbuilderprovide)
1702
- * [`precise` flag](#mockbuilder-precise-flag)
1703
- * [`export` flag](#mockbuilder-export-flag)
1704
- * [`exportAll` flag](#mockbuilder-exportall-flag)
1705
- * [`dependency` flag](#mockbuilder-dependency-flag)
1706
- * [`render` flag](#mockbuilder-render-flag)
1707
- * [`NG_MOCKS_GUARDS` token](#ng_mocks_guards-token)
1708
- * [`NG_MOCKS_INTERCEPTORS` token](#ng_mocks_interceptors-token)
1709
- * [`NG_MOCKS_ROOT_PROVIDERS` token](#ng_mocks_root_providers-token)
1710
- * [Good to know](#mockbuilder-good-to-know)
1711
-
1712
- <details><summary>Click to see <strong>a code sample demonstrating ease of creating mocks in Angular tests</strong></summary>
1713
- <p>
1714
-
1715
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/MockBuilder/test.simple.spec.ts),
1716
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/MockBuilder/test.simple.spec.ts&initialpath=%3Fspec%3DMockBuilder%3Asimple),
1717
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/MockBuilder/test.simple.spec.ts&initialpath=%3Fspec%3DMockBuilder%3Asimple).
1718
-
1719
- ```typescript
1720
- describe('MockBuilder:simple', () => {
1721
- // Do not forget to return the promise of MockBuilder.
1722
- beforeEach(() => MockBuilder(MyComponent, MyModule));
1723
- // The same as
1724
- // beforeEach(() => TestBed.configureTestingModule({{
1725
- // imports: [MockModule(MyModule)],
1726
- // }).compileComponents());
1727
- // but MyComponent has not been replaced with a mock object for
1728
- // the testing purposes.
1729
-
1730
- it('should render content ignoring all dependencies', () => {
1731
- const fixture = MockRender(MyComponent);
1732
- expect(fixture).toBeDefined();
1733
- expect(fixture.nativeElement.innerHTML).toContain(
1734
- '<div>My Content</div>',
1735
- );
1736
- });
1737
- });
1738
- ```
1739
-
1740
- </p>
1741
- </details>
1742
-
1743
- #### MockBuilder factory
1744
-
1745
- ```typescript
1746
- const ngModule = MockBuilder(MyComponent, MyModule).build();
1747
- ```
1748
-
1749
- The code above creates mocks for everything in `MyModule` (imports, declarations, providers and exports), but keeps `MyComponent` as it is for testing purposes.
1750
- Actually, it does the next:
1751
-
1752
- ```typescript
1753
- const ngModule = MockBuilder()
1754
- .keep(MyComponent, { export: true })
1755
- .mock(MyModule, { exportAll: true })
1756
- .build();
1757
- ```
1758
-
1759
- Also, you can suppress the first parameter with `null` if you want to create mocks for all declarations.
1760
-
1761
- ```typescript
1762
- const ngModule = MockBuilder(null, MyModule).build();
1763
- ```
1764
-
1765
- It does the next:
1766
-
1767
- ```typescript
1768
- const ngModule = MockBuilder()
1769
- .mock(MyModule, { exportAll: true })
1770
- .build();
1771
- ```
1772
-
1773
- If you do not plan further customization of `ngModule` then you do not need to call `.build()`. Simply return result of `MockBuilder` in `beforeEach`.
1774
-
1775
- ```typescript
1776
- // Do not forget to return the promise of MockBuilder.
1777
- beforeEach(() => MockBuilder(MyComponent, MyModule));
1778
- ```
1779
-
1780
- It does the next:
1781
-
1782
- ```typescript
1783
- beforeEach(() => {
1784
- const ngModule = MockBuilder()
1785
- .keep(MyComponent, { export: true })
1786
- .mock(MyModule, { exportAll: true })
1787
- .build();
1788
- TestBed.configureTestingModule(ngModule);
1789
- return TestBed.compileComponents();
1790
- });
1791
- ```
1792
-
1793
- #### MockBuilder.keep
1794
-
1795
- If we want to keep a module, component, directive, pipe or provider as it is. We should use `.keep`.
1796
-
1797
- ```typescript
1798
- beforeEach(() => {
1799
- return MockBuilder(MyComponent, MyModule)
1800
- .keep(SomeModule)
1801
- .keep(SomeModule.forSome())
1802
- .keep(SomeModule.forAnother())
1803
- .keep(SomeComponent)
1804
- .keep(SomeDirective)
1805
- .keep(SomePipe)
1806
- .keep(SomeService)
1807
- .keep(SomeInjectionToken);
1808
- });
1809
- ```
1810
-
1811
- #### MockBuilder.mock
1812
-
1813
- If we want to turn anything into a mock object, even a part of a kept module we should use `.mock`.
1814
-
1815
- ```typescript
1816
- beforeEach(() => {
1817
- return MockBuilder(MyComponent, MyModule)
1818
- .mock(SomeModule)
1819
- .mock(SomeModule.forSome())
1820
- .mock(SomeModule.forAnother())
1821
- .mock(SomeComponent)
1822
- .mock(SomeDirective)
1823
- .mock(SomePipe)
1824
- .mock(SomeService)
1825
- .mock(SomeInjectionToken);
1826
- });
1827
- ```
1828
-
1829
- For pipes, we can set their handlers as the 2nd parameter of `.mock`.
1830
-
1831
- ```typescript
1832
- beforeEach(() => {
1833
- return MockBuilder(MyComponent, MyModule).mock(
1834
- SomePipe,
1835
- value => 'My Custom Content',
1836
- );
1837
- });
1838
- ```
1839
-
1840
- For services and tokens, we can optionally provide their stubs.
1841
- Please keep in mind that the mock object of the service will be extended with the provided value.
1842
-
1843
- ```typescript
1844
- beforeEach(() => {
1845
- return MockBuilder(MyComponent, MyModule)
1846
- .mock(SomeService3, anything1)
1847
- .mock(SOME_TOKEN, anything2);
1848
- });
1849
- ```
1850
-
1851
- #### MockBuilder.exclude
1852
-
1853
- If we want to exclude something, even a part of a kept module we should use `.exclude`.
1854
-
1855
- ```typescript
1856
- beforeEach(() => {
1857
- return MockBuilder(MyComponent, MyModule)
1858
- .exclude(SomeModule)
1859
- .exclude(SomeComponent)
1860
- .exclude(SomeDirective)
1861
- .exclude(SomePipe)
1862
- .exclude(SomeDependency)
1863
- .exclude(SomeInjectionToken);
1864
- });
1865
- ```
1866
-
1867
- #### MockBuilder.replace
1868
-
1869
- If we want to replace something with something, we should use `.replace`.
1870
- The replacement has to be decorated with the same decorator as the source.
1871
- It is not impossible to replace a provider / service, we should use [`.provide`](#mockbuilderprovide) or [`.mock`](#mockbuildermock) for that.
1872
-
1873
- ```typescript
1874
- beforeEach(() => {
1875
- return MockBuilder(MyComponent, MyModule)
1876
- .replace(SomeModule, SomeOtherModule)
1877
- .replace(SomeComponent, SomeOtherComponent)
1878
- .replace(SomeDirective, SomeOtherDirective)
1879
- .replace(SomePipe, SomeOtherPipe);
1880
- });
1881
- ```
1882
-
1883
- In case of `HttpClientTestingModule` you can use `.replace` too.
1884
-
1885
- ```typescript
1886
- beforeEach(() => {
1887
- return MockBuilder(MyComponent, MyModule).replace(
1888
- HttpClientModule,
1889
- HttpClientTestingModule,
1890
- );
1891
- });
1892
- ```
1893
-
1894
- In case of `RouterTestingModule` you need to use [`.keep`](#mockbuilderkeep) for both of the modules and to pass an empty array into `.withRoutes`.
1895
-
1896
- ```typescript
1897
- beforeEach(() => {
1898
- return MockBuilder(MyComponent, MyModule)
1899
- .keep(RouterModule)
1900
- .keep(RouterTestingModule.withRoutes([]));
1901
- });
1902
- ```
1903
-
1904
- #### MockBuilder.provide
1905
-
1906
- If we want to add or replace providers / services, we should use `.provide`. It has the same interface as a regular provider.
1907
-
1908
- ```typescript
1909
- beforeEach(() => {
1910
- return MockBuilder(MyComponent, MyModule)
1911
- .provide(MyService)
1912
- .provide([SomeService1, SomeService2])
1913
- .provide({ provide: SomeComponent3, useValue: anything1 })
1914
- .provide({ provide: SOME_TOKEN, useFactory: () => anything2 });
1915
- });
1916
- ```
1917
-
1918
- #### MockBuilder `precise` flag
1919
-
1920
- By default, when [`.mock(Service, mock)`](#mockbuildermock) is used it creates a mock object via
1921
- [`MockService(Service, mock)`](#how-to-mock-services).
1922
- In some cases, we might want to use the exactly passed mock object instead of extension.
1923
- For this behavior we need to set `precise` flag to `true`. Tokens are always precise.
1924
-
1925
- ```typescript
1926
- declare class MyService {
1927
- p1: boolean;
1928
- getP1(): boolean;
1929
- }
1930
- const mock = {
1931
- p1: true,
1932
- };
1933
-
1934
- beforeEach(() => {
1935
- return (
1936
- MockBuilder(MyComponent, MyModule)
1937
- // its instance !== mock, but instance.p1 === mock.p1
1938
- // instance.getP1() returns undefined
1939
- .mock(MyService, mock)
1940
- // its instance === mock, therefore instance.p1 === mock.p1
1941
- // and instance.getP1 does not exist.
1942
- .mock(MyService, mock, {
1943
- precise: true,
1944
- })
1945
- );
1946
- });
1947
- ```
1948
-
1949
- #### MockBuilder `export` flag
1950
-
1951
- If we want to test a component, directive or pipe which, unfortunately, has not been exported,
1952
- then we need to mark it with the `export` flag.
1953
- Does not matter how deep it is. It will be exported to the level of `TestingModule`.
1954
-
1955
- ```typescript
1956
- beforeEach(() => {
1957
- return MockBuilder(MyComponent, MyModule)
1958
- .keep(SomeDeclaration1, {
1959
- export: true,
1960
- })
1961
- .mock(SomeDeclaration2, {
1962
- export: true,
1963
- });
1964
- });
1965
- ```
1966
-
1967
- #### MockBuilder `exportAll` flag
1968
-
1969
- If we want to use all the declarations of a module which have not been exported,
1970
- we need to mark the module with the `exportAll` flag. Then all its imports and declarations will be exported.
1971
- If the module is nested, then add the [`export`](#mockbuilder-export-flag) flag beside `exportAll` too.
1972
-
1973
- ```typescript
1974
- beforeEach(() => {
1975
- return MockBuilder(MyComponent)
1976
- .keep(MyModule, {
1977
- exportAll: true,
1978
- })
1979
- .mock(MyNestedModule, {
1980
- exportAll: true,
1981
- export: true,
1982
- });
1983
- });
1984
- ```
1985
-
1986
- #### MockBuilder `dependency` flag
1987
-
1988
- By default, all definitions are added to the `TestingModule` if they are not a dependency of another definition.
1989
- Modules are added as imports to the `TestingModule`.
1990
- Components, Directive, Pipes are added as declarations to the `TestingModule`.
1991
- Tokens and Services are added as providers to the `TestingModule`.
1992
- If we do not want something to be added to the `TestingModule` at all, then we need to mark it with the `dependency` flag.
1993
-
1994
- ```typescript
1995
- beforeEach(() => {
1996
- return (
1997
- MockBuilder(MyComponent, MyModule)
1998
- .keep(SomeModuleComponentDirectivePipeProvider1, {
1999
- dependency: true,
2000
- })
2001
- .mock(SomeModuleComponentDirectivePipe, {
2002
- dependency: true,
2003
- })
2004
- // Pass the same def as a mock instance, if you want only to
2005
- // specify the config.
2006
- .mock(SomeProvider, SomeProvider, {
2007
- dependency: true,
2008
- })
2009
- // Or provide a mock instance together with the config.
2010
- .mock(SomeProvider, mockInstance, {
2011
- dependency: true,
2012
- })
2013
- .replace(SomeModuleComponentDirectivePipeProvider1, anything1, {
2014
- dependency: true,
2015
- })
2016
- );
2017
- });
2018
- ```
2019
-
2020
- #### MockBuilder `render` flag
2021
-
2022
- If we want to render a structural directive by default. Now we can do that via adding the `render` flag in its config.
2023
-
2024
- ```typescript
2025
- beforeEach(() => {
2026
- return MockBuilder(MyComponent, MyModule).mock(MyDirective, {
2027
- render: true,
2028
- });
2029
- });
2030
- ```
2031
-
2032
- If the directive has own context and variables. Then instead of setting `render` to true we can set the context.
2033
-
2034
- ```typescript
2035
- beforeEach(() => {
2036
- return MockBuilder(MyComponent, MyModule).mock(MyDirective, {
2037
- render: {
2038
- $implicit: something1,
2039
- variables: { something2: something3 },
2040
- },
2041
- });
2042
- });
2043
- ```
2044
-
2045
- If we use `ContentChild` in a component, and we want to render it by default, we should use its id for that in the same way as for a mock directive.
2046
-
2047
- ```typescript
2048
- beforeEach(() => {
2049
- return MockBuilder(MyComponent, MyModule).mock(MyComponent, {
2050
- render: {
2051
- blockId: true,
2052
- blockWithContext: {
2053
- $implicit: something1,
2054
- variables: { something2: something3 },
2055
- },
2056
- },
2057
- });
2058
- });
2059
- ```
2060
-
2061
- #### `NG_MOCKS_GUARDS` token
2062
-
2063
- If we want to test guards, we need to [`.keep`](#mockbuilderkeep) them, but what should we do with other guards we do not want to care about at all?
2064
- The answer is to exclude `NG_MOCKS_GUARDS` token, it will **remove all the guards from routes** except the explicitly configured ones.
2065
-
2066
- ```typescript
2067
- beforeEach(() => {
2068
- return MockBuilder(MyGuard, MyModule).exclude(NG_MOCKS_GUARDS);
2069
- });
2070
- ```
2071
-
2072
- #### `NG_MOCKS_INTERCEPTORS` token
2073
-
2074
- Usually, when we want to test an interceptor, we want to avoid influences of other interceptors.
2075
- To **remove all interceptors in an angular test** we need to exclude `NG_MOCKS_INTERCEPTORS` token,
2076
- then all interceptors will be excluded except the explicitly configured ones.
2077
-
2078
- ```typescript
2079
- beforeEach(() => {
2080
- return MockBuilder(MyInterceptor, MyModule).exclude(
2081
- NG_MOCKS_INTERCEPTORS,
2082
- );
2083
- });
2084
- ```
2085
-
2086
- #### `NG_MOCKS_ROOT_PROVIDERS` token
2087
-
2088
- There are root services and tokens apart from provided ones in Angular applications.
2089
- It might happen that in a test we want these providers to be replaced with their mocks or to be kept.
2090
-
2091
- If we want to replace all root providers with their mocks in an angular test,
2092
- we need to pass `NG_MOCKS_ROOT_PROVIDERS` token into [`.mock`](#mockbuildermock).
2093
-
2094
- ```typescript
2095
- beforeEach(() => {
2096
- return MockBuilder(
2097
- MyComponentWithRootServices,
2098
- MyModuleWithRootTokens,
2099
- ).mock(NG_MOCKS_ROOT_PROVIDERS);
2100
- });
2101
- ```
2102
-
2103
- In contrast to that, we might want to keep all root providers for mock declarations.
2104
- For that, we need to keep `NG_MOCKS_ROOT_PROVIDERS` token.
2105
-
2106
- ```typescript
2107
- beforeEach(() => {
2108
- return MockBuilder(
2109
- MyComponentWithRootServices,
2110
- MyModuleWithRootTokens,
2111
- ).keep(NG_MOCKS_ROOT_PROVIDERS);
2112
- });
2113
- ```
2114
-
2115
- If we do not pass `NG_MOCKS_ROOT_PROVIDERS` anywhere,
2116
- then only root providers for kept modules will stay as they are.
2117
- All other root providers will be replaced with their mocks, even for kept declarations of mock modules.
2118
-
2119
- #### MockBuilder good to know
2120
-
2121
- Anytime we can change our decision. The last action on the same object wins.
2122
- `SomeModule` will be replaced with its mock object.
2123
-
2124
- ```typescript
2125
- beforeEach(() => {
2126
- return MockBuilder(MyComponent, MyModule)
2127
- .keep(SomeModule)
2128
- .mock(SomeModule)
2129
- .keep(SomeModule)
2130
- .mock(SomeModule);
2131
- });
2132
- ```
2133
-
2134
- [to the top](#table-of-contents)
2135
-
2136
- ### MockRender
2137
-
2138
- `MockRender` is a simple tool that helps with **shallow rendering in Angular tests**
2139
- when we want to assert `Inputs`, `Outputs`, `ChildContent` and custom templates.
2140
-
2141
- The best thing about it is that `MockRender` properly triggers all lifecycle hooks
2142
- and allows **to test `ngOnChanges` hook from `OnChanges` interface**.
2143
-
2144
- **Please note**, that `MockRender(Component)` is not assignable to
2145
- `ComponentFixture<Component>`. You should use either
2146
-
2147
- ```typescript
2148
- MockedComponentFixture<Component>
2149
- ```
2150
-
2151
- or
2152
-
2153
- ```typescript
2154
- ComponentFixture<
2155
- DefaultRenderComponent<Component>
2156
- >
2157
- ```
2158
-
2159
- It happens because `MockRender` generates an additional component to
2160
- render the desired thing and its interface differs.
2161
-
2162
- It returns `MockedComponentFixture<T>` type. The difference is an additional `point` property.
2163
- The best thing about it is that `fixture.point.componentInstance` is typed to the component's class instead of `any`.
2164
-
2165
- ```typescript
2166
- const fixture = MockRender(ComponentToRender);
2167
- fixture.componentInstance; // is a middle component, mostly useless
2168
- fixture.point.componentInstance; // the thing we need
2169
- ```
2170
-
2171
- If you want, you can specify providers for the render passing them via the 3rd parameter.
2172
- It is useful when you want to create mock system tokens / services such as `APP_INITIALIZER`, `DOCUMENT` etc.
2173
-
2174
- ```typescript
2175
- const fixture = MockRender(
2176
- ComponentToRender,
2177
- {},
2178
- {
2179
- providers: [
2180
- SomeService,
2181
- {
2182
- provide: DOCUMENT,
2183
- useValue: MockService(Document),
2184
- },
2185
- ],
2186
- },
2187
- );
2188
- ```
2189
-
2190
- And do not forget to call `fixture.detectChanges()` and / or `await fixture.whenStable()` to reflect changes in
2191
- the render.
2192
-
2193
- There is **an example how to render a custom template in an Angular test** below.
2194
-
2195
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/MockRender/test.spec.ts),
2196
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/MockRender/test.spec.ts&initialpath=%3Fspec%3DMockRender),
2197
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/MockRender/test.spec.ts&initialpath=%3Fspec%3DMockRender).
2198
-
2199
- ```typescript
2200
- describe('MockRender', () => {
2201
- // Do not forget to return the promise of MockBuilder.
2202
- beforeEach(() => MockBuilder(TestedComponent, DependencyModule));
2203
-
2204
- it('renders template', () => {
2205
- const spy = jasmine.createSpy();
2206
- // in case of jest
2207
- // const spy = jest.fn();
2208
-
2209
- const fixture = MockRender(
2210
- `
2211
- <tested
2212
- (trigger)="myListener1($event)"
2213
- [value1]="myParam1"
2214
- value2="check"
2215
- >
2216
- <ng-template #header>
2217
- something as ng-template
2218
- </ng-template>
2219
- something as ng-content
2220
- </tested>
2221
- `,
2222
- {
2223
- myListener1: spy,
2224
- myParam1: 'something1',
2225
- },
2226
- );
2227
-
2228
- // ngMocks.input helps to get the current value of an input on
2229
- // a related debugElement without knowing its owner.
2230
- expect(ngMocks.input(fixture.point, 'value1')).toEqual(
2231
- 'something1',
2232
- );
2233
- expect(ngMocks.input(fixture.point, 'value2')).toEqual('check');
2234
-
2235
- // ngMocks.output does the same with outputs.
2236
- ngMocks.output(fixture.point, 'trigger').emit('foo1');
2237
- expect(spy).toHaveBeenCalledWith('foo1');
2238
- });
2239
-
2240
- it('renders inputs and outputs automatically', () => {
2241
- const spy = jasmine.createSpy();
2242
- // in case of jest
2243
- // const logoClickSpy = jest.fn();
2244
-
2245
- // Generates a template like:
2246
- // <tested [value1]="value1" [value2]="value2"
2247
- // (trigger)="trigger"></tested>.
2248
- const fixture = MockRender(TestedComponent, {
2249
- trigger: spy,
2250
- value1: 'something2',
2251
- });
2252
-
2253
- // Checking the inputs.
2254
- expect(ngMocks.input(fixture.point, 'value1')).toEqual(
2255
- 'something2',
2256
- );
2257
- expect(ngMocks.input(fixture.point, 'value2')).toBeUndefined();
2258
-
2259
- // Checking the outputs.
2260
- ngMocks.output(fixture.point, 'trigger').emit('foo2');
2261
- expect(spy).toHaveBeenCalledWith('foo2');
2262
-
2263
- // checking that an updated value has been passed into
2264
- // the testing component.
2265
- fixture.componentInstance.value1 = 'updated';
2266
- fixture.detectChanges();
2267
- expect(ngMocks.input(fixture.point, 'value1')).toEqual('updated');
2268
- });
2269
- });
2270
- ```
2271
-
2272
- [to the top](#table-of-contents)
2273
-
2274
- ### MockInstance
2275
-
2276
- A mock instance of service or declaration in tests may be customized via `MockInstance`.
2277
- It's useful, when you want to configure spies before its usage.
2278
- It supports: Modules, Components, Directives, Pipes, Services and Tokens.
2279
-
2280
- There are two ways how to customize a mock instance:
2281
-
2282
- - directly define properties and methods
2283
- - return a desired shape
2284
-
2285
- ```ts
2286
- // setting values to instance
2287
- MockInstance(Service, (instance, injector) => {
2288
- instance.prop1 = injector.get(SOME_TOKEN);
2289
- instance.method1 = jasmine.createSpy().and.returnValue(5);
2290
- instance.method2 = value => (instance.prop2 = value);
2291
- });
2292
- // returning a custom shape
2293
- MockInstance(Service, (instance, injector) => ({
2294
- prop1: injector.get(SOME_TOKEN),
2295
- method1: jasmine.createSpy().and.returnValue(5),
2296
- method2: value => (instance.prop2 = value),
2297
- }));
2298
- // a simple shape
2299
- MockInstance(Service, () => ({
2300
- prop1: 1,
2301
- method1: jasmine.createSpy(),
2302
- method2: jasmine.createSpy(),
2303
- }));
2304
- ```
2305
-
2306
- In case of tokens, the handler should return the token value.
2307
-
2308
- ```ts
2309
- MockInstance(TOKEN, (instance, injector) => {
2310
- return injector.get(SOME_OTHER_TOKEN);
2311
- });
2312
- MockInstance(TOKEN, () => true);
2313
- ```
2314
-
2315
- In order to reset the handler, `MockInstance` should be called without it.
2316
-
2317
- ```ts
2318
- MockInstance(Service);
2319
- MockInstance(TOKEN);
2320
- // Or simply one call.
2321
- // It resets all handlers for all declarations.
2322
- MockReset();
2323
- ```
2324
-
2325
- Every call of `MockInstance` overrides the previous handler.
2326
- `MockInstance` can be called anywhere,
2327
- but if it's called in `beforeEach` or in `it`, then the handler has an effect only during the current spec.
2328
-
2329
- ```ts
2330
- beforeAll(() => MockInstance(TOKEN, () => true));
2331
- // If we don't call MockReset,
2332
- // then TOKEN will be true in other suites too.
2333
- // To avoid this side effect, beforeEach should be used.
2334
- afterAll(MockReset);
2335
-
2336
- it('test 1', () => {
2337
- // token is true
2338
- expect(TestBed.get(TOKEN)).toEqual(true);
2339
- });
2340
-
2341
- it('test 2', () => {
2342
- // token is false
2343
- MockInstance(TOKEN, () => false);
2344
- expect(TestBed.get(TOKEN)).toEqual(false);
2345
- });
2346
-
2347
- it('test 3', () => {
2348
- // token is true again
2349
- expect(TestBed.get(TOKEN)).toEqual(true);
2350
- });
2351
- ```
2352
-
2353
- It's definitely the time to use it, when a test fails like:
2354
-
2355
- - [TypeError: Cannot read property 'subscribe' of undefined](#how-to-fix-typeerror-cannot-read-property-subscribe-of-undefined)
2356
- - [TypeError: Cannot read property 'pipe' of undefined](#how-to-fix-typeerror-cannot-read-property-subscribe-of-undefined)
2357
- - or any other issue like reading properties or calling methods of undefined
2358
-
2359
- Or you want to customize a mock declaration which is accessed via:
2360
-
2361
- - `@ViewChild`
2362
- - `@ViewChildren`
2363
- - `@ContentChild`
2364
- - `@ContentChildren`
2365
-
2366
- Let's pretend a situation when our component uses `ViewChild` to access a child component instance.
2367
-
2368
- ```typescript
2369
- class RealComponent implements AfterViewInit {
2370
- @ViewChild(ChildComponent) public readonly child: ChildComponent;
2371
-
2372
- ngAfterViewInit() {
2373
- this.child.update$.subscribe();
2374
- }
2375
- }
2376
- ```
2377
-
2378
- When we test `RealComponent` we would like to have a mock `ChildComponent`,
2379
- and it would mean, if we replaced it with a mock `ChildComponent` then its `update$` would be return `undefined`,
2380
- therefore our test would fail in `ngAfterViewInit` because of [`TypeError: Cannot read property 'subscribe' of undefined`](#how-to-fix-typeerror-cannot-read-property-subscribe-of-undefined).
2381
-
2382
- In our case, we have a component instance created by Angular, and does not look like `TestBed` provides
2383
- a solution here. That's where `ng-mocks` helps again with the `MockInstance` helper function.
2384
- It accepts a class as the first parameter, and a tiny callback describing how to customize its instances as the second one.
2385
-
2386
- ```typescript
2387
- beforeEach(() =>
2388
- MockInstance(ChildComponent, () => ({
2389
- // Now we can customize a mock object of ChildComponent in its ctor call.
2390
- // The object will be extended with the returned object.
2391
- update$: EMPTY,
2392
- })),
2393
- );
2394
- ```
2395
-
2396
- Profit. When Angular creates an instance of `ChildComponent`, the callback is called in its ctor, and `update$` property
2397
- of the instance is an `Observable` instead of `undefined`.
2398
-
2399
- <details><summary>Click to see <strong>a usage example of mock services before initialization in Angular tests</strong></summary>
2400
- <p>
2401
-
2402
- [Source](https://github.com/ike18t/ng-mocks/blob/master/examples/MockInstance/test.spec.ts),
2403
- [StackBlitz](https://stackblitz.com/github/ng-mocks/examples?file=src/examples/MockInstance/test.spec.ts&initialpath=%3Fspec%3DMockInstance),
2404
- [CodeSandbox](https://codesandbox.io/s/github/ng-mocks/examples?file=/src/examples/MockInstance/test.spec.ts&initialpath=%3Fspec%3DMockInstance).
2405
-
2406
- ```typescript
2407
- describe('MockInstance', () => {
2408
- // A normal setup of the TestBed, TargetComponent will be replaced
2409
- // with its mock object.
2410
- // Do not forget to return the promise of MockBuilder.
2411
- beforeEach(() => MockBuilder(RealComponent).mock(ChildComponent));
2412
-
2413
- beforeEach(() => {
2414
- // Because TargetComponent is replaced with its mock object,
2415
- // its update$ is undefined and ngAfterViewInit of the parent
2416
- // component will fail on .subscribe().
2417
- // Let's fix it via defining customization for the mock object.
2418
- MockInstance(ChildComponent, () => ({
2419
- // comment the next line to check the failure.
2420
- update$: EMPTY,
2421
- }));
2422
- });
2423
-
2424
- it('should render', () => {
2425
- // Without the custom initialization rendering would fail here
2426
- // with "Cannot read property 'subscribe' of undefined".
2427
- expect(() => MockRender(RealComponent)).not.toThrow();
2428
- });
2429
- });
2430
- ```
2431
-
2432
- </p>
2433
- </details>
2434
-
2435
- [to the top](#table-of-contents)
2436
-
2437
- ### ngMocks
2438
-
2439
- `ngMocks` provides functions to get attribute and structural directives from an element, find components and create mock objects.
2440
-
2441
- - [`.guts()`](#ngmocksguts)
2442
- - [`.defaultMock()`](#ngmocksdefaultmock)
2443
- - [`.get()`](#ngmocksget)
2444
- - [`.findInstance()`](#ngmocksfindinstance)
2445
- - [`.findInstances()`](#ngmocksfindinstances)
2446
- - [`.find()`](#ngmocksfind)
2447
- - [`.findAll()`](#ngmocksfindall)
2448
- - [`.input()`](#ngmocksinput)
2449
- - [`.output()`](#ngmocksoutput)
2450
- - [`.stub()`](#ngmocksstub)
2451
- - [`.faster()`](#ngmocksfaster)
2452
- - [`.flushTestBed()`](#ngmocksflushtestbed)
2453
- - [`.reset()`](#ngmocksreset)
2454
-
2455
- #### ngMocks.guts
2456
-
2457
- Generates and returns metadata for `TestBed` module.
2458
-
2459
- - `ngMocks.guts( TestingDeclaration, ItsModule )`
2460
- - `ngMocks.guts( [Thing1, Thing2], [ToMock1, ToMock2], [Skip1, Skip2] )`
2461
-
2462
- The first parameter can be a declaration or an array of them which we want to test.
2463
- The second parameter can be a declaration or an array of them out of which we want to create mocks.
2464
- The third parameter can be a declaration or an array of them which we want to exclude.
2465
- They support: Modules, Components, Directives, Pipes, Services and tokens.
2466
-
2467
- If there is a module in the second parameter, then its guts will be replaced with their mocks excluding things from the first parameter.
2468
- Any parameter might be `null` if we need to skip it.
2469
-
2470
- ```typescript
2471
- const ngModuleMeta = ngMocks.guts(Component, ItsModule);
2472
- ```
2473
-
2474
- ```typescript
2475
- const ngModuleMeta = ngMocks.guts(
2476
- [Component1, Component2, Service3],
2477
- [ModuleToMock, DirectiveToMock, WhateverToMock],
2478
- [ServiceToExclude, DirectiveToExclude],
2479
- );
2480
- ```
2481
-
2482
- ```typescript
2483
- const ngModuleMeta = ngMocks.guts(
2484
- null,
2485
- ModuleToMock,
2486
- ComponentToExclude,
2487
- );
2488
- ```
2489
-
2490
- #### ngMocks.defaultMock
2491
-
2492
- Sets default values for mocks in the whole testing environment.
2493
-
2494
- - `ngMocks.defaultMock( Service, (instance, injector) => overrides )` - adds an override for a class
2495
- - `ngMocks.defaultMock( TOKEN, (value, injector) => value )` - adds an override for a token
2496
- - `ngMocks.defaultMock( Component )` - removes overrides
2497
- - `ngMocks.defaultMock( TOKEN )` - removes overrides
2498
-
2499
- The best place to do that is in `src/test.ts` for jasmine or in `src/setupJest.ts` for jest.
2500
-
2501
- For example, if a service or a component has a property that should be an `Observable`.
2502
- Then, we can configure it to be an `EMPTY` stream in the whole test suite.
2503
-
2504
- ```typescript
2505
- declare class MyComponent {
2506
- public url: string;
2507
- public stream$: Observable<void>;
2508
- public getStream(): Observable<void>;
2509
- }
2510
- ```
2511
-
2512
- ```typescript
2513
- // src/test.ts
2514
-
2515
- // the returned object will be applied to the component instance.
2516
- ngMocks.defaultMock(MyComponent, () => ({
2517
- stream$: EMPTY,
2518
- getStream: () => EMPTY,
2519
- }));
2520
-
2521
- // manual override.
2522
- ngMocks.defaultMock(MyComponent, instance => {
2523
- instance.stream$ = EMPTY;
2524
- });
2525
-
2526
- // overriding tokens.
2527
- ngMocks.defaultMock(MY_TOKEN, () => 'DEFAULT_VALUE');
2528
-
2529
- // url will be 'DEFAULT_VALUE'.
2530
- ngMocks.defaultMock(MyComponent, (_, injector) => ({
2531
- url: injector.get(MY_TOKEN),
2532
- }));
2533
-
2534
- // removing all overrides.
2535
- ngMocks.defaultMock(MyComponent);
2536
- ```
2537
-
2538
- #### ngMocks.get
2539
-
2540
- Returns an attribute or structural directive which belongs to the current element.
2541
-
2542
- - `ngMocks.get( debugElement, directive, notFoundValue? )`
2543
-
2544
- ```typescript
2545
- const directive = ngMocks.get(fixture.debugElement, Directive);
2546
- ```
2547
-
2548
- #### ngMocks.findInstance
2549
-
2550
- Returns the first found component, directive, pipe or service which belongs to the current element or its any child.
2551
- If the element isn't specified, then the current fixture is used.
2552
-
2553
- - `ngMocks.findInstance( fixture?, directive, notFoundValue? )`
2554
- - `ngMocks.findInstance( debugElement?, directive, notFoundValue? )`
2555
-
2556
- ```typescript
2557
- const directive1 = ngMocks.findInstance(Directive1);
2558
- const directive2 = ngMocks.findInstance(fixture, Directive2);
2559
- const directive3 = ngMocks.findInstance(
2560
- fixture.debugElement,
2561
- Directive3,
2562
- );
2563
- const pipe = ngMocks.findInstance(fixture.debugElement, MyPipe);
2564
- const service = ngMocks.findInstance(fixture, MyService);
2565
- ```
2566
-
2567
- #### ngMocks.findInstances
2568
-
2569
- Returns an array of all found components, directives, pipes or services which belong to the current element and all its children.
2570
- If the element isn't specified, then the current fixture is used.
2571
-
2572
- - `ngMocks.findInstances( fixture?, directive )`
2573
- - `ngMocks.findInstances( debugElement?, directive )`
2574
-
2575
- ```typescript
2576
- const directives1 = ngMocks.findInstances(Directive1);
2577
- const directives2 = ngMocks.findInstances(fixture, Directive2);
2578
- const directives3 = ngMocks.findInstances(
2579
- fixture.debugElement,
2580
- Directive3,
2581
- );
2582
- const pipes = ngMocks.findInstances(fixture.debugElement, MyPipe);
2583
- const services = ngMocks.findInstance(fixture, MyService);
2584
- ```
2585
-
2586
- #### ngMocks.find
2587
-
2588
- Returns a found DebugElement which belongs to a component with the correctly typed componentInstance,
2589
- or matches a css selector.
2590
- If a root element or a fixture aren't specified, then the current fixture is used.
2591
-
2592
- - `ngMocks.find( fixture?, component, notFoundValue? )`
2593
- - `ngMocks.find( fixture?, cssSelector, notFoundValue? )`
2594
- - `ngMocks.find( debugElement?, component, notFoundValue? )`
2595
- - `ngMocks.find( debugElement?, cssSelector, notFoundValue? )`
2596
-
2597
- ```typescript
2598
- const element1 = ngMocks.find(Component1);
2599
- const element2 = ngMocks.find(fixture, Component2);
2600
- const element3 = ngMocks.find(fixture.debugElement, Component3);
2601
- ```
2602
-
2603
- ```typescript
2604
- const element1 = ngMocks.find('div.con1');
2605
- const element2 = ngMocks.find(fixture, 'div.con2');
2606
- const element3 = ngMocks.find(fixture.debugElement, 'div.con3');
2607
- ```
2608
-
2609
- #### ngMocks.findAll
2610
-
2611
- Returns an array of found DebugElements which belong to a component with the correctly typed componentInstance,
2612
- or match a css selector.
2613
- If a root element or a fixture aren't specified, then the current fixture is used.
2614
-
2615
- - `ngMocks.findAll( fixture?, component )`
2616
- - `ngMocks.findAll( fixture?, cssSelector )`
2617
- - `ngMocks.findAll( debugElement?, component )`
2618
- - `ngMocks.findAll( debugElement?, cssSelector )`
2619
-
2620
- ```typescript
2621
- const elements1 = ngMocks.findAll(Component1);
2622
- const elements2 = ngMocks.findAll(fixture, Component2);
2623
- const elements3 = ngMocks.findAll(fixture.debugElement, Component3);
2624
- ```
2625
-
2626
- ```typescript
2627
- const elements1 = ngMocks.findAll('div.item1');
2628
- const elements2 = ngMocks.findAll(fixture, 'div.item2');
2629
- const elements3 = ngMocks.findAll(fixture.debugElement, 'div.item3');
2630
- ```
2631
-
2632
- #### ngMocks.input
2633
-
2634
- Returns value of an `input` of an element.
2635
- It avoids the issue of knowing the name of a component / directive the input belongs to.
2636
-
2637
- - `ngMocks.input( debugElement, input, notFoundValue? )`
2638
-
2639
- ```typescript
2640
- const inputValue = ngMocks.input(debugElement, 'param1');
2641
- ```
2642
-
2643
- #### ngMocks.output
2644
-
2645
- Returns an emitter of an `output` of an element.
2646
- It avoids the issue of knowing the name of a component / directive the output belongs to.
2647
-
2648
- - `ngMocks.output( debugElement, output, notFoundValue? )`
2649
-
2650
- ```typescript
2651
- const outputEmitter = ngMocks.output(debugElement, 'update');
2652
- ```
2653
-
2654
- #### ngMocks.stub
2655
-
2656
- In case if we want to create stub methods / properties of a service.
2657
-
2658
- - `ngMocks.stub( service, method )`
2659
- - `ngMocks.stub( service, methods )`
2660
- - `ngMocks.stub( service, property, 'get' | 'set' )`
2661
-
2662
- Returns a mock function / spy of the method. If the method has not been replaced with a stub yet - it will.
2663
-
2664
- ```typescript
2665
- const spy: Function = ngMocks.stub(instance, methodName);
2666
- ```
2667
-
2668
- Returns a mock function / spy of the property. If the property has not been replaced with a stub yet - it will.
2669
-
2670
- ```typescript
2671
- const spyGet: Function = ngMocks.stub(instance, propertyName, 'get');
2672
- const spySet: Function = ngMocks.stub(instance, propertyName, 'set');
2673
- ```
2674
-
2675
- Or override properties and methods.
2676
-
2677
- ```typescript
2678
- ngMocks.stub(instance, {
2679
- existingProperty: true,
2680
- existingMethod: jasmine.createSpy(),
2681
- });
2682
- ```
2683
-
2684
- #### ngMocks.faster
2685
-
2686
- `ngMocks.faster()` [optimizes setup](#making-angular-tests-faster) between tests in a suite.
2687
-
2688
- #### ngMocks.flushTestBed
2689
-
2690
- `ngMocks.flushTestBed()` flushes initialization of TestBed.
2691
-
2692
- #### ngMocks.reset
2693
-
2694
- `ngMocks.reset()` resets cache of [`ngMocks`](#ngmocks).
2695
-
2696
- [to the top](#table-of-contents)
2697
-
2698
- ### Helper functions
2699
-
2700
- `ng-mocks` provides several functions which help with **detection of mock objects**.
2701
- For example, they are useful in situations when we want to render `ChildContent` of a mock component,
2702
- or to touch a mock form control.
2703
-
2704
- - [isMockControlValueAccessor](#ismockcontrolvalueaccessor)
2705
- - [isMockValidator](#ismockvalidator)
2706
- - [isMockOf](#ismockof)
2707
- - [isMockedNgDefOf](#ismockedngdefof)
2708
- - [getMockedNgDefOf](#getmockedngdefof)
2709
- - [isNgDef](#isngdef)
2710
- - [getSourceOfMock](#getsourceofmock)
2711
- - [isNgInjectionToken](#isnginjectiontoken)
2712
-
2713
- #### isMockControlValueAccessor
2714
-
2715
- This function helps when you need to access callbacks
2716
- which were set via `registerOnChange` and `registerOnTouched`
2717
- on a mock object that implements `ControlValueAccessor`,
2718
- and to call `__simulateChange`, `__simulateTouch` to trigger them.
2719
- It verifies whether an instance respects `MockControlValueAccessor` interface.
2720
-
2721
- You need it when you get an error like:
2722
-
2723
- - `Property '__simulateChange' does not exist on type ...`
2724
- - `Property '__simulateTouch' does not exist on type ...`
2725
-
2726
- ```typescript
2727
- const instance = ngMocks.findInstance(MyCustomFormControl);
2728
- // instance.__simulateChange('foo'); // doesn't work.
2729
- if (isMockControlValueAccessor(instance)) {
2730
- // now works
2731
- instance.__simulateChange('foo');
2732
- instance.__simulateTouch();
2733
- }
2734
- ```
2735
-
2736
- #### isMockValidator
2737
-
2738
- The function is useful when you need to access the callback
2739
- which was set via `registerOnValidatorChange`
2740
- on a mock object that implements `Validator` or `AsyncValidator`,
2741
- and to call `__simulateValidatorChange` to trigger it.
2742
- It verifies whether an instance respects `MockValidator` interface.
2743
-
2744
- You need it when you get an error like:
2745
-
2746
- - `Property '__simulateValidatorChange' does not exist on type ...`
2747
-
2748
- ```typescript
2749
- const instance = ngMocks.findInstance(MyValidatorDirective);
2750
- // instance.simulateValidatorChange(); // doesn't work.
2751
- if (isMockValidator(instance)) {
2752
- // now works
2753
- instance.__simulateValidatorChange();
2754
- }
2755
- ```
2756
-
2757
- #### isMockOf
2758
-
2759
- This function helps when we want to use `ng-mocks` tools for rendering,
2760
- but typescript doesn't recognize `instance` as a mock object.
2761
-
2762
- You need this when you get an error like:
2763
-
2764
- - `Property '__render' does not exist on type ...`
2765
- - `Property '__hide' does not exist on type ...`
2766
-
2767
- ```typescript
2768
- if (isMockOf(instance, SomeComponent, 'c')) {
2769
- instance.__render('block', '$implicit');
2770
- instance.__hide('block');
2771
- }
2772
- if (isMockOf(instance, StructuralDirective, 'd')) {
2773
- instance.__render('$implicit');
2774
- instance.__hide();
2775
- }
2776
- ```
2777
-
2778
- - `isMockOf( inst, SomeClass, 'm' )` - checks whether `inst` is an instance of `MockedModule<SomeClass>`
2779
- - `isMockOf( inst, SomeClass, 'c' )` - checks whether `inst` is an instance of `MockedComponent<SomeClass>`
2780
- - `isMockOf( inst, SomeClass, 'd' )` - checks whether `inst` is an instance of `MockedDirective<SomeClass>`
2781
- - `isMockOf( inst, SomeClass, 'p' )` - checks whether `inst` is an instance of `MockedPipe<SomeClass>`
2782
- - `isMockOf( inst, SomeClass )` - checks whether `inst` is an instance of mock `SomeClass`
2783
-
2784
- #### isMockedNgDefOf
2785
-
2786
- This function helps when we need to verify that a class is actually a mock class.
2787
-
2788
- - `isMockedNgDefOf( MockClass, SomeClass, 'm' )` - checks whether `MockClass` is a mock object of `SomeClass` and a module
2789
- - `isMockedNgDefOf( MockClass, SomeClass, 'c' )` - checks whether `MockClass` is a mock object of `SomeClass` and a component
2790
- - `isMockedNgDefOf( MockClass, SomeClass, 'd' )` - checks whether `MockClass` is a mock object of `SomeClass` and a directive
2791
- - `isMockedNgDefOf( MockClass, SomeClass, 'p' )` - checks whether `MockClass` is a mock object of `SomeClass` and a pipe
2792
- - `isMockedNgDefOf( MockClass, SomeClass )` - checks whether `MockClass` is a mock object of `SomeClass`
2793
-
2794
- #### getMockedNgDefOf
2795
-
2796
- This function helps when in a test we want to get a mock class of something configured in TestBed.
2797
-
2798
- - `getMockedNgDefOf( SomeClass, 'm' )` - returns an existing `MockedModule<SomeClass>` of `SomeClass`
2799
- - `getMockedNgDefOf( SomeClass, 'c' )` - returns an existing `MockedComponent<SomeClass>` of `SomeClass`
2800
- - `getMockedNgDefOf( SomeClass, 'd' )` - returns an existing `MockedDirective<SomeClass>` of `SomeClass`
2801
- - `getMockedNgDefOf( SomeClass, 'p' )` - returns an existing `MockedPipe<SomeClass>` of `SomeClass`
2802
- - `getMockedNgDefOf( SomeClass )` - returns an existing mock class of `SomeClass`
2803
-
2804
- #### isNgDef
2805
-
2806
- This function verifies how a class has been decorated.
2807
-
2808
- - `isNgDef( SomeClass, 'm' )` - checks whether `SomeClass` is a module
2809
- - `isNgDef( SomeClass, 'c' )` - checks whether `SomeClass` is a component
2810
- - `isNgDef( SomeClass, 'd' )` - checks whether `SomeClass` is a directive
2811
- - `isNgDef( SomeClass, 'p' )` - checks whether `SomeClass` is a pipe
2812
- - `isNgDef( SomeClass, 'i' )` - checks whether `SomeClass` is a service
2813
- - `isNgDef( SomeClass )` - checks whether `SomeClass` is a module / component / directive / pipe / service.
2814
-
2815
- #### getSourceOfMock
2816
-
2817
- This function returns the origin of a mock class.
2818
-
2819
- - `getSourceOfMock( MockClass )` - returns the source class of `MockClass`
2820
-
2821
- #### isNgInjectionToken
2822
-
2823
- This function verifies tokens.
2824
-
2825
- - `isNgInjectionToken( TOKEN )` - checks whether `TOKEN` is a token
2826
-
2827
- [to the top](#table-of-contents)
2828
-
2829
- ### Usage with 3rd-party libraries
2830
-
2831
- `ng-mocks` provides flexibility via [`ngMocks.guts`](#ngmocksguts) and [`MockBuilder`](#mockbuilder)
2832
- that allows developers to use other **Angular testing libraries**,
2833
- and at the same time to **turn dependencies into mocks**.
2834
-
2835
- For example, if we use `@ngneat/spectator` and its functions
2836
- like `createHostFactory`, `createComponentFactory`, `createDirectiveFactory` and so on,
2837
- then to get mock declarations properly we need:
2838
-
2839
- - exclude the component we want to test
2840
- - to turn declarations of its module into mocks
2841
- - export all declarations the module has
2842
-
2843
- if we use [`ngMocks.guts`](#ngmocksguts) we need to skip the first parameter, pass the module
2844
- as the second parameter to export its declaration, and to pass the component as the third one to exclude it.
2845
-
2846
- ```typescript
2847
- const dependencies = ngMocks.guts(null, MyModule, MyComponent);
2848
- const createComponent = createComponentFactory({
2849
- component: MyComponent,
2850
- ...dependencies,
2851
- });
2852
- ```
2853
-
2854
- If we use [`MockBuilder`](#mockbuilder) we need [`.exclude`](#mockbuilderexclude), [`.mock`](#mockbuildermock) and [`exportAll`](#mockbuilder-exportall-flag) flag.
2855
-
2856
- ```typescript
2857
- const dependencies = MockBuilder()
2858
- .exclude(MyComponent)
2859
- .mock(MyModule, {
2860
- exportAll: true,
2861
- })
2862
- .build();
2863
-
2864
- const createComponent = createComponentFactory({
2865
- component: MyComponent,
2866
- ...dependencies,
2867
- });
2868
- ```
2869
-
2870
60
  Profit.
2871
- [Subscribe](https://github.com/ike18t/ng-mocks),
2872
- [like](https://github.com/ike18t/ng-mocks),
2873
- [share](https://twitter.com/intent/tweet?text=Check+ng-mocks+package&url=https%3A%2F%2Fgithub.com%2Fike18t%2Fng-mocks)!
2874
-
2875
- [to the top](#table-of-contents)
2876
-
2877
- ### Making Angular tests faster
2878
-
2879
- There is a `ngMocks.faster` feature that optimizes setup of similar test modules between tests
2880
- and reduces required time on their execution.
2881
-
2882
- Imagine a situation when `beforeEach` creates the same setup used by dozens of `it`.
2883
- This is the case where `ngMocks.faster` might be useful, simply call it before `beforeEach` and
2884
- **the Angular tests will run faster**.
2885
-
2886
- ```typescript
2887
- describe('performance:correct', () => {
2888
- ngMocks.faster(); // <-- add it before
2889
-
2890
- // The TestBed is not going to be changed between tests.
2891
- beforeEach(() => {
2892
- return MockBuilder(TargetComponent, TargetModule).keep(
2893
- TargetService,
2894
- );
2895
- });
2896
-
2897
- it('...', () => {
2898
- // ...
2899
- });
2900
-
2901
- it('...', () => {
2902
- // ...
2903
- });
2904
-
2905
- // ...
2906
- });
2907
- ```
2908
-
2909
- If a test creates spies in `beforeEach` then this should be tuned,
2910
- because `ngMocks.faster` will detect this difference and display a notice.
2911
-
2912
- A possible solution is usage of [MockInstance](#mockinstance) or to move creation of spies
2913
- outside of `beforeEach`.
2914
-
2915
- <details><summary>Click to see <strong>an example of MockInstance</strong></summary>
2916
- <p>
2917
-
2918
- ```typescript
2919
- describe('beforeEach:mock-instance', () => {
2920
- ngMocks.faster(); // <-- add it before
2921
-
2922
- // A normal setup of the TestBed, TargetService will be replaced
2923
- // with its mock object.
2924
- // Do not forget to return the promise of MockBuilder.
2925
- beforeEach(() => MockBuilder(TargetComponent).mock(TargetService));
2926
-
2927
- // Configuring behavior of the mock TargetService.
2928
- beforeAll(() => {
2929
- MockInstance(TargetService, {
2930
- init: instance => {
2931
- instance.method = jasmine.createSpy().and.returnValue(5);
2932
- // in case of jest
2933
- // instance.method = jest.fn().mockReturnValue(5);
2934
- instance.prop = 123;
2935
- },
2936
- });
2937
- });
2938
-
2939
- // Do not forget to reset the spy between runs.
2940
- afterAll(MockReset);
2941
- });
2942
- ```
2943
-
2944
- </p>
2945
- </details>
2946
-
2947
- <details><summary>Click to see <strong>an example of optimizing spies in beforeEach</strong></summary>
2948
- <p>
2949
-
2950
- ```typescript
2951
- describe('beforeEach:manual-spy', () => {
2952
- ngMocks.faster(); // <-- add it before
2953
-
2954
- // Creating a spy outside of `beforeEach` allows its pointer being
2955
- // the same between tests and this let ngMocks.faster do its job.
2956
- const mock = {
2957
- method: jasmine.createSpy().and.returnValue(5),
2958
- // in case of jest
2959
- // method: jest.fn().mockReturnValue(5),
2960
- prop: 123,
2961
- };
2962
-
2963
- // Do not forget to reset the spy between runs.
2964
- beforeEach(() => {
2965
- mock.method.calls.reset();
2966
- // in case of jest
2967
- // mock.method = jest.fn().mockReturnValue(5);
2968
- mock.prop = 123;
2969
- });
2970
-
2971
- // A normal setup of the TestBed, TargetService will be replaced
2972
- // with its mock object.
2973
- beforeEach(() => {
2974
- return MockBuilder(TargetComponent).mock(TargetService, mock);
2975
- });
2976
- });
2977
- ```
2978
-
2979
- </p>
2980
- </details>
2981
-
2982
- [to the top](#table-of-contents)
2983
-
2984
- ### Auto Spy
2985
-
2986
- By default, all mock methods are empty functions which return `undefined`.
2987
- If you want **to spy automatically all methods of services, components**, directives and pipes in Angular tests then
2988
- add the next code to `src/test.ts`.
2989
-
2990
- ```typescript
2991
- import { ngMocks } from 'ng-mocks';
2992
-
2993
- ngMocks.autoSpy('jasmine');
2994
- // // uncomment in case if existing tests are with spies already.
2995
- // jasmine.getEnv().allowRespy(true);
2996
- ```
2997
-
2998
- In case of jest add it to `src/setupJest.ts`.
2999
-
3000
- ```typescript
3001
- import { ngMocks } from 'ng-mocks';
3002
-
3003
- ngMocks.autoSpy('jest');
3004
- ```
3005
-
3006
- You can provide your own factory function if you need a customized initialization.
3007
- It should return a custom spy function.
3008
-
3009
- ```typescript
3010
- ngMocks.autoSpy(spyName => {
3011
- return () => {
3012
- console.log(`call: ${spyName}`);
3013
- };
3014
- });
3015
- ```
3016
-
3017
- Pass `default` as the parameter, if you want to get the default behavior.
3018
-
3019
- ```typescript
3020
- ngMocks.autoSpy('default');
3021
- ```
3022
-
3023
- Also, it remembers the calls, and you can reset to the previous config.
3024
- It might be useful if you need to change **auto spy behavior in a test** via `beforeEach` or `beforeAll`,
3025
- and restore it later in `afterEach` or `afterAll` without caring what it was.
3026
-
3027
- ```typescript
3028
- beforeEach(() => ngMocks.autoSpy('jasmine'));
3029
- beforeEach(() => ngMocks.autoSpy('default'));
3030
- beforeEach(() => ngMocks.autoSpy('jasmine'));
3031
- afterEach(() => ngMocks.autoSpy('reset')); // now it's default
3032
- afterEach(() => ngMocks.autoSpy('reset')); // now it's jasmine
3033
- // out of calls, now it's default
3034
- afterEach(() => ngMocks.autoSpy('reset'));
3035
- ```
3036
-
3037
- [to the top](#table-of-contents)
3038
-
3039
- ## How to fix an error in Angular tests
3040
-
3041
- We may encounter different unpleasant issues, when we create mocks in testing environment.
3042
-
3043
- There is a list of most common issues and their solutions below,
3044
- feel free to [contact us](#find-an-issue-or-have-a-question-or-a-request) if you are facing or struggling with them or anything else.
3045
-
3046
- - [`TypeError: Cannot read property 'subscribe' of undefined`](#how-to-fix-typeerror-cannot-read-property-subscribe-of-undefined)
3047
- - [`Error: Type is part of the declarations of 2 modules`](#how-to-fix-error-type-is-part-of-the-declarations-of-2-modules)
3048
- - [`Error: Directive has no selector, please add it!`](#how-to-fix-error-directive-has-no-selector-please-add-it)
3049
- - [`Template parse errors: <component> is not a known element`](#how-to-fix-template-parse-errors-component-is-not-a-known-element)
3050
-
3051
- ### How to fix `TypeError: Cannot read property 'subscribe' of undefined`
3052
-
3053
- This issue means that something has been replaced with a mock object and returns a dummy result (`undefined`) instead of observable streams.
3054
-
3055
- There is an answer for this error in the section called [How to mock observables](#how-to-mock-observables),
3056
- if the error has been triggered by a mock service, and its property is of type of `undefined`.
3057
-
3058
- Or you might check [`MockInstance`](#mockinstance) or [`ngMocks.defaultMock`](#ngmocksdefaultmock)
3059
- in the case if the error has been caused by a mock component or a mock directive.
3060
-
3061
- [to the top](#table-of-contents)
3062
-
3063
- ### How to fix `Error: Type is part of the declarations of 2 modules`
3064
-
3065
- If you encounter the issue, highly likely it means that a mock declaration,
3066
- usually a mock module, contains something, that is declared in the `TestBed` module directly.
3067
-
3068
- Let's imagine a situation that we have a module which exports declarations, for example directives, we need in our test.
3069
- At the same time, we have another module that has other declarations, our component depends on,
3070
- we would like to turn into a mock object, but, at the same time, it imports the same module we want to keep as it is
3071
- via an import in `TestBed`.
3072
-
3073
- ```typescript
3074
- TestBed.configureTestingModule({
3075
- imports: [
3076
- SharedModule,
3077
- MockModule(ModuleWithServicesAndSharedModule),
3078
- ],
3079
- declarations: [ComponentToTest],
3080
- });
3081
- ```
3082
-
3083
- The problem is clear: when we create the mock module, [`MockModule`](#how-to-mock-modules) recursively creates its mock dependencies, and, therefore, it creates a mock class of `SharedModule`.
3084
- Now imported and mock declarations are part of 2 modules.
3085
-
3086
- To solve this, we need to let [`MockModule`](#how-to-mock-modules) know, that `SharedModule` should stay as it is.
3087
-
3088
- There are good and bad news.
3089
- The bad news is that [`MockModule`](#how-to-mock-modules) does not support that,
3090
- but the good news is that `ng-mocks` has [`MockBuilder`](#mockbuilder) for such a complicated case.
3091
- The only problem now is to rewrite `beforeEach` to use [`MockBuilder`](#mockbuilder) instead of [`MockModule`](#how-to-mock-modules).
3092
- A possible solution might look like:
3093
-
3094
- ```typescript
3095
- beforeEach(() => {
3096
- return MockBuilder(ComponentToTest)
3097
- .keep(SharedModule)
3098
- .mock(ModuleWithServicesAndSharedModule);
3099
- });
3100
- ```
3101
-
3102
- The configuration says that we want to test `ComponentToTest`, which depends on `SharedModule` and `ModuleWithServicesAndSharedModule`, but `SharedModule` should stay as it is.
3103
-
3104
- Now, during the building process, [`MockBuilder`](#mockbuilder) will keep `SharedModule` as it is, although it is a dependency of the mock module, and that avoids declarations of the same things in 2 modules.
3105
-
3106
- More detailed information how to use it you can find in the section called [`MockBuilder`](#mockbuilder).
3107
-
3108
- [to the top](#table-of-contents)
3109
-
3110
- ### How to fix Error: Directive has no selector, please add it!
3111
-
3112
- This issue means that a module imports a declaration (usually a parent class) which does not have a selector.
3113
- Such directives and components are created during a [migration](https://angular.io/guide/migration-undecorated-classes)
3114
- if their parent classes haven't been decorated yet.
3115
-
3116
- The right fix is to remove these declarations from modules, only final classes should be specified in there.
3117
-
3118
- If you cannot remove them for a reason, for example, it is a 3rd-party library,
3119
- then you need to write tests with usage of [`MockBuilder`](#mockbuilder) and its [`.exclude`](#mockbuilderexclude) feature.
3120
-
3121
- ```typescript
3122
- beforeEach(() => {
3123
- return MockBuilder(MyComponent, MyModule).exclude(ParentDirective);
3124
- });
3125
- ```
3126
-
3127
- That fixes declarations of the module and resolves the error,
3128
- a directive without a selector has been gone from the module definition.
3129
-
3130
- [to the top](#table-of-contents)
3131
-
3132
- ### How to fix Template parse errors: \<component\> is not a known element
3133
-
3134
- This error might happen in a test when we have a mock module of the module
3135
- a testing component depends on, but its declarations have not been exported.
3136
-
3137
- ```typescript
3138
- @NgModule({
3139
- declarations: [DependencyComponent],
3140
- })
3141
- class MyModule {}
3142
- ```
3143
-
3144
- ```typescript
3145
- beforeEach(() => {
3146
- TestBed.configureTestingModule({
3147
- declarations: [
3148
- MyComponent, // <- the only declaration we care about.
3149
- ],
3150
- imports: [MockModule(MyModule)],
3151
- });
3152
- return TestBed.compileComponents();
3153
- });
3154
- ```
3155
-
3156
- In this case, a test will throw `Template parse errors: <DependencyComponent> is not a known element`.
3157
-
3158
- The problem here is that `DependencyComponent` isn't exported,
3159
- and to get access to a mock `DependencyComponent` we need either
3160
- to declare it on the same level where `MyComponent` has been declared
3161
- or to export `DependencyComponent`.
3162
-
3163
- there are 3 solutions to do it:
3164
-
3165
- 1. to call [`MockComponent`](#how-to-mock-components) on it directly in the `TestBed`
3166
-
3167
- ```typescript
3168
- beforeEach(() => {
3169
- TestBed.configureTestingModule({
3170
- declarations: [
3171
- MyComponent,
3172
- MockComponent(DependencyComponent),
3173
- ],
3174
- });
3175
- return TestBed.compileComponents();
3176
- });
3177
- ```
3178
-
3179
- 2. to use [`ngMocks.guts`](#ngmocksguts),
3180
- it does the same things as the first solution,
3181
- but provides mocks of all imports and declarations from `MyModule`.
3182
61
 
3183
- ```typescript
3184
- beforeEach(() => {
3185
- TestBed.configureTestingModule(
3186
- ngMocks.guts(MyComponent, MyModule),
3187
- );
3188
- return TestBed.compileComponents();
3189
- });
3190
- ```
62
+ ## Extra
3191
63
 
3192
- 3. to use [`MockBuilder`](#mockbuilder),
3193
- its behavior differs from the solutions above. It creates a mock `MyModule`,
3194
- that exports all its imports and declarations including a mock `DependencyComponent`.
64
+ Please support, if you like it:
3195
65
 
3196
- ```typescript
3197
- // Do not forget to return the promise of MockBuilder.
3198
- beforeEach(() => MockBuilder(MyComponent, MyModule));
3199
- ```
66
+ - [give a star on GitHub](https://github.com/ike18t/ng-mocks)
67
+ - [share on twitter](https://twitter.com/intent/tweet?text=Check+ng-mocks+package&url=https%3A%2F%2Fgithub.com%2Fike18t%2Fng-mocks)
3200
68
 
3201
- Profit. More detailed information about pros and cons of each approach you can read in
3202
- [motivation and easy start from ng-mocks](#motivation-and-easy-start).
69
+ Thank you!
3203
70
 
3204
- [to the top](#table-of-contents)
71
+ P.S. Feel free to [contact us](https://ng-mocks.sudo.eu/need-help) if you need help.