ngx-speculoos 12.0.0 → 13.0.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.
- package/README.md +151 -10
- package/fesm2022/ngx-speculoos.mjs +99 -29
- package/fesm2022/ngx-speculoos.mjs.map +1 -1
- package/lib/component-tester.d.ts +13 -2
- package/lib/matchers.d.ts +0 -1
- package/lib/mock.d.ts +0 -1
- package/lib/providers.d.ts +11 -0
- package/lib/test-element.d.ts +2 -2
- package/lib/test-html-element.d.ts +1 -1
- package/lib/test-input.d.ts +3 -3
- package/lib/test-select.d.ts +3 -3
- package/lib/test-textarea.d.ts +1 -1
- package/package.json +5 -7
- package/public_api.d.ts +2 -1
- package/esm2022/jasmine-matchers.mjs +0 -2
- package/esm2022/lib/component-tester.mjs +0 -154
- package/esm2022/lib/matchers.mjs +0 -283
- package/esm2022/lib/mock.mjs +0 -25
- package/esm2022/lib/route.mjs +0 -269
- package/esm2022/lib/routing-tester.mjs +0 -43
- package/esm2022/lib/test-button.mjs +0 -16
- package/esm2022/lib/test-element-querier.mjs +0 -140
- package/esm2022/lib/test-element.mjs +0 -142
- package/esm2022/lib/test-html-element.mjs +0 -25
- package/esm2022/lib/test-input.mjs +0 -50
- package/esm2022/lib/test-select.mjs +0 -95
- package/esm2022/lib/test-textarea.mjs +0 -30
- package/esm2022/ngx-speculoos.mjs +0 -5
- package/esm2022/public_api.mjs +0 -17
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@ how to write Angular unit tests.
|
|
|
18
18
|
- [Getting started](#getting-started)
|
|
19
19
|
- [Features in details](#features-in-details)
|
|
20
20
|
- [ComponentTester](#componenttester)
|
|
21
|
+
- [Automatic change detection](#automatic-change-detection)
|
|
21
22
|
- [Queries](#queries)
|
|
22
23
|
- [Queries for elements](#queries-for-elements)
|
|
23
24
|
- [CSS and Type selectors](#css-and-type-selectors)
|
|
@@ -37,6 +38,7 @@ how to write Angular unit tests.
|
|
|
37
38
|
- [Can I use the TestElement methods to act on the component element itself, rather than a sub-element?](#can-i-use-the-testelement-methods-to-act-on-the-component-element-itself-rather-than-a-sub-element)
|
|
38
39
|
- [Issues, questions](#issues-questions)
|
|
39
40
|
- [Complete example](#complete-example)
|
|
41
|
+
- [Upgrading to v13](#upgrading-to-v13)
|
|
40
42
|
|
|
41
43
|
## Quick presentation
|
|
42
44
|
|
|
@@ -181,7 +183,7 @@ describe('My component', () => {
|
|
|
181
183
|
});
|
|
182
184
|
|
|
183
185
|
tester = new MyComponentTester();
|
|
184
|
-
tester.
|
|
186
|
+
tester.change();
|
|
185
187
|
});
|
|
186
188
|
|
|
187
189
|
it('should ...', () => {
|
|
@@ -189,6 +191,74 @@ describe('My component', () => {
|
|
|
189
191
|
});
|
|
190
192
|
```
|
|
191
193
|
|
|
194
|
+
### Automatic change detection
|
|
195
|
+
|
|
196
|
+
The future of Angular is zoneless. Without ZoneJS, components have to make sure to properly notify
|
|
197
|
+
Angular that they must be checked for changes, typically by updating signals.
|
|
198
|
+
Instead of imperatively triggering change detections in tests, it's thus a better idea to let
|
|
199
|
+
Angular decide if change detection must be run, in order to spot bugs where the component doesn't
|
|
200
|
+
properly handle its state changes.
|
|
201
|
+
|
|
202
|
+
This can be done by:
|
|
203
|
+
|
|
204
|
+
- adding a provider in the testing module to configure the fixtures to be in _automatic_ mode
|
|
205
|
+
- awaiting the component fixture stability when the test *thinks* that a change detection should
|
|
206
|
+
automatically happen.
|
|
207
|
+
|
|
208
|
+
When the `provideAutomaticChangeDetection()` provider is added, the `ComponentTester` will run in
|
|
209
|
+
_automatic_ mode. In this mode, calling `detectChanges()` throws an error, because you should always
|
|
210
|
+
let Angular decide if change detection is necessary.
|
|
211
|
+
|
|
212
|
+
Here's an example of a test that uses this technique:
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
class AppComponentTester extends ComponentTester<AppComponent> {
|
|
216
|
+
constructor() {
|
|
217
|
+
super(AppComponent);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
get incrementButton() {
|
|
221
|
+
return this.button('button');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
get count() {
|
|
225
|
+
return this.element('#count');
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
describe('AppComponent', () => {
|
|
230
|
+
let tester: AppComponentTester;
|
|
231
|
+
|
|
232
|
+
beforeEach(async () => {
|
|
233
|
+
TestBed.configureTestingModule({
|
|
234
|
+
providers: [
|
|
235
|
+
provideComponentFixtureAutoDetection(),
|
|
236
|
+
provideExperimentalZonelessChangeDetection() // if you already uses zoneless also add this provider
|
|
237
|
+
]
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
jasmine.addMatchers(speculoosMatchers);
|
|
241
|
+
|
|
242
|
+
tester = new AppComponentTester();
|
|
243
|
+
// a first call to change() is necessary to let Angular run its first change detection
|
|
244
|
+
await tester.change();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('should display the counter value and increment it', async () => {
|
|
248
|
+
expect(tester.count).toHaveText('0');
|
|
249
|
+
|
|
250
|
+
// this clicks the button and then lets Angular decide if a CD is necessary, and waits until
|
|
251
|
+
// the DOM has been updated (or not)
|
|
252
|
+
await tester.incrementButton.click();
|
|
253
|
+
|
|
254
|
+
expect(tester.count).toHaveText('1');
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
In _automatic_ mode, your test functions should be `async`, and each action you do with the elements
|
|
260
|
+
(`click()`, `dispatchEvent`, etc.) should be awaited.
|
|
261
|
+
|
|
192
262
|
### Queries
|
|
193
263
|
|
|
194
264
|
#### Queries for elements
|
|
@@ -281,12 +351,12 @@ class TestDatepicker extends TestHtmlElement<HTMLElement> {
|
|
|
281
351
|
return this.input('input');
|
|
282
352
|
}
|
|
283
353
|
|
|
284
|
-
setDate(year: number, month: number, day: number) {
|
|
285
|
-
this.inputField.fillWith(`${year}-${month}-${day}`);
|
|
354
|
+
async setDate(year: number, month: number, day: number) {
|
|
355
|
+
await this.inputField.fillWith(`${year}-${month}-${day}`);
|
|
286
356
|
}
|
|
287
357
|
|
|
288
|
-
toggleDropdown() {
|
|
289
|
-
this.button('button').click();
|
|
358
|
+
async toggleDropdown() {
|
|
359
|
+
await this.button('button').click();
|
|
290
360
|
}
|
|
291
361
|
}
|
|
292
362
|
```
|
|
@@ -301,14 +371,26 @@ get birthDate() {
|
|
|
301
371
|
```
|
|
302
372
|
|
|
303
373
|
```typescript
|
|
304
|
-
it('should not save if birth date is in the future') {
|
|
374
|
+
it('should not save if birth date is in the future', () =>) {
|
|
305
375
|
// ...
|
|
306
376
|
tester.birthDate.setDate(2200, 1, 1);
|
|
307
377
|
tester.save.click();
|
|
308
378
|
expect(userService.create).not.toHaveBenCalled();
|
|
309
|
-
}
|
|
379
|
+
});
|
|
310
380
|
```
|
|
311
381
|
|
|
382
|
+
or, in _automatic_ mode
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
it('should not save if birth date is in the future'), async () => {
|
|
386
|
+
// ...
|
|
387
|
+
await tester.birthDate.setDate(2200, 1, 1);
|
|
388
|
+
await tester.save.click();
|
|
389
|
+
expect(userService.create).not.toHaveBenCalled();
|
|
390
|
+
});
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
|
|
312
394
|
#### Subqueries
|
|
313
395
|
|
|
314
396
|
A query is made from the root `ComponentTester`. But `TestElement` themselves also support queries.
|
|
@@ -540,10 +622,10 @@ using the usual queries.
|
|
|
540
622
|
|
|
541
623
|
## Gotchas
|
|
542
624
|
|
|
543
|
-
### When do I need to call `detectChanges()`?
|
|
625
|
+
### When do I need to call `change` or `detectChanges()`?
|
|
544
626
|
|
|
545
|
-
|
|
546
|
-
But you still need to call `detectChanges()` by yourself in the other cases:
|
|
627
|
+
In _imperative_ mode, any event dispatched through a `TestElement` automatically calls `detectChanges()` for you.
|
|
628
|
+
But you still need to call `change()` or `detectChanges()` by yourself in the other cases:
|
|
547
629
|
|
|
548
630
|
- to actually initialize your component. Sometimes, you want to configure some mocks before the `ngOnInit()`
|
|
549
631
|
method of your component is called. That's why creating a `ComponentTester` does not automatically call
|
|
@@ -553,6 +635,15 @@ But you still need to call `detectChanges()` by yourself in the other cases:
|
|
|
553
635
|
by changing the state, or emitting an event through a subject, or triggering a navigation
|
|
554
636
|
from the `ActivatedRouteStub`
|
|
555
637
|
|
|
638
|
+
Note that, in _imperative_ mode, `change()` calls `detectChanges()`. So you can call either one of the other
|
|
639
|
+
when you want to trigger a change detection.
|
|
640
|
+
|
|
641
|
+
In _automatic_ mode, any event dispatched through a `TestElement` automatically calls `await change()` for you.
|
|
642
|
+
But you still need to call `await change()` by yourself in the same other cases as in the _imperative_ mode:
|
|
643
|
+
|
|
644
|
+
- to actually initialize your component.
|
|
645
|
+
- to force change detection once you've changed the state of your component without dispatching an event.
|
|
646
|
+
|
|
556
647
|
### Can I use the `TestElement` methods to act on the component element itself, rather than a sub-element?
|
|
557
648
|
|
|
558
649
|
Yes. The `ComponentTester` has a `testElement` property, which is the `TestHtmlElement` wrapping the component's element.
|
|
@@ -564,3 +655,53 @@ Please, provide feedback by filing issues, or by submitting pull requests, to th
|
|
|
564
655
|
## Complete example
|
|
565
656
|
|
|
566
657
|
You can look at a minimal complete example in the [demo](https://github.com/Ninja-Squad/ngx-speculoos/tree/master/projects/demo/src/app) project.
|
|
658
|
+
|
|
659
|
+
## Upgrading to v13
|
|
660
|
+
|
|
661
|
+
Version 13 of `ngx-speculoos` introduces the _automatic_ mode, consisting in using automatic change detection
|
|
662
|
+
instead of imperatively running change detections. See the [Automatic change detection](#automatic-change-detection)
|
|
663
|
+
section above for details.
|
|
664
|
+
|
|
665
|
+
As a result, all the methods that used to call `detectChanges()` for you now return a `Promise` instead of returning
|
|
666
|
+
`void`. In _imperative_ mode (the default), they are in fact synchronous and call `detectChanges()`, just as before.
|
|
667
|
+
In _automatic_ mode however, they call `await change()` and should thus be awaited.
|
|
668
|
+
|
|
669
|
+
Your tests should generally keep compiling and running without changes.
|
|
670
|
+
But if you created custom test elements which override methods that now return a promise, and return something
|
|
671
|
+
other than `void`, for example:
|
|
672
|
+
|
|
673
|
+
```typescript
|
|
674
|
+
class CustomInput extends TestInput {
|
|
675
|
+
//...
|
|
676
|
+
fillWith(s: string): CustomInput {
|
|
677
|
+
super.fillWith(s);
|
|
678
|
+
return this;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
Then that won't compile anymore.
|
|
684
|
+
|
|
685
|
+
And in general, if you want your custom test element to be usable in both modes, all their method that explicitly
|
|
686
|
+
or indirectly called `detectChanges()` should now return a promise and explicitly of indirectly call `await change()`.
|
|
687
|
+
For example:
|
|
688
|
+
|
|
689
|
+
```typescript
|
|
690
|
+
class CustomInput extends TestHtmlElement {
|
|
691
|
+
//...
|
|
692
|
+
async fillInput(s: string): Promise<void> {
|
|
693
|
+
await this.element('input').fillWith(s);
|
|
694
|
+
// ...
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
async clickButton(): Promise<void> {
|
|
698
|
+
await this.element('button').click();
|
|
699
|
+
// ...
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
async changeState(): Promise<void> {
|
|
703
|
+
this.component(Foo).doSomething();
|
|
704
|
+
await this.change();
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
```
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
|
1
|
+
import { TestBed, ComponentFixture, ComponentFixtureAutoDetect } from '@angular/core/testing';
|
|
2
2
|
import { By } from '@angular/platform-browser';
|
|
3
3
|
import { RouterTestingHarness } from '@angular/router/testing';
|
|
4
4
|
import { Router, ActivatedRouteSnapshot, convertToParamMap, ActivatedRoute } from '@angular/router';
|
|
5
5
|
import { BehaviorSubject } from 'rxjs';
|
|
6
|
+
import { makeEnvironmentProviders } from '@angular/core';
|
|
7
|
+
|
|
8
|
+
"use strict";
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* A wrapped DOM element, providing additional methods and attributes helping with writing tests
|
|
9
12
|
*/
|
|
10
13
|
class TestElement {
|
|
14
|
+
tester;
|
|
15
|
+
debugElement;
|
|
16
|
+
querier;
|
|
11
17
|
constructor(tester,
|
|
12
18
|
/**
|
|
13
19
|
* the wrapped debug element
|
|
@@ -29,16 +35,16 @@ class TestElement {
|
|
|
29
35
|
/**
|
|
30
36
|
* dispatches an event of the given type from the wrapped element, then triggers a change detection
|
|
31
37
|
*/
|
|
32
|
-
dispatchEventOfType(type) {
|
|
38
|
+
async dispatchEventOfType(type) {
|
|
33
39
|
this.nativeElement.dispatchEvent(new Event(type));
|
|
34
|
-
this.tester.
|
|
40
|
+
await this.tester.change();
|
|
35
41
|
}
|
|
36
42
|
/**
|
|
37
43
|
* dispatches the given event from the wrapped element, then triggers a change detection
|
|
38
44
|
*/
|
|
39
|
-
dispatchEvent(event) {
|
|
45
|
+
async dispatchEvent(event) {
|
|
40
46
|
this.nativeElement.dispatchEvent(event);
|
|
41
|
-
this.tester.
|
|
47
|
+
await this.tester.change();
|
|
42
48
|
}
|
|
43
49
|
/**
|
|
44
50
|
* Gets the CSS classes of the wrapped element, as an array
|
|
@@ -155,9 +161,9 @@ class TestHtmlElement extends TestElement {
|
|
|
155
161
|
/**
|
|
156
162
|
* Clicks on the wrapped element, then triggers a change detection
|
|
157
163
|
*/
|
|
158
|
-
click() {
|
|
164
|
+
async click() {
|
|
159
165
|
this.nativeElement.click();
|
|
160
|
-
this.tester.
|
|
166
|
+
await this.tester.change();
|
|
161
167
|
}
|
|
162
168
|
/**
|
|
163
169
|
* Tests if the element is visible, in the same meaning (and implementation) as in jQuery, i.e.
|
|
@@ -200,7 +206,7 @@ class TestSelect extends TestHtmlElement {
|
|
|
200
206
|
throw new Error(`The index ${index} is out of bounds`);
|
|
201
207
|
}
|
|
202
208
|
this.nativeElement.selectedIndex = index;
|
|
203
|
-
this.dispatchEventOfType('change');
|
|
209
|
+
return this.dispatchEventOfType('change');
|
|
204
210
|
}
|
|
205
211
|
/**
|
|
206
212
|
* Selects the first option with the given value, then dispatches an event of type change and triggers a change detection.
|
|
@@ -209,10 +215,10 @@ class TestSelect extends TestHtmlElement {
|
|
|
209
215
|
selectValue(value) {
|
|
210
216
|
const index = this.optionValues.indexOf(value);
|
|
211
217
|
if (index >= 0) {
|
|
212
|
-
this.selectIndex(index);
|
|
218
|
+
return this.selectIndex(index);
|
|
213
219
|
}
|
|
214
220
|
else {
|
|
215
|
-
throw new Error(`The value ${value} is not part of the option values (${this.optionValues.join(', ')}`);
|
|
221
|
+
throw new Error(`The value ${value} is not part of the option values (${this.optionValues.join(', ')})`);
|
|
216
222
|
}
|
|
217
223
|
}
|
|
218
224
|
/**
|
|
@@ -222,10 +228,10 @@ class TestSelect extends TestHtmlElement {
|
|
|
222
228
|
selectLabel(label) {
|
|
223
229
|
const index = this.optionLabels.indexOf(label);
|
|
224
230
|
if (index >= 0) {
|
|
225
|
-
this.selectIndex(index);
|
|
231
|
+
return this.selectIndex(index);
|
|
226
232
|
}
|
|
227
233
|
else {
|
|
228
|
-
throw new Error(`The label ${label} is not part of the option labels (${this.optionLabels.join(', ')}`);
|
|
234
|
+
throw new Error(`The label ${label} is not part of the option labels (${this.optionLabels.join(', ')})`);
|
|
229
235
|
}
|
|
230
236
|
}
|
|
231
237
|
/**
|
|
@@ -289,9 +295,9 @@ class TestTextArea extends TestHtmlElement {
|
|
|
289
295
|
* Sets the value of the wrapped textarea, then dispatches an event of type input and triggers a change detection
|
|
290
296
|
* @param value the new value of the textarea
|
|
291
297
|
*/
|
|
292
|
-
fillWith(value) {
|
|
298
|
+
async fillWith(value) {
|
|
293
299
|
this.nativeElement.value = value;
|
|
294
|
-
this.dispatchEventOfType('input');
|
|
300
|
+
await this.dispatchEventOfType('input');
|
|
295
301
|
}
|
|
296
302
|
/**
|
|
297
303
|
* the value of the wrapped textarea
|
|
@@ -318,9 +324,9 @@ class TestInput extends TestHtmlElement {
|
|
|
318
324
|
* Sets the value of the wrapped input, then dispatches an event of type input and triggers a change detection
|
|
319
325
|
* @param value the new value of the input
|
|
320
326
|
*/
|
|
321
|
-
fillWith(value) {
|
|
327
|
+
async fillWith(value) {
|
|
322
328
|
this.nativeElement.value = value;
|
|
323
|
-
this.dispatchEventOfType('input');
|
|
329
|
+
await this.dispatchEventOfType('input');
|
|
324
330
|
}
|
|
325
331
|
/**
|
|
326
332
|
* the value of the wrapped input
|
|
@@ -343,16 +349,16 @@ class TestInput extends TestHtmlElement {
|
|
|
343
349
|
/**
|
|
344
350
|
* Checks the wrapped input, then dispatches an event of type change and triggers a change detection
|
|
345
351
|
*/
|
|
346
|
-
check() {
|
|
352
|
+
async check() {
|
|
347
353
|
this.nativeElement.checked = true;
|
|
348
|
-
this.dispatchEventOfType('change');
|
|
354
|
+
await this.dispatchEventOfType('change');
|
|
349
355
|
}
|
|
350
356
|
/**
|
|
351
357
|
* Unchecks the wrapped input, then dispatches an event of type change and triggers a change detection
|
|
352
358
|
*/
|
|
353
|
-
uncheck() {
|
|
359
|
+
async uncheck() {
|
|
354
360
|
this.nativeElement.checked = false;
|
|
355
|
-
this.dispatchEventOfType('change');
|
|
361
|
+
await this.dispatchEventOfType('change');
|
|
356
362
|
}
|
|
357
363
|
}
|
|
358
364
|
|
|
@@ -361,6 +367,8 @@ class TestInput extends TestHtmlElement {
|
|
|
361
367
|
* @internal
|
|
362
368
|
*/
|
|
363
369
|
class TestElementQuerier {
|
|
370
|
+
tester;
|
|
371
|
+
root;
|
|
364
372
|
constructor(tester, root) {
|
|
365
373
|
this.tester = tester;
|
|
366
374
|
this.root = root;
|
|
@@ -497,6 +505,18 @@ class TestElementQuerier {
|
|
|
497
505
|
* @param <C> the type of the component to test
|
|
498
506
|
*/
|
|
499
507
|
class ComponentTester {
|
|
508
|
+
/**
|
|
509
|
+
* The test element of the component
|
|
510
|
+
*/
|
|
511
|
+
testElement;
|
|
512
|
+
/**
|
|
513
|
+
* The component fixture of the component
|
|
514
|
+
*/
|
|
515
|
+
fixture;
|
|
516
|
+
/**
|
|
517
|
+
* The mode used by the ComponentTester
|
|
518
|
+
*/
|
|
519
|
+
mode;
|
|
500
520
|
/**
|
|
501
521
|
* Creates a component fixture of the given type with the TestBed and wraps it into a ComponentTester
|
|
502
522
|
*/
|
|
@@ -517,7 +537,9 @@ class ComponentTester {
|
|
|
517
537
|
*/
|
|
518
538
|
constructor(arg) {
|
|
519
539
|
this.fixture = arg instanceof ComponentFixture ? arg : TestBed.createComponent(arg);
|
|
540
|
+
const autoDetect = TestBed.inject(ComponentFixtureAutoDetect, false);
|
|
520
541
|
this.testElement = TestElementQuerier.wrap(this.debugElement, this);
|
|
542
|
+
this.mode = autoDetect ? 'automatic' : 'imperative';
|
|
521
543
|
}
|
|
522
544
|
/**
|
|
523
545
|
* The native DOM host element of the component
|
|
@@ -627,17 +649,36 @@ class ComponentTester {
|
|
|
627
649
|
return this.testElement.customs(selector, customTestElementType);
|
|
628
650
|
}
|
|
629
651
|
/**
|
|
630
|
-
* Triggers a change detection using the wrapped fixture
|
|
652
|
+
* Triggers a change detection using the wrapped fixture in imperative mode.
|
|
653
|
+
* Throws an error in autodetection mode.
|
|
654
|
+
* You should generally prever
|
|
631
655
|
*/
|
|
632
656
|
detectChanges(checkNoChanges) {
|
|
657
|
+
if (this.mode === 'automatic') {
|
|
658
|
+
throw new Error('In automatic mode, you should not call detectChanges');
|
|
659
|
+
}
|
|
633
660
|
this.fixture.detectChanges(checkNoChanges);
|
|
634
661
|
}
|
|
635
662
|
/**
|
|
636
|
-
*
|
|
663
|
+
* In imperative mode, runs change detection.
|
|
664
|
+
* In implicit mode, awaits stability.
|
|
665
|
+
*/
|
|
666
|
+
async change() {
|
|
667
|
+
if (this.mode === 'automatic') {
|
|
668
|
+
await this.stable();
|
|
669
|
+
}
|
|
670
|
+
else {
|
|
671
|
+
this.fixture.detectChanges();
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Delegates to the wrapped fixture whenStable and, in imperative mode, detect changes
|
|
637
676
|
*/
|
|
638
677
|
async stable() {
|
|
639
678
|
await this.fixture.whenStable();
|
|
640
|
-
this.
|
|
679
|
+
if (this.mode === 'imperative') {
|
|
680
|
+
this.detectChanges();
|
|
681
|
+
}
|
|
641
682
|
}
|
|
642
683
|
}
|
|
643
684
|
|
|
@@ -649,6 +690,7 @@ class ComponentTester {
|
|
|
649
690
|
* for example.
|
|
650
691
|
*/
|
|
651
692
|
class RoutingTester extends ComponentTester {
|
|
693
|
+
harness;
|
|
652
694
|
constructor(harness) {
|
|
653
695
|
super(harness.fixture);
|
|
654
696
|
this.harness = harness;
|
|
@@ -681,6 +723,12 @@ class RoutingTester extends ComponentTester {
|
|
|
681
723
|
}
|
|
682
724
|
|
|
683
725
|
class ActivatedRouteSnapshotStub extends ActivatedRouteSnapshot {
|
|
726
|
+
_parent = null;
|
|
727
|
+
_root;
|
|
728
|
+
_firstChild = null;
|
|
729
|
+
_children = [];
|
|
730
|
+
_pathFromRoot = [];
|
|
731
|
+
_title;
|
|
684
732
|
get parent() {
|
|
685
733
|
return this._parent;
|
|
686
734
|
}
|
|
@@ -725,10 +773,6 @@ class ActivatedRouteSnapshotStub extends ActivatedRouteSnapshot {
|
|
|
725
773
|
}
|
|
726
774
|
constructor() {
|
|
727
775
|
super();
|
|
728
|
-
this._parent = null;
|
|
729
|
-
this._firstChild = null;
|
|
730
|
-
this._children = [];
|
|
731
|
-
this._pathFromRoot = [];
|
|
732
776
|
this._root = this;
|
|
733
777
|
}
|
|
734
778
|
}
|
|
@@ -749,6 +793,17 @@ class ActivatedRouteSnapshotStub extends ActivatedRouteSnapshot {
|
|
|
749
793
|
* on the stub route. So if the code keeps a reference to params or paramMaps, it won't see the changes.
|
|
750
794
|
*/
|
|
751
795
|
class ActivatedRouteStub extends ActivatedRoute {
|
|
796
|
+
_firstChild;
|
|
797
|
+
_children;
|
|
798
|
+
paramsSubject;
|
|
799
|
+
queryParamsSubject;
|
|
800
|
+
dataSubject;
|
|
801
|
+
fragmentSubject;
|
|
802
|
+
urlSubject;
|
|
803
|
+
titleSubject;
|
|
804
|
+
_parent;
|
|
805
|
+
_root;
|
|
806
|
+
_pathFromRoot;
|
|
752
807
|
/**
|
|
753
808
|
* Constructs a new instance, based on the given options.
|
|
754
809
|
* If an option is not provided (or if no option is provided at all), then the route has a default value for this option
|
|
@@ -1249,15 +1304,30 @@ function createMock(type) {
|
|
|
1249
1304
|
return jasmine.createSpyObj(type.name, collectMethodNames(type.prototype));
|
|
1250
1305
|
}
|
|
1251
1306
|
|
|
1307
|
+
const COMPONENT_FIXTURE_AUTO_DETECTION = makeEnvironmentProviders([
|
|
1308
|
+
{ provide: ComponentFixtureAutoDetect, useValue: true }
|
|
1309
|
+
]);
|
|
1310
|
+
/**
|
|
1311
|
+
* Provide function which returns the provider `{ provide: ComponentFixtureAutoDetect, useValue: true }`.
|
|
1312
|
+
* This provider can be added to the testing module to configure the component testers
|
|
1313
|
+
* (and the underlying ComponentFixture) in automatic mode:
|
|
1314
|
+
*
|
|
1315
|
+
* ```
|
|
1316
|
+
* TestBed.configureTestingModule({ providers: [provideAutomaticChangeDetection()] });
|
|
1317
|
+
* ```
|
|
1318
|
+
*/
|
|
1319
|
+
function provideAutomaticChangeDetection() {
|
|
1320
|
+
return COMPONENT_FIXTURE_AUTO_DETECTION;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1252
1323
|
/* eslint-disable */
|
|
1253
1324
|
/*
|
|
1254
1325
|
* Public API Surface of ngx-speculoos
|
|
1255
1326
|
*/
|
|
1256
|
-
/// <reference path="./jasmine-matchers.ts" />
|
|
1257
1327
|
|
|
1258
1328
|
/**
|
|
1259
1329
|
* Generated bundle index. Do not edit.
|
|
1260
1330
|
*/
|
|
1261
1331
|
|
|
1262
|
-
export { ActivatedRouteStub, ComponentTester, RoutingTester, TestButton, TestElement, TestHtmlElement, TestInput, TestSelect, TestTextArea, createMock, speculoosMatchers, stubRoute };
|
|
1332
|
+
export { ActivatedRouteStub, ComponentTester, RoutingTester, TestButton, TestElement, TestHtmlElement, TestInput, TestSelect, TestTextArea, createMock, provideAutomaticChangeDetection, speculoosMatchers, stubRoute };
|
|
1263
1333
|
//# sourceMappingURL=ngx-speculoos.mjs.map
|