ngx-speculoos 10.0.0 → 11.1.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 CHANGED
@@ -27,7 +27,9 @@ how to write Angular unit tests.
27
27
  - [Subqueries](#subqueries)
28
28
  - [Dispatching events](#dispatching-events)
29
29
  - [Custom Jasmine matchers](#custom-jasmine-matchers)
30
- - [Routing helper](#routing-helper)
30
+ - [Routing helpers](#routing-helpers)
31
+ - [ActivatedRoute stub](#activated-route-stub)
32
+ - [RoutingTester](#routing-tester)
31
33
  - [Mocking helper](#mocking-helper)
32
34
  - [Testing with a host component](#testing-with-a-host-component)
33
35
  - [Gotchas](#gotchas)
@@ -182,7 +184,7 @@ describe('My component', () => {
182
184
  tester.detectChanges();
183
185
  });
184
186
 
185
- it ('should ...`, () => {
187
+ it('should ...', () => {
186
188
 
187
189
  });
188
190
  ```
@@ -372,9 +374,11 @@ For example
372
374
  Creating your own TestElement subclasses is a good way to provide such custom methods to interact
373
375
  with your own reusable components in tests.
374
376
 
375
- ### Routing helper
377
+ ### Routing helpers
376
378
 
377
- The library provides a stub for the `ActivatedRoute` class that you typically inject in your routing components.
379
+ #### ActivatedRoute stub
380
+
381
+ The library provides a stub for the `ActivatedRoute` class that you typically inject in your routed components.
378
382
  It mimics the behavior of the actual `ActivatedRoute`, by having a snapshot and observables that emit when this
379
383
  snapshot changes. And it also allows simulating navigations by imperatively changing the parameters, query parameters,
380
384
  etc.
@@ -422,6 +426,67 @@ describe('routing component', () => {
422
426
  });
423
427
  ```
424
428
 
429
+ #### RoutingTester
430
+
431
+ An alternative approach to injecting a stub activated route consists in using the Angular RouterTestingHarness.
432
+ The library helps using it by providing a RoutingTester, which is a ComponentTester wrapping the
433
+ RouterTestingHarness in addition to wrapping its fixture, and additionally provides helpe properties.
434
+
435
+ Here's an example usage for a component displaying the value of the query parameter `'page'` and allowing
436
+ to navigate to itself with a different value for that query parameter.
437
+
438
+ ```typescript
439
+ class PageComponentTester extends RoutingTester {
440
+ constructor(harness: RouterTestingHarness) {
441
+ super(harness);
442
+ }
443
+
444
+ get title() {
445
+ return this.element('h1');
446
+ }
447
+
448
+ get link() {
449
+ return this.element('a');
450
+ }
451
+ }
452
+
453
+ describe('RoutingTester', () => {
454
+ beforeEach(() => {
455
+ TestBed.configureTestingModule({
456
+ providers: [
457
+ provideRouter([
458
+ { path: 'list', component: PageComponent }
459
+ ])
460
+ ]
461
+ });
462
+ });
463
+
464
+ it('should display the page of the query params', async () => {
465
+ const tester = new PageComponentTester(await RouterTestingHarness.create('/list?page=42'));
466
+
467
+ expect(tester.title).toHaveText('Current page: 42');
468
+
469
+ await tester.harness.navigateByUrl('/list?page=54');
470
+
471
+ expect(tester.title).toHaveText('Current page: 54');
472
+ });
473
+
474
+ it('should navigate to the next page when clicking the link', async () => {
475
+ const tester = new PageComponentTester(await RouterTestingHarness.create('/list?page=42'));
476
+
477
+ expect(tester.title).toHaveText('Current page: 42');
478
+
479
+ tester.link.click();
480
+ await tester.stable();
481
+
482
+ expect(tester.urlTree.queryParamMap.get('page')).toBe('43');
483
+ expect(tester.url).toBe('/list?page=43');
484
+ expect(tester.title).toHaveText('Current page: 43');
485
+ });
486
+ });
487
+
488
+ ```
489
+
425
490
  ### Mocking helper
426
491
 
427
492
  Jasmine is quite verbose when creating mock objects in a typesafe way:
@@ -143,5 +143,12 @@ export class ComponentTester {
143
143
  detectChanges(checkNoChanges) {
144
144
  this.fixture.detectChanges(checkNoChanges);
145
145
  }
146
+ /**
147
+ * Delegates to the wrapped fixture whenStable and then detect changes
148
+ */
149
+ async stable() {
150
+ await this.fixture.whenStable();
151
+ this.detectChanges();
152
+ }
146
153
  }
147
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LXRlc3Rlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1zcGVjdWxvb3Mvc3JjL2xpYi9jb21wb25lbnQtdGVzdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHNEQUFzRDtBQUN0RCx1REFBdUQ7QUFDdkQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE9BQU8sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBT2xFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRzVEOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sZUFBZTtJQVcxQjs7T0FFRztJQUNILE1BQU0sQ0FBQyxNQUFNLENBQUksYUFBc0I7UUFDckMsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLGVBQWUsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUN2RCxPQUFPLElBQUksZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3RDLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0gsWUFBWSxHQUFrQztRQUM1QyxJQUFJLENBQUMsT0FBTyxHQUFHLEdBQUcsWUFBWSxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3BGLElBQUksQ0FBQyxXQUFXLEdBQUcsa0JBQWtCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUE2QixDQUFDO0lBQ2xHLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksYUFBYTtRQUNmLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUM7SUFDcEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsSUFBSSxpQkFBaUI7UUFDbkIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUFDO0lBQ3hDLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksWUFBWTtRQUNkLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUM7SUFDbkMsQ0FBQztJQThHRCxPQUFPLENBQUMsUUFBNEI7UUFDbEMsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM1QyxDQUFDO0lBOEdELFFBQVEsQ0FBQyxRQUE0QjtRQUNuQyxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzdDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLFFBQTRCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDMUMsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxNQUFNLENBQUMsUUFBNEI7UUFDakMsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUMzQyxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxRQUFRLENBQUMsUUFBNEI7UUFDbkMsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE1BQU0sQ0FBQyxRQUE0QjtRQUNqQyxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFRDs7O09BR0c7SUFDSCxTQUFTLENBQUksUUFBaUI7UUFDNUIsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM5QyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsVUFBVSxDQUFJLFFBQWlCO1FBQzdCLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUksUUFBNEIsRUFBRSxLQUF1QjtRQUM1RCxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE1BQU0sQ0FBSSxRQUE0QixFQUFFLEtBQXVCO1FBQzdELE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxNQUFNLENBQXdCLFFBQTRCLEVBQUUscUJBQThCO1FBQ3hGLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLHFCQUFxQixDQUFDLENBQUM7SUFDbEUsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILE9BQU8sQ0FBd0IsUUFBNEIsRUFBRSxxQkFBOEI7UUFDekYsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUscUJBQXFCLENBQUMsQ0FBQztJQUNuRSxDQUFDO0lBRUQ7O09BRUc7SUFDSCxhQUFhLENBQUMsY0FBd0I7UUFDcEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDN0MsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzICovXG4vKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55ICovXG5pbXBvcnQgeyBDb21wb25lbnRGaXh0dXJlLCBUZXN0QmVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS90ZXN0aW5nJztcbmltcG9ydCB7IERlYnVnRWxlbWVudCwgUHJvdmlkZXJUb2tlbiwgVHlwZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgVGVzdFRleHRBcmVhIH0gZnJvbSAnLi90ZXN0LXRleHRhcmVhJztcbmltcG9ydCB7IFRlc3RFbGVtZW50IH0gZnJvbSAnLi90ZXN0LWVsZW1lbnQnO1xuaW1wb3J0IHsgVGVzdElucHV0IH0gZnJvbSAnLi90ZXN0LWlucHV0JztcbmltcG9ydCB7IFRlc3RTZWxlY3QgfSBmcm9tICcuL3Rlc3Qtc2VsZWN0JztcbmltcG9ydCB7IFRlc3RCdXR0b24gfSBmcm9tICcuL3Rlc3QtYnV0dG9uJztcbmltcG9ydCB7IFRlc3RFbGVtZW50UXVlcmllciB9IGZyb20gJy4vdGVzdC1lbGVtZW50LXF1ZXJpZXInO1xuaW1wb3J0IHsgVGVzdEh0bWxFbGVtZW50IH0gZnJvbSAnLi90ZXN0LWh0bWwtZWxlbWVudCc7XG5cbi8qKlxuICogVGhlIG1haW4gZW50cnkgcG9pbnQgb2YgdGhlIEFQSS4gSXQgd3JhcHMgYW4gQW5ndWxhciBDb21wb25lbnRGaXh0dXJlPFQ+LCBhbmQgZ2l2ZXMgYWNjZXNzIHRvIGl0c1xuICogbW9zdCB1c2VkIHByb3BlcnRpZXMgYW5kIG1ldGhvZHMuIEl0IGFsc28gYWxsb3dzIGdldHRpbmcgZWxlbWVudHMgd3JhcHBlZCBpbiBUZXN0RWxlbWVudCAoYW5kIGl0cyBzdWJjbGFzc2VzKVxuICogQHBhcmFtIDxDPiB0aGUgdHlwZSBvZiB0aGUgY29tcG9uZW50IHRvIHRlc3RcbiAqL1xuZXhwb3J0IGNsYXNzIENvbXBvbmVudFRlc3RlcjxDPiB7XG4gIC8qKlxuICAgKiBUaGUgdGVzdCBlbGVtZW50IG9mIHRoZSBjb21wb25lbnRcbiAgICovXG4gIHJlYWRvbmx5IHRlc3RFbGVtZW50OiBUZXN0RWxlbWVudDxIVE1MRWxlbWVudD47XG5cbiAgLyoqXG4gICAqIFRoZSBjb21wb25lbnQgZml4dHVyZSBvZiB0aGUgY29tcG9uZW50XG4gICAqL1xuICByZWFkb25seSBmaXh0dXJlOiBDb21wb25lbnRGaXh0dXJlPEM+O1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgY29tcG9uZW50IGZpeHR1cmUgb2YgdGhlIGdpdmVuIHR5cGUgd2l0aCB0aGUgVGVzdEJlZCBhbmQgd3JhcHMgaXQgaW50byBhIENvbXBvbmVudFRlc3RlclxuICAgKi9cbiAgc3RhdGljIGNyZWF0ZTxDPihjb21wb25lbnRUeXBlOiBUeXBlPEM+KTogQ29tcG9uZW50VGVzdGVyPEM+IHtcbiAgICBjb25zdCBmaXh0dXJlID0gVGVzdEJlZC5jcmVhdGVDb21wb25lbnQoY29tcG9uZW50VHlwZSk7XG4gICAgcmV0dXJuIG5ldyBDb21wb25lbnRUZXN0ZXIoZml4dHVyZSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIENvbXBvbmVudEZpeHR1cmUgZm9yIHRoZSBnaXZlbiBjb21wb25lbnQgdHlwZSB1c2luZyB0aGUgVGVzdEJlZCwgYW5kIGNyZWF0ZXMgYSBDb21wb25lbnRUZXN0ZXJcbiAgICogd3JhcHBpbmcgKGFuZCBkZWxlZ2F0aW5nKSB0byB0aGlzIGZpeHR1cmUuIElmIGEgZml4dHVyZSBpcyBwYXNzZWQsIHRoZW4gZGVsZWdhdGVzIHRvIHRoaXMgZml4dHVyZSBkaXJlY3RseS5cbiAgICpcbiAgICogTm90ZSB0aGF0IG5vIGBkZXRlY3RDaGFuZ2VzKClgIGNhbGwgaXMgbWFkZSBieSB0aGlzIGNvbnN0cnVjdG9yLiBJdCdzIHVwIHRvIHRoZSBzdWJjbGFzcyBjb25zdHJ1Y3RvcixcbiAgICogb3IgdG8gdGhlIHVzZXIgb2YgdGhlIGNyZWF0ZWQgQ29tcG9uZW50VGVzdGVyLCB0byBjYWxsIGBkZXRlY3RDaGFuZ2VzKClgIGF0IGxlYXN0IG9uY2UgdG8gdHJpZ2dlciBjaGFuZ2VcbiAgICogZGV0ZWN0aW9uLiBUaGlzIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIHNvbWUgY29tcG9uZW50IHRlbXBsYXRlcyBjYW4gb25seSBiZSBldmFsdWF0ZWQgb25jZSBpbnB1dHNcbiAgICogaGF2ZSBiZWVuIHNldCBvbiB0aGUgY29tcG9uZW50IGluc3RhbmNlLlxuICAgKlxuICAgKiBAcGFyYW0gYXJnIHRoZSB0eXBlIG9mIHRoZSBjb21wb25lbnQgdG8gd3JhcCwgb3IgYSBjb21wb25lbnQgZml4dHVyZSB0byB3cmFwXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihhcmc6IFR5cGU8Qz4gfCBDb21wb25lbnRGaXh0dXJlPEM+KSB7XG4gICAgdGhpcy5maXh0dXJlID0gYXJnIGluc3RhbmNlb2YgQ29tcG9uZW50Rml4dHVyZSA/IGFyZyA6IFRlc3RCZWQuY3JlYXRlQ29tcG9uZW50KGFyZyk7XG4gICAgdGhpcy50ZXN0RWxlbWVudCA9IFRlc3RFbGVtZW50UXVlcmllci53cmFwKHRoaXMuZGVidWdFbGVtZW50LCB0aGlzKSBhcyBUZXN0RWxlbWVudDxIVE1MRWxlbWVudD47XG4gIH1cblxuICAvKipcbiAgICogVGhlIG5hdGl2ZSBET00gaG9zdCBlbGVtZW50IG9mIHRoZSBjb21wb25lbnRcbiAgICovXG4gIGdldCBuYXRpdmVFbGVtZW50KCk6IEhUTUxFbGVtZW50IHtcbiAgICByZXR1cm4gdGhpcy5maXh0dXJlLm5hdGl2ZUVsZW1lbnQ7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgaW5zdGFuY2Ugb2YgdGhlIHRlc3RlZCBjb21wb25lbnQgZnJvbSB0aGUgd3JhcHBlZCBmaXh0dXJlXG4gICAqL1xuICBnZXQgY29tcG9uZW50SW5zdGFuY2UoKTogQyB7XG4gICAgcmV0dXJuIHRoaXMuZml4dHVyZS5jb21wb25lbnRJbnN0YW5jZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBkZWJ1ZyBlbGVtZW50IGZyb20gdGhlIHdyYXBwZWQgZml4dHVyZVxuICAgKi9cbiAgZ2V0IGRlYnVnRWxlbWVudCgpOiBEZWJ1Z0VsZW1lbnQge1xuICAgIHJldHVybiB0aGlzLmZpeHR1cmUuZGVidWdFbGVtZW50O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IGVsZW1lbnQgbWF0Y2hpbmcgdGhlIGdpdmVuIENTUyBzZWxlY3RvciBhbmQgd3JhcHMgaXQgaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIHZhbHVlIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnQgaXMgYW4gaW5wdXQgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYSBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50OiBUZXN0SHRtbEVsZW1lbnQmbHQ7SFRNTERpdkVsZW1lbnQ+IHwgbnVsbCA9IHRlc3Rlci5lbGVtZW50KCdkaXYnKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgZWxlbWVudCwgb3IgbnVsbCBpZiBubyBlbGVtZW50IG1hdGNoZXMgdGhlIHNlbGVjdG9yLlxuICAgKi9cbiAgZWxlbWVudDxLIGV4dGVuZHMga2V5b2YgSFRNTEVsZW1lbnRUYWdOYW1lTWFwPihzZWxlY3RvcjogSyk6IFRlc3RIdG1sRWxlbWVudDxIVE1MRWxlbWVudFRhZ05hbWVNYXBbS10+IHwgbnVsbDtcbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IGVsZW1lbnQgbWF0Y2hpbmcgdGhlIGdpdmVuIENTUyBzZWxlY3RvciBhbmQgd3JhcHMgaXQgaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIHZhbHVlIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnQgaXMgYW4gaW5wdXQgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYSBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50OiBUZXN0RWxlbWVudCZsdDtTVkdMaW5lRWxlbWVudD4gfCBudWxsID0gdGVzdGVyLmVsZW1lbnQoJ2xpbmUnKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgZWxlbWVudCwgb3IgbnVsbCBpZiBubyBlbGVtZW50IG1hdGNoZXMgdGhlIHNlbGVjdG9yLlxuICAgKi9cbiAgZWxlbWVudDxLIGV4dGVuZHMga2V5b2YgU1ZHRWxlbWVudFRhZ05hbWVNYXA+KHNlbGVjdG9yOiBLKTogVGVzdEVsZW1lbnQ8U1ZHRWxlbWVudFRhZ05hbWVNYXBbS10+IHwgbnVsbDtcbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IGVsZW1lbnQgbWF0Y2hpbmcgdGhlIGdpdmVuIENTUyBzZWxlY3RvciBhbmQgd3JhcHMgaXQgaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIHZhbHVlIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnQgaXMgYW4gaW5wdXQgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYSBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50OiBUZXN0RWxlbWVudCB8IG51bGwgPSB0ZXN0ZXIuZWxlbWVudCgnLnNlbGVjdG9yJyk7XG4gICAqIDwvY29kZT5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgd3JhcHBlZCBlbGVtZW50LCBvciBudWxsIGlmIG5vIGVsZW1lbnQgbWF0Y2hlcyB0aGUgc2VsZWN0b3IuXG4gICAqL1xuICBlbGVtZW50KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0RWxlbWVudCB8IG51bGw7XG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBlbGVtZW50IG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciBhbmQgd3JhcHMgaXQgaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIHZhbHVlIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnQgaXMgYW4gaW5wdXQgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYSBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50OiBUZXN0SW5wdXQgfCBudWxsID0gdGVzdGVyLmVsZW1lbnQmbHQ7SFRNTElucHV0RWxlbWVudD4oJy5zZWxlY3RvcicpO1xuICAgKiA8L2NvZGU+XG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgZWxlbWVudCwgb3IgbnVsbCBpZiBubyBlbGVtZW50IG1hdGNoZXMgdGhlIHNlbGVjdG9yLlxuICAgKi9cbiAgZWxlbWVudDxUIGV4dGVuZHMgSFRNTElucHV0RWxlbWVudD4oc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RJbnB1dCB8IG51bGw7XG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBlbGVtZW50IG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciBhbmQgd3JhcHMgaXQgaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIHZhbHVlIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnQgaXMgYW4gaW5wdXQgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYSBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50OiBUZXN0VGV4dEFyZWEgfCBudWxsID0gdGVzdGVyLmVsZW1lbnQmbHQ7SFRNTFRleHRBcmVhRWxlbWVudD4oJy5zZWxlY3RvcicpO1xuICAgKiA8L2NvZGU+XG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgZWxlbWVudCwgb3IgbnVsbCBpZiBubyBlbGVtZW50IG1hdGNoZXMgdGhlIHNlbGVjdG9yLlxuICAgKi9cbiAgZWxlbWVudDxUIGV4dGVuZHMgSFRNTFRleHRBcmVhRWxlbWVudD4oc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RUZXh0QXJlYSB8IG51bGw7XG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBlbGVtZW50IG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciBhbmQgd3JhcHMgaXQgaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIHZhbHVlIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnQgaXMgYW4gaW5wdXQgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYSBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50OiBUZXN0U2VsZWN0IHwgbnVsbCA9IHRlc3Rlci5lbGVtZW50Jmx0O0hUTUxTZWxlY3RFbGVtZW50PignLnNlbGVjdG9yJyk7XG4gICAqIDwvY29kZT5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgd3JhcHBlZCBlbGVtZW50LCBvciBudWxsIGlmIG5vIGVsZW1lbnQgbWF0Y2hlcyB0aGUgc2VsZWN0b3IuXG4gICAqL1xuICBlbGVtZW50PFQgZXh0ZW5kcyBIVE1MU2VsZWN0RWxlbWVudD4oc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RTZWxlY3QgfCBudWxsO1xuICAvKipcbiAgICogR2V0cyB0aGUgZmlyc3QgZWxlbWVudCBtYXRjaGluZyB0aGUgZ2l2ZW4gc2VsZWN0b3IgYW5kIHdyYXBzIGl0IGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCB2YWx1ZSBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50IGlzIGFuIGlucHV0IGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGEgVGVzdElucHV0LlxuICAgKiA8cD5Vc2FnZTo8L3A+XG4gICAqIDxjb2RlPlxuICAgKiBjb25zdCB0ZXN0RWxlbWVudDogVGVzdEJ1dHRvbiB8IG51bGwgPSB0ZXN0ZXIuZWxlbWVudCZsdDtIVE1MQnV0dG9uRWxlbWVudD4oJy5zZWxlY3RvcicpO1xuICAgKiA8L2NvZGU+XG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgZWxlbWVudCwgb3IgbnVsbCBpZiBubyBlbGVtZW50IG1hdGNoZXMgdGhlIHNlbGVjdG9yLlxuICAgKi9cbiAgZWxlbWVudDxUIGV4dGVuZHMgSFRNTEJ1dHRvbkVsZW1lbnQ+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0QnV0dG9uIHwgbnVsbDtcbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IGVsZW1lbnQgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yIGFuZCB3cmFwcyBpdCBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgdmFsdWUgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudCBpcyBhbiBpbnB1dCBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhIFRlc3RJbnB1dC5cbiAgICogPHA+VXNhZ2U6PC9wPlxuICAgKiA8Y29kZT5cbiAgICogY29uc3QgdGVzdEVsZW1lbnQ6IFRlc3RIdG1sRWxlbWVudCZsdDtIVE1MRGl2RWxlbWVudD4gfCBudWxsID0gdGVzdGVyLmVsZW1lbnQmbHQ7SFRNTERpdkVsZW1lbnQ+KCcuc2VsZWN0b3InKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIGVsZW1lbnQsIG9yIG51bGwgaWYgbm8gZWxlbWVudCBtYXRjaGVzIHRoZSBzZWxlY3Rvci5cbiAgICovXG4gIGVsZW1lbnQ8VCBleHRlbmRzIEhUTUxFbGVtZW50PihzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+KTogVGVzdEh0bWxFbGVtZW50PFQ+IHwgbnVsbDtcbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IGVsZW1lbnQgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yIGFuZCB3cmFwcyBpdCBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgdmFsdWUgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudCBpcyBhbiBpbnB1dCBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhIFRlc3RJbnB1dC5cbiAgICogPHA+VXNhZ2U6PC9wPlxuICAgKiA8Y29kZT5cbiAgICogY29uc3QgdGVzdEVsZW1lbnQ6IFRlc3RFbGVtZW50Jmx0O1NWR0xpbmVFbGVtZW50PiB8IG51bGwgPSB0ZXN0ZXIuZWxlbWVudCZsdDtTVkdMaW5lRWxlbWVudD4oJy5zZWxlY3RvcicpO1xuICAgKiA8L2NvZGU+XG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgZWxlbWVudCwgb3IgbnVsbCBpZiBubyBlbGVtZW50IG1hdGNoZXMgdGhlIHNlbGVjdG9yLlxuICAgKi9cbiAgZWxlbWVudDxUIGV4dGVuZHMgRWxlbWVudD4oc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RFbGVtZW50PFQ+IHwgbnVsbDtcbiAgZWxlbWVudChzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+KTogVGVzdEVsZW1lbnQgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy50ZXN0RWxlbWVudC5lbGVtZW50KHNlbGVjdG9yKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIGFsbCB0aGUgZWxlbWVudHMgbWF0Y2hpbmcgdGhlIGdpdmVuIENTUyBzZWxlY3RvciBhbmQgd3JhcHMgdGhlbSBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgZWxlbWVudHMgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudHMgYXJlIGlucHV0cyBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhbiBhcnJheSBvZiBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50czogQXJyYXkmbHQ7VGVzdEh0bWxFbGVtZW50Jmx0O0hUTUxEaXZFbGVtZW50Pj4gPSB0ZXN0ZXIuZWxlbWVudHMoJ2RpdicpO1xuICAgKiA8L2NvZGU+XG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgYXJyYXkgb2YgbWF0Y2hlZCBlbGVtZW50cywgZW1wdHkgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgZWxlbWVudHM8SyBleHRlbmRzIGtleW9mIEhUTUxFbGVtZW50VGFnTmFtZU1hcD4oc2VsZWN0b3I6IEspOiBBcnJheTxUZXN0SHRtbEVsZW1lbnQ8SFRNTEVsZW1lbnRUYWdOYW1lTWFwW0tdPj47XG4gIC8qKlxuICAgKiBHZXRzIGFsbCB0aGUgZWxlbWVudHMgbWF0Y2hpbmcgdGhlIGdpdmVuIENTUyBzZWxlY3RvciBhbmQgd3JhcHMgdGhlbSBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgZWxlbWVudHMgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudHMgYXJlIGlucHV0cyBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhbiBhcnJheSBvZiBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50czogQXJyYXkmbHQ7VGVzdEVsZW1lbnQmbHQ7U1ZHTGluZUVsZW1lbnQ+PiA9IHRlc3Rlci5lbGVtZW50cygnbGluZScpO1xuICAgKiA8L2NvZGU+XG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgYXJyYXkgb2YgbWF0Y2hlZCBlbGVtZW50cywgZW1wdHkgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgZWxlbWVudHM8SyBleHRlbmRzIGtleW9mIFNWR0VsZW1lbnRUYWdOYW1lTWFwPihzZWxlY3RvcjogSyk6IEFycmF5PFRlc3RFbGVtZW50PFNWR0VsZW1lbnRUYWdOYW1lTWFwW0tdPj47XG4gIC8qKlxuICAgKiBHZXRzIGFsbCB0aGUgZWxlbWVudHMgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yIGFuZCB3cmFwcyB0aGVtIGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCBlbGVtZW50cyBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50cyBhcmUgaW5wdXRzIGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGFuIGFycmF5IG9mIFRlc3RJbnB1dC5cbiAgICogPHA+VXNhZ2U6PC9wPlxuICAgKiA8Y29kZT5cbiAgICogY29uc3QgdGVzdEVsZW1lbnRzOiBBcnJheSZsdDtUZXN0RWxlbWVudD4gPSB0ZXN0ZXIuZWxlbWVudHMoJy5zZWxlY3RvcicpO1xuICAgKiA8L2NvZGU+XG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIGFycmF5IG9mIG1hdGNoZWQgZWxlbWVudHMsIGVtcHR5IGlmIG5vIGVsZW1lbnQgd2FzIG1hdGNoZWRcbiAgICovXG4gIGVsZW1lbnRzKHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBBcnJheTxUZXN0RWxlbWVudD47XG4gIC8qKlxuICAgKiBHZXRzIGFsbCB0aGUgZWxlbWVudHMgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yIGFuZCB3cmFwcyB0aGVtIGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCBlbGVtZW50cyBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50cyBhcmUgaW5wdXRzIGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGFuIGFycmF5IG9mIFRlc3RJbnB1dC5cbiAgICogPHA+VXNhZ2U6PC9wPlxuICAgKiA8Y29kZT5cbiAgICogY29uc3QgdGVzdEVsZW1lbnRzOiBBcnJheSZsdDtUZXN0SW5wdXQ+ID0gdGVzdGVyLmVsZW1lbnRzJmx0O0hUTUxJbnB1dEVsZW1lbnQ+KCcuc2VsZWN0b3InKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSBhcnJheSBvZiBtYXRjaGVkIGVsZW1lbnRzLCBlbXB0eSBpZiBubyBlbGVtZW50IHdhcyBtYXRjaGVkXG4gICAqL1xuICBlbGVtZW50czxUIGV4dGVuZHMgSFRNTElucHV0RWxlbWVudD4oc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IEFycmF5PFRlc3RJbnB1dD47XG4gIC8qKlxuICAgKiBHZXRzIGFsbCB0aGUgZWxlbWVudHMgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yIGFuZCB3cmFwcyB0aGVtIGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCBlbGVtZW50cyBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50cyBhcmUgaW5wdXRzIGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGFuIGFycmF5IG9mIFRlc3RJbnB1dC5cbiAgICogPHA+VXNhZ2U6PC9wPlxuICAgKiA8Y29kZT5cbiAgICogY29uc3QgdGVzdEVsZW1lbnRzOiBBcnJheSZsdDtUZXN0VGV4dEFyZWE+ID0gdGVzdGVyLmVsZW1lbnRzJmx0O0hUTUxUZXh0QXJlYUVsZW1lbnQ+KCcuc2VsZWN0b3InKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSBhcnJheSBvZiBtYXRjaGVkIGVsZW1lbnRzLCBlbXB0eSBpZiBubyBlbGVtZW50IHdhcyBtYXRjaGVkXG4gICAqL1xuICBlbGVtZW50czxUIGV4dGVuZHMgSFRNTFRleHRBcmVhRWxlbWVudD4oc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IEFycmF5PFRlc3RUZXh0QXJlYT47XG4gIC8qKlxuICAgKiBHZXRzIGFsbCB0aGUgZWxlbWVudHMgbWF0Y2hpbmcgdGhlIGdpdmVuIENTUyBzZWxlY3RvciBhbmQgd3JhcHMgdGhlbSBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgZWxlbWVudHMgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudHMgYXJlIGlucHV0cyBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhbiBhcnJheSBvZiBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50czogQXJyYXkmbHQ7VGVzdEJ1dHRvbj4gPSB0ZXN0ZXIuZWxlbWVudHMmbHQ7SFRNTEJ1dHRvbkVsZW1lbnQ+KCcuc2VsZWN0b3InKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSBhcnJheSBvZiBtYXRjaGVkIGVsZW1lbnRzLCBlbXB0eSBpZiBubyBlbGVtZW50IHdhcyBtYXRjaGVkXG4gICAqL1xuICBlbGVtZW50czxUIGV4dGVuZHMgSFRNTEJ1dHRvbkVsZW1lbnQ+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBBcnJheTxUZXN0QnV0dG9uPjtcbiAgLyoqXG4gICAqIEdldHMgYWxsIHRoZSBlbGVtZW50cyBtYXRjaGluZyB0aGUgZ2l2ZW4gc2VsZWN0b3IgYW5kIHdyYXBzIHRoZW0gaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIGVsZW1lbnRzIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnRzIGFyZSBpbnB1dHMgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYW4gYXJyYXkgb2YgVGVzdElucHV0LlxuICAgKiA8cD5Vc2FnZTo8L3A+XG4gICAqIDxjb2RlPlxuICAgKiBjb25zdCB0ZXN0RWxlbWVudHM6IEFycmF5Jmx0O1Rlc3RTZWxlY3Q+ID0gdGVzdGVyLmVsZW1lbnRzPEhUTUxTZWxlY3RFbGVtZW50PignLnNlbGVjdG9yJyk7XG4gICAqIDwvY29kZT5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgYXJyYXkgb2YgbWF0Y2hlZCBlbGVtZW50cywgZW1wdHkgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgZWxlbWVudHM8VCBleHRlbmRzIEhUTUxTZWxlY3RFbGVtZW50PihzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+KTogQXJyYXk8VGVzdFNlbGVjdD47XG4gIC8qKlxuICAgKiBHZXRzIGFsbCB0aGUgZWxlbWVudHMgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yIGFuZCB3cmFwcyB0aGVtIGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCBlbGVtZW50cyBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50cyBhcmUgaW5wdXRzIGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGFuIGFycmF5IG9mIFRlc3RJbnB1dC5cbiAgICogPHA+VXNhZ2U6PC9wPlxuICAgKiA8Y29kZT5cbiAgICogY29uc3QgdGVzdEVsZW1lbnRzOiBBcnJheSZsdDtUZXN0SHRtbEVsZW1lbnQmbHQ7SFRNTERpdkVsZW1lbnQ+PiA9IHRlc3Rlci5lbGVtZW50cyZsdDtIVE1MRGl2RWxlbWVudD4oJy5zZWxlY3RvcicpO1xuICAgKiA8L2NvZGU+XG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIGFycmF5IG9mIG1hdGNoZWQgZWxlbWVudHMsIGVtcHR5IGlmIG5vIGVsZW1lbnQgd2FzIG1hdGNoZWRcbiAgICovXG4gIGVsZW1lbnRzPFQgZXh0ZW5kcyBIVE1MRWxlbWVudD4oc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IEFycmF5PFRlc3RIdG1sRWxlbWVudDxUPj47XG4gIC8qKlxuICAgKiBHZXRzIGFsbCB0aGUgZWxlbWVudHMgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yIGFuZCB3cmFwcyB0aGVtIGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCBlbGVtZW50cyBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50cyBhcmUgaW5wdXRzIGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGFuIGFycmF5IG9mIFRlc3RJbnB1dC5cbiAgICogPHA+VXNhZ2U6PC9wPlxuICAgKiA8Y29kZT5cbiAgICogY29uc3QgdGVzdEVsZW1lbnRzOiBBcnJheSZsdDtUZXN0RWxlbWVudCZsdDtTVkdMaW5lRWxlbWVudD4+ID0gdGVzdGVyLmVsZW1lbnRzJmx0O1NWR0xpbmVFbGVtZW50PignLnNlbGVjdG9yJyk7XG4gICAqIDwvY29kZT5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgYXJyYXkgb2YgbWF0Y2hlZCBlbGVtZW50cywgZW1wdHkgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgZWxlbWVudHM8VCBleHRlbmRzIEVsZW1lbnQ+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBBcnJheTxUZXN0RWxlbWVudDxUPj47XG4gIGVsZW1lbnRzKHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBBcnJheTxUZXN0RWxlbWVudD4ge1xuICAgIHJldHVybiB0aGlzLnRlc3RFbGVtZW50LmVsZW1lbnRzKHNlbGVjdG9yKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBpbnB1dCBtYXRjaGVkIGJ5IHRoZSBnaXZlbiBzZWxlY3Rvci4gVGhyb3dzIGFuIEVycm9yIGlmIHRoZSBtYXRjaGVkIGVsZW1lbnQgaXNuJ3QgYWN0dWFsbHkgYW4gaW5wdXQuXG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgaW5wdXQsIG9yIG51bGwgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgaW5wdXQoc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RJbnB1dCB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLnRlc3RFbGVtZW50LmlucHV0KHNlbGVjdG9yKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBzZWxlY3QgbWF0Y2hlZCBieSB0aGUgZ2l2ZW4gc2VsZWN0b3IuIFRocm93cyBhbiBFcnJvciBpZiB0aGUgbWF0Y2hlZCBlbGVtZW50IGlzbid0IGFjdHVhbGx5IGEgc2VsZWN0LlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIHNlbGVjdCwgb3IgbnVsbCBpZiBubyBlbGVtZW50IHdhcyBtYXRjaGVkXG4gICAqL1xuICBzZWxlY3Qoc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RTZWxlY3QgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy50ZXN0RWxlbWVudC5zZWxlY3Qoc2VsZWN0b3IpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IHRleHRhcmVhIG1hdGNoZWQgYnkgdGhlIGdpdmVuIHNlbGVjdG9yXG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgdGV4dGFyZWEsIG9yIG51bGwgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZC4gVGhyb3dzIGFuIEVycm9yIGlmIHRoZSBtYXRjaGVkIGVsZW1lbnQgaXNuJ3QgYWN0dWFsbHkgYSB0ZXh0YXJlYS5cbiAgICogQHRocm93cyB7RXJyb3J9IGlmIHRoZSBtYXRjaGVkIGVsZW1lbnQgaXNuJ3QgYWN0dWFsbHkgYSB0ZXh0YXJlYVxuICAgKi9cbiAgdGV4dGFyZWEoc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RUZXh0QXJlYSB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLnRlc3RFbGVtZW50LnRleHRhcmVhKHNlbGVjdG9yKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBidXR0b24gbWF0Y2hlZCBieSB0aGUgZ2l2ZW4gc2VsZWN0b3IuIFRocm93cyBhbiBFcnJvciBpZiB0aGUgbWF0Y2hlZCBlbGVtZW50IGlzbid0IGFjdHVhbGx5IGEgYnV0dG9uLlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIGJ1dHRvbiwgb3IgbnVsbCBpZiBubyBlbGVtZW50IHdhcyBtYXRjaGVkXG4gICAqL1xuICBidXR0b24oc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RCdXR0b24gfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy50ZXN0RWxlbWVudC5idXR0b24oc2VsZWN0b3IpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IGRpcmVjdGl2ZSBtYXRjaGluZyB0aGUgZ2l2ZW4gY29tcG9uZW50IGRpcmVjdGl2ZSBzZWxlY3RvciBhbmQgcmV0dXJucyBpdHMgY29tcG9uZW50IGluc3RhbmNlXG4gICAqIEBwYXJhbSBzZWxlY3RvciB0aGUgc2VsZWN0b3Igb2YgYSBjb21wb25lbnQgZGlyZWN0aXZlXG4gICAqL1xuICBjb21wb25lbnQ8Uj4oc2VsZWN0b3I6IFR5cGU8Uj4pOiBSIHtcbiAgICByZXR1cm4gdGhpcy50ZXN0RWxlbWVudC5jb21wb25lbnQoc2VsZWN0b3IpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGRpcmVjdGl2ZXMgbWF0Y2hpbmcgdGhlIGdpdmVuIGNvbXBvbmVudCBkaXJlY3RpdmUgc2VsZWN0b3IgYW5kIHJldHVybnMgdGhlaXIgY29tcG9uZW50IGluc3RhbmNlXG4gICAqIEBwYXJhbSBzZWxlY3RvciB0aGUgc2VsZWN0b3Igb2YgYSBjb21wb25lbnQgZGlyZWN0aXZlXG4gICAqL1xuICBjb21wb25lbnRzPFI+KHNlbGVjdG9yOiBUeXBlPFI+KTogQXJyYXk8Uj4ge1xuICAgIHJldHVybiB0aGlzLnRlc3RFbGVtZW50LmNvbXBvbmVudHMoc2VsZWN0b3IpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IGVsZW1lbnQgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yLCB0aGVuIGdldHMgdGhlIGdpdmVuIHRva2VuIGZyb20gaXRzIGluamVjdG9yLCBvciBudWxsIGlmIHRoZXJlIGlzIG5vIHN1Y2ggdG9rZW5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcGFyYW0gdG9rZW4gdGhlIHRva2VuIHRvIGdldCBmcm9tIHRoZSBtYXRjaGVkIGVsZW1lbnQgaW5qZWN0b3JcbiAgICovXG4gIHRva2VuPFI+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4sIHRva2VuOiBQcm92aWRlclRva2VuPFI+KTogUiB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLnRlc3RFbGVtZW50LnRva2VuKHNlbGVjdG9yLCB0b2tlbik7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgZWxlbWVudHMgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yLCB0aGVuIGdldHMgdGhlaXIgZ2l2ZW4gdG9rZW4gZnJvbSB0aGVpciBpbmplY3Rvciwgb3IgbnVsbCBpZiB0aGVyZSBpcyBubyBzdWNoIHRva2VuXG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHBhcmFtIHRva2VuIHRoZSB0b2tlbiB0byBnZXQgZnJvbSB0aGUgbWF0Y2hlZCBlbGVtZW50IGluamVjdG9yXG4gICAqL1xuICB0b2tlbnM8Uj4oc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55PiwgdG9rZW46IFByb3ZpZGVyVG9rZW48Uj4pOiBBcnJheTxSIHwgbnVsbD4ge1xuICAgIHJldHVybiB0aGlzLnRlc3RFbGVtZW50LnRva2VucyhzZWxlY3RvciwgdG9rZW4pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGVsZW1lbnQgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yLCBhbmQgaWYgZm91bmQsIGNyZWF0ZXMgYW5kIHJldHVybnMgYSBjdXN0b20gVGVzdEVsZW1lbnQgb2YgdGhlIHByb3ZpZGVkXG4gICAqIHR5cGUuIFRoaXMgaXMgdXNlZnVsIHRvIGNyZWF0ZSBjdXN0b20gaGlnaGVyLWxldmVsIGFic3RyYWN0aW9ucyBzaW1pbGFyIHRvIFRlc3RJbnB1dCwgVGVzdFNlbGVjdCwgZXRjLiBmb3JcbiAgICogY3VzdG9tIGVsZW1lbnRzIG9yIGNvbXBvbmVudHMuXG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHBhcmFtIGN1c3RvbVRlc3RFbGVtZW50VHlwZSB0aGUgdHlwZSBvZiB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgdGhhdCB3aWxsIHdyYXAgdGhlIGZvdW5kIGVsZW1lbnRcbiAgICovXG4gIGN1c3RvbTxFIGV4dGVuZHMgVGVzdEVsZW1lbnQ+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4sIGN1c3RvbVRlc3RFbGVtZW50VHlwZTogVHlwZTxFPik6IEUgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy50ZXN0RWxlbWVudC5jdXN0b20oc2VsZWN0b3IsIGN1c3RvbVRlc3RFbGVtZW50VHlwZSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgZWxlbWVudHMgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yLCBhbmQgY3JlYXRlcyBhbmQgcmV0dXJucyBjdXN0b20gVGVzdEVsZW1lbnRzIG9mIHRoZSBwcm92aWRlZFxuICAgKiB0eXBlLiBUaGlzIGlzIHVzZWZ1bCB0byBjcmVhdGUgY3VzdG9tIGhpZ2hlci1sZXZlbCBhYnN0cmFjdGlvbnMgc2ltaWxhciB0byBUZXN0SW5wdXQsIFRlc3RTZWxlY3QsIGV0Yy4gZm9yXG4gICAqIGN1c3RvbSBlbGVtZW50cyBvciBjb21wb25lbnRzLlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEBwYXJhbSBjdXN0b21UZXN0RWxlbWVudFR5cGUgdGhlIHR5cGUgb2YgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIHRoYXQgd2lsbCB3cmFwIHRoZSBmb3VuZCBlbGVtZW50c1xuICAgKi9cbiAgY3VzdG9tczxFIGV4dGVuZHMgVGVzdEVsZW1lbnQ+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4sIGN1c3RvbVRlc3RFbGVtZW50VHlwZTogVHlwZTxFPik6IEFycmF5PEU+IHtcbiAgICByZXR1cm4gdGhpcy50ZXN0RWxlbWVudC5jdXN0b21zKHNlbGVjdG9yLCBjdXN0b21UZXN0RWxlbWVudFR5cGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyaWdnZXJzIGEgY2hhbmdlIGRldGVjdGlvbiB1c2luZyB0aGUgd3JhcHBlZCBmaXh0dXJlXG4gICAqL1xuICBkZXRlY3RDaGFuZ2VzKGNoZWNrTm9DaGFuZ2VzPzogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuZml4dHVyZS5kZXRlY3RDaGFuZ2VzKGNoZWNrTm9DaGFuZ2VzKTtcbiAgfVxufVxuIl19
154
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LXRlc3Rlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1zcGVjdWxvb3Mvc3JjL2xpYi9jb21wb25lbnQtdGVzdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHNEQUFzRDtBQUN0RCx1REFBdUQ7QUFDdkQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE9BQU8sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBT2xFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRzVEOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sZUFBZTtJQVcxQjs7T0FFRztJQUNILE1BQU0sQ0FBQyxNQUFNLENBQUksYUFBc0I7UUFDckMsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLGVBQWUsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUN2RCxPQUFPLElBQUksZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3RDLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0gsWUFBWSxHQUFrQztRQUM1QyxJQUFJLENBQUMsT0FBTyxHQUFHLEdBQUcsWUFBWSxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3BGLElBQUksQ0FBQyxXQUFXLEdBQUcsa0JBQWtCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUE2QixDQUFDO0lBQ2xHLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksYUFBYTtRQUNmLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUM7SUFDcEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsSUFBSSxpQkFBaUI7UUFDbkIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUFDO0lBQ3hDLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksWUFBWTtRQUNkLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUM7SUFDbkMsQ0FBQztJQThHRCxPQUFPLENBQUMsUUFBNEI7UUFDbEMsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM1QyxDQUFDO0lBOEdELFFBQVEsQ0FBQyxRQUE0QjtRQUNuQyxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzdDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLFFBQTRCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDMUMsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxNQUFNLENBQUMsUUFBNEI7UUFDakMsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUMzQyxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxRQUFRLENBQUMsUUFBNEI7UUFDbkMsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE1BQU0sQ0FBQyxRQUE0QjtRQUNqQyxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFRDs7O09BR0c7SUFDSCxTQUFTLENBQUksUUFBaUI7UUFDNUIsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM5QyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsVUFBVSxDQUFJLFFBQWlCO1FBQzdCLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUksUUFBNEIsRUFBRSxLQUF1QjtRQUM1RCxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE1BQU0sQ0FBSSxRQUE0QixFQUFFLEtBQXVCO1FBQzdELE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxNQUFNLENBQXdCLFFBQTRCLEVBQUUscUJBQThCO1FBQ3hGLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLHFCQUFxQixDQUFDLENBQUM7SUFDbEUsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILE9BQU8sQ0FBd0IsUUFBNEIsRUFBRSxxQkFBOEI7UUFDekYsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUscUJBQXFCLENBQUMsQ0FBQztJQUNuRSxDQUFDO0lBRUQ7O09BRUc7SUFDSCxhQUFhLENBQUMsY0FBd0I7UUFDcEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDN0MsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLE1BQU07UUFDVixNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDaEMsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQ3ZCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyAqL1xuLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueSAqL1xuaW1wb3J0IHsgQ29tcG9uZW50Rml4dHVyZSwgVGVzdEJlZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUvdGVzdGluZyc7XG5pbXBvcnQgeyBEZWJ1Z0VsZW1lbnQsIFByb3ZpZGVyVG9rZW4sIFR5cGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFRlc3RUZXh0QXJlYSB9IGZyb20gJy4vdGVzdC10ZXh0YXJlYSc7XG5pbXBvcnQgeyBUZXN0RWxlbWVudCB9IGZyb20gJy4vdGVzdC1lbGVtZW50JztcbmltcG9ydCB7IFRlc3RJbnB1dCB9IGZyb20gJy4vdGVzdC1pbnB1dCc7XG5pbXBvcnQgeyBUZXN0U2VsZWN0IH0gZnJvbSAnLi90ZXN0LXNlbGVjdCc7XG5pbXBvcnQgeyBUZXN0QnV0dG9uIH0gZnJvbSAnLi90ZXN0LWJ1dHRvbic7XG5pbXBvcnQgeyBUZXN0RWxlbWVudFF1ZXJpZXIgfSBmcm9tICcuL3Rlc3QtZWxlbWVudC1xdWVyaWVyJztcbmltcG9ydCB7IFRlc3RIdG1sRWxlbWVudCB9IGZyb20gJy4vdGVzdC1odG1sLWVsZW1lbnQnO1xuXG4vKipcbiAqIFRoZSBtYWluIGVudHJ5IHBvaW50IG9mIHRoZSBBUEkuIEl0IHdyYXBzIGFuIEFuZ3VsYXIgQ29tcG9uZW50Rml4dHVyZTxUPiwgYW5kIGdpdmVzIGFjY2VzcyB0byBpdHNcbiAqIG1vc3QgdXNlZCBwcm9wZXJ0aWVzIGFuZCBtZXRob2RzLiBJdCBhbHNvIGFsbG93cyBnZXR0aW5nIGVsZW1lbnRzIHdyYXBwZWQgaW4gVGVzdEVsZW1lbnQgKGFuZCBpdHMgc3ViY2xhc3NlcylcbiAqIEBwYXJhbSA8Qz4gdGhlIHR5cGUgb2YgdGhlIGNvbXBvbmVudCB0byB0ZXN0XG4gKi9cbmV4cG9ydCBjbGFzcyBDb21wb25lbnRUZXN0ZXI8Qz4ge1xuICAvKipcbiAgICogVGhlIHRlc3QgZWxlbWVudCBvZiB0aGUgY29tcG9uZW50XG4gICAqL1xuICByZWFkb25seSB0ZXN0RWxlbWVudDogVGVzdEVsZW1lbnQ8SFRNTEVsZW1lbnQ+O1xuXG4gIC8qKlxuICAgKiBUaGUgY29tcG9uZW50IGZpeHR1cmUgb2YgdGhlIGNvbXBvbmVudFxuICAgKi9cbiAgcmVhZG9ubHkgZml4dHVyZTogQ29tcG9uZW50Rml4dHVyZTxDPjtcblxuICAvKipcbiAgICogQ3JlYXRlcyBhIGNvbXBvbmVudCBmaXh0dXJlIG9mIHRoZSBnaXZlbiB0eXBlIHdpdGggdGhlIFRlc3RCZWQgYW5kIHdyYXBzIGl0IGludG8gYSBDb21wb25lbnRUZXN0ZXJcbiAgICovXG4gIHN0YXRpYyBjcmVhdGU8Qz4oY29tcG9uZW50VHlwZTogVHlwZTxDPik6IENvbXBvbmVudFRlc3RlcjxDPiB7XG4gICAgY29uc3QgZml4dHVyZSA9IFRlc3RCZWQuY3JlYXRlQ29tcG9uZW50KGNvbXBvbmVudFR5cGUpO1xuICAgIHJldHVybiBuZXcgQ29tcG9uZW50VGVzdGVyKGZpeHR1cmUpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBDb21wb25lbnRGaXh0dXJlIGZvciB0aGUgZ2l2ZW4gY29tcG9uZW50IHR5cGUgdXNpbmcgdGhlIFRlc3RCZWQsIGFuZCBjcmVhdGVzIGEgQ29tcG9uZW50VGVzdGVyXG4gICAqIHdyYXBwaW5nIChhbmQgZGVsZWdhdGluZykgdG8gdGhpcyBmaXh0dXJlLiBJZiBhIGZpeHR1cmUgaXMgcGFzc2VkLCB0aGVuIGRlbGVnYXRlcyB0byB0aGlzIGZpeHR1cmUgZGlyZWN0bHkuXG4gICAqXG4gICAqIE5vdGUgdGhhdCBubyBgZGV0ZWN0Q2hhbmdlcygpYCBjYWxsIGlzIG1hZGUgYnkgdGhpcyBjb25zdHJ1Y3Rvci4gSXQncyB1cCB0byB0aGUgc3ViY2xhc3MgY29uc3RydWN0b3IsXG4gICAqIG9yIHRvIHRoZSB1c2VyIG9mIHRoZSBjcmVhdGVkIENvbXBvbmVudFRlc3RlciwgdG8gY2FsbCBgZGV0ZWN0Q2hhbmdlcygpYCBhdCBsZWFzdCBvbmNlIHRvIHRyaWdnZXIgY2hhbmdlXG4gICAqIGRldGVjdGlvbi4gVGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSBzb21lIGNvbXBvbmVudCB0ZW1wbGF0ZXMgY2FuIG9ubHkgYmUgZXZhbHVhdGVkIG9uY2UgaW5wdXRzXG4gICAqIGhhdmUgYmVlbiBzZXQgb24gdGhlIGNvbXBvbmVudCBpbnN0YW5jZS5cbiAgICpcbiAgICogQHBhcmFtIGFyZyB0aGUgdHlwZSBvZiB0aGUgY29tcG9uZW50IHRvIHdyYXAsIG9yIGEgY29tcG9uZW50IGZpeHR1cmUgdG8gd3JhcFxuICAgKi9cbiAgY29uc3RydWN0b3IoYXJnOiBUeXBlPEM+IHwgQ29tcG9uZW50Rml4dHVyZTxDPikge1xuICAgIHRoaXMuZml4dHVyZSA9IGFyZyBpbnN0YW5jZW9mIENvbXBvbmVudEZpeHR1cmUgPyBhcmcgOiBUZXN0QmVkLmNyZWF0ZUNvbXBvbmVudChhcmcpO1xuICAgIHRoaXMudGVzdEVsZW1lbnQgPSBUZXN0RWxlbWVudFF1ZXJpZXIud3JhcCh0aGlzLmRlYnVnRWxlbWVudCwgdGhpcykgYXMgVGVzdEVsZW1lbnQ8SFRNTEVsZW1lbnQ+O1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBuYXRpdmUgRE9NIGhvc3QgZWxlbWVudCBvZiB0aGUgY29tcG9uZW50XG4gICAqL1xuICBnZXQgbmF0aXZlRWxlbWVudCgpOiBIVE1MRWxlbWVudCB7XG4gICAgcmV0dXJuIHRoaXMuZml4dHVyZS5uYXRpdmVFbGVtZW50O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGluc3RhbmNlIG9mIHRoZSB0ZXN0ZWQgY29tcG9uZW50IGZyb20gdGhlIHdyYXBwZWQgZml4dHVyZVxuICAgKi9cbiAgZ2V0IGNvbXBvbmVudEluc3RhbmNlKCk6IEMge1xuICAgIHJldHVybiB0aGlzLmZpeHR1cmUuY29tcG9uZW50SW5zdGFuY2U7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgZGVidWcgZWxlbWVudCBmcm9tIHRoZSB3cmFwcGVkIGZpeHR1cmVcbiAgICovXG4gIGdldCBkZWJ1Z0VsZW1lbnQoKTogRGVidWdFbGVtZW50IHtcbiAgICByZXR1cm4gdGhpcy5maXh0dXJlLmRlYnVnRWxlbWVudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBlbGVtZW50IG1hdGNoaW5nIHRoZSBnaXZlbiBDU1Mgc2VsZWN0b3IgYW5kIHdyYXBzIGl0IGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCB2YWx1ZSBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50IGlzIGFuIGlucHV0IGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGEgVGVzdElucHV0LlxuICAgKiA8cD5Vc2FnZTo8L3A+XG4gICAqIDxjb2RlPlxuICAgKiBjb25zdCB0ZXN0RWxlbWVudDogVGVzdEh0bWxFbGVtZW50Jmx0O0hUTUxEaXZFbGVtZW50PiB8IG51bGwgPSB0ZXN0ZXIuZWxlbWVudCgnZGl2Jyk7XG4gICAqIDwvY29kZT5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIGVsZW1lbnQsIG9yIG51bGwgaWYgbm8gZWxlbWVudCBtYXRjaGVzIHRoZSBzZWxlY3Rvci5cbiAgICovXG4gIGVsZW1lbnQ8SyBleHRlbmRzIGtleW9mIEhUTUxFbGVtZW50VGFnTmFtZU1hcD4oc2VsZWN0b3I6IEspOiBUZXN0SHRtbEVsZW1lbnQ8SFRNTEVsZW1lbnRUYWdOYW1lTWFwW0tdPiB8IG51bGw7XG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBlbGVtZW50IG1hdGNoaW5nIHRoZSBnaXZlbiBDU1Mgc2VsZWN0b3IgYW5kIHdyYXBzIGl0IGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCB2YWx1ZSBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50IGlzIGFuIGlucHV0IGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGEgVGVzdElucHV0LlxuICAgKiA8cD5Vc2FnZTo8L3A+XG4gICAqIDxjb2RlPlxuICAgKiBjb25zdCB0ZXN0RWxlbWVudDogVGVzdEVsZW1lbnQmbHQ7U1ZHTGluZUVsZW1lbnQ+IHwgbnVsbCA9IHRlc3Rlci5lbGVtZW50KCdsaW5lJyk7XG4gICAqIDwvY29kZT5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIGVsZW1lbnQsIG9yIG51bGwgaWYgbm8gZWxlbWVudCBtYXRjaGVzIHRoZSBzZWxlY3Rvci5cbiAgICovXG4gIGVsZW1lbnQ8SyBleHRlbmRzIGtleW9mIFNWR0VsZW1lbnRUYWdOYW1lTWFwPihzZWxlY3RvcjogSyk6IFRlc3RFbGVtZW50PFNWR0VsZW1lbnRUYWdOYW1lTWFwW0tdPiB8IG51bGw7XG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBlbGVtZW50IG1hdGNoaW5nIHRoZSBnaXZlbiBDU1Mgc2VsZWN0b3IgYW5kIHdyYXBzIGl0IGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCB2YWx1ZSBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50IGlzIGFuIGlucHV0IGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGEgVGVzdElucHV0LlxuICAgKiA8cD5Vc2FnZTo8L3A+XG4gICAqIDxjb2RlPlxuICAgKiBjb25zdCB0ZXN0RWxlbWVudDogVGVzdEVsZW1lbnQgfCBudWxsID0gdGVzdGVyLmVsZW1lbnQoJy5zZWxlY3RvcicpO1xuICAgKiA8L2NvZGU+XG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgZWxlbWVudCwgb3IgbnVsbCBpZiBubyBlbGVtZW50IG1hdGNoZXMgdGhlIHNlbGVjdG9yLlxuICAgKi9cbiAgZWxlbWVudChzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+KTogVGVzdEVsZW1lbnQgfCBudWxsO1xuICAvKipcbiAgICogR2V0cyB0aGUgZmlyc3QgZWxlbWVudCBtYXRjaGluZyB0aGUgZ2l2ZW4gc2VsZWN0b3IgYW5kIHdyYXBzIGl0IGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCB2YWx1ZSBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50IGlzIGFuIGlucHV0IGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGEgVGVzdElucHV0LlxuICAgKiA8cD5Vc2FnZTo8L3A+XG4gICAqIDxjb2RlPlxuICAgKiBjb25zdCB0ZXN0RWxlbWVudDogVGVzdElucHV0IHwgbnVsbCA9IHRlc3Rlci5lbGVtZW50Jmx0O0hUTUxJbnB1dEVsZW1lbnQ+KCcuc2VsZWN0b3InKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIGVsZW1lbnQsIG9yIG51bGwgaWYgbm8gZWxlbWVudCBtYXRjaGVzIHRoZSBzZWxlY3Rvci5cbiAgICovXG4gIGVsZW1lbnQ8VCBleHRlbmRzIEhUTUxJbnB1dEVsZW1lbnQ+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0SW5wdXQgfCBudWxsO1xuICAvKipcbiAgICogR2V0cyB0aGUgZmlyc3QgZWxlbWVudCBtYXRjaGluZyB0aGUgZ2l2ZW4gc2VsZWN0b3IgYW5kIHdyYXBzIGl0IGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCB2YWx1ZSBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50IGlzIGFuIGlucHV0IGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGEgVGVzdElucHV0LlxuICAgKiA8cD5Vc2FnZTo8L3A+XG4gICAqIDxjb2RlPlxuICAgKiBjb25zdCB0ZXN0RWxlbWVudDogVGVzdFRleHRBcmVhIHwgbnVsbCA9IHRlc3Rlci5lbGVtZW50Jmx0O0hUTUxUZXh0QXJlYUVsZW1lbnQ+KCcuc2VsZWN0b3InKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIGVsZW1lbnQsIG9yIG51bGwgaWYgbm8gZWxlbWVudCBtYXRjaGVzIHRoZSBzZWxlY3Rvci5cbiAgICovXG4gIGVsZW1lbnQ8VCBleHRlbmRzIEhUTUxUZXh0QXJlYUVsZW1lbnQ+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0VGV4dEFyZWEgfCBudWxsO1xuICAvKipcbiAgICogR2V0cyB0aGUgZmlyc3QgZWxlbWVudCBtYXRjaGluZyB0aGUgZ2l2ZW4gc2VsZWN0b3IgYW5kIHdyYXBzIGl0IGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCB2YWx1ZSBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50IGlzIGFuIGlucHV0IGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGEgVGVzdElucHV0LlxuICAgKiA8cD5Vc2FnZTo8L3A+XG4gICAqIDxjb2RlPlxuICAgKiBjb25zdCB0ZXN0RWxlbWVudDogVGVzdFNlbGVjdCB8IG51bGwgPSB0ZXN0ZXIuZWxlbWVudCZsdDtIVE1MU2VsZWN0RWxlbWVudD4oJy5zZWxlY3RvcicpO1xuICAgKiA8L2NvZGU+XG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgZWxlbWVudCwgb3IgbnVsbCBpZiBubyBlbGVtZW50IG1hdGNoZXMgdGhlIHNlbGVjdG9yLlxuICAgKi9cbiAgZWxlbWVudDxUIGV4dGVuZHMgSFRNTFNlbGVjdEVsZW1lbnQ+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0U2VsZWN0IHwgbnVsbDtcbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IGVsZW1lbnQgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yIGFuZCB3cmFwcyBpdCBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgdmFsdWUgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudCBpcyBhbiBpbnB1dCBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhIFRlc3RJbnB1dC5cbiAgICogPHA+VXNhZ2U6PC9wPlxuICAgKiA8Y29kZT5cbiAgICogY29uc3QgdGVzdEVsZW1lbnQ6IFRlc3RCdXR0b24gfCBudWxsID0gdGVzdGVyLmVsZW1lbnQmbHQ7SFRNTEJ1dHRvbkVsZW1lbnQ+KCcuc2VsZWN0b3InKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIGVsZW1lbnQsIG9yIG51bGwgaWYgbm8gZWxlbWVudCBtYXRjaGVzIHRoZSBzZWxlY3Rvci5cbiAgICovXG4gIGVsZW1lbnQ8VCBleHRlbmRzIEhUTUxCdXR0b25FbGVtZW50PihzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+KTogVGVzdEJ1dHRvbiB8IG51bGw7XG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBlbGVtZW50IG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciBhbmQgd3JhcHMgaXQgaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIHZhbHVlIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnQgaXMgYW4gaW5wdXQgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYSBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50OiBUZXN0SHRtbEVsZW1lbnQmbHQ7SFRNTERpdkVsZW1lbnQ+IHwgbnVsbCA9IHRlc3Rlci5lbGVtZW50Jmx0O0hUTUxEaXZFbGVtZW50PignLnNlbGVjdG9yJyk7XG4gICAqIDwvY29kZT5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgd3JhcHBlZCBlbGVtZW50LCBvciBudWxsIGlmIG5vIGVsZW1lbnQgbWF0Y2hlcyB0aGUgc2VsZWN0b3IuXG4gICAqL1xuICBlbGVtZW50PFQgZXh0ZW5kcyBIVE1MRWxlbWVudD4oc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RIdG1sRWxlbWVudDxUPiB8IG51bGw7XG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBlbGVtZW50IG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciBhbmQgd3JhcHMgaXQgaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIHZhbHVlIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnQgaXMgYW4gaW5wdXQgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYSBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50OiBUZXN0RWxlbWVudCZsdDtTVkdMaW5lRWxlbWVudD4gfCBudWxsID0gdGVzdGVyLmVsZW1lbnQmbHQ7U1ZHTGluZUVsZW1lbnQ+KCcuc2VsZWN0b3InKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIGVsZW1lbnQsIG9yIG51bGwgaWYgbm8gZWxlbWVudCBtYXRjaGVzIHRoZSBzZWxlY3Rvci5cbiAgICovXG4gIGVsZW1lbnQ8VCBleHRlbmRzIEVsZW1lbnQ+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0RWxlbWVudDxUPiB8IG51bGw7XG4gIGVsZW1lbnQoc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RFbGVtZW50IHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMudGVzdEVsZW1lbnQuZWxlbWVudChzZWxlY3Rvcik7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBhbGwgdGhlIGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBnaXZlbiBDU1Mgc2VsZWN0b3IgYW5kIHdyYXBzIHRoZW0gaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIGVsZW1lbnRzIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnRzIGFyZSBpbnB1dHMgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYW4gYXJyYXkgb2YgVGVzdElucHV0LlxuICAgKiA8cD5Vc2FnZTo8L3A+XG4gICAqIDxjb2RlPlxuICAgKiBjb25zdCB0ZXN0RWxlbWVudHM6IEFycmF5Jmx0O1Rlc3RIdG1sRWxlbWVudCZsdDtIVE1MRGl2RWxlbWVudD4+ID0gdGVzdGVyLmVsZW1lbnRzKCdkaXYnKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIGFycmF5IG9mIG1hdGNoZWQgZWxlbWVudHMsIGVtcHR5IGlmIG5vIGVsZW1lbnQgd2FzIG1hdGNoZWRcbiAgICovXG4gIGVsZW1lbnRzPEsgZXh0ZW5kcyBrZXlvZiBIVE1MRWxlbWVudFRhZ05hbWVNYXA+KHNlbGVjdG9yOiBLKTogQXJyYXk8VGVzdEh0bWxFbGVtZW50PEhUTUxFbGVtZW50VGFnTmFtZU1hcFtLXT4+O1xuICAvKipcbiAgICogR2V0cyBhbGwgdGhlIGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBnaXZlbiBDU1Mgc2VsZWN0b3IgYW5kIHdyYXBzIHRoZW0gaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIGVsZW1lbnRzIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnRzIGFyZSBpbnB1dHMgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYW4gYXJyYXkgb2YgVGVzdElucHV0LlxuICAgKiA8cD5Vc2FnZTo8L3A+XG4gICAqIDxjb2RlPlxuICAgKiBjb25zdCB0ZXN0RWxlbWVudHM6IEFycmF5Jmx0O1Rlc3RFbGVtZW50Jmx0O1NWR0xpbmVFbGVtZW50Pj4gPSB0ZXN0ZXIuZWxlbWVudHMoJ2xpbmUnKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIGFycmF5IG9mIG1hdGNoZWQgZWxlbWVudHMsIGVtcHR5IGlmIG5vIGVsZW1lbnQgd2FzIG1hdGNoZWRcbiAgICovXG4gIGVsZW1lbnRzPEsgZXh0ZW5kcyBrZXlvZiBTVkdFbGVtZW50VGFnTmFtZU1hcD4oc2VsZWN0b3I6IEspOiBBcnJheTxUZXN0RWxlbWVudDxTVkdFbGVtZW50VGFnTmFtZU1hcFtLXT4+O1xuICAvKipcbiAgICogR2V0cyBhbGwgdGhlIGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciBhbmQgd3JhcHMgdGhlbSBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgZWxlbWVudHMgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudHMgYXJlIGlucHV0cyBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhbiBhcnJheSBvZiBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50czogQXJyYXkmbHQ7VGVzdEVsZW1lbnQ+ID0gdGVzdGVyLmVsZW1lbnRzKCcuc2VsZWN0b3InKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSBhcnJheSBvZiBtYXRjaGVkIGVsZW1lbnRzLCBlbXB0eSBpZiBubyBlbGVtZW50IHdhcyBtYXRjaGVkXG4gICAqL1xuICBlbGVtZW50cyhzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+KTogQXJyYXk8VGVzdEVsZW1lbnQ+O1xuICAvKipcbiAgICogR2V0cyBhbGwgdGhlIGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciBhbmQgd3JhcHMgdGhlbSBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgZWxlbWVudHMgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudHMgYXJlIGlucHV0cyBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhbiBhcnJheSBvZiBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50czogQXJyYXkmbHQ7VGVzdElucHV0PiA9IHRlc3Rlci5lbGVtZW50cyZsdDtIVE1MSW5wdXRFbGVtZW50PignLnNlbGVjdG9yJyk7XG4gICAqIDwvY29kZT5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgYXJyYXkgb2YgbWF0Y2hlZCBlbGVtZW50cywgZW1wdHkgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgZWxlbWVudHM8VCBleHRlbmRzIEhUTUxJbnB1dEVsZW1lbnQ+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBBcnJheTxUZXN0SW5wdXQ+O1xuICAvKipcbiAgICogR2V0cyBhbGwgdGhlIGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciBhbmQgd3JhcHMgdGhlbSBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgZWxlbWVudHMgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudHMgYXJlIGlucHV0cyBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhbiBhcnJheSBvZiBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50czogQXJyYXkmbHQ7VGVzdFRleHRBcmVhPiA9IHRlc3Rlci5lbGVtZW50cyZsdDtIVE1MVGV4dEFyZWFFbGVtZW50PignLnNlbGVjdG9yJyk7XG4gICAqIDwvY29kZT5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgYXJyYXkgb2YgbWF0Y2hlZCBlbGVtZW50cywgZW1wdHkgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgZWxlbWVudHM8VCBleHRlbmRzIEhUTUxUZXh0QXJlYUVsZW1lbnQ+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBBcnJheTxUZXN0VGV4dEFyZWE+O1xuICAvKipcbiAgICogR2V0cyBhbGwgdGhlIGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBnaXZlbiBDU1Mgc2VsZWN0b3IgYW5kIHdyYXBzIHRoZW0gaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIGVsZW1lbnRzIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnRzIGFyZSBpbnB1dHMgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYW4gYXJyYXkgb2YgVGVzdElucHV0LlxuICAgKiA8cD5Vc2FnZTo8L3A+XG4gICAqIDxjb2RlPlxuICAgKiBjb25zdCB0ZXN0RWxlbWVudHM6IEFycmF5Jmx0O1Rlc3RCdXR0b24+ID0gdGVzdGVyLmVsZW1lbnRzJmx0O0hUTUxCdXR0b25FbGVtZW50PignLnNlbGVjdG9yJyk7XG4gICAqIDwvY29kZT5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgYXJyYXkgb2YgbWF0Y2hlZCBlbGVtZW50cywgZW1wdHkgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgZWxlbWVudHM8VCBleHRlbmRzIEhUTUxCdXR0b25FbGVtZW50PihzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+KTogQXJyYXk8VGVzdEJ1dHRvbj47XG4gIC8qKlxuICAgKiBHZXRzIGFsbCB0aGUgZWxlbWVudHMgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yIGFuZCB3cmFwcyB0aGVtIGludG8gYSBUZXN0RWxlbWVudC4gVGhlIGFjdHVhbCB0eXBlXG4gICAqIG9mIHRoZSByZXR1cm5lZCBlbGVtZW50cyBpcyB0aGUgVGVzdEVsZW1lbnQgc3ViY2xhc3MgbWF0Y2hpbmcgdGhlIHR5cGUgb2YgdGhlIGZvdW5kIGVsZW1lbnQuIFNvLCBpZiB0aGVcbiAgICogbWF0Y2hlZCBlbGVtZW50cyBhcmUgaW5wdXRzIGZvciBleGFtcGxlLCB0aGUgbWV0aG9kIHdpbGwgcmV0dXJuIGFuIGFycmF5IG9mIFRlc3RJbnB1dC5cbiAgICogPHA+VXNhZ2U6PC9wPlxuICAgKiA8Y29kZT5cbiAgICogY29uc3QgdGVzdEVsZW1lbnRzOiBBcnJheSZsdDtUZXN0U2VsZWN0PiA9IHRlc3Rlci5lbGVtZW50czxIVE1MU2VsZWN0RWxlbWVudD4oJy5zZWxlY3RvcicpO1xuICAgKiA8L2NvZGU+XG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIGFycmF5IG9mIG1hdGNoZWQgZWxlbWVudHMsIGVtcHR5IGlmIG5vIGVsZW1lbnQgd2FzIG1hdGNoZWRcbiAgICovXG4gIGVsZW1lbnRzPFQgZXh0ZW5kcyBIVE1MU2VsZWN0RWxlbWVudD4oc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IEFycmF5PFRlc3RTZWxlY3Q+O1xuICAvKipcbiAgICogR2V0cyBhbGwgdGhlIGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciBhbmQgd3JhcHMgdGhlbSBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgZWxlbWVudHMgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudHMgYXJlIGlucHV0cyBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhbiBhcnJheSBvZiBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50czogQXJyYXkmbHQ7VGVzdEh0bWxFbGVtZW50Jmx0O0hUTUxEaXZFbGVtZW50Pj4gPSB0ZXN0ZXIuZWxlbWVudHMmbHQ7SFRNTERpdkVsZW1lbnQ+KCcuc2VsZWN0b3InKTtcbiAgICogPC9jb2RlPlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSBhcnJheSBvZiBtYXRjaGVkIGVsZW1lbnRzLCBlbXB0eSBpZiBubyBlbGVtZW50IHdhcyBtYXRjaGVkXG4gICAqL1xuICBlbGVtZW50czxUIGV4dGVuZHMgSFRNTEVsZW1lbnQ+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBBcnJheTxUZXN0SHRtbEVsZW1lbnQ8VD4+O1xuICAvKipcbiAgICogR2V0cyBhbGwgdGhlIGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciBhbmQgd3JhcHMgdGhlbSBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgZWxlbWVudHMgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudHMgYXJlIGlucHV0cyBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhbiBhcnJheSBvZiBUZXN0SW5wdXQuXG4gICAqIDxwPlVzYWdlOjwvcD5cbiAgICogPGNvZGU+XG4gICAqIGNvbnN0IHRlc3RFbGVtZW50czogQXJyYXkmbHQ7VGVzdEVsZW1lbnQmbHQ7U1ZHTGluZUVsZW1lbnQ+PiA9IHRlc3Rlci5lbGVtZW50cyZsdDtTVkdMaW5lRWxlbWVudD4oJy5zZWxlY3RvcicpO1xuICAgKiA8L2NvZGU+XG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIGFycmF5IG9mIG1hdGNoZWQgZWxlbWVudHMsIGVtcHR5IGlmIG5vIGVsZW1lbnQgd2FzIG1hdGNoZWRcbiAgICovXG4gIGVsZW1lbnRzPFQgZXh0ZW5kcyBFbGVtZW50PihzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+KTogQXJyYXk8VGVzdEVsZW1lbnQ8VD4+O1xuICBlbGVtZW50cyhzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+KTogQXJyYXk8VGVzdEVsZW1lbnQ+IHtcbiAgICByZXR1cm4gdGhpcy50ZXN0RWxlbWVudC5lbGVtZW50cyhzZWxlY3Rvcik7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgZmlyc3QgaW5wdXQgbWF0Y2hlZCBieSB0aGUgZ2l2ZW4gc2VsZWN0b3IuIFRocm93cyBhbiBFcnJvciBpZiB0aGUgbWF0Y2hlZCBlbGVtZW50IGlzbid0IGFjdHVhbGx5IGFuIGlucHV0LlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIGlucHV0LCBvciBudWxsIGlmIG5vIGVsZW1lbnQgd2FzIG1hdGNoZWRcbiAgICovXG4gIGlucHV0KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0SW5wdXQgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy50ZXN0RWxlbWVudC5pbnB1dChzZWxlY3Rvcik7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgZmlyc3Qgc2VsZWN0IG1hdGNoZWQgYnkgdGhlIGdpdmVuIHNlbGVjdG9yLiBUaHJvd3MgYW4gRXJyb3IgaWYgdGhlIG1hdGNoZWQgZWxlbWVudCBpc24ndCBhY3R1YWxseSBhIHNlbGVjdC5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgd3JhcHBlZCBzZWxlY3QsIG9yIG51bGwgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgc2VsZWN0KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0U2VsZWN0IHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMudGVzdEVsZW1lbnQuc2VsZWN0KHNlbGVjdG9yKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCB0ZXh0YXJlYSBtYXRjaGVkIGJ5IHRoZSBnaXZlbiBzZWxlY3RvclxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIHRleHRhcmVhLCBvciBudWxsIGlmIG5vIGVsZW1lbnQgd2FzIG1hdGNoZWQuIFRocm93cyBhbiBFcnJvciBpZiB0aGUgbWF0Y2hlZCBlbGVtZW50IGlzbid0IGFjdHVhbGx5IGEgdGV4dGFyZWEuXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBpZiB0aGUgbWF0Y2hlZCBlbGVtZW50IGlzbid0IGFjdHVhbGx5IGEgdGV4dGFyZWFcbiAgICovXG4gIHRleHRhcmVhKHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0VGV4dEFyZWEgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy50ZXN0RWxlbWVudC50ZXh0YXJlYShzZWxlY3Rvcik7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgZmlyc3QgYnV0dG9uIG1hdGNoZWQgYnkgdGhlIGdpdmVuIHNlbGVjdG9yLiBUaHJvd3MgYW4gRXJyb3IgaWYgdGhlIG1hdGNoZWQgZWxlbWVudCBpc24ndCBhY3R1YWxseSBhIGJ1dHRvbi5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgd3JhcHBlZCBidXR0b24sIG9yIG51bGwgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgYnV0dG9uKHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0QnV0dG9uIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMudGVzdEVsZW1lbnQuYnV0dG9uKHNlbGVjdG9yKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBkaXJlY3RpdmUgbWF0Y2hpbmcgdGhlIGdpdmVuIGNvbXBvbmVudCBkaXJlY3RpdmUgc2VsZWN0b3IgYW5kIHJldHVybnMgaXRzIGNvbXBvbmVudCBpbnN0YW5jZVxuICAgKiBAcGFyYW0gc2VsZWN0b3IgdGhlIHNlbGVjdG9yIG9mIGEgY29tcG9uZW50IGRpcmVjdGl2ZVxuICAgKi9cbiAgY29tcG9uZW50PFI+KHNlbGVjdG9yOiBUeXBlPFI+KTogUiB7XG4gICAgcmV0dXJuIHRoaXMudGVzdEVsZW1lbnQuY29tcG9uZW50KHNlbGVjdG9yKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBkaXJlY3RpdmVzIG1hdGNoaW5nIHRoZSBnaXZlbiBjb21wb25lbnQgZGlyZWN0aXZlIHNlbGVjdG9yIGFuZCByZXR1cm5zIHRoZWlyIGNvbXBvbmVudCBpbnN0YW5jZVxuICAgKiBAcGFyYW0gc2VsZWN0b3IgdGhlIHNlbGVjdG9yIG9mIGEgY29tcG9uZW50IGRpcmVjdGl2ZVxuICAgKi9cbiAgY29tcG9uZW50czxSPihzZWxlY3RvcjogVHlwZTxSPik6IEFycmF5PFI+IHtcbiAgICByZXR1cm4gdGhpcy50ZXN0RWxlbWVudC5jb21wb25lbnRzKHNlbGVjdG9yKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBlbGVtZW50IG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciwgdGhlbiBnZXRzIHRoZSBnaXZlbiB0b2tlbiBmcm9tIGl0cyBpbmplY3Rvciwgb3IgbnVsbCBpZiB0aGVyZSBpcyBubyBzdWNoIHRva2VuXG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHBhcmFtIHRva2VuIHRoZSB0b2tlbiB0byBnZXQgZnJvbSB0aGUgbWF0Y2hlZCBlbGVtZW50IGluamVjdG9yXG4gICAqL1xuICB0b2tlbjxSPihzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+LCB0b2tlbjogUHJvdmlkZXJUb2tlbjxSPik6IFIgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy50ZXN0RWxlbWVudC50b2tlbihzZWxlY3RvciwgdG9rZW4pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciwgdGhlbiBnZXRzIHRoZWlyIGdpdmVuIHRva2VuIGZyb20gdGhlaXIgaW5qZWN0b3IsIG9yIG51bGwgaWYgdGhlcmUgaXMgbm8gc3VjaCB0b2tlblxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEBwYXJhbSB0b2tlbiB0aGUgdG9rZW4gdG8gZ2V0IGZyb20gdGhlIG1hdGNoZWQgZWxlbWVudCBpbmplY3RvclxuICAgKi9cbiAgdG9rZW5zPFI+KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4sIHRva2VuOiBQcm92aWRlclRva2VuPFI+KTogQXJyYXk8UiB8IG51bGw+IHtcbiAgICByZXR1cm4gdGhpcy50ZXN0RWxlbWVudC50b2tlbnMoc2VsZWN0b3IsIHRva2VuKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBlbGVtZW50IG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciwgYW5kIGlmIGZvdW5kLCBjcmVhdGVzIGFuZCByZXR1cm5zIGEgY3VzdG9tIFRlc3RFbGVtZW50IG9mIHRoZSBwcm92aWRlZFxuICAgKiB0eXBlLiBUaGlzIGlzIHVzZWZ1bCB0byBjcmVhdGUgY3VzdG9tIGhpZ2hlci1sZXZlbCBhYnN0cmFjdGlvbnMgc2ltaWxhciB0byBUZXN0SW5wdXQsIFRlc3RTZWxlY3QsIGV0Yy4gZm9yXG4gICAqIGN1c3RvbSBlbGVtZW50cyBvciBjb21wb25lbnRzLlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEBwYXJhbSBjdXN0b21UZXN0RWxlbWVudFR5cGUgdGhlIHR5cGUgb2YgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIHRoYXQgd2lsbCB3cmFwIHRoZSBmb3VuZCBlbGVtZW50XG4gICAqL1xuICBjdXN0b208RSBleHRlbmRzIFRlc3RFbGVtZW50PihzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+LCBjdXN0b21UZXN0RWxlbWVudFR5cGU6IFR5cGU8RT4pOiBFIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMudGVzdEVsZW1lbnQuY3VzdG9tKHNlbGVjdG9yLCBjdXN0b21UZXN0RWxlbWVudFR5cGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciwgYW5kIGNyZWF0ZXMgYW5kIHJldHVybnMgY3VzdG9tIFRlc3RFbGVtZW50cyBvZiB0aGUgcHJvdmlkZWRcbiAgICogdHlwZS4gVGhpcyBpcyB1c2VmdWwgdG8gY3JlYXRlIGN1c3RvbSBoaWdoZXItbGV2ZWwgYWJzdHJhY3Rpb25zIHNpbWlsYXIgdG8gVGVzdElucHV0LCBUZXN0U2VsZWN0LCBldGMuIGZvclxuICAgKiBjdXN0b20gZWxlbWVudHMgb3IgY29tcG9uZW50cy5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcGFyYW0gY3VzdG9tVGVzdEVsZW1lbnRUeXBlIHRoZSB0eXBlIG9mIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyB0aGF0IHdpbGwgd3JhcCB0aGUgZm91bmQgZWxlbWVudHNcbiAgICovXG4gIGN1c3RvbXM8RSBleHRlbmRzIFRlc3RFbGVtZW50PihzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+LCBjdXN0b21UZXN0RWxlbWVudFR5cGU6IFR5cGU8RT4pOiBBcnJheTxFPiB7XG4gICAgcmV0dXJuIHRoaXMudGVzdEVsZW1lbnQuY3VzdG9tcyhzZWxlY3RvciwgY3VzdG9tVGVzdEVsZW1lbnRUeXBlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmlnZ2VycyBhIGNoYW5nZSBkZXRlY3Rpb24gdXNpbmcgdGhlIHdyYXBwZWQgZml4dHVyZVxuICAgKi9cbiAgZGV0ZWN0Q2hhbmdlcyhjaGVja05vQ2hhbmdlcz86IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmZpeHR1cmUuZGV0ZWN0Q2hhbmdlcyhjaGVja05vQ2hhbmdlcyk7XG4gIH1cblxuICAvKipcbiAgICogRGVsZWdhdGVzIHRvIHRoZSB3cmFwcGVkIGZpeHR1cmUgd2hlblN0YWJsZSBhbmQgdGhlbiBkZXRlY3QgY2hhbmdlc1xuICAgKi9cbiAgYXN5bmMgc3RhYmxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuZml4dHVyZS53aGVuU3RhYmxlKCk7XG4gICAgdGhpcy5kZXRlY3RDaGFuZ2VzKCk7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,43 @@
1
+ import { ComponentTester } from './component-tester';
2
+ import { RouterTestingHarness } from '@angular/router/testing';
3
+ import { Router } from '@angular/router';
4
+ import { TestBed } from '@angular/core/testing';
5
+ /**
6
+ * A thin wrapper around Angular RouterTestingHarness which helps testing routed components.
7
+ * It allows, based on a configured testing module where the router is provided, to initially navigate
8
+ * to a given route, then test the routed component. It's then possible to either navigate again with
9
+ * the wrapped harness, or to use the component to trigger navigation, and test that the URL has changed
10
+ * for example.
11
+ */
12
+ export class RoutingTester extends ComponentTester {
13
+ constructor(harness) {
14
+ super(harness.fixture);
15
+ this.harness = harness;
16
+ }
17
+ /**
18
+ * Creates a RouterTestngHarness and uses it to navigate to the given URL
19
+ * @param url the URL to initially navigate to.
20
+ * @return a promise which resolves to a RoutingTester which wraps the harness
21
+ * and its fixture.
22
+ */
23
+ static async forUrl(url) {
24
+ const harness = await RouterTestingHarness.create(url);
25
+ return new RoutingTester(harness);
26
+ }
27
+ /**
28
+ * Gets the current URL of the Router service as a string
29
+ */
30
+ get url() {
31
+ const router = TestBed.inject(Router);
32
+ return router.url;
33
+ }
34
+ /**
35
+ * Gets the current URL of the Router service as an UrlTree, to be able to test its
36
+ * elements (query params, etc.)
37
+ */
38
+ get urlTree() {
39
+ const router = TestBed.inject(Router);
40
+ return router.parseUrl(router.url);
41
+ }
42
+ }
43
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGluZy10ZXN0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtc3BlY3Vsb29zL3NyYy9saWIvcm91dGluZy10ZXN0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQy9ELE9BQU8sRUFBRSxNQUFNLEVBQVcsTUFBTSxpQkFBaUIsQ0FBQztBQUNsRCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFFaEQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxPQUFPLGFBQWMsU0FBUSxlQUF3QjtJQUN6RCxZQUFxQixPQUE2QjtRQUNoRCxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBREosWUFBTyxHQUFQLE9BQU8sQ0FBc0I7SUFFbEQsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBVztRQUM3QixNQUFNLE9BQU8sR0FBRyxNQUFNLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2RCxPQUFPLElBQUksYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksR0FBRztRQUNMLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDdEMsT0FBTyxNQUFNLENBQUMsR0FBRyxDQUFDO0lBQ3BCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxJQUFJLE9BQU87UUFDVCxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3RDLE9BQU8sTUFBTSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDckMsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50VGVzdGVyIH0gZnJvbSAnLi9jb21wb25lbnQtdGVzdGVyJztcbmltcG9ydCB7IFJvdXRlclRlc3RpbmdIYXJuZXNzIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyL3Rlc3RpbmcnO1xuaW1wb3J0IHsgUm91dGVyLCBVcmxUcmVlIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IFRlc3RCZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3Rlc3RpbmcnO1xuXG4vKipcbiAqIEEgdGhpbiB3cmFwcGVyIGFyb3VuZCBBbmd1bGFyIFJvdXRlclRlc3RpbmdIYXJuZXNzIHdoaWNoIGhlbHBzIHRlc3Rpbmcgcm91dGVkIGNvbXBvbmVudHMuXG4gKiBJdCBhbGxvd3MsIGJhc2VkIG9uIGEgY29uZmlndXJlZCB0ZXN0aW5nIG1vZHVsZSB3aGVyZSB0aGUgcm91dGVyIGlzIHByb3ZpZGVkLCB0byBpbml0aWFsbHkgbmF2aWdhdGVcbiAqIHRvIGEgZ2l2ZW4gcm91dGUsIHRoZW4gdGVzdCB0aGUgcm91dGVkIGNvbXBvbmVudC4gSXQncyB0aGVuIHBvc3NpYmxlIHRvIGVpdGhlciBuYXZpZ2F0ZSBhZ2FpbiB3aXRoXG4gKiB0aGUgd3JhcHBlZCBoYXJuZXNzLCBvciB0byB1c2UgdGhlIGNvbXBvbmVudCB0byB0cmlnZ2VyIG5hdmlnYXRpb24sIGFuZCB0ZXN0IHRoYXQgdGhlIFVSTCBoYXMgY2hhbmdlZFxuICogZm9yIGV4YW1wbGUuXG4gKi9cbmV4cG9ydCBjbGFzcyBSb3V0aW5nVGVzdGVyIGV4dGVuZHMgQ29tcG9uZW50VGVzdGVyPHVua25vd24+IHtcbiAgY29uc3RydWN0b3IocmVhZG9ubHkgaGFybmVzczogUm91dGVyVGVzdGluZ0hhcm5lc3MpIHtcbiAgICBzdXBlcihoYXJuZXNzLmZpeHR1cmUpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBSb3V0ZXJUZXN0bmdIYXJuZXNzIGFuZCB1c2VzIGl0IHRvIG5hdmlnYXRlIHRvIHRoZSBnaXZlbiBVUkxcbiAgICogQHBhcmFtIHVybCB0aGUgVVJMIHRvIGluaXRpYWxseSBuYXZpZ2F0ZSB0by5cbiAgICogQHJldHVybiBhIHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgdG8gYSBSb3V0aW5nVGVzdGVyIHdoaWNoIHdyYXBzIHRoZSBoYXJuZXNzXG4gICAqIGFuZCBpdHMgZml4dHVyZS5cbiAgICovXG4gIHN0YXRpYyBhc3luYyBmb3JVcmwodXJsOiBzdHJpbmcpIHtcbiAgICBjb25zdCBoYXJuZXNzID0gYXdhaXQgUm91dGVyVGVzdGluZ0hhcm5lc3MuY3JlYXRlKHVybCk7XG4gICAgcmV0dXJuIG5ldyBSb3V0aW5nVGVzdGVyKGhhcm5lc3MpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGN1cnJlbnQgVVJMIG9mIHRoZSBSb3V0ZXIgc2VydmljZSBhcyBhIHN0cmluZ1xuICAgKi9cbiAgZ2V0IHVybCgpOiBzdHJpbmcge1xuICAgIGNvbnN0IHJvdXRlciA9IFRlc3RCZWQuaW5qZWN0KFJvdXRlcik7XG4gICAgcmV0dXJuIHJvdXRlci51cmw7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgY3VycmVudCBVUkwgb2YgdGhlIFJvdXRlciBzZXJ2aWNlIGFzIGFuIFVybFRyZWUsIHRvIGJlIGFibGUgdG8gdGVzdCBpdHNcbiAgICogZWxlbWVudHMgKHF1ZXJ5IHBhcmFtcywgZXRjLilcbiAgICovXG4gIGdldCB1cmxUcmVlKCk6IFVybFRyZWUge1xuICAgIGNvbnN0IHJvdXRlciA9IFRlc3RCZWQuaW5qZWN0KFJvdXRlcik7XG4gICAgcmV0dXJuIHJvdXRlci5wYXJzZVVybChyb3V0ZXIudXJsKTtcbiAgfVxufVxuIl19
@@ -137,4 +137,4 @@ export class TestElementQuerier {
137
137
  }
138
138
  }
139
139
  }
140
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC1lbGVtZW50LXF1ZXJpZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtc3BlY3Vsb29zL3NyYy9saWIvdGVzdC1lbGVtZW50LXF1ZXJpZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsdURBQXVEO0FBQ3ZELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDekMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBR3RELE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUUvQzs7R0FFRztBQUNILE1BQU0sT0FBTyxrQkFBa0I7SUFDN0IsWUFBb0IsTUFBZ0MsRUFBVSxJQUFrQjtRQUE1RCxXQUFNLEdBQU4sTUFBTSxDQUEwQjtRQUFVLFNBQUksR0FBSixJQUFJLENBQWM7SUFBRyxDQUFDO0lBRXBGLE1BQU0sQ0FBQyxJQUFJLENBQUMsaUJBQStCLEVBQUUsTUFBZ0M7UUFDM0UsTUFBTSxZQUFZLEdBQUcsaUJBQWlCLENBQUMsYUFBYSxDQUFDO1FBQ3JELElBQUksWUFBWSxZQUFZLGlCQUFpQixFQUFFO1lBQzdDLE9BQU8sSUFBSSxVQUFVLENBQUMsTUFBTSxFQUFFLGlCQUFpQixDQUFDLENBQUM7U0FDbEQ7YUFBTSxJQUFJLFlBQVksWUFBWSxnQkFBZ0IsRUFBRTtZQUNuRCxPQUFPLElBQUksU0FBUyxDQUFDLE1BQU0sRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO1NBQ2pEO2FBQU0sSUFBSSxZQUFZLFlBQVksaUJBQWlCLEVBQUU7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LElBQUksQ0FBQyxZQUFZLEVBQUU7WUFDakIsT0FBTyxJQUFJLENBQUM7U0FDYjthQUFNLElBQUksQ0FBQyxDQUFDLFlBQVksQ0FBQyxhQUFhLFlBQVksaUJBQWlCLENBQUMsRUFBRTtZQUNyRSxNQUFNLElBQUksS0FBSyxDQUFDLHlCQUF5QixRQUFRLDhCQUE4QixDQUFDLENBQUM7U0FDbEY7UUFDRCxPQUFPLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFDbkQsQ0FBQztJQUVPLEtBQUssQ0FBQyxRQUE0QjtRQUN4QyxJQUFJLE9BQU8sUUFBUSxLQUFLLFFBQVEsRUFBRTtZQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztTQUMxQzthQUFNO1lBQ0wsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7U0FDaEQ7SUFDSCxDQUFDO0lBRU8sUUFBUSxDQUFDLFFBQTRCO1FBQzNDLElBQUksT0FBTyxRQUFRLEtBQUssUUFBUSxFQUFFO1lBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO1NBQzdDO2FBQU07WUFDTCxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztTQUNuRDtJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkgKi9cbmltcG9ydCB7IFRlc3RCdXR0b24gfSBmcm9tICcuL3Rlc3QtYnV0dG9uJztcbmltcG9ydCB7IFRlc3RTZWxlY3QgfSBmcm9tICcuL3Rlc3Qtc2VsZWN0JztcbmltcG9ydCB7IFRlc3RFbGVtZW50IH0gZnJvbSAnLi90ZXN0LWVsZW1lbnQnO1xuaW1wb3J0IHsgVGVzdFRleHRBcmVhIH0gZnJvbSAnLi90ZXN0LXRleHRhcmVhJztcbmltcG9ydCB7IFRlc3RJbnB1dCB9IGZyb20gJy4vdGVzdC1pbnB1dCc7XG5pbXBvcnQgeyBUZXN0SHRtbEVsZW1lbnQgfSBmcm9tICcuL3Rlc3QtaHRtbC1lbGVtZW50JztcbmltcG9ydCB7IENvbXBvbmVudFRlc3RlciB9IGZyb20gJy4vY29tcG9uZW50LXRlc3Rlcic7XG5pbXBvcnQgeyBEZWJ1Z0VsZW1lbnQsIFR5cGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJ5IH0gZnJvbSAnQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3Nlcic7XG5cbi8qKlxuICogQGludGVybmFsXG4gKi9cbmV4cG9ydCBjbGFzcyBUZXN0RWxlbWVudFF1ZXJpZXIge1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHRlc3RlcjogQ29tcG9uZW50VGVzdGVyPHVua25vd24+LCBwcml2YXRlIHJvb3Q6IERlYnVnRWxlbWVudCkge31cblxuICBzdGF0aWMgd3JhcChjaGlsZERlYnVnRWxlbWVudDogRGVidWdFbGVtZW50LCB0ZXN0ZXI6IENvbXBvbmVudFRlc3Rlcjx1bmtub3duPik6IFRlc3RFbGVtZW50IHtcbiAgICBjb25zdCBjaGlsZEVsZW1lbnQgPSBjaGlsZERlYnVnRWxlbWVudC5uYXRpdmVFbGVtZW50O1xuICAgIGlmIChjaGlsZEVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MQnV0dG9uRWxlbWVudCkge1xuICAgICAgcmV0dXJuIG5ldyBUZXN0QnV0dG9uKHRlc3RlciwgY2hpbGREZWJ1Z0VsZW1lbnQpO1xuICAgIH0gZWxzZSBpZiAoY2hpbGRFbGVtZW50IGluc3RhbmNlb2YgSFRNTElucHV0RWxlbWVudCkge1xuICAgICAgcmV0dXJuIG5ldyBUZXN0SW5wdXQodGVzdGVyLCBjaGlsZERlYnVnRWxlbWVudCk7XG4gICAgfSBlbHNlIGlmIChjaGlsZEVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MU2VsZWN0RWxlbWVudCkge1xuICAgICAgcmV0dXJuIG5ldyBUZXN0U2VsZWN0KHRlc3RlciwgY2hpbGREZWJ1Z0VsZW1lbnQpO1xuICAgIH0gZWxzZSBpZiAoY2hpbGRFbGVtZW50IGluc3RhbmNlb2YgSFRNTFRleHRBcmVhRWxlbWVudCkge1xuICAgICAgcmV0dXJuIG5ldyBUZXN0VGV4dEFyZWEodGVzdGVyLCBjaGlsZERlYnVnRWxlbWVudCk7XG4gICAgfSBlbHNlIGlmIChjaGlsZEVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCkge1xuICAgICAgcmV0dXJuIG5ldyBUZXN0SHRtbEVsZW1lbnQodGVzdGVyLCBjaGlsZERlYnVnRWxlbWVudCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBuZXcgVGVzdEVsZW1lbnQodGVzdGVyLCBjaGlsZERlYnVnRWxlbWVudCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IGVsZW1lbnQgbWF0Y2hpbmcgdGhlIGdpdmVuIHNlbGVjdG9yIGFuZCB3cmFwcyBpdCBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgdmFsdWUgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudCBpcyBhbiBpbnB1dCBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhIFRlc3RJbnB1dC4gWW91IGNhbiB0aHVzIHVzZVxuICAgKiBgdGVzdGVyLmVsZW1lbnQoJyNzb21lLWlucHV0JykgYXMgVGVzdElucHV0YC5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgd3JhcHBlZCBlbGVtZW50LCBvciBudWxsIGlmIG5vIGVsZW1lbnQgbWF0Y2hlcyB0aGUgc2VsZWN0b3IuXG4gICAqL1xuICBlbGVtZW50KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0RWxlbWVudCB8IG51bGwge1xuICAgIGNvbnN0IGNoaWxkRWxlbWVudCA9IHRoaXMucXVlcnkoc2VsZWN0b3IpO1xuICAgIHJldHVybiBjaGlsZEVsZW1lbnQgJiYgVGVzdEVsZW1lbnRRdWVyaWVyLndyYXAoY2hpbGRFbGVtZW50LCB0aGlzLnRlc3Rlcik7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBhbGwgdGhlIGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciBhbmQgd3JhcHMgdGhlbSBpbnRvIGEgVGVzdEVsZW1lbnQuIFRoZSBhY3R1YWwgdHlwZVxuICAgKiBvZiB0aGUgcmV0dXJuZWQgZWxlbWVudHMgaXMgdGhlIFRlc3RFbGVtZW50IHN1YmNsYXNzIG1hdGNoaW5nIHRoZSB0eXBlIG9mIHRoZSBmb3VuZCBlbGVtZW50LiBTbywgaWYgdGhlXG4gICAqIG1hdGNoZWQgZWxlbWVudHMgYXJlIGlucHV0cyBmb3IgZXhhbXBsZSwgdGhlIG1ldGhvZCB3aWxsIHJldHVybiBhbiBhcnJheSBvZiBUZXN0SW5wdXQuIFlvdSBjYW4gdGh1cyB1c2VcbiAgICogYHRlc3Rlci5lbGVtZW50cygnaW5wdXQnKSBhcyBBcnJheTxUZXN0SW5wdXQ+YC5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgYXJyYXkgb2YgbWF0Y2hlZCBlbGVtZW50cywgZW1wdHkgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgZWxlbWVudHMoc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IEFycmF5PFRlc3RFbGVtZW50PiB7XG4gICAgY29uc3QgY2hpbGRFbGVtZW50cyA9IHRoaXMucXVlcnlBbGwoc2VsZWN0b3IpO1xuICAgIHJldHVybiBjaGlsZEVsZW1lbnRzLm1hcChkZWJ1Z0VsZW1lbnQgPT4gVGVzdEVsZW1lbnRRdWVyaWVyLndyYXAoZGVidWdFbGVtZW50LCB0aGlzLnRlc3RlcikpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IGlucHV0IG1hdGNoZWQgYnkgdGhlIGdpdmVuIHNlbGVjdG9yLiBUaHJvd3MgYW4gRXJyb3IgaWYgdGhlIG1hdGNoZWQgZWxlbWVudCBpc24ndCBhY3R1YWxseSBhbiBpbnB1dC5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgd3JhcHBlZCBpbnB1dCwgb3IgbnVsbCBpZiBubyBlbGVtZW50IHdhcyBtYXRjaGVkXG4gICAqL1xuICBpbnB1dChzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+KTogVGVzdElucHV0IHwgbnVsbCB7XG4gICAgY29uc3QgY2hpbGRFbGVtZW50ID0gdGhpcy5xdWVyeShzZWxlY3Rvcik7XG4gICAgaWYgKCFjaGlsZEVsZW1lbnQpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gZWxzZSBpZiAoIShjaGlsZEVsZW1lbnQubmF0aXZlRWxlbWVudCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEVsZW1lbnQgd2l0aCBzZWxlY3RvciAke3NlbGVjdG9yfSBpcyBub3QgYW4gSFRNTElucHV0RWxlbWVudGApO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IFRlc3RJbnB1dCh0aGlzLnRlc3RlciwgY2hpbGRFbGVtZW50KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBzZWxlY3QgbWF0Y2hlZCBieSB0aGUgZ2l2ZW4gc2VsZWN0b3IuIFRocm93cyBhbiBFcnJvciBpZiB0aGUgbWF0Y2hlZCBlbGVtZW50IGlzbid0IGFjdHVhbGx5IGEgc2VsZWN0LlxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIHNlbGVjdCwgb3IgbnVsbCBpZiBubyBlbGVtZW50IHdhcyBtYXRjaGVkXG4gICAqL1xuICBzZWxlY3Qoc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RTZWxlY3QgfCBudWxsIHtcbiAgICBjb25zdCBjaGlsZEVsZW1lbnQgPSB0aGlzLnF1ZXJ5KHNlbGVjdG9yKTtcbiAgICBpZiAoIWNoaWxkRWxlbWVudCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSBlbHNlIGlmICghKGNoaWxkRWxlbWVudC5uYXRpdmVFbGVtZW50IGluc3RhbmNlb2YgSFRNTFNlbGVjdEVsZW1lbnQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEVsZW1lbnQgd2l0aCBzZWxlY3RvciAke3NlbGVjdG9yfSBpcyBub3QgYW4gSFRNTFNlbGVjdEVsZW1lbnRgKTtcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBUZXN0U2VsZWN0KHRoaXMudGVzdGVyLCBjaGlsZEVsZW1lbnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IHRleHRhcmVhIG1hdGNoZWQgYnkgdGhlIGdpdmVuIHNlbGVjdG9yXG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgdGV4dGFyZWEsIG9yIG51bGwgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZC4gVGhyb3dzIGFuIEVycm9yIGlmIHRoZSBtYXRjaGVkIGVsZW1lbnQgaXNuJ3QgYWN0dWFsbHkgYSB0ZXh0YXJlYS5cbiAgICogQHRocm93cyB7RXJyb3J9IGlmIHRoZSBtYXRjaGVkIGVsZW1lbnQgaXNuJ3QgYWN0dWFsbHkgYSB0ZXh0YXJlYVxuICAgKi9cbiAgdGV4dGFyZWEoc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RUZXh0QXJlYSB8IG51bGwge1xuICAgIGNvbnN0IGNoaWxkRWxlbWVudCA9IHRoaXMucXVlcnkoc2VsZWN0b3IpO1xuICAgIGlmICghY2hpbGRFbGVtZW50KSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9IGVsc2UgaWYgKCEoY2hpbGRFbGVtZW50Lm5hdGl2ZUVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MVGV4dEFyZWFFbGVtZW50KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFbGVtZW50IHdpdGggc2VsZWN0b3IgJHtzZWxlY3Rvcn0gaXMgbm90IGFuIEhUTUxUZXh0QXJlYUVsZW1lbnRgKTtcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBUZXN0VGV4dEFyZWEodGhpcy50ZXN0ZXIsIGNoaWxkRWxlbWVudCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgZmlyc3QgYnV0dG9uIG1hdGNoZWQgYnkgdGhlIGdpdmVuIHNlbGVjdG9yLiBUaHJvd3MgYW4gRXJyb3IgaWYgdGhlIG1hdGNoZWQgZWxlbWVudCBpc24ndCBhY3R1YWxseSBhIGJ1dHRvbi5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgd3JhcHBlZCBidXR0b24sIG9yIG51bGwgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgYnV0dG9uKHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0QnV0dG9uIHwgbnVsbCB7XG4gICAgY29uc3QgY2hpbGRFbGVtZW50ID0gdGhpcy5xdWVyeShzZWxlY3Rvcik7XG4gICAgaWYgKCFjaGlsZEVsZW1lbnQpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gZWxzZSBpZiAoIShjaGlsZEVsZW1lbnQubmF0aXZlRWxlbWVudCBpbnN0YW5jZW9mIEhUTUxCdXR0b25FbGVtZW50KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFbGVtZW50IHdpdGggc2VsZWN0b3IgJHtzZWxlY3Rvcn0gaXMgbm90IGFuIEhUTUxCdXR0b25FbGVtZW50YCk7XG4gICAgfVxuICAgIHJldHVybiBuZXcgVGVzdEJ1dHRvbih0aGlzLnRlc3RlciwgY2hpbGRFbGVtZW50KTtcbiAgfVxuXG4gIHByaXZhdGUgcXVlcnkoc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IERlYnVnRWxlbWVudCB8IG51bGwge1xuICAgIGlmICh0eXBlb2Ygc2VsZWN0b3IgPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gdGhpcy5yb290LnF1ZXJ5KEJ5LmNzcyhzZWxlY3RvcikpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdGhpcy5yb290LnF1ZXJ5KEJ5LmRpcmVjdGl2ZShzZWxlY3RvcikpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcXVlcnlBbGwoc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IEFycmF5PERlYnVnRWxlbWVudD4ge1xuICAgIGlmICh0eXBlb2Ygc2VsZWN0b3IgPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gdGhpcy5yb290LnF1ZXJ5QWxsKEJ5LmNzcyhzZWxlY3RvcikpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdGhpcy5yb290LnF1ZXJ5QWxsKEJ5LmRpcmVjdGl2ZShzZWxlY3RvcikpO1xuICAgIH1cbiAgfVxufVxuIl19
140
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC1lbGVtZW50LXF1ZXJpZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtc3BlY3Vsb29zL3NyYy9saWIvdGVzdC1lbGVtZW50LXF1ZXJpZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsdURBQXVEO0FBQ3ZELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDekMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBR3RELE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUUvQzs7R0FFRztBQUNILE1BQU0sT0FBTyxrQkFBa0I7SUFDN0IsWUFDVSxNQUFnQyxFQUNoQyxJQUFrQjtRQURsQixXQUFNLEdBQU4sTUFBTSxDQUEwQjtRQUNoQyxTQUFJLEdBQUosSUFBSSxDQUFjO0lBQ3pCLENBQUM7SUFFSixNQUFNLENBQUMsSUFBSSxDQUFDLGlCQUErQixFQUFFLE1BQWdDO1FBQzNFLE1BQU0sWUFBWSxHQUFHLGlCQUFpQixDQUFDLGFBQWEsQ0FBQztRQUNyRCxJQUFJLFlBQVksWUFBWSxpQkFBaUIsRUFBRTtZQUM3QyxPQUFPLElBQUksVUFBVSxDQUFDLE1BQU0sRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO1NBQ2xEO2FBQU0sSUFBSSxZQUFZLFlBQVksZ0JBQWdCLEVBQUU7WUFDbkQsT0FBTyxJQUFJLFNBQVMsQ0FBQyxNQUFNLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztTQUNqRDthQUFNLElBQUksWUFBWSxZQUFZLGlCQUFpQixFQUFF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QyxJQUFJLENBQUMsWUFBWSxFQUFFO1lBQ2pCLE9BQU8sSUFBSSxDQUFDO1NBQ2I7YUFBTSxJQUFJLENBQUMsQ0FBQyxZQUFZLENBQUMsYUFBYSxZQUFZLGlCQUFpQixDQUFDLEVBQUU7WUFDckUsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsUUFBUSw4QkFBOEIsQ0FBQyxDQUFDO1NBQ2xGO1FBQ0QsT0FBTyxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLFlBQVksQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFTyxLQUFLLENBQUMsUUFBNEI7UUFDeEMsSUFBSSxPQUFPLFFBQVEsS0FBSyxRQUFRLEVBQUU7WUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7U0FDMUM7YUFBTTtZQUNMLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO1NBQ2hEO0lBQ0gsQ0FBQztJQUVPLFFBQVEsQ0FBQyxRQUE0QjtRQUMzQyxJQUFJLE9BQU8sUUFBUSxLQUFLLFFBQVEsRUFBRTtZQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztTQUM3QzthQUFNO1lBQ0wsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7U0FDbkQ7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55ICovXG5pbXBvcnQgeyBUZXN0QnV0dG9uIH0gZnJvbSAnLi90ZXN0LWJ1dHRvbic7XG5pbXBvcnQgeyBUZXN0U2VsZWN0IH0gZnJvbSAnLi90ZXN0LXNlbGVjdCc7XG5pbXBvcnQgeyBUZXN0RWxlbWVudCB9IGZyb20gJy4vdGVzdC1lbGVtZW50JztcbmltcG9ydCB7IFRlc3RUZXh0QXJlYSB9IGZyb20gJy4vdGVzdC10ZXh0YXJlYSc7XG5pbXBvcnQgeyBUZXN0SW5wdXQgfSBmcm9tICcuL3Rlc3QtaW5wdXQnO1xuaW1wb3J0IHsgVGVzdEh0bWxFbGVtZW50IH0gZnJvbSAnLi90ZXN0LWh0bWwtZWxlbWVudCc7XG5pbXBvcnQgeyBDb21wb25lbnRUZXN0ZXIgfSBmcm9tICcuL2NvbXBvbmVudC10ZXN0ZXInO1xuaW1wb3J0IHsgRGVidWdFbGVtZW50LCBUeXBlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBCeSB9IGZyb20gJ0Bhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXInO1xuXG4vKipcbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgY2xhc3MgVGVzdEVsZW1lbnRRdWVyaWVyIHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSB0ZXN0ZXI6IENvbXBvbmVudFRlc3Rlcjx1bmtub3duPixcbiAgICBwcml2YXRlIHJvb3Q6IERlYnVnRWxlbWVudFxuICApIHt9XG5cbiAgc3RhdGljIHdyYXAoY2hpbGREZWJ1Z0VsZW1lbnQ6IERlYnVnRWxlbWVudCwgdGVzdGVyOiBDb21wb25lbnRUZXN0ZXI8dW5rbm93bj4pOiBUZXN0RWxlbWVudCB7XG4gICAgY29uc3QgY2hpbGRFbGVtZW50ID0gY2hpbGREZWJ1Z0VsZW1lbnQubmF0aXZlRWxlbWVudDtcbiAgICBpZiAoY2hpbGRFbGVtZW50IGluc3RhbmNlb2YgSFRNTEJ1dHRvbkVsZW1lbnQpIHtcbiAgICAgIHJldHVybiBuZXcgVGVzdEJ1dHRvbih0ZXN0ZXIsIGNoaWxkRGVidWdFbGVtZW50KTtcbiAgICB9IGVsc2UgaWYgKGNoaWxkRWxlbWVudCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQpIHtcbiAgICAgIHJldHVybiBuZXcgVGVzdElucHV0KHRlc3RlciwgY2hpbGREZWJ1Z0VsZW1lbnQpO1xuICAgIH0gZWxzZSBpZiAoY2hpbGRFbGVtZW50IGluc3RhbmNlb2YgSFRNTFNlbGVjdEVsZW1lbnQpIHtcbiAgICAgIHJldHVybiBuZXcgVGVzdFNlbGVjdCh0ZXN0ZXIsIGNoaWxkRGVidWdFbGVtZW50KTtcbiAgICB9IGVsc2UgaWYgKGNoaWxkRWxlbWVudCBpbnN0YW5jZW9mIEhUTUxUZXh0QXJlYUVsZW1lbnQpIHtcbiAgICAgIHJldHVybiBuZXcgVGVzdFRleHRBcmVhKHRlc3RlciwgY2hpbGREZWJ1Z0VsZW1lbnQpO1xuICAgIH0gZWxzZSBpZiAoY2hpbGRFbGVtZW50IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHtcbiAgICAgIHJldHVybiBuZXcgVGVzdEh0bWxFbGVtZW50KHRlc3RlciwgY2hpbGREZWJ1Z0VsZW1lbnQpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gbmV3IFRlc3RFbGVtZW50KHRlc3RlciwgY2hpbGREZWJ1Z0VsZW1lbnQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBlbGVtZW50IG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciBhbmQgd3JhcHMgaXQgaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIHZhbHVlIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnQgaXMgYW4gaW5wdXQgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYSBUZXN0SW5wdXQuIFlvdSBjYW4gdGh1cyB1c2VcbiAgICogYHRlc3Rlci5lbGVtZW50KCcjc29tZS1pbnB1dCcpIGFzIFRlc3RJbnB1dGAuXG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgZWxlbWVudCwgb3IgbnVsbCBpZiBubyBlbGVtZW50IG1hdGNoZXMgdGhlIHNlbGVjdG9yLlxuICAgKi9cbiAgZWxlbWVudChzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+KTogVGVzdEVsZW1lbnQgfCBudWxsIHtcbiAgICBjb25zdCBjaGlsZEVsZW1lbnQgPSB0aGlzLnF1ZXJ5KHNlbGVjdG9yKTtcbiAgICByZXR1cm4gY2hpbGRFbGVtZW50ICYmIFRlc3RFbGVtZW50UXVlcmllci53cmFwKGNoaWxkRWxlbWVudCwgdGhpcy50ZXN0ZXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgYWxsIHRoZSBlbGVtZW50cyBtYXRjaGluZyB0aGUgZ2l2ZW4gc2VsZWN0b3IgYW5kIHdyYXBzIHRoZW0gaW50byBhIFRlc3RFbGVtZW50LiBUaGUgYWN0dWFsIHR5cGVcbiAgICogb2YgdGhlIHJldHVybmVkIGVsZW1lbnRzIGlzIHRoZSBUZXN0RWxlbWVudCBzdWJjbGFzcyBtYXRjaGluZyB0aGUgdHlwZSBvZiB0aGUgZm91bmQgZWxlbWVudC4gU28sIGlmIHRoZVxuICAgKiBtYXRjaGVkIGVsZW1lbnRzIGFyZSBpbnB1dHMgZm9yIGV4YW1wbGUsIHRoZSBtZXRob2Qgd2lsbCByZXR1cm4gYW4gYXJyYXkgb2YgVGVzdElucHV0LiBZb3UgY2FuIHRodXMgdXNlXG4gICAqIGB0ZXN0ZXIuZWxlbWVudHMoJ2lucHV0JykgYXMgQXJyYXk8VGVzdElucHV0PmAuXG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIGFycmF5IG9mIG1hdGNoZWQgZWxlbWVudHMsIGVtcHR5IGlmIG5vIGVsZW1lbnQgd2FzIG1hdGNoZWRcbiAgICovXG4gIGVsZW1lbnRzKHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBBcnJheTxUZXN0RWxlbWVudD4ge1xuICAgIGNvbnN0IGNoaWxkRWxlbWVudHMgPSB0aGlzLnF1ZXJ5QWxsKHNlbGVjdG9yKTtcbiAgICByZXR1cm4gY2hpbGRFbGVtZW50cy5tYXAoZGVidWdFbGVtZW50ID0+IFRlc3RFbGVtZW50UXVlcmllci53cmFwKGRlYnVnRWxlbWVudCwgdGhpcy50ZXN0ZXIpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCBpbnB1dCBtYXRjaGVkIGJ5IHRoZSBnaXZlbiBzZWxlY3Rvci4gVGhyb3dzIGFuIEVycm9yIGlmIHRoZSBtYXRjaGVkIGVsZW1lbnQgaXNuJ3QgYWN0dWFsbHkgYW4gaW5wdXQuXG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgaW5wdXQsIG9yIG51bGwgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgaW5wdXQoc2VsZWN0b3I6IHN0cmluZyB8IFR5cGU8YW55Pik6IFRlc3RJbnB1dCB8IG51bGwge1xuICAgIGNvbnN0IGNoaWxkRWxlbWVudCA9IHRoaXMucXVlcnkoc2VsZWN0b3IpO1xuICAgIGlmICghY2hpbGRFbGVtZW50KSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9IGVsc2UgaWYgKCEoY2hpbGRFbGVtZW50Lm5hdGl2ZUVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MSW5wdXRFbGVtZW50KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFbGVtZW50IHdpdGggc2VsZWN0b3IgJHtzZWxlY3Rvcn0gaXMgbm90IGFuIEhUTUxJbnB1dEVsZW1lbnRgKTtcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBUZXN0SW5wdXQodGhpcy50ZXN0ZXIsIGNoaWxkRWxlbWVudCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgZmlyc3Qgc2VsZWN0IG1hdGNoZWQgYnkgdGhlIGdpdmVuIHNlbGVjdG9yLiBUaHJvd3MgYW4gRXJyb3IgaWYgdGhlIG1hdGNoZWQgZWxlbWVudCBpc24ndCBhY3R1YWxseSBhIHNlbGVjdC5cbiAgICogQHBhcmFtIHNlbGVjdG9yIGEgQ1NTIG9yIGRpcmVjdGl2ZSBzZWxlY3RvclxuICAgKiBAcmV0dXJucyB0aGUgd3JhcHBlZCBzZWxlY3QsIG9yIG51bGwgaWYgbm8gZWxlbWVudCB3YXMgbWF0Y2hlZFxuICAgKi9cbiAgc2VsZWN0KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0U2VsZWN0IHwgbnVsbCB7XG4gICAgY29uc3QgY2hpbGRFbGVtZW50ID0gdGhpcy5xdWVyeShzZWxlY3Rvcik7XG4gICAgaWYgKCFjaGlsZEVsZW1lbnQpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gZWxzZSBpZiAoIShjaGlsZEVsZW1lbnQubmF0aXZlRWxlbWVudCBpbnN0YW5jZW9mIEhUTUxTZWxlY3RFbGVtZW50KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFbGVtZW50IHdpdGggc2VsZWN0b3IgJHtzZWxlY3Rvcn0gaXMgbm90IGFuIEhUTUxTZWxlY3RFbGVtZW50YCk7XG4gICAgfVxuICAgIHJldHVybiBuZXcgVGVzdFNlbGVjdCh0aGlzLnRlc3RlciwgY2hpbGRFbGVtZW50KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBmaXJzdCB0ZXh0YXJlYSBtYXRjaGVkIGJ5IHRoZSBnaXZlbiBzZWxlY3RvclxuICAgKiBAcGFyYW0gc2VsZWN0b3IgYSBDU1Mgb3IgZGlyZWN0aXZlIHNlbGVjdG9yXG4gICAqIEByZXR1cm5zIHRoZSB3cmFwcGVkIHRleHRhcmVhLCBvciBudWxsIGlmIG5vIGVsZW1lbnQgd2FzIG1hdGNoZWQuIFRocm93cyBhbiBFcnJvciBpZiB0aGUgbWF0Y2hlZCBlbGVtZW50IGlzbid0IGFjdHVhbGx5IGEgdGV4dGFyZWEuXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBpZiB0aGUgbWF0Y2hlZCBlbGVtZW50IGlzbid0IGFjdHVhbGx5IGEgdGV4dGFyZWFcbiAgICovXG4gIHRleHRhcmVhKHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBUZXN0VGV4dEFyZWEgfCBudWxsIHtcbiAgICBjb25zdCBjaGlsZEVsZW1lbnQgPSB0aGlzLnF1ZXJ5KHNlbGVjdG9yKTtcbiAgICBpZiAoIWNoaWxkRWxlbWVudCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSBlbHNlIGlmICghKGNoaWxkRWxlbWVudC5uYXRpdmVFbGVtZW50IGluc3RhbmNlb2YgSFRNTFRleHRBcmVhRWxlbWVudCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRWxlbWVudCB3aXRoIHNlbGVjdG9yICR7c2VsZWN0b3J9IGlzIG5vdCBhbiBIVE1MVGV4dEFyZWFFbGVtZW50YCk7XG4gICAgfVxuICAgIHJldHVybiBuZXcgVGVzdFRleHRBcmVhKHRoaXMudGVzdGVyLCBjaGlsZEVsZW1lbnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGZpcnN0IGJ1dHRvbiBtYXRjaGVkIGJ5IHRoZSBnaXZlbiBzZWxlY3Rvci4gVGhyb3dzIGFuIEVycm9yIGlmIHRoZSBtYXRjaGVkIGVsZW1lbnQgaXNuJ3QgYWN0dWFsbHkgYSBidXR0b24uXG4gICAqIEBwYXJhbSBzZWxlY3RvciBhIENTUyBvciBkaXJlY3RpdmUgc2VsZWN0b3JcbiAgICogQHJldHVybnMgdGhlIHdyYXBwZWQgYnV0dG9uLCBvciBudWxsIGlmIG5vIGVsZW1lbnQgd2FzIG1hdGNoZWRcbiAgICovXG4gIGJ1dHRvbihzZWxlY3Rvcjogc3RyaW5nIHwgVHlwZTxhbnk+KTogVGVzdEJ1dHRvbiB8IG51bGwge1xuICAgIGNvbnN0IGNoaWxkRWxlbWVudCA9IHRoaXMucXVlcnkoc2VsZWN0b3IpO1xuICAgIGlmICghY2hpbGRFbGVtZW50KSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9IGVsc2UgaWYgKCEoY2hpbGRFbGVtZW50Lm5hdGl2ZUVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MQnV0dG9uRWxlbWVudCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRWxlbWVudCB3aXRoIHNlbGVjdG9yICR7c2VsZWN0b3J9IGlzIG5vdCBhbiBIVE1MQnV0dG9uRWxlbWVudGApO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IFRlc3RCdXR0b24odGhpcy50ZXN0ZXIsIGNoaWxkRWxlbWVudCk7XG4gIH1cblxuICBwcml2YXRlIHF1ZXJ5KHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBEZWJ1Z0VsZW1lbnQgfCBudWxsIHtcbiAgICBpZiAodHlwZW9mIHNlbGVjdG9yID09PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIHRoaXMucm9vdC5xdWVyeShCeS5jc3Moc2VsZWN0b3IpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHRoaXMucm9vdC5xdWVyeShCeS5kaXJlY3RpdmUoc2VsZWN0b3IpKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHF1ZXJ5QWxsKHNlbGVjdG9yOiBzdHJpbmcgfCBUeXBlPGFueT4pOiBBcnJheTxEZWJ1Z0VsZW1lbnQ+IHtcbiAgICBpZiAodHlwZW9mIHNlbGVjdG9yID09PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIHRoaXMucm9vdC5xdWVyeUFsbChCeS5jc3Moc2VsZWN0b3IpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHRoaXMucm9vdC5xdWVyeUFsbChCeS5kaXJlY3RpdmUoc2VsZWN0b3IpKTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -4,6 +4,7 @@
4
4
  */
5
5
  /// <reference path="./jasmine-matchers.ts" />
6
6
  export * from './lib/component-tester';
7
+ export * from './lib/routing-tester';
7
8
  export * from './lib/test-element';
8
9
  export * from './lib/test-html-element';
9
10
  export * from './lib/test-input';
@@ -13,4 +14,4 @@ export * from './lib/test-textarea';
13
14
  export * from './lib/route';
14
15
  export * from './lib/matchers';
15
16
  export * from './lib/mock';
16
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljX2FwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL25neC1zcGVjdWxvb3Mvc3JjL3B1YmxpY19hcGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsb0JBQW9CO0FBQ3BCOztHQUVHO0FBQ0gsOENBQThDO0FBRTlDLGNBQWMsd0JBQXdCLENBQUM7QUFDdkMsY0FBYyxvQkFBb0IsQ0FBQztBQUNuQyxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsa0JBQWtCLENBQUM7QUFDakMsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLG1CQUFtQixDQUFDO0FBQ2xDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxnQkFBZ0IsQ0FBQztBQUMvQixjQUFjLFlBQVksQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlICovXG4vKlxuICogUHVibGljIEFQSSBTdXJmYWNlIG9mIG5neC1zcGVjdWxvb3NcbiAqL1xuLy8vIDxyZWZlcmVuY2UgcGF0aD1cIi4vamFzbWluZS1tYXRjaGVycy50c1wiIC8+XG5cbmV4cG9ydCAqIGZyb20gJy4vbGliL2NvbXBvbmVudC10ZXN0ZXInO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvdGVzdC1lbGVtZW50JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3Rlc3QtaHRtbC1lbGVtZW50JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3Rlc3QtaW5wdXQnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvdGVzdC1idXR0b24nO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvdGVzdC1zZWxlY3QnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvdGVzdC10ZXh0YXJlYSc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9yb3V0ZSc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9tYXRjaGVycyc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9tb2NrJztcbiJdfQ==
17
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljX2FwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL25neC1zcGVjdWxvb3Mvc3JjL3B1YmxpY19hcGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsb0JBQW9CO0FBQ3BCOztHQUVHO0FBQ0gsOENBQThDO0FBRTlDLGNBQWMsd0JBQXdCLENBQUM7QUFDdkMsY0FBYyxzQkFBc0IsQ0FBQztBQUNyQyxjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYyxrQkFBa0IsQ0FBQztBQUNqQyxjQUFjLG1CQUFtQixDQUFDO0FBQ2xDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGdCQUFnQixDQUFDO0FBQy9CLGNBQWMsWUFBWSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgKi9cbi8qXG4gKiBQdWJsaWMgQVBJIFN1cmZhY2Ugb2Ygbmd4LXNwZWN1bG9vc1xuICovXG4vLy8gPHJlZmVyZW5jZSBwYXRoPVwiLi9qYXNtaW5lLW1hdGNoZXJzLnRzXCIgLz5cblxuZXhwb3J0ICogZnJvbSAnLi9saWIvY29tcG9uZW50LXRlc3Rlcic7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9yb3V0aW5nLXRlc3Rlcic7XG5leHBvcnQgKiBmcm9tICcuL2xpYi90ZXN0LWVsZW1lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvdGVzdC1odG1sLWVsZW1lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvdGVzdC1pbnB1dCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi90ZXN0LWJ1dHRvbic7XG5leHBvcnQgKiBmcm9tICcuL2xpYi90ZXN0LXNlbGVjdCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi90ZXN0LXRleHRhcmVhJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3JvdXRlJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL21hdGNoZXJzJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL21vY2snO1xuIl19
@@ -1,6 +1,7 @@
1
1
  import { TestBed, ComponentFixture } from '@angular/core/testing';
2
2
  import { By } from '@angular/platform-browser';
3
- import { convertToParamMap, ActivatedRouteSnapshot, ActivatedRoute } from '@angular/router';
3
+ import { RouterTestingHarness } from '@angular/router/testing';
4
+ import { Router, convertToParamMap, ActivatedRouteSnapshot, ActivatedRoute } from '@angular/router';
4
5
  import { map, BehaviorSubject } from 'rxjs';
5
6
 
6
7
  /**
@@ -623,6 +624,52 @@ class ComponentTester {
623
624
  detectChanges(checkNoChanges) {
624
625
  this.fixture.detectChanges(checkNoChanges);
625
626
  }
627
+ /**
628
+ * Delegates to the wrapped fixture whenStable and then detect changes
629
+ */
630
+ async stable() {
631
+ await this.fixture.whenStable();
632
+ this.detectChanges();
633
+ }
634
+ }
635
+
636
+ /**
637
+ * A thin wrapper around Angular RouterTestingHarness which helps testing routed components.
638
+ * It allows, based on a configured testing module where the router is provided, to initially navigate
639
+ * to a given route, then test the routed component. It's then possible to either navigate again with
640
+ * the wrapped harness, or to use the component to trigger navigation, and test that the URL has changed
641
+ * for example.
642
+ */
643
+ class RoutingTester extends ComponentTester {
644
+ constructor(harness) {
645
+ super(harness.fixture);
646
+ this.harness = harness;
647
+ }
648
+ /**
649
+ * Creates a RouterTestngHarness and uses it to navigate to the given URL
650
+ * @param url the URL to initially navigate to.
651
+ * @return a promise which resolves to a RoutingTester which wraps the harness
652
+ * and its fixture.
653
+ */
654
+ static async forUrl(url) {
655
+ const harness = await RouterTestingHarness.create(url);
656
+ return new RoutingTester(harness);
657
+ }
658
+ /**
659
+ * Gets the current URL of the Router service as a string
660
+ */
661
+ get url() {
662
+ const router = TestBed.inject(Router);
663
+ return router.url;
664
+ }
665
+ /**
666
+ * Gets the current URL of the Router service as an UrlTree, to be able to test its
667
+ * elements (query params, etc.)
668
+ */
669
+ get urlTree() {
670
+ const router = TestBed.inject(Router);
671
+ return router.parseUrl(router.url);
672
+ }
626
673
  }
627
674
 
628
675
  /**
@@ -1286,5 +1333,5 @@ function createMock(type) {
1286
1333
  * Generated bundle index. Do not edit.
1287
1334
  */
1288
1335
 
1289
- export { ActivatedRouteStub, ComponentTester, TestButton, TestElement, TestHtmlElement, TestInput, TestSelect, TestTextArea, createMock, fakeRoute, fakeSnapshot, speculoosMatchers, stubRoute };
1336
+ export { ActivatedRouteStub, ComponentTester, RoutingTester, TestButton, TestElement, TestHtmlElement, TestInput, TestSelect, TestTextArea, createMock, fakeRoute, fakeSnapshot, speculoosMatchers, stubRoute };
1290
1337
  //# sourceMappingURL=ngx-speculoos.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ngx-speculoos.mjs","sources":["../../../projects/ngx-speculoos/src/lib/test-element.ts","../../../projects/ngx-speculoos/src/lib/test-html-element.ts","../../../projects/ngx-speculoos/src/lib/test-button.ts","../../../projects/ngx-speculoos/src/lib/test-select.ts","../../../projects/ngx-speculoos/src/lib/test-textarea.ts","../../../projects/ngx-speculoos/src/lib/test-input.ts","../../../projects/ngx-speculoos/src/lib/test-element-querier.ts","../../../projects/ngx-speculoos/src/lib/component-tester.ts","../../../projects/ngx-speculoos/src/lib/route.ts","../../../projects/ngx-speculoos/src/lib/matchers.ts","../../../projects/ngx-speculoos/src/lib/mock.ts","../../../projects/ngx-speculoos/src/public_api.ts","../../../projects/ngx-speculoos/src/ngx-speculoos.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { ComponentTester } from './component-tester';\nimport { TestButton } from './test-button';\nimport { TestSelect } from './test-select';\nimport { TestTextArea } from './test-textarea';\nimport { TestInput } from './test-input';\nimport { TestElementQuerier } from './test-element-querier';\nimport { DebugElement, ProviderToken, Type } from '@angular/core';\nimport { TestHtmlElement } from './test-html-element';\n\n/**\n * A wrapped DOM element, providing additional methods and attributes helping with writing tests\n */\nexport class TestElement<E extends Element = Element> {\n private querier: TestElementQuerier;\n\n constructor(\n protected tester: ComponentTester<unknown>,\n /**\n * the wrapped debug element\n */\n readonly debugElement: DebugElement\n ) {\n this.querier = new TestElementQuerier(tester, debugElement);\n }\n\n get nativeElement(): E {\n return this.debugElement.nativeElement;\n }\n\n /**\n * the text content of this element\n */\n get textContent(): string | null {\n return this.nativeElement.textContent;\n }\n\n /**\n * dispatches an event of the given type from the wrapped element, then triggers a change detection\n */\n dispatchEventOfType(type: string): void {\n this.nativeElement.dispatchEvent(new Event(type));\n this.tester.detectChanges();\n }\n\n /**\n * dispatches the given event from the wrapped element, then triggers a change detection\n */\n dispatchEvent(event: Event): void {\n this.nativeElement.dispatchEvent(event);\n this.tester.detectChanges();\n }\n\n /**\n * Gets the CSS classes of the wrapped element, as an array\n */\n get classes(): Array<string> {\n return Array.prototype.slice.call(this.nativeElement.classList);\n }\n\n /**\n * Gets the attribute of the wrapped element with the given name\n * @param name the name of the attribute to get\n */\n attr(name: string): string | null {\n return this.nativeElement.getAttribute(name);\n }\n\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestHtmlElement&lt;HTMLDivElement> | null = tester.element('div');\n * </code>\n * @param selector a CSS selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<K extends keyof HTMLElementTagNameMap>(selector: K): TestHtmlElement<HTMLElementTagNameMap[K]> | null;\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement&lt;SVGLineElement> | null = tester.element('line');\n * </code>\n * @param selector a CSS selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<K extends keyof SVGElementTagNameMap>(selector: K): TestElement<SVGElementTagNameMap[K]> | null;\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement | null = tester.element('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element(selector: string | Type<any>): TestElement | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestInput | null = tester.element&lt;HTMLInputElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLInputElement>(selector: string | Type<any>): TestInput | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestTextArea | null = tester.element&lt;HTMLTextAreaElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLTextAreaElement>(selector: string | Type<any>): TestTextArea | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestSelect | null = tester.element&lt;HTMLSelectElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLSelectElement>(selector: string | Type<any>): TestSelect | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestButton | null = tester.element&lt;HTMLButtonElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLButtonElement>(selector: string | Type<any>): TestButton | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestHtmlElement&lt;HTMLDivElement> | null = tester.element&lt;HTMLDivElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLElement>(selector: string | Type<any>): TestHtmlElement<T> | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement&lt;SVGLineElement> | null = tester.element&lt;SVGLineElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends Element>(selector: string | Type<any>): TestElement<T> | null;\n element(selector: string | Type<any>): TestElement | null {\n return this.querier.element(selector);\n }\n\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestHtmlElement&lt;HTMLDivElement>> = tester.elements('div');\n * </code>\n * @param selector a CSS selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<K extends keyof HTMLElementTagNameMap>(selector: K): Array<TestHtmlElement<HTMLElementTagNameMap[K]>>;\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestElement&lt;SVGLineElement>> = tester.elements('line');\n * </code>\n * @param selector a CSS selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<K extends keyof SVGElementTagNameMap>(selector: K): Array<TestElement<SVGElementTagNameMap[K]>>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestElement> = tester.elements('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements(selector: string | Type<any>): Array<TestElement>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestInput> = tester.elements&lt;HTMLInputElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLInputElement>(selector: string | Type<any>): Array<TestInput>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestTextArea> = tester.elements&lt;HTMLTextAreaElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLTextAreaElement>(selector: string | Type<any>): Array<TestTextArea>;\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestButton> = tester.elements&lt;HTMLButtonElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLButtonElement>(selector: string | Type<any>): Array<TestButton>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestSelect> = tester.elements<HTMLSelectElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLSelectElement>(selector: string | Type<any>): Array<TestSelect>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestHtmlElement&lt;HTMLDivElement>> = tester.elements&lt;HTMLDivElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLElement>(selector: string | Type<any>): Array<TestHtmlElement<T>>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestElement&lt;SVGLineElement>> = tester.elements&lt;SVGLineElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends Element>(selector: string | Type<any>): Array<TestElement<T>>;\n elements(selector: string | Type<any>): Array<TestElement> {\n return this.querier.elements(selector);\n }\n\n /**\n * Gets the first input matched by the given selector. Throws an Error if the matched element isn't actually an input.\n * @param selector a CSS or directive selector\n * @returns the wrapped input, or null if no element was matched\n */\n input(selector: string | Type<any>): TestInput | null {\n return this.querier.input(selector);\n }\n\n /**\n * Gets the first select matched by the given selector. Throws an Error if the matched element isn't actually a select.\n * @param selector a CSS or directive selector\n * @returns the wrapped select, or null if no element was matched\n */\n select(selector: string | Type<any>): TestSelect | null {\n return this.querier.select(selector);\n }\n\n /**\n * Gets the first textarea matched by the given selector\n * @param selector a CSS or directive selector\n * @returns the wrapped textarea, or null if no element was matched. Throws an Error if the matched element isn't actually a textarea.\n * @throws {Error} if the matched element isn't actually a textarea\n */\n textarea(selector: string | Type<any>): TestTextArea | null {\n return this.querier.textarea(selector);\n }\n\n /**\n * Gets the first button matched by the given selector. Throws an Error if the matched element isn't actually a button.\n * @param selector a CSS or directive selector\n * @returns the wrapped button, or null if no element was matched\n */\n button(selector: string | Type<any>): TestButton | null {\n return this.querier.button(selector);\n }\n\n /**\n * Gets the first directive matching the given component directive selector and returns its component instance\n * @param selector the selector of a component directive\n */\n component<R>(selector: Type<R>): R {\n return this.querier.element(selector)?.debugElement?.componentInstance ?? null;\n }\n\n /**\n * Gets the directives matching the given component directive selector and returns their component instance\n * @param selector the selector of a component directive\n */\n components<R>(selector: Type<R>): Array<R> {\n return this.querier.elements(selector).map(e => e.debugElement.componentInstance);\n }\n\n /**\n * Gets the first element matching the given selector, then gets the given token from its injector, or null if there is no such token\n * @param selector a CSS or directive selector\n * @param token the token to get from the matched element injector\n */\n token<R>(selector: string | Type<any>, token: ProviderToken<R>): R | null {\n return this.querier.element(selector)?.debugElement?.injector?.get(token, null) ?? null;\n }\n\n /**\n * Gets the elements matching the given selector, then gets their given token from their injector, or null if there is no such token\n * @param selector a CSS or directive selector\n * @param token the token to get from the matched element injector\n */\n tokens<R>(selector: string | Type<any>, token: ProviderToken<R>): Array<R | null> {\n return this.querier.elements(selector).map(e => e.debugElement.injector.get(token, null) ?? null);\n }\n\n /**\n * Gets the element matching the given selector, and if found, creates and returns a custom TestElement of the provided\n * type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for\n * custom elements or components.\n * @param selector a CSS or directive selector\n * @param customTestElementType the type of the TestElement subclass that will wrap the found element\n */\n custom<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): E | null {\n const element = this.querier.element(selector);\n return element && new customTestElementType(this.tester, element.debugElement);\n }\n\n /**\n * Gets the elements matching the given selector, and creates and returns custom TestElements of the provided\n * type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for\n * custom elements or components.\n * @param selector a CSS or directive selector\n * @param customTestElementType the type of the TestElement subclass that will wrap the found elements\n */\n customs<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): Array<E> {\n return this.querier.elements(selector).map(element => new customTestElementType(this.tester, element.debugElement));\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestElement } from './test-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped DOM HTML element, providing additional methods and attributes helping with writing tests\n */\nexport class TestHtmlElement<E extends HTMLElement> extends TestElement<E> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * Clicks on the wrapped element, then triggers a change detection\n */\n click(): void {\n this.nativeElement.click();\n this.tester.detectChanges();\n }\n\n /**\n * Tests if the element is visible, in the same meaning (and implementation) as in jQuery, i.e.\n * present anywhere in the DOM, and visible.\n * An element is not visible typically, if its display style or any of its ancestors display style is none.\n */\n get visible(): boolean {\n return !!(this.nativeElement.offsetWidth || this.nativeElement.offsetHeight || this.nativeElement.getClientRects().length);\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestHtmlElement } from './test-html-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped button element, providing additional methods and attributes helping with writing tests\n */\nexport class TestButton extends TestHtmlElement<HTMLButtonElement> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * the disabled flag of the button\n */\n get disabled(): boolean {\n return this.nativeElement.disabled;\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestHtmlElement } from './test-html-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped DOM HTML select element, providing additional methods and attributes helping with writing tests\n */\nexport class TestSelect extends TestHtmlElement<HTMLSelectElement> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * Selects the option at the given index, then dispatches an event of type change and triggers a change detection\n */\n selectIndex(index: number): void {\n this.nativeElement.selectedIndex = index;\n this.dispatchEventOfType('change');\n }\n\n /**\n * Selects the first option with the given value, then dispatches an event of type change and triggers a change detection.\n * If there is no option with the given value, then does nothing\n * TODO should it throw instead?\n */\n selectValue(value: string): void {\n const index = this.optionValues.indexOf(value);\n if (index >= 0) {\n this.selectIndex(index);\n }\n }\n\n /**\n * Selects the first option with the given label (or text), then dispatches an event of type change and triggers a change detection.\n * If there is no option with the given label, then does nothing\n * TODO should it throw instead?\n */\n selectLabel(label: string): void {\n const index = this.optionLabels.indexOf(label);\n if (index >= 0) {\n this.selectIndex(index);\n }\n }\n\n /**\n * the selected index of the wrapped select\n */\n get selectedIndex(): number {\n return this.nativeElement.selectedIndex;\n }\n\n /**\n * the value of the selected option of the wrapped select, or null if there is no selected option\n */\n get selectedValue(): string | null {\n if (this.selectedIndex < 0) {\n return null;\n }\n return this.nativeElement.options[this.selectedIndex].value;\n }\n\n /**\n * the label (or text if no label) of the selected option of the wrapped select, or null if there is no selected option\n */\n get selectedLabel(): string | null {\n if (this.selectedIndex < 0) {\n return null;\n }\n return this.nativeElement.options[this.selectedIndex].label;\n }\n\n /**\n * the values of the options, as an array\n */\n get optionValues(): Array<string> {\n return (Array.prototype.slice.call(this.nativeElement.options) as Array<HTMLOptionElement>).map(option => option.value);\n }\n\n /**\n * the labels (or texts if no label) of the options, as an array\n */\n get optionLabels(): Array<string> {\n return (Array.prototype.slice.call(this.nativeElement.options) as Array<HTMLOptionElement>).map(option => option.label);\n }\n\n /**\n * the number of options in the select\n */\n get size(): number {\n return this.nativeElement.options.length;\n }\n\n /**\n * the disabled property of the wrapped select\n */\n get disabled(): boolean {\n return this.nativeElement.disabled;\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestHtmlElement } from './test-html-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped DOM HTML textarea element, providing additional methods and attributes helping with writing tests\n */\nexport class TestTextArea extends TestHtmlElement<HTMLTextAreaElement> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * Sets the value of the wrapped textarea, then dispatches an event of type input and triggers a change detection\n * @param value the new value of the textarea\n */\n fillWith(value: string): void {\n this.nativeElement.value = value;\n this.dispatchEventOfType('input');\n }\n\n /**\n * the value of the wrapped textarea\n */\n get value(): string {\n return this.nativeElement.value;\n }\n\n /**\n * the disabled property of the wrapped textarea\n */\n get disabled(): boolean {\n return this.nativeElement.disabled;\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestHtmlElement } from './test-html-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped DOM HTML input element, providing additional methods and attributes helping with writing tests\n */\nexport class TestInput extends TestHtmlElement<HTMLInputElement> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * Sets the value of the wrapped input, then dispatches an event of type input and triggers a change detection\n * @param value the new value of the input\n */\n fillWith(value: string): void {\n this.nativeElement.value = value;\n this.dispatchEventOfType('input');\n }\n\n /**\n * the value of the wrapped input\n */\n get value(): string {\n return this.nativeElement.value;\n }\n\n /**\n * the checked property of the wrapped input\n */\n get checked(): boolean {\n return this.nativeElement.checked;\n }\n\n /**\n * the disabled property of the wrapped input\n */\n get disabled(): boolean {\n return this.nativeElement.disabled;\n }\n\n /**\n * Checks the wrapped input, then dispatches an event of type change and triggers a change detection\n */\n check(): void {\n this.nativeElement.checked = true;\n this.dispatchEventOfType('change');\n }\n\n /**\n * Unchecks the wrapped input, then dispatches an event of type change and triggers a change detection\n */\n uncheck(): void {\n this.nativeElement.checked = false;\n this.dispatchEventOfType('change');\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { TestButton } from './test-button';\nimport { TestSelect } from './test-select';\nimport { TestElement } from './test-element';\nimport { TestTextArea } from './test-textarea';\nimport { TestInput } from './test-input';\nimport { TestHtmlElement } from './test-html-element';\nimport { ComponentTester } from './component-tester';\nimport { DebugElement, Type } from '@angular/core';\nimport { By } from '@angular/platform-browser';\n\n/**\n * @internal\n */\nexport class TestElementQuerier {\n constructor(private tester: ComponentTester<unknown>, private root: DebugElement) {}\n\n static wrap(childDebugElement: DebugElement, tester: ComponentTester<unknown>): TestElement {\n const childElement = childDebugElement.nativeElement;\n if (childElement instanceof HTMLButtonElement) {\n return new TestButton(tester, childDebugElement);\n } else if (childElement instanceof HTMLInputElement) {\n return new TestInput(tester, childDebugElement);\n } else if (childElement instanceof HTMLSelectElement) {\n return new TestSelect(tester, childDebugElement);\n } else if (childElement instanceof HTMLTextAreaElement) {\n return new TestTextArea(tester, childDebugElement);\n } else if (childElement instanceof HTMLElement) {\n return new TestHtmlElement(tester, childDebugElement);\n } else {\n return new TestElement(tester, childDebugElement);\n }\n }\n\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput. You can thus use\n * `tester.element('#some-input') as TestInput`.\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element(selector: string | Type<any>): TestElement | null {\n const childElement = this.query(selector);\n return childElement && TestElementQuerier.wrap(childElement, this.tester);\n }\n\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput. You can thus use\n * `tester.elements('input') as Array<TestInput>`.\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements(selector: string | Type<any>): Array<TestElement> {\n const childElements = this.queryAll(selector);\n return childElements.map(debugElement => TestElementQuerier.wrap(debugElement, this.tester));\n }\n\n /**\n * Gets the first input matched by the given selector. Throws an Error if the matched element isn't actually an input.\n * @param selector a CSS or directive selector\n * @returns the wrapped input, or null if no element was matched\n */\n input(selector: string | Type<any>): TestInput | null {\n const childElement = this.query(selector);\n if (!childElement) {\n return null;\n } else if (!(childElement.nativeElement instanceof HTMLInputElement)) {\n throw new Error(`Element with selector ${selector} is not an HTMLInputElement`);\n }\n return new TestInput(this.tester, childElement);\n }\n\n /**\n * Gets the first select matched by the given selector. Throws an Error if the matched element isn't actually a select.\n * @param selector a CSS or directive selector\n * @returns the wrapped select, or null if no element was matched\n */\n select(selector: string | Type<any>): TestSelect | null {\n const childElement = this.query(selector);\n if (!childElement) {\n return null;\n } else if (!(childElement.nativeElement instanceof HTMLSelectElement)) {\n throw new Error(`Element with selector ${selector} is not an HTMLSelectElement`);\n }\n return new TestSelect(this.tester, childElement);\n }\n\n /**\n * Gets the first textarea matched by the given selector\n * @param selector a CSS or directive selector\n * @returns the wrapped textarea, or null if no element was matched. Throws an Error if the matched element isn't actually a textarea.\n * @throws {Error} if the matched element isn't actually a textarea\n */\n textarea(selector: string | Type<any>): TestTextArea | null {\n const childElement = this.query(selector);\n if (!childElement) {\n return null;\n } else if (!(childElement.nativeElement instanceof HTMLTextAreaElement)) {\n throw new Error(`Element with selector ${selector} is not an HTMLTextAreaElement`);\n }\n return new TestTextArea(this.tester, childElement);\n }\n\n /**\n * Gets the first button matched by the given selector. Throws an Error if the matched element isn't actually a button.\n * @param selector a CSS or directive selector\n * @returns the wrapped button, or null if no element was matched\n */\n button(selector: string | Type<any>): TestButton | null {\n const childElement = this.query(selector);\n if (!childElement) {\n return null;\n } else if (!(childElement.nativeElement instanceof HTMLButtonElement)) {\n throw new Error(`Element with selector ${selector} is not an HTMLButtonElement`);\n }\n return new TestButton(this.tester, childElement);\n }\n\n private query(selector: string | Type<any>): DebugElement | null {\n if (typeof selector === 'string') {\n return this.root.query(By.css(selector));\n } else {\n return this.root.query(By.directive(selector));\n }\n }\n\n private queryAll(selector: string | Type<any>): Array<DebugElement> {\n if (typeof selector === 'string') {\n return this.root.queryAll(By.css(selector));\n } else {\n return this.root.queryAll(By.directive(selector));\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { DebugElement, ProviderToken, Type } from '@angular/core';\nimport { TestTextArea } from './test-textarea';\nimport { TestElement } from './test-element';\nimport { TestInput } from './test-input';\nimport { TestSelect } from './test-select';\nimport { TestButton } from './test-button';\nimport { TestElementQuerier } from './test-element-querier';\nimport { TestHtmlElement } from './test-html-element';\n\n/**\n * The main entry point of the API. It wraps an Angular ComponentFixture<T>, and gives access to its\n * most used properties and methods. It also allows getting elements wrapped in TestElement (and its subclasses)\n * @param <C> the type of the component to test\n */\nexport class ComponentTester<C> {\n /**\n * The test element of the component\n */\n readonly testElement: TestElement<HTMLElement>;\n\n /**\n * The component fixture of the component\n */\n readonly fixture: ComponentFixture<C>;\n\n /**\n * Creates a component fixture of the given type with the TestBed and wraps it into a ComponentTester\n */\n static create<C>(componentType: Type<C>): ComponentTester<C> {\n const fixture = TestBed.createComponent(componentType);\n return new ComponentTester(fixture);\n }\n\n /**\n * Creates a ComponentFixture for the given component type using the TestBed, and creates a ComponentTester\n * wrapping (and delegating) to this fixture. If a fixture is passed, then delegates to this fixture directly.\n *\n * Note that no `detectChanges()` call is made by this constructor. It's up to the subclass constructor,\n * or to the user of the created ComponentTester, to call `detectChanges()` at least once to trigger change\n * detection. This is necessary because some component templates can only be evaluated once inputs\n * have been set on the component instance.\n *\n * @param arg the type of the component to wrap, or a component fixture to wrap\n */\n constructor(arg: Type<C> | ComponentFixture<C>) {\n this.fixture = arg instanceof ComponentFixture ? arg : TestBed.createComponent(arg);\n this.testElement = TestElementQuerier.wrap(this.debugElement, this) as TestElement<HTMLElement>;\n }\n\n /**\n * The native DOM host element of the component\n */\n get nativeElement(): HTMLElement {\n return this.fixture.nativeElement;\n }\n\n /**\n * Gets the instance of the tested component from the wrapped fixture\n */\n get componentInstance(): C {\n return this.fixture.componentInstance;\n }\n\n /**\n * Gets the debug element from the wrapped fixture\n */\n get debugElement(): DebugElement {\n return this.fixture.debugElement;\n }\n\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestHtmlElement&lt;HTMLDivElement> | null = tester.element('div');\n * </code>\n * @param selector a CSS selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<K extends keyof HTMLElementTagNameMap>(selector: K): TestHtmlElement<HTMLElementTagNameMap[K]> | null;\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement&lt;SVGLineElement> | null = tester.element('line');\n * </code>\n * @param selector a CSS selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<K extends keyof SVGElementTagNameMap>(selector: K): TestElement<SVGElementTagNameMap[K]> | null;\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement | null = tester.element('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element(selector: string | Type<any>): TestElement | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestInput | null = tester.element&lt;HTMLInputElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLInputElement>(selector: string | Type<any>): TestInput | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestTextArea | null = tester.element&lt;HTMLTextAreaElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLTextAreaElement>(selector: string | Type<any>): TestTextArea | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestSelect | null = tester.element&lt;HTMLSelectElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLSelectElement>(selector: string | Type<any>): TestSelect | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestButton | null = tester.element&lt;HTMLButtonElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLButtonElement>(selector: string | Type<any>): TestButton | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestHtmlElement&lt;HTMLDivElement> | null = tester.element&lt;HTMLDivElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLElement>(selector: string | Type<any>): TestHtmlElement<T> | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement&lt;SVGLineElement> | null = tester.element&lt;SVGLineElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends Element>(selector: string | Type<any>): TestElement<T> | null;\n element(selector: string | Type<any>): TestElement | null {\n return this.testElement.element(selector);\n }\n\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestHtmlElement&lt;HTMLDivElement>> = tester.elements('div');\n * </code>\n * @param selector a CSS selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<K extends keyof HTMLElementTagNameMap>(selector: K): Array<TestHtmlElement<HTMLElementTagNameMap[K]>>;\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestElement&lt;SVGLineElement>> = tester.elements('line');\n * </code>\n * @param selector a CSS selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<K extends keyof SVGElementTagNameMap>(selector: K): Array<TestElement<SVGElementTagNameMap[K]>>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestElement> = tester.elements('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements(selector: string | Type<any>): Array<TestElement>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestInput> = tester.elements&lt;HTMLInputElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLInputElement>(selector: string | Type<any>): Array<TestInput>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestTextArea> = tester.elements&lt;HTMLTextAreaElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLTextAreaElement>(selector: string | Type<any>): Array<TestTextArea>;\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestButton> = tester.elements&lt;HTMLButtonElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLButtonElement>(selector: string | Type<any>): Array<TestButton>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestSelect> = tester.elements<HTMLSelectElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLSelectElement>(selector: string | Type<any>): Array<TestSelect>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestHtmlElement&lt;HTMLDivElement>> = tester.elements&lt;HTMLDivElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLElement>(selector: string | Type<any>): Array<TestHtmlElement<T>>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestElement&lt;SVGLineElement>> = tester.elements&lt;SVGLineElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends Element>(selector: string | Type<any>): Array<TestElement<T>>;\n elements(selector: string | Type<any>): Array<TestElement> {\n return this.testElement.elements(selector);\n }\n\n /**\n * Gets the first input matched by the given selector. Throws an Error if the matched element isn't actually an input.\n * @param selector a CSS or directive selector\n * @returns the wrapped input, or null if no element was matched\n */\n input(selector: string | Type<any>): TestInput | null {\n return this.testElement.input(selector);\n }\n\n /**\n * Gets the first select matched by the given selector. Throws an Error if the matched element isn't actually a select.\n * @param selector a CSS or directive selector\n * @returns the wrapped select, or null if no element was matched\n */\n select(selector: string | Type<any>): TestSelect | null {\n return this.testElement.select(selector);\n }\n\n /**\n * Gets the first textarea matched by the given selector\n * @param selector a CSS or directive selector\n * @returns the wrapped textarea, or null if no element was matched. Throws an Error if the matched element isn't actually a textarea.\n * @throws {Error} if the matched element isn't actually a textarea\n */\n textarea(selector: string | Type<any>): TestTextArea | null {\n return this.testElement.textarea(selector);\n }\n\n /**\n * Gets the first button matched by the given selector. Throws an Error if the matched element isn't actually a button.\n * @param selector a CSS or directive selector\n * @returns the wrapped button, or null if no element was matched\n */\n button(selector: string | Type<any>): TestButton | null {\n return this.testElement.button(selector);\n }\n\n /**\n * Gets the first directive matching the given component directive selector and returns its component instance\n * @param selector the selector of a component directive\n */\n component<R>(selector: Type<R>): R {\n return this.testElement.component(selector);\n }\n\n /**\n * Gets the directives matching the given component directive selector and returns their component instance\n * @param selector the selector of a component directive\n */\n components<R>(selector: Type<R>): Array<R> {\n return this.testElement.components(selector);\n }\n\n /**\n * Gets the first element matching the given selector, then gets the given token from its injector, or null if there is no such token\n * @param selector a CSS or directive selector\n * @param token the token to get from the matched element injector\n */\n token<R>(selector: string | Type<any>, token: ProviderToken<R>): R | null {\n return this.testElement.token(selector, token);\n }\n\n /**\n * Gets the elements matching the given selector, then gets their given token from their injector, or null if there is no such token\n * @param selector a CSS or directive selector\n * @param token the token to get from the matched element injector\n */\n tokens<R>(selector: string | Type<any>, token: ProviderToken<R>): Array<R | null> {\n return this.testElement.tokens(selector, token);\n }\n\n /**\n * Gets the element matching the given selector, and if found, creates and returns a custom TestElement of the provided\n * type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for\n * custom elements or components.\n * @param selector a CSS or directive selector\n * @param customTestElementType the type of the TestElement subclass that will wrap the found element\n */\n custom<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): E | null {\n return this.testElement.custom(selector, customTestElementType);\n }\n\n /**\n * Gets the elements matching the given selector, and creates and returns custom TestElements of the provided\n * type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for\n * custom elements or components.\n * @param selector a CSS or directive selector\n * @param customTestElementType the type of the TestElement subclass that will wrap the found elements\n */\n customs<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): Array<E> {\n return this.testElement.customs(selector, customTestElementType);\n }\n\n /**\n * Triggers a change detection using the wrapped fixture\n */\n detectChanges(checkNoChanges?: boolean): void {\n this.fixture.detectChanges(checkNoChanges);\n }\n}\n","import { ActivatedRoute, ActivatedRouteSnapshot, convertToParamMap, Data, ParamMap, Params, Route, UrlSegment } from '@angular/router';\nimport { BehaviorSubject, map, Observable } from 'rxjs';\nimport { Type } from '@angular/core';\n\n/**\n * Creates a fake partial ActivatedRoute for tests.\n *\n * If you pass params, then the created route's paramMap will contain the same values.\n * The same goes for queryParams and queryParamMap.\n *\n * If you pass a parent route and a snapshot, and the passed snapshot doesn't have a parent, then the snapshot's\n * parent will be set to the parent route snapshot. This allows the code under test to use\n * `route.parent.snapshot` or `route.snapshot.parent`.\n *\n * If you pass a snapshot with a parent, but don't pass a parent or pass a parent without snapshot, then the route's\n * parent snapshot will be set to the given snapshot's parent. This allows the code under test to use\n * `route.parent.snapshot` or `route.snapshot.parent`.\n *\n * @returns a partially populated, fake ActivatedRoute, depending on what you passed in\n * @deprecated favor stubRoute, which creates an easier to use and more logical stub\n */\nexport function fakeRoute(options: {\n url?: Observable<UrlSegment[]>;\n /** An observable of the matrix parameters scoped to this route */\n params?: Observable<Params>;\n /** An observable of the query parameters shared by all the routes */\n queryParams?: Observable<Params>;\n /** An observable of the URL fragment shared by all the routes */\n fragment?: Observable<string>;\n /** An observable of the static and resolved data of this route. */\n data?: Observable<Data>;\n /** The outlet name of the route. It's a constant */\n outlet?: string;\n /** The component of the route. It's a constant */\n component?: Type<unknown> | string | null;\n /** The current snapshot of this route */\n snapshot?: ActivatedRouteSnapshot;\n /** The configuration used to match this route */\n routeConfig?: Route | null;\n /** The root of the router state */\n root?: ActivatedRoute;\n /** The parent of this route in the router state tree */\n parent?: ActivatedRoute | null;\n /** The first child of this route in the router state tree */\n firstChild?: ActivatedRoute;\n /** The children of this route in the router state tree */\n children?: ActivatedRoute[];\n /** The path from the root of the router state tree to this route */\n pathFromRoot?: ActivatedRoute[];\n}): ActivatedRoute {\n const result = {\n url: options.url,\n params: options.params,\n paramMap: options.params && options.params.pipe(map(params => convertToParamMap(params))),\n queryParams: options.queryParams,\n queryParamMap: options.queryParams && options.queryParams.pipe(map(params => convertToParamMap(params))),\n fragment: options.fragment,\n data: options.data,\n outlet: options.outlet,\n component: options.component,\n snapshot: options.snapshot,\n routeConfig: options.routeConfig,\n root: options.root,\n parent: options.parent,\n firstChild: options.firstChild,\n children: options.children,\n pathFromRoot: options.pathFromRoot\n } as ActivatedRoute;\n\n for (let route: null | ActivatedRoute = result; route; route = route.parent) {\n if (route.parent && route.parent.snapshot && !route.snapshot) {\n // eslint-disable-next-line deprecation/deprecation\n route.snapshot = fakeSnapshot({});\n }\n if (route.parent && route.parent.snapshot && !route.snapshot.parent) {\n (route.snapshot as Omit<ActivatedRouteSnapshot, 'parent'> & { parent: ActivatedRouteSnapshot }).parent = route.parent.snapshot;\n }\n\n if (route.snapshot && route.snapshot.parent && !route.parent) {\n // eslint-disable-next-line deprecation/deprecation\n (route as Omit<ActivatedRoute, 'parent'> & { parent: ActivatedRoute }).parent = fakeRoute({});\n }\n if (route.snapshot && route.snapshot.parent && route.parent && !route.parent.snapshot) {\n route.parent.snapshot = route.snapshot.parent;\n }\n }\n\n return result;\n}\n\n/**\n * Creates a fake partial ActivatedRouteSnapshot for tests.\n *\n * If you pass params, then the created snapshot's paramMap will contain the same values.\n * The same goes for queryParams and queryParamMap.\n *\n * @returns a partially populated, fake ActivatedRoute, depending on what you passed in\n * @deprecated favor stubRoute, which creates an easier to use and more logical stub for both the route and its snapshot\n */\nexport function fakeSnapshot(options: {\n url?: UrlSegment[];\n /** The matrix parameters scoped to this route */\n params?: Params;\n /** The query parameters shared by all the routes */\n queryParams?: Params;\n /** The URL fragment shared by all the routes */\n fragment?: string;\n /** The static and resolved data of this route */\n data?: Data;\n /** The outlet name of the route */\n outlet?: string;\n /** The component of the route */\n component?: Type<unknown> | string | null;\n /** The configuration used to match this route */\n routeConfig?: Route;\n /** The root of the router state */\n root?: ActivatedRouteSnapshot;\n /** The parent of this route in the router state tree */\n parent?: ActivatedRouteSnapshot | null;\n /** The first child of this route in the router state tree */\n firstChild?: ActivatedRouteSnapshot | null;\n /** The children of this route in the router state tree */\n children?: ActivatedRouteSnapshot[];\n /** The path from the root of the router state tree to this route */\n pathFromRoot?: ActivatedRouteSnapshot[];\n}): ActivatedRouteSnapshot {\n return {\n url: options.url,\n params: options.params,\n paramMap: options.params && convertToParamMap(options.params),\n queryParams: options.queryParams,\n queryParamMap: options.queryParams && convertToParamMap(options.queryParams),\n fragment: options.fragment,\n data: options.data,\n outlet: options.outlet,\n component: options.component,\n routeConfig: options.routeConfig,\n root: options.root,\n parent: options.parent,\n firstChild: options.firstChild,\n children: options.children,\n pathFromRoot: options.pathFromRoot\n } as ActivatedRouteSnapshot;\n}\n\n/**\n * The options that are passed when creating an ActivatedRouteStub.\n */\nexport interface ActivatedRouteStubOptions {\n /**\n * The initial values of the parameters of the route\n */\n params?: Params;\n /**\n * The initial values of the query parameters of the route\n */\n queryParams?: Params;\n /**\n * The initial values of the data of the route\n */\n data?: Data;\n /**\n * The initial values of the title of the route\n */\n title?: string;\n /**\n * The initial fragment of the route\n */\n fragment?: string | null;\n /**\n * The initial url of the route\n */\n url?: UrlSegment[];\n /**\n * The parent of the route\n */\n parent?: ActivatedRouteStub | null;\n /**\n * The first child of the route\n */\n firstChild?: ActivatedRouteStub | null;\n /**\n * The children of the route\n */\n children?: ActivatedRouteStub[] | null;\n /**\n * The configuration of the route\n */\n routeConfig?: Route | null;\n}\n\nclass ActivatedRouteSnapshotStub extends ActivatedRouteSnapshot {\n private _parent: ActivatedRouteSnapshot | null = null;\n private _root: ActivatedRouteSnapshot;\n private _firstChild: ActivatedRouteSnapshot | null = null;\n private _children: Array<ActivatedRouteSnapshot> = [];\n private _pathFromRoot: Array<ActivatedRouteSnapshot> = [];\n private _title: string | undefined;\n\n get parent(): ActivatedRouteSnapshot | null {\n return this._parent;\n }\n\n set parent(value: ActivatedRouteSnapshot | null) {\n this._parent = value;\n }\n\n get root(): ActivatedRouteSnapshot {\n return this._root;\n }\n\n set root(value: ActivatedRouteSnapshot) {\n this._root = value;\n }\n\n get firstChild(): ActivatedRouteSnapshot | null {\n return this._firstChild;\n }\n\n set firstChild(value: ActivatedRouteSnapshot | null) {\n this._firstChild = value;\n }\n\n get children(): Array<ActivatedRouteSnapshot> {\n return this._children;\n }\n\n set children(value: Array<ActivatedRouteSnapshot>) {\n this._children = value;\n }\n\n get pathFromRoot(): Array<ActivatedRouteSnapshot> {\n return this._pathFromRoot;\n }\n\n set pathFromRoot(value: Array<ActivatedRouteSnapshot>) {\n this._pathFromRoot = value;\n }\n\n get title(): string | undefined {\n return this._title;\n }\n\n set title(value: string | undefined) {\n this._title = value;\n }\n\n get paramMap(): ParamMap {\n return convertToParamMap(this.params);\n }\n\n get queryParamMap(): ParamMap {\n return convertToParamMap(this.queryParams);\n }\n\n constructor() {\n super();\n this._root = this;\n }\n}\n\n/**\n * A stub for ActivatedRoute. It behaves almost the same way as the actual ActivatedRoute, exposing a snapshot\n * and observables for the params, query params etc., which are kept in sync.\n *\n * In addition, this stub allows simulating a navigation by changing the params, the query params, the fragment, etc.\n * When that happens, the snapshot is modified, then the relevant observables emit the new values.\n *\n * There are some things that don't really work the same way as the real ActivatedRoute though:\n * - the handling of the firstChild and of the children is entirely under the tester's responsibility. Setting the parent\n * of a route stub does not add this route to the children of its parent, for example.\n * - when changing the params, query params, fragment, etc., their associated observable emits unconditionally, instead of\n * first checking if the value is actually different from before. It's thus the responsibility of the tester to not\n * change the values if they're the same as before.\n * - the params, paramMap, queryParams and queryParamMap objects of the route snapshot change when params or query params are set\n * on the stub route. So if the code keeps a reference to params or paramMaps, it won't see the changes.\n */\nexport class ActivatedRouteStub extends ActivatedRoute {\n private _firstChild: ActivatedRouteStub | null;\n private _children: Array<ActivatedRouteStub>;\n\n private readonly paramsSubject: BehaviorSubject<Params>;\n private readonly queryParamsSubject: BehaviorSubject<Params>;\n private readonly dataSubject: BehaviorSubject<Data>;\n private readonly fragmentSubject: BehaviorSubject<string | null>;\n private readonly urlSubject: BehaviorSubject<Array<UrlSegment>>;\n private readonly titleSubject: BehaviorSubject<string | undefined>;\n\n private _parent: ActivatedRouteStub | null;\n private _root: ActivatedRouteStub;\n private _pathFromRoot: Array<ActivatedRouteStub>;\n\n /**\n * Constructs a new instance, based on the given options.\n * If an option is not provided (or if no option is provided at all), then the route has a default value for this option\n * (empty parameters for example, null fragment, etc.)\n * If no parent is passed, then this route has no parent and is thus set as the root. Otherwise, the root and the path\n * from root are created based on the root and path from root of the given parent route.\n */\n constructor(options?: ActivatedRouteStubOptions) {\n super();\n\n const snapshot = new ActivatedRouteSnapshotStub();\n this.snapshot = snapshot;\n\n this._firstChild = options?.firstChild ?? null;\n this._children = options?.children ?? [];\n this._parent = options?.parent ?? null;\n this._root = this.parent?.root ?? this;\n this._pathFromRoot = this.parent ? [...this.parent.pathFromRoot, this] : [this];\n\n snapshot.params = options?.params ?? {};\n snapshot.queryParams = options?.queryParams ?? {};\n snapshot.data = options?.data ?? {};\n snapshot.title = options?.title;\n snapshot.fragment = options?.fragment ?? null;\n snapshot.url = options?.url ?? [];\n // @ts-expect-error the routeConfig is readonly, but we need to overwrite it here\n snapshot.routeConfig = options?.routeConfig ?? null;\n\n snapshot.firstChild = this.firstChild?.snapshot ?? null;\n snapshot.children = this.children?.map(route => route.snapshot) ?? [];\n snapshot.parent = this.parent?.snapshot ?? null;\n snapshot.root = this.root.snapshot;\n snapshot.pathFromRoot = this.pathFromRoot.map(route => route.snapshot);\n\n this.paramsSubject = new BehaviorSubject<Params>(this.snapshot.params);\n this.queryParamsSubject = new BehaviorSubject<Params>(this.snapshot.queryParams);\n this.dataSubject = new BehaviorSubject<Data>(this.snapshot.data);\n this.titleSubject = new BehaviorSubject<string | undefined>(this.snapshot.title);\n this.fragmentSubject = new BehaviorSubject<string | null>(this.snapshot.fragment);\n this.urlSubject = new BehaviorSubject<Array<UrlSegment>>(this.snapshot.url);\n\n this.params = this.paramsSubject.asObservable();\n this.queryParams = this.queryParamsSubject.asObservable();\n this.data = this.dataSubject.asObservable();\n this.fragment = this.fragmentSubject.asObservable();\n this.url = this.urlSubject.asObservable();\n // @ts-expect-error the title is readonly, but we need to be able to initialize it here\n this.title = this.titleSubject.asObservable();\n }\n\n get root() {\n return this._root;\n }\n\n get parent(): ActivatedRouteStub | null {\n return this._parent;\n }\n\n get pathFromRoot(): Array<ActivatedRouteStub> {\n return this._pathFromRoot;\n }\n\n get firstChild(): ActivatedRouteStub | null {\n return this._firstChild;\n }\n\n get children(): Array<ActivatedRouteStub> {\n return this._children;\n }\n\n get routeConfig(): Route | null {\n return this.snapshot.routeConfig;\n }\n\n /**\n * Triggers a navigation with the given new parameters. All the other parts (query params etc.) stay as they are.\n * This is a shortcut to `triggerNavigation` that can be used to only change the parameters.\n */\n public setParams(params: Params): void {\n this.triggerNavigation({ params });\n }\n\n /**\n * Triggers a navigation with the given new parameter. The other parameters, as well as all the other parts (query params etc.)\n * stay as they are.\n * This is a shortcut to `triggerNavigation` that can be used to only change one parameter.\n */\n public setParam(name: string, value: string): void {\n this.setParams({ ...this.snapshot.params, [name]: value });\n }\n\n /**\n * Triggers a navigation with the given new query parameters. All the other parts (params etc.) stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change the query parameters.\n */\n public setQueryParams(queryParams: Params): void {\n this.triggerNavigation({ queryParams });\n }\n\n /**\n * Triggers a navigation with the given new parameter. The other query parameters, as well as all the other parts (params etc.)\n * stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change one query parameter.\n */\n public setQueryParam(name: string, value: string): void {\n this.setQueryParams({ ...this.snapshot.queryParams, [name]: value });\n }\n\n /**\n * Triggers a navigation with the given new data. The other parameters, as well as all the other parts (params etc.)\n * stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change the data.\n */\n public setData(data: Data): void {\n this.triggerNavigation({ data });\n }\n\n /**\n * Triggers a navigation with the given new data item. The other data, as well as all the other parts (params etc.)\n * stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change one data item.\n */\n public setDataItem(name: string, value: unknown): void {\n this.setData({ ...this.snapshot.data, [name]: value });\n }\n\n /**\n * Triggers a navigation with the given new title. The other parameters, as well as all the other parts (params etc.)\n * stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change the title.\n */\n public setTitle(title: string | undefined): void {\n this.triggerNavigation({ title: { value: title } });\n }\n\n /**\n * Triggers a navigation with the given new fragment. The other parts (params etc.) stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change the fragment.\n */\n public setFragment(fragment: string | null): void {\n this.triggerNavigation({ fragment });\n }\n\n /**\n * Triggers a navigation with the given new url. The other parts (params etc.) stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change the url.\n */\n public setUrl(url: Array<UrlSegment>): void {\n this.triggerNavigation({ url });\n }\n\n /**\n * Triggers a navigation based on the given options. If an option is undefined or null, it's ignored. Except for fragment, which is only\n * ignored if it's undefined, because null is a valid value for a fragment.\n *\n * The non-ignored values are used to change the snapshot of the route. Once the snapshot has been modified,\n * the observables corresponding to the updated parts emit the new value.\n *\n * So, setting params and query params will make the params and queryParams observables emit, but not the fragment, data and\n * url observables for example. This is consistent to how the router behaves.\n *\n * Note: since the title of a route can become undefined, in order to be able to distinguish between a navigation which leaves the title\n * as it is and a navigation that sets the title to undefined, a wrapper object is used for the title. So\n *\n * - `triggerNavigation({ params:... })` leaves the title as is because it's undefined in the options\n * - `triggerNavigation({ title: { value: 'test' } })` sets the title to 'test'\n * - `triggerNavigation({ title: { value: undefined } })` sets the title to undefined\n */\n public triggerNavigation(options: {\n params?: Params;\n queryParams?: Params;\n fragment?: string | null;\n data?: Data | null;\n title?: { value: string | undefined } | null;\n url?: Array<UrlSegment> | null;\n }): void {\n // set the snapshot first\n if (options.params) {\n this.snapshot.params = options.params;\n }\n if (options.queryParams) {\n this.snapshot.queryParams = options.queryParams;\n }\n if (options.fragment !== undefined) {\n this.snapshot.fragment = options.fragment;\n }\n if (options.data) {\n this.snapshot.data = options.data;\n }\n if (options.title) {\n // @ts-expect-error the title is readonly, but we need to be able to overwrite it here\n this.snapshot.title = options.title.value;\n }\n if (options.url) {\n this.snapshot.url = options.url;\n }\n\n // then emit everything that has changed\n if (options.params) {\n this.paramsSubject.next(this.snapshot.params);\n }\n if (options.queryParams) {\n this.queryParamsSubject.next(this.snapshot.queryParams);\n }\n if (options.fragment !== undefined) {\n this.fragmentSubject.next(this.snapshot.fragment);\n }\n if (options.data) {\n this.dataSubject.next(this.snapshot.data);\n }\n if (options.title) {\n this.titleSubject.next(this.snapshot.title);\n }\n if (options.url) {\n this.urlSubject.next(this.snapshot.url);\n }\n }\n\n public toString(): string {\n return 'ActivatedRouteStub';\n }\n}\n\n/**\n * Creates a new ActivatedRouteStub, by calling its constructor.\n */\nexport function stubRoute(options?: ActivatedRouteStubOptions): ActivatedRouteStub {\n return new ActivatedRouteStub(options);\n}\n","import { TestTextArea } from './test-textarea';\nimport { TestInput } from './test-input';\nimport { TestElement } from './test-element';\nimport { TestSelect } from './test-select';\nimport { TestHtmlElement } from './test-html-element';\n\nconst speculoosMatchers: jasmine.CustomMatcherFactories = {\n /**\n * Checks that the receiver is a TestElement wrapping a DOM element and as the given CSS class\n */\n toHaveClass(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n if (!el) {\n return { pass: false, message: `Expected to check class '${expected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestElement)) {\n return { pass: false, message: `Expected to check class '${expected}' on element, but element was not a TestElement` };\n }\n const actual = el.classes;\n const pass = actual.indexOf(expected) !== -1;\n const message =\n `Expected element to ${isNegative ? 'not ' : ''}have class '${expected}', ` +\n `but had ${actual.length ? \"'\" + actual.join(', ') + \"'\" : 'none'}`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestInput or a TestTextArea and has the given value\n */\n toHaveValue(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n if (!el) {\n return { pass: false, message: `Expected to check value '${expected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestInput) && !(el instanceof TestTextArea)) {\n return {\n pass: false,\n message: `Expected to check value '${expected}' on element, but element was neither a TestInput nor a TestTextArea`\n };\n }\n const actual = el.value;\n const pass = actual === expected;\n const message = `Expected element to ${isNegative ? 'not ' : ''}have value '${expected}', but had value '${actual}'`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestElement wrapping a DOM element and has the exact given textContent\n */\n toHaveText(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n if (!el) {\n return { pass: false, message: `Expected to check text '${expected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestElement)) {\n return { pass: false, message: `Expected to check text '${expected}' on element, but element was not a TestElement` };\n }\n const actual = el.textContent;\n const pass = actual === expected;\n const message = `Expected element to ${isNegative ? 'not ' : ''}have text '${expected}', but had '${actual}'`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestElement wrapping a DOM element and has the given textContent, after both have been trimmed.\n * So, An element such as\n * ```\n * <h1>\n * Some title\n * </h1>\n * ```\n * will pass the test\n * ```\n * expect(tester.title).toHaveTrimmedText('Some title')\n * ```\n */\n toHaveTrimmedText(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n const trimmedExpected = expected.trim();\n if (!el) {\n return { pass: false, message: `Expected to check trimmed text '${trimmedExpected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestElement)) {\n return {\n pass: false,\n message: `Expected to check trimmed text '${trimmedExpected}' on element, but element was not a TestElement`\n };\n }\n const actual = el.textContent?.trim();\n const pass = actual === trimmedExpected;\n const message = `Expected element to ${isNegative ? 'not ' : ''}have trimmed text '${trimmedExpected}', but had '${actual}'`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestElement wrapping a DOM element and contains the given textContent\n */\n toContainText(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n if (!el) {\n return { pass: false, message: `Expected to check text '${expected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestElement)) {\n return { pass: false, message: `Expected to check text '${expected}' on element, but element was not a TestElement` };\n }\n const actual = el.textContent;\n if (!actual) {\n return {\n pass: isNegative,\n message: `Expected element to ${isNegative ? 'not ' : ''}contain text '${expected}', but had no text`\n };\n }\n const pass = actual.indexOf(expected) !== -1;\n const message = `Expected element to ${isNegative ? 'not ' : ''}contain text '${expected}', but had text '${actual}'`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestElement wrapping a DOM element and contains the given textContent\n */\n toBeChecked(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown) => {\n if (!el) {\n return { pass: false, message: `Expected to check if element was checked, but element was falsy` };\n }\n if (!(el instanceof TestInput)) {\n return { pass: false, message: `Expected to check if element was checked, but element was not a TestInput` };\n }\n const pass = el.checked;\n const message = `Expected element to be ${isNegative ? 'not ' : ''}checked, but was${!isNegative ? ' not' : ''}`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown): jasmine.CustomMatcherResult {\n return assert(false, el);\n },\n negativeCompare(el: unknown): jasmine.CustomMatcherResult {\n return assert(true, el);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestSelect wrapping a DOM element and has the given selected index\n */\n toHaveSelectedIndex(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: number) => {\n if (!el) {\n return { pass: false, message: `Expected to check selected index ${expected} on element, but element was falsy` };\n }\n if (!(el instanceof TestSelect)) {\n return { pass: false, message: `Expected to check selected index ${expected} on element, but element was not a TestSelect` };\n }\n const actual = el.selectedIndex;\n const pass = actual === expected;\n const message = `Expected element to ${isNegative ? 'not ' : ''}have selected index ${expected}, but had ${actual}`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: number): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: number): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestSelect wrapping a DOM element with the selected option's value equal to the given value\n */\n toHaveSelectedValue(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n if (!el) {\n return { pass: false, message: `Expected to check selected value '${expected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestSelect)) {\n return { pass: false, message: `Expected to check selected value '${expected}' on element, but element was not a TestSelect` };\n }\n const actual = el.selectedValue;\n const pass = actual === expected;\n const message = `Expected element to ${isNegative ? 'not ' : ''}have selected value '${expected}', but had '${actual}'`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestSelect wrapping a DOM element with the selected option's label equal to the given label\n */\n toHaveSelectedLabel(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n if (!el) {\n return { pass: false, message: `Expected to check selected label '${expected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestSelect)) {\n return { pass: false, message: `Expected to check selected label '${expected}' on element, but element was not a TestSelect` };\n }\n const actual = el.selectedLabel;\n const pass = actual === expected;\n const message = `Expected element to ${isNegative ? 'not ' : ''}have selected label '${expected}', but had '${actual}'`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestHtmlElement which is visible\n */\n toBeVisible(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown) => {\n const expectedState = `${isNegative ? 'in' : ''}visible`;\n const inverseState = `${isNegative ? '' : 'in'}visible`;\n if (!el) {\n return { pass: false, message: `Expected to check if element was ${expectedState}, but element was falsy` };\n }\n if (!(el instanceof TestHtmlElement)) {\n return { pass: false, message: `Expected to check if element was ${expectedState}, but element was not a TestHtmlElement` };\n }\n const pass = el.visible;\n const message = `Expected element to be ${expectedState}, but was ${inverseState}`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown): jasmine.CustomMatcherResult {\n return assert(false, el);\n },\n negativeCompare(el: unknown): jasmine.CustomMatcherResult {\n return assert(true, el);\n }\n };\n }\n};\n\nexport { speculoosMatchers };\n","import { Type } from '@angular/core';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction collectMethodNames(proto: unknown): Array<string> {\n if (!proto || proto === Object.prototype) {\n return [];\n }\n const methodNames: Array<string> = [];\n for (const key of Object.getOwnPropertyNames(proto)) {\n const descriptor = Object.getOwnPropertyDescriptor(proto, key);\n if (descriptor && typeof descriptor.value === 'function' && key !== 'constructor') {\n methodNames.push(key);\n }\n }\n return [...methodNames, ...collectMethodNames(Object.getPrototypeOf(proto))];\n}\n\n/**\n * Creates a spy object for a class where all the methods of the class (and of its superclasses) are spies.\n * I.e., for a class `UserService` with methods `get()`, `create()`, `update()` and `delete()`, calling\n * `createMock(UserService)` is equivalent to calling\n * `jasmine.createSpyObj<UserService>('UserService', ['get', 'create', 'update', 'delete'])`.\n * @param type the type to mock (usually a service class)\n */\nexport function createMock<T>(type: Type<T>): jasmine.SpyObj<T> {\n return jasmine.createSpyObj<T>(type.name, collectMethodNames(type.prototype) as unknown as jasmine.SpyObjMethodNames<T>);\n}\n","/* eslint-disable */\n/*\n * Public API Surface of ngx-speculoos\n */\n/// <reference path=\"./jasmine-matchers.ts\" />\n\nexport * from './lib/component-tester';\nexport * from './lib/test-element';\nexport * from './lib/test-html-element';\nexport * from './lib/test-input';\nexport * from './lib/test-button';\nexport * from './lib/test-select';\nexport * from './lib/test-textarea';\nexport * from './lib/route';\nexport * from './lib/matchers';\nexport * from './lib/mock';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngx-speculoos.mjs","sources":["../../../projects/ngx-speculoos/src/lib/test-element.ts","../../../projects/ngx-speculoos/src/lib/test-html-element.ts","../../../projects/ngx-speculoos/src/lib/test-button.ts","../../../projects/ngx-speculoos/src/lib/test-select.ts","../../../projects/ngx-speculoos/src/lib/test-textarea.ts","../../../projects/ngx-speculoos/src/lib/test-input.ts","../../../projects/ngx-speculoos/src/lib/test-element-querier.ts","../../../projects/ngx-speculoos/src/lib/component-tester.ts","../../../projects/ngx-speculoos/src/lib/routing-tester.ts","../../../projects/ngx-speculoos/src/lib/route.ts","../../../projects/ngx-speculoos/src/lib/matchers.ts","../../../projects/ngx-speculoos/src/lib/mock.ts","../../../projects/ngx-speculoos/src/public_api.ts","../../../projects/ngx-speculoos/src/ngx-speculoos.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { ComponentTester } from './component-tester';\nimport { TestButton } from './test-button';\nimport { TestSelect } from './test-select';\nimport { TestTextArea } from './test-textarea';\nimport { TestInput } from './test-input';\nimport { TestElementQuerier } from './test-element-querier';\nimport { DebugElement, ProviderToken, Type } from '@angular/core';\nimport { TestHtmlElement } from './test-html-element';\n\n/**\n * A wrapped DOM element, providing additional methods and attributes helping with writing tests\n */\nexport class TestElement<E extends Element = Element> {\n private querier: TestElementQuerier;\n\n constructor(\n protected tester: ComponentTester<unknown>,\n /**\n * the wrapped debug element\n */\n readonly debugElement: DebugElement\n ) {\n this.querier = new TestElementQuerier(tester, debugElement);\n }\n\n get nativeElement(): E {\n return this.debugElement.nativeElement;\n }\n\n /**\n * the text content of this element\n */\n get textContent(): string | null {\n return this.nativeElement.textContent;\n }\n\n /**\n * dispatches an event of the given type from the wrapped element, then triggers a change detection\n */\n dispatchEventOfType(type: string): void {\n this.nativeElement.dispatchEvent(new Event(type));\n this.tester.detectChanges();\n }\n\n /**\n * dispatches the given event from the wrapped element, then triggers a change detection\n */\n dispatchEvent(event: Event): void {\n this.nativeElement.dispatchEvent(event);\n this.tester.detectChanges();\n }\n\n /**\n * Gets the CSS classes of the wrapped element, as an array\n */\n get classes(): Array<string> {\n return Array.prototype.slice.call(this.nativeElement.classList);\n }\n\n /**\n * Gets the attribute of the wrapped element with the given name\n * @param name the name of the attribute to get\n */\n attr(name: string): string | null {\n return this.nativeElement.getAttribute(name);\n }\n\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestHtmlElement&lt;HTMLDivElement> | null = tester.element('div');\n * </code>\n * @param selector a CSS selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<K extends keyof HTMLElementTagNameMap>(selector: K): TestHtmlElement<HTMLElementTagNameMap[K]> | null;\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement&lt;SVGLineElement> | null = tester.element('line');\n * </code>\n * @param selector a CSS selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<K extends keyof SVGElementTagNameMap>(selector: K): TestElement<SVGElementTagNameMap[K]> | null;\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement | null = tester.element('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element(selector: string | Type<any>): TestElement | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestInput | null = tester.element&lt;HTMLInputElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLInputElement>(selector: string | Type<any>): TestInput | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestTextArea | null = tester.element&lt;HTMLTextAreaElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLTextAreaElement>(selector: string | Type<any>): TestTextArea | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestSelect | null = tester.element&lt;HTMLSelectElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLSelectElement>(selector: string | Type<any>): TestSelect | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestButton | null = tester.element&lt;HTMLButtonElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLButtonElement>(selector: string | Type<any>): TestButton | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestHtmlElement&lt;HTMLDivElement> | null = tester.element&lt;HTMLDivElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLElement>(selector: string | Type<any>): TestHtmlElement<T> | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement&lt;SVGLineElement> | null = tester.element&lt;SVGLineElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends Element>(selector: string | Type<any>): TestElement<T> | null;\n element(selector: string | Type<any>): TestElement | null {\n return this.querier.element(selector);\n }\n\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestHtmlElement&lt;HTMLDivElement>> = tester.elements('div');\n * </code>\n * @param selector a CSS selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<K extends keyof HTMLElementTagNameMap>(selector: K): Array<TestHtmlElement<HTMLElementTagNameMap[K]>>;\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestElement&lt;SVGLineElement>> = tester.elements('line');\n * </code>\n * @param selector a CSS selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<K extends keyof SVGElementTagNameMap>(selector: K): Array<TestElement<SVGElementTagNameMap[K]>>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestElement> = tester.elements('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements(selector: string | Type<any>): Array<TestElement>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestInput> = tester.elements&lt;HTMLInputElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLInputElement>(selector: string | Type<any>): Array<TestInput>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestTextArea> = tester.elements&lt;HTMLTextAreaElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLTextAreaElement>(selector: string | Type<any>): Array<TestTextArea>;\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestButton> = tester.elements&lt;HTMLButtonElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLButtonElement>(selector: string | Type<any>): Array<TestButton>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestSelect> = tester.elements<HTMLSelectElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLSelectElement>(selector: string | Type<any>): Array<TestSelect>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestHtmlElement&lt;HTMLDivElement>> = tester.elements&lt;HTMLDivElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLElement>(selector: string | Type<any>): Array<TestHtmlElement<T>>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestElement&lt;SVGLineElement>> = tester.elements&lt;SVGLineElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends Element>(selector: string | Type<any>): Array<TestElement<T>>;\n elements(selector: string | Type<any>): Array<TestElement> {\n return this.querier.elements(selector);\n }\n\n /**\n * Gets the first input matched by the given selector. Throws an Error if the matched element isn't actually an input.\n * @param selector a CSS or directive selector\n * @returns the wrapped input, or null if no element was matched\n */\n input(selector: string | Type<any>): TestInput | null {\n return this.querier.input(selector);\n }\n\n /**\n * Gets the first select matched by the given selector. Throws an Error if the matched element isn't actually a select.\n * @param selector a CSS or directive selector\n * @returns the wrapped select, or null if no element was matched\n */\n select(selector: string | Type<any>): TestSelect | null {\n return this.querier.select(selector);\n }\n\n /**\n * Gets the first textarea matched by the given selector\n * @param selector a CSS or directive selector\n * @returns the wrapped textarea, or null if no element was matched. Throws an Error if the matched element isn't actually a textarea.\n * @throws {Error} if the matched element isn't actually a textarea\n */\n textarea(selector: string | Type<any>): TestTextArea | null {\n return this.querier.textarea(selector);\n }\n\n /**\n * Gets the first button matched by the given selector. Throws an Error if the matched element isn't actually a button.\n * @param selector a CSS or directive selector\n * @returns the wrapped button, or null if no element was matched\n */\n button(selector: string | Type<any>): TestButton | null {\n return this.querier.button(selector);\n }\n\n /**\n * Gets the first directive matching the given component directive selector and returns its component instance\n * @param selector the selector of a component directive\n */\n component<R>(selector: Type<R>): R {\n return this.querier.element(selector)?.debugElement?.componentInstance ?? null;\n }\n\n /**\n * Gets the directives matching the given component directive selector and returns their component instance\n * @param selector the selector of a component directive\n */\n components<R>(selector: Type<R>): Array<R> {\n return this.querier.elements(selector).map(e => e.debugElement.componentInstance);\n }\n\n /**\n * Gets the first element matching the given selector, then gets the given token from its injector, or null if there is no such token\n * @param selector a CSS or directive selector\n * @param token the token to get from the matched element injector\n */\n token<R>(selector: string | Type<any>, token: ProviderToken<R>): R | null {\n return this.querier.element(selector)?.debugElement?.injector?.get(token, null) ?? null;\n }\n\n /**\n * Gets the elements matching the given selector, then gets their given token from their injector, or null if there is no such token\n * @param selector a CSS or directive selector\n * @param token the token to get from the matched element injector\n */\n tokens<R>(selector: string | Type<any>, token: ProviderToken<R>): Array<R | null> {\n return this.querier.elements(selector).map(e => e.debugElement.injector.get(token, null) ?? null);\n }\n\n /**\n * Gets the element matching the given selector, and if found, creates and returns a custom TestElement of the provided\n * type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for\n * custom elements or components.\n * @param selector a CSS or directive selector\n * @param customTestElementType the type of the TestElement subclass that will wrap the found element\n */\n custom<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): E | null {\n const element = this.querier.element(selector);\n return element && new customTestElementType(this.tester, element.debugElement);\n }\n\n /**\n * Gets the elements matching the given selector, and creates and returns custom TestElements of the provided\n * type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for\n * custom elements or components.\n * @param selector a CSS or directive selector\n * @param customTestElementType the type of the TestElement subclass that will wrap the found elements\n */\n customs<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): Array<E> {\n return this.querier.elements(selector).map(element => new customTestElementType(this.tester, element.debugElement));\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestElement } from './test-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped DOM HTML element, providing additional methods and attributes helping with writing tests\n */\nexport class TestHtmlElement<E extends HTMLElement> extends TestElement<E> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * Clicks on the wrapped element, then triggers a change detection\n */\n click(): void {\n this.nativeElement.click();\n this.tester.detectChanges();\n }\n\n /**\n * Tests if the element is visible, in the same meaning (and implementation) as in jQuery, i.e.\n * present anywhere in the DOM, and visible.\n * An element is not visible typically, if its display style or any of its ancestors display style is none.\n */\n get visible(): boolean {\n return !!(this.nativeElement.offsetWidth || this.nativeElement.offsetHeight || this.nativeElement.getClientRects().length);\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestHtmlElement } from './test-html-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped button element, providing additional methods and attributes helping with writing tests\n */\nexport class TestButton extends TestHtmlElement<HTMLButtonElement> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * the disabled flag of the button\n */\n get disabled(): boolean {\n return this.nativeElement.disabled;\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestHtmlElement } from './test-html-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped DOM HTML select element, providing additional methods and attributes helping with writing tests\n */\nexport class TestSelect extends TestHtmlElement<HTMLSelectElement> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * Selects the option at the given index, then dispatches an event of type change and triggers a change detection\n */\n selectIndex(index: number): void {\n this.nativeElement.selectedIndex = index;\n this.dispatchEventOfType('change');\n }\n\n /**\n * Selects the first option with the given value, then dispatches an event of type change and triggers a change detection.\n * If there is no option with the given value, then does nothing\n * TODO should it throw instead?\n */\n selectValue(value: string): void {\n const index = this.optionValues.indexOf(value);\n if (index >= 0) {\n this.selectIndex(index);\n }\n }\n\n /**\n * Selects the first option with the given label (or text), then dispatches an event of type change and triggers a change detection.\n * If there is no option with the given label, then does nothing\n * TODO should it throw instead?\n */\n selectLabel(label: string): void {\n const index = this.optionLabels.indexOf(label);\n if (index >= 0) {\n this.selectIndex(index);\n }\n }\n\n /**\n * the selected index of the wrapped select\n */\n get selectedIndex(): number {\n return this.nativeElement.selectedIndex;\n }\n\n /**\n * the value of the selected option of the wrapped select, or null if there is no selected option\n */\n get selectedValue(): string | null {\n if (this.selectedIndex < 0) {\n return null;\n }\n return this.nativeElement.options[this.selectedIndex].value;\n }\n\n /**\n * the label (or text if no label) of the selected option of the wrapped select, or null if there is no selected option\n */\n get selectedLabel(): string | null {\n if (this.selectedIndex < 0) {\n return null;\n }\n return this.nativeElement.options[this.selectedIndex].label;\n }\n\n /**\n * the values of the options, as an array\n */\n get optionValues(): Array<string> {\n return (Array.prototype.slice.call(this.nativeElement.options) as Array<HTMLOptionElement>).map(option => option.value);\n }\n\n /**\n * the labels (or texts if no label) of the options, as an array\n */\n get optionLabels(): Array<string> {\n return (Array.prototype.slice.call(this.nativeElement.options) as Array<HTMLOptionElement>).map(option => option.label);\n }\n\n /**\n * the number of options in the select\n */\n get size(): number {\n return this.nativeElement.options.length;\n }\n\n /**\n * the disabled property of the wrapped select\n */\n get disabled(): boolean {\n return this.nativeElement.disabled;\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestHtmlElement } from './test-html-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped DOM HTML textarea element, providing additional methods and attributes helping with writing tests\n */\nexport class TestTextArea extends TestHtmlElement<HTMLTextAreaElement> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * Sets the value of the wrapped textarea, then dispatches an event of type input and triggers a change detection\n * @param value the new value of the textarea\n */\n fillWith(value: string): void {\n this.nativeElement.value = value;\n this.dispatchEventOfType('input');\n }\n\n /**\n * the value of the wrapped textarea\n */\n get value(): string {\n return this.nativeElement.value;\n }\n\n /**\n * the disabled property of the wrapped textarea\n */\n get disabled(): boolean {\n return this.nativeElement.disabled;\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestHtmlElement } from './test-html-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped DOM HTML input element, providing additional methods and attributes helping with writing tests\n */\nexport class TestInput extends TestHtmlElement<HTMLInputElement> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * Sets the value of the wrapped input, then dispatches an event of type input and triggers a change detection\n * @param value the new value of the input\n */\n fillWith(value: string): void {\n this.nativeElement.value = value;\n this.dispatchEventOfType('input');\n }\n\n /**\n * the value of the wrapped input\n */\n get value(): string {\n return this.nativeElement.value;\n }\n\n /**\n * the checked property of the wrapped input\n */\n get checked(): boolean {\n return this.nativeElement.checked;\n }\n\n /**\n * the disabled property of the wrapped input\n */\n get disabled(): boolean {\n return this.nativeElement.disabled;\n }\n\n /**\n * Checks the wrapped input, then dispatches an event of type change and triggers a change detection\n */\n check(): void {\n this.nativeElement.checked = true;\n this.dispatchEventOfType('change');\n }\n\n /**\n * Unchecks the wrapped input, then dispatches an event of type change and triggers a change detection\n */\n uncheck(): void {\n this.nativeElement.checked = false;\n this.dispatchEventOfType('change');\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { TestButton } from './test-button';\nimport { TestSelect } from './test-select';\nimport { TestElement } from './test-element';\nimport { TestTextArea } from './test-textarea';\nimport { TestInput } from './test-input';\nimport { TestHtmlElement } from './test-html-element';\nimport { ComponentTester } from './component-tester';\nimport { DebugElement, Type } from '@angular/core';\nimport { By } from '@angular/platform-browser';\n\n/**\n * @internal\n */\nexport class TestElementQuerier {\n constructor(\n private tester: ComponentTester<unknown>,\n private root: DebugElement\n ) {}\n\n static wrap(childDebugElement: DebugElement, tester: ComponentTester<unknown>): TestElement {\n const childElement = childDebugElement.nativeElement;\n if (childElement instanceof HTMLButtonElement) {\n return new TestButton(tester, childDebugElement);\n } else if (childElement instanceof HTMLInputElement) {\n return new TestInput(tester, childDebugElement);\n } else if (childElement instanceof HTMLSelectElement) {\n return new TestSelect(tester, childDebugElement);\n } else if (childElement instanceof HTMLTextAreaElement) {\n return new TestTextArea(tester, childDebugElement);\n } else if (childElement instanceof HTMLElement) {\n return new TestHtmlElement(tester, childDebugElement);\n } else {\n return new TestElement(tester, childDebugElement);\n }\n }\n\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput. You can thus use\n * `tester.element('#some-input') as TestInput`.\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element(selector: string | Type<any>): TestElement | null {\n const childElement = this.query(selector);\n return childElement && TestElementQuerier.wrap(childElement, this.tester);\n }\n\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput. You can thus use\n * `tester.elements('input') as Array<TestInput>`.\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements(selector: string | Type<any>): Array<TestElement> {\n const childElements = this.queryAll(selector);\n return childElements.map(debugElement => TestElementQuerier.wrap(debugElement, this.tester));\n }\n\n /**\n * Gets the first input matched by the given selector. Throws an Error if the matched element isn't actually an input.\n * @param selector a CSS or directive selector\n * @returns the wrapped input, or null if no element was matched\n */\n input(selector: string | Type<any>): TestInput | null {\n const childElement = this.query(selector);\n if (!childElement) {\n return null;\n } else if (!(childElement.nativeElement instanceof HTMLInputElement)) {\n throw new Error(`Element with selector ${selector} is not an HTMLInputElement`);\n }\n return new TestInput(this.tester, childElement);\n }\n\n /**\n * Gets the first select matched by the given selector. Throws an Error if the matched element isn't actually a select.\n * @param selector a CSS or directive selector\n * @returns the wrapped select, or null if no element was matched\n */\n select(selector: string | Type<any>): TestSelect | null {\n const childElement = this.query(selector);\n if (!childElement) {\n return null;\n } else if (!(childElement.nativeElement instanceof HTMLSelectElement)) {\n throw new Error(`Element with selector ${selector} is not an HTMLSelectElement`);\n }\n return new TestSelect(this.tester, childElement);\n }\n\n /**\n * Gets the first textarea matched by the given selector\n * @param selector a CSS or directive selector\n * @returns the wrapped textarea, or null if no element was matched. Throws an Error if the matched element isn't actually a textarea.\n * @throws {Error} if the matched element isn't actually a textarea\n */\n textarea(selector: string | Type<any>): TestTextArea | null {\n const childElement = this.query(selector);\n if (!childElement) {\n return null;\n } else if (!(childElement.nativeElement instanceof HTMLTextAreaElement)) {\n throw new Error(`Element with selector ${selector} is not an HTMLTextAreaElement`);\n }\n return new TestTextArea(this.tester, childElement);\n }\n\n /**\n * Gets the first button matched by the given selector. Throws an Error if the matched element isn't actually a button.\n * @param selector a CSS or directive selector\n * @returns the wrapped button, or null if no element was matched\n */\n button(selector: string | Type<any>): TestButton | null {\n const childElement = this.query(selector);\n if (!childElement) {\n return null;\n } else if (!(childElement.nativeElement instanceof HTMLButtonElement)) {\n throw new Error(`Element with selector ${selector} is not an HTMLButtonElement`);\n }\n return new TestButton(this.tester, childElement);\n }\n\n private query(selector: string | Type<any>): DebugElement | null {\n if (typeof selector === 'string') {\n return this.root.query(By.css(selector));\n } else {\n return this.root.query(By.directive(selector));\n }\n }\n\n private queryAll(selector: string | Type<any>): Array<DebugElement> {\n if (typeof selector === 'string') {\n return this.root.queryAll(By.css(selector));\n } else {\n return this.root.queryAll(By.directive(selector));\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { DebugElement, ProviderToken, Type } from '@angular/core';\nimport { TestTextArea } from './test-textarea';\nimport { TestElement } from './test-element';\nimport { TestInput } from './test-input';\nimport { TestSelect } from './test-select';\nimport { TestButton } from './test-button';\nimport { TestElementQuerier } from './test-element-querier';\nimport { TestHtmlElement } from './test-html-element';\n\n/**\n * The main entry point of the API. It wraps an Angular ComponentFixture<T>, and gives access to its\n * most used properties and methods. It also allows getting elements wrapped in TestElement (and its subclasses)\n * @param <C> the type of the component to test\n */\nexport class ComponentTester<C> {\n /**\n * The test element of the component\n */\n readonly testElement: TestElement<HTMLElement>;\n\n /**\n * The component fixture of the component\n */\n readonly fixture: ComponentFixture<C>;\n\n /**\n * Creates a component fixture of the given type with the TestBed and wraps it into a ComponentTester\n */\n static create<C>(componentType: Type<C>): ComponentTester<C> {\n const fixture = TestBed.createComponent(componentType);\n return new ComponentTester(fixture);\n }\n\n /**\n * Creates a ComponentFixture for the given component type using the TestBed, and creates a ComponentTester\n * wrapping (and delegating) to this fixture. If a fixture is passed, then delegates to this fixture directly.\n *\n * Note that no `detectChanges()` call is made by this constructor. It's up to the subclass constructor,\n * or to the user of the created ComponentTester, to call `detectChanges()` at least once to trigger change\n * detection. This is necessary because some component templates can only be evaluated once inputs\n * have been set on the component instance.\n *\n * @param arg the type of the component to wrap, or a component fixture to wrap\n */\n constructor(arg: Type<C> | ComponentFixture<C>) {\n this.fixture = arg instanceof ComponentFixture ? arg : TestBed.createComponent(arg);\n this.testElement = TestElementQuerier.wrap(this.debugElement, this) as TestElement<HTMLElement>;\n }\n\n /**\n * The native DOM host element of the component\n */\n get nativeElement(): HTMLElement {\n return this.fixture.nativeElement;\n }\n\n /**\n * Gets the instance of the tested component from the wrapped fixture\n */\n get componentInstance(): C {\n return this.fixture.componentInstance;\n }\n\n /**\n * Gets the debug element from the wrapped fixture\n */\n get debugElement(): DebugElement {\n return this.fixture.debugElement;\n }\n\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestHtmlElement&lt;HTMLDivElement> | null = tester.element('div');\n * </code>\n * @param selector a CSS selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<K extends keyof HTMLElementTagNameMap>(selector: K): TestHtmlElement<HTMLElementTagNameMap[K]> | null;\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement&lt;SVGLineElement> | null = tester.element('line');\n * </code>\n * @param selector a CSS selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<K extends keyof SVGElementTagNameMap>(selector: K): TestElement<SVGElementTagNameMap[K]> | null;\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement | null = tester.element('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element(selector: string | Type<any>): TestElement | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestInput | null = tester.element&lt;HTMLInputElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLInputElement>(selector: string | Type<any>): TestInput | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestTextArea | null = tester.element&lt;HTMLTextAreaElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLTextAreaElement>(selector: string | Type<any>): TestTextArea | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestSelect | null = tester.element&lt;HTMLSelectElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLSelectElement>(selector: string | Type<any>): TestSelect | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestButton | null = tester.element&lt;HTMLButtonElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLButtonElement>(selector: string | Type<any>): TestButton | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestHtmlElement&lt;HTMLDivElement> | null = tester.element&lt;HTMLDivElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLElement>(selector: string | Type<any>): TestHtmlElement<T> | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement&lt;SVGLineElement> | null = tester.element&lt;SVGLineElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends Element>(selector: string | Type<any>): TestElement<T> | null;\n element(selector: string | Type<any>): TestElement | null {\n return this.testElement.element(selector);\n }\n\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestHtmlElement&lt;HTMLDivElement>> = tester.elements('div');\n * </code>\n * @param selector a CSS selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<K extends keyof HTMLElementTagNameMap>(selector: K): Array<TestHtmlElement<HTMLElementTagNameMap[K]>>;\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestElement&lt;SVGLineElement>> = tester.elements('line');\n * </code>\n * @param selector a CSS selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<K extends keyof SVGElementTagNameMap>(selector: K): Array<TestElement<SVGElementTagNameMap[K]>>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestElement> = tester.elements('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements(selector: string | Type<any>): Array<TestElement>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestInput> = tester.elements&lt;HTMLInputElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLInputElement>(selector: string | Type<any>): Array<TestInput>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestTextArea> = tester.elements&lt;HTMLTextAreaElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLTextAreaElement>(selector: string | Type<any>): Array<TestTextArea>;\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestButton> = tester.elements&lt;HTMLButtonElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLButtonElement>(selector: string | Type<any>): Array<TestButton>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestSelect> = tester.elements<HTMLSelectElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLSelectElement>(selector: string | Type<any>): Array<TestSelect>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestHtmlElement&lt;HTMLDivElement>> = tester.elements&lt;HTMLDivElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLElement>(selector: string | Type<any>): Array<TestHtmlElement<T>>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array&lt;TestElement&lt;SVGLineElement>> = tester.elements&lt;SVGLineElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends Element>(selector: string | Type<any>): Array<TestElement<T>>;\n elements(selector: string | Type<any>): Array<TestElement> {\n return this.testElement.elements(selector);\n }\n\n /**\n * Gets the first input matched by the given selector. Throws an Error if the matched element isn't actually an input.\n * @param selector a CSS or directive selector\n * @returns the wrapped input, or null if no element was matched\n */\n input(selector: string | Type<any>): TestInput | null {\n return this.testElement.input(selector);\n }\n\n /**\n * Gets the first select matched by the given selector. Throws an Error if the matched element isn't actually a select.\n * @param selector a CSS or directive selector\n * @returns the wrapped select, or null if no element was matched\n */\n select(selector: string | Type<any>): TestSelect | null {\n return this.testElement.select(selector);\n }\n\n /**\n * Gets the first textarea matched by the given selector\n * @param selector a CSS or directive selector\n * @returns the wrapped textarea, or null if no element was matched. Throws an Error if the matched element isn't actually a textarea.\n * @throws {Error} if the matched element isn't actually a textarea\n */\n textarea(selector: string | Type<any>): TestTextArea | null {\n return this.testElement.textarea(selector);\n }\n\n /**\n * Gets the first button matched by the given selector. Throws an Error if the matched element isn't actually a button.\n * @param selector a CSS or directive selector\n * @returns the wrapped button, or null if no element was matched\n */\n button(selector: string | Type<any>): TestButton | null {\n return this.testElement.button(selector);\n }\n\n /**\n * Gets the first directive matching the given component directive selector and returns its component instance\n * @param selector the selector of a component directive\n */\n component<R>(selector: Type<R>): R {\n return this.testElement.component(selector);\n }\n\n /**\n * Gets the directives matching the given component directive selector and returns their component instance\n * @param selector the selector of a component directive\n */\n components<R>(selector: Type<R>): Array<R> {\n return this.testElement.components(selector);\n }\n\n /**\n * Gets the first element matching the given selector, then gets the given token from its injector, or null if there is no such token\n * @param selector a CSS or directive selector\n * @param token the token to get from the matched element injector\n */\n token<R>(selector: string | Type<any>, token: ProviderToken<R>): R | null {\n return this.testElement.token(selector, token);\n }\n\n /**\n * Gets the elements matching the given selector, then gets their given token from their injector, or null if there is no such token\n * @param selector a CSS or directive selector\n * @param token the token to get from the matched element injector\n */\n tokens<R>(selector: string | Type<any>, token: ProviderToken<R>): Array<R | null> {\n return this.testElement.tokens(selector, token);\n }\n\n /**\n * Gets the element matching the given selector, and if found, creates and returns a custom TestElement of the provided\n * type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for\n * custom elements or components.\n * @param selector a CSS or directive selector\n * @param customTestElementType the type of the TestElement subclass that will wrap the found element\n */\n custom<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): E | null {\n return this.testElement.custom(selector, customTestElementType);\n }\n\n /**\n * Gets the elements matching the given selector, and creates and returns custom TestElements of the provided\n * type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for\n * custom elements or components.\n * @param selector a CSS or directive selector\n * @param customTestElementType the type of the TestElement subclass that will wrap the found elements\n */\n customs<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): Array<E> {\n return this.testElement.customs(selector, customTestElementType);\n }\n\n /**\n * Triggers a change detection using the wrapped fixture\n */\n detectChanges(checkNoChanges?: boolean): void {\n this.fixture.detectChanges(checkNoChanges);\n }\n\n /**\n * Delegates to the wrapped fixture whenStable and then detect changes\n */\n async stable(): Promise<void> {\n await this.fixture.whenStable();\n this.detectChanges();\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { RouterTestingHarness } from '@angular/router/testing';\nimport { Router, UrlTree } from '@angular/router';\nimport { TestBed } from '@angular/core/testing';\n\n/**\n * A thin wrapper around Angular RouterTestingHarness which helps testing routed components.\n * It allows, based on a configured testing module where the router is provided, to initially navigate\n * to a given route, then test the routed component. It's then possible to either navigate again with\n * the wrapped harness, or to use the component to trigger navigation, and test that the URL has changed\n * for example.\n */\nexport class RoutingTester extends ComponentTester<unknown> {\n constructor(readonly harness: RouterTestingHarness) {\n super(harness.fixture);\n }\n\n /**\n * Creates a RouterTestngHarness and uses it to navigate to the given URL\n * @param url the URL to initially navigate to.\n * @return a promise which resolves to a RoutingTester which wraps the harness\n * and its fixture.\n */\n static async forUrl(url: string) {\n const harness = await RouterTestingHarness.create(url);\n return new RoutingTester(harness);\n }\n\n /**\n * Gets the current URL of the Router service as a string\n */\n get url(): string {\n const router = TestBed.inject(Router);\n return router.url;\n }\n\n /**\n * Gets the current URL of the Router service as an UrlTree, to be able to test its\n * elements (query params, etc.)\n */\n get urlTree(): UrlTree {\n const router = TestBed.inject(Router);\n return router.parseUrl(router.url);\n }\n}\n","import { ActivatedRoute, ActivatedRouteSnapshot, convertToParamMap, Data, ParamMap, Params, Route, UrlSegment } from '@angular/router';\nimport { BehaviorSubject, map, Observable } from 'rxjs';\nimport { Type } from '@angular/core';\n\n/**\n * Creates a fake partial ActivatedRoute for tests.\n *\n * If you pass params, then the created route's paramMap will contain the same values.\n * The same goes for queryParams and queryParamMap.\n *\n * If you pass a parent route and a snapshot, and the passed snapshot doesn't have a parent, then the snapshot's\n * parent will be set to the parent route snapshot. This allows the code under test to use\n * `route.parent.snapshot` or `route.snapshot.parent`.\n *\n * If you pass a snapshot with a parent, but don't pass a parent or pass a parent without snapshot, then the route's\n * parent snapshot will be set to the given snapshot's parent. This allows the code under test to use\n * `route.parent.snapshot` or `route.snapshot.parent`.\n *\n * @returns a partially populated, fake ActivatedRoute, depending on what you passed in\n * @deprecated favor stubRoute, which creates an easier to use and more logical stub\n */\nexport function fakeRoute(options: {\n url?: Observable<UrlSegment[]>;\n /** An observable of the matrix parameters scoped to this route */\n params?: Observable<Params>;\n /** An observable of the query parameters shared by all the routes */\n queryParams?: Observable<Params>;\n /** An observable of the URL fragment shared by all the routes */\n fragment?: Observable<string>;\n /** An observable of the static and resolved data of this route. */\n data?: Observable<Data>;\n /** The outlet name of the route. It's a constant */\n outlet?: string;\n /** The component of the route. It's a constant */\n component?: Type<unknown> | string | null;\n /** The current snapshot of this route */\n snapshot?: ActivatedRouteSnapshot;\n /** The configuration used to match this route */\n routeConfig?: Route | null;\n /** The root of the router state */\n root?: ActivatedRoute;\n /** The parent of this route in the router state tree */\n parent?: ActivatedRoute | null;\n /** The first child of this route in the router state tree */\n firstChild?: ActivatedRoute;\n /** The children of this route in the router state tree */\n children?: ActivatedRoute[];\n /** The path from the root of the router state tree to this route */\n pathFromRoot?: ActivatedRoute[];\n}): ActivatedRoute {\n const result = {\n url: options.url,\n params: options.params,\n paramMap: options.params && options.params.pipe(map(params => convertToParamMap(params))),\n queryParams: options.queryParams,\n queryParamMap: options.queryParams && options.queryParams.pipe(map(params => convertToParamMap(params))),\n fragment: options.fragment,\n data: options.data,\n outlet: options.outlet,\n component: options.component,\n snapshot: options.snapshot,\n routeConfig: options.routeConfig,\n root: options.root,\n parent: options.parent,\n firstChild: options.firstChild,\n children: options.children,\n pathFromRoot: options.pathFromRoot\n } as ActivatedRoute;\n\n for (let route: null | ActivatedRoute = result; route; route = route.parent) {\n if (route.parent && route.parent.snapshot && !route.snapshot) {\n // eslint-disable-next-line deprecation/deprecation\n route.snapshot = fakeSnapshot({});\n }\n if (route.parent && route.parent.snapshot && !route.snapshot.parent) {\n (route.snapshot as Omit<ActivatedRouteSnapshot, 'parent'> & { parent: ActivatedRouteSnapshot }).parent = route.parent.snapshot;\n }\n\n if (route.snapshot && route.snapshot.parent && !route.parent) {\n // eslint-disable-next-line deprecation/deprecation\n (route as Omit<ActivatedRoute, 'parent'> & { parent: ActivatedRoute }).parent = fakeRoute({});\n }\n if (route.snapshot && route.snapshot.parent && route.parent && !route.parent.snapshot) {\n route.parent.snapshot = route.snapshot.parent;\n }\n }\n\n return result;\n}\n\n/**\n * Creates a fake partial ActivatedRouteSnapshot for tests.\n *\n * If you pass params, then the created snapshot's paramMap will contain the same values.\n * The same goes for queryParams and queryParamMap.\n *\n * @returns a partially populated, fake ActivatedRoute, depending on what you passed in\n * @deprecated favor stubRoute, which creates an easier to use and more logical stub for both the route and its snapshot\n */\nexport function fakeSnapshot(options: {\n url?: UrlSegment[];\n /** The matrix parameters scoped to this route */\n params?: Params;\n /** The query parameters shared by all the routes */\n queryParams?: Params;\n /** The URL fragment shared by all the routes */\n fragment?: string;\n /** The static and resolved data of this route */\n data?: Data;\n /** The outlet name of the route */\n outlet?: string;\n /** The component of the route */\n component?: Type<unknown> | string | null;\n /** The configuration used to match this route */\n routeConfig?: Route;\n /** The root of the router state */\n root?: ActivatedRouteSnapshot;\n /** The parent of this route in the router state tree */\n parent?: ActivatedRouteSnapshot | null;\n /** The first child of this route in the router state tree */\n firstChild?: ActivatedRouteSnapshot | null;\n /** The children of this route in the router state tree */\n children?: ActivatedRouteSnapshot[];\n /** The path from the root of the router state tree to this route */\n pathFromRoot?: ActivatedRouteSnapshot[];\n}): ActivatedRouteSnapshot {\n return {\n url: options.url,\n params: options.params,\n paramMap: options.params && convertToParamMap(options.params),\n queryParams: options.queryParams,\n queryParamMap: options.queryParams && convertToParamMap(options.queryParams),\n fragment: options.fragment,\n data: options.data,\n outlet: options.outlet,\n component: options.component,\n routeConfig: options.routeConfig,\n root: options.root,\n parent: options.parent,\n firstChild: options.firstChild,\n children: options.children,\n pathFromRoot: options.pathFromRoot\n } as ActivatedRouteSnapshot;\n}\n\n/**\n * The options that are passed when creating an ActivatedRouteStub.\n */\nexport interface ActivatedRouteStubOptions {\n /**\n * The initial values of the parameters of the route\n */\n params?: Params;\n /**\n * The initial values of the query parameters of the route\n */\n queryParams?: Params;\n /**\n * The initial values of the data of the route\n */\n data?: Data;\n /**\n * The initial values of the title of the route\n */\n title?: string;\n /**\n * The initial fragment of the route\n */\n fragment?: string | null;\n /**\n * The initial url of the route\n */\n url?: UrlSegment[];\n /**\n * The parent of the route\n */\n parent?: ActivatedRouteStub | null;\n /**\n * The first child of the route\n */\n firstChild?: ActivatedRouteStub | null;\n /**\n * The children of the route\n */\n children?: ActivatedRouteStub[] | null;\n /**\n * The configuration of the route\n */\n routeConfig?: Route | null;\n}\n\nclass ActivatedRouteSnapshotStub extends ActivatedRouteSnapshot {\n private _parent: ActivatedRouteSnapshot | null = null;\n private _root: ActivatedRouteSnapshot;\n private _firstChild: ActivatedRouteSnapshot | null = null;\n private _children: Array<ActivatedRouteSnapshot> = [];\n private _pathFromRoot: Array<ActivatedRouteSnapshot> = [];\n private _title: string | undefined;\n\n get parent(): ActivatedRouteSnapshot | null {\n return this._parent;\n }\n\n set parent(value: ActivatedRouteSnapshot | null) {\n this._parent = value;\n }\n\n get root(): ActivatedRouteSnapshot {\n return this._root;\n }\n\n set root(value: ActivatedRouteSnapshot) {\n this._root = value;\n }\n\n get firstChild(): ActivatedRouteSnapshot | null {\n return this._firstChild;\n }\n\n set firstChild(value: ActivatedRouteSnapshot | null) {\n this._firstChild = value;\n }\n\n get children(): Array<ActivatedRouteSnapshot> {\n return this._children;\n }\n\n set children(value: Array<ActivatedRouteSnapshot>) {\n this._children = value;\n }\n\n get pathFromRoot(): Array<ActivatedRouteSnapshot> {\n return this._pathFromRoot;\n }\n\n set pathFromRoot(value: Array<ActivatedRouteSnapshot>) {\n this._pathFromRoot = value;\n }\n\n get title(): string | undefined {\n return this._title;\n }\n\n set title(value: string | undefined) {\n this._title = value;\n }\n\n get paramMap(): ParamMap {\n return convertToParamMap(this.params);\n }\n\n get queryParamMap(): ParamMap {\n return convertToParamMap(this.queryParams);\n }\n\n constructor() {\n super();\n this._root = this;\n }\n}\n\n/**\n * A stub for ActivatedRoute. It behaves almost the same way as the actual ActivatedRoute, exposing a snapshot\n * and observables for the params, query params etc., which are kept in sync.\n *\n * In addition, this stub allows simulating a navigation by changing the params, the query params, the fragment, etc.\n * When that happens, the snapshot is modified, then the relevant observables emit the new values.\n *\n * There are some things that don't really work the same way as the real ActivatedRoute though:\n * - the handling of the firstChild and of the children is entirely under the tester's responsibility. Setting the parent\n * of a route stub does not add this route to the children of its parent, for example.\n * - when changing the params, query params, fragment, etc., their associated observable emits unconditionally, instead of\n * first checking if the value is actually different from before. It's thus the responsibility of the tester to not\n * change the values if they're the same as before.\n * - the params, paramMap, queryParams and queryParamMap objects of the route snapshot change when params or query params are set\n * on the stub route. So if the code keeps a reference to params or paramMaps, it won't see the changes.\n */\nexport class ActivatedRouteStub extends ActivatedRoute {\n private _firstChild: ActivatedRouteStub | null;\n private _children: Array<ActivatedRouteStub>;\n\n private readonly paramsSubject: BehaviorSubject<Params>;\n private readonly queryParamsSubject: BehaviorSubject<Params>;\n private readonly dataSubject: BehaviorSubject<Data>;\n private readonly fragmentSubject: BehaviorSubject<string | null>;\n private readonly urlSubject: BehaviorSubject<Array<UrlSegment>>;\n private readonly titleSubject: BehaviorSubject<string | undefined>;\n\n private _parent: ActivatedRouteStub | null;\n private _root: ActivatedRouteStub;\n private _pathFromRoot: Array<ActivatedRouteStub>;\n\n /**\n * Constructs a new instance, based on the given options.\n * If an option is not provided (or if no option is provided at all), then the route has a default value for this option\n * (empty parameters for example, null fragment, etc.)\n * If no parent is passed, then this route has no parent and is thus set as the root. Otherwise, the root and the path\n * from root are created based on the root and path from root of the given parent route.\n */\n constructor(options?: ActivatedRouteStubOptions) {\n super();\n\n const snapshot = new ActivatedRouteSnapshotStub();\n this.snapshot = snapshot;\n\n this._firstChild = options?.firstChild ?? null;\n this._children = options?.children ?? [];\n this._parent = options?.parent ?? null;\n this._root = this.parent?.root ?? this;\n this._pathFromRoot = this.parent ? [...this.parent.pathFromRoot, this] : [this];\n\n snapshot.params = options?.params ?? {};\n snapshot.queryParams = options?.queryParams ?? {};\n snapshot.data = options?.data ?? {};\n snapshot.title = options?.title;\n snapshot.fragment = options?.fragment ?? null;\n snapshot.url = options?.url ?? [];\n // @ts-expect-error the routeConfig is readonly, but we need to overwrite it here\n snapshot.routeConfig = options?.routeConfig ?? null;\n\n snapshot.firstChild = this.firstChild?.snapshot ?? null;\n snapshot.children = this.children?.map(route => route.snapshot) ?? [];\n snapshot.parent = this.parent?.snapshot ?? null;\n snapshot.root = this.root.snapshot;\n snapshot.pathFromRoot = this.pathFromRoot.map(route => route.snapshot);\n\n this.paramsSubject = new BehaviorSubject<Params>(this.snapshot.params);\n this.queryParamsSubject = new BehaviorSubject<Params>(this.snapshot.queryParams);\n this.dataSubject = new BehaviorSubject<Data>(this.snapshot.data);\n this.titleSubject = new BehaviorSubject<string | undefined>(this.snapshot.title);\n this.fragmentSubject = new BehaviorSubject<string | null>(this.snapshot.fragment);\n this.urlSubject = new BehaviorSubject<Array<UrlSegment>>(this.snapshot.url);\n\n this.params = this.paramsSubject.asObservable();\n this.queryParams = this.queryParamsSubject.asObservable();\n this.data = this.dataSubject.asObservable();\n this.fragment = this.fragmentSubject.asObservable();\n this.url = this.urlSubject.asObservable();\n // @ts-expect-error the title is readonly, but we need to be able to initialize it here\n this.title = this.titleSubject.asObservable();\n }\n\n get root() {\n return this._root;\n }\n\n get parent(): ActivatedRouteStub | null {\n return this._parent;\n }\n\n get pathFromRoot(): Array<ActivatedRouteStub> {\n return this._pathFromRoot;\n }\n\n get firstChild(): ActivatedRouteStub | null {\n return this._firstChild;\n }\n\n get children(): Array<ActivatedRouteStub> {\n return this._children;\n }\n\n get routeConfig(): Route | null {\n return this.snapshot.routeConfig;\n }\n\n /**\n * Triggers a navigation with the given new parameters. All the other parts (query params etc.) stay as they are.\n * This is a shortcut to `triggerNavigation` that can be used to only change the parameters.\n */\n public setParams(params: Params): void {\n this.triggerNavigation({ params });\n }\n\n /**\n * Triggers a navigation with the given new parameter. The other parameters, as well as all the other parts (query params etc.)\n * stay as they are.\n * This is a shortcut to `triggerNavigation` that can be used to only change one parameter.\n */\n public setParam(name: string, value: string): void {\n this.setParams({ ...this.snapshot.params, [name]: value });\n }\n\n /**\n * Triggers a navigation with the given new query parameters. All the other parts (params etc.) stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change the query parameters.\n */\n public setQueryParams(queryParams: Params): void {\n this.triggerNavigation({ queryParams });\n }\n\n /**\n * Triggers a navigation with the given new parameter. The other query parameters, as well as all the other parts (params etc.)\n * stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change one query parameter.\n */\n public setQueryParam(name: string, value: string): void {\n this.setQueryParams({ ...this.snapshot.queryParams, [name]: value });\n }\n\n /**\n * Triggers a navigation with the given new data. The other parameters, as well as all the other parts (params etc.)\n * stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change the data.\n */\n public setData(data: Data): void {\n this.triggerNavigation({ data });\n }\n\n /**\n * Triggers a navigation with the given new data item. The other data, as well as all the other parts (params etc.)\n * stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change one data item.\n */\n public setDataItem(name: string, value: unknown): void {\n this.setData({ ...this.snapshot.data, [name]: value });\n }\n\n /**\n * Triggers a navigation with the given new title. The other parameters, as well as all the other parts (params etc.)\n * stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change the title.\n */\n public setTitle(title: string | undefined): void {\n this.triggerNavigation({ title: { value: title } });\n }\n\n /**\n * Triggers a navigation with the given new fragment. The other parts (params etc.) stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change the fragment.\n */\n public setFragment(fragment: string | null): void {\n this.triggerNavigation({ fragment });\n }\n\n /**\n * Triggers a navigation with the given new url. The other parts (params etc.) stay as the are.\n * This is a shortcut to `triggerNavigation` that can be used to only change the url.\n */\n public setUrl(url: Array<UrlSegment>): void {\n this.triggerNavigation({ url });\n }\n\n /**\n * Triggers a navigation based on the given options. If an option is undefined or null, it's ignored. Except for fragment, which is only\n * ignored if it's undefined, because null is a valid value for a fragment.\n *\n * The non-ignored values are used to change the snapshot of the route. Once the snapshot has been modified,\n * the observables corresponding to the updated parts emit the new value.\n *\n * So, setting params and query params will make the params and queryParams observables emit, but not the fragment, data and\n * url observables for example. This is consistent to how the router behaves.\n *\n * Note: since the title of a route can become undefined, in order to be able to distinguish between a navigation which leaves the title\n * as it is and a navigation that sets the title to undefined, a wrapper object is used for the title. So\n *\n * - `triggerNavigation({ params:... })` leaves the title as is because it's undefined in the options\n * - `triggerNavigation({ title: { value: 'test' } })` sets the title to 'test'\n * - `triggerNavigation({ title: { value: undefined } })` sets the title to undefined\n */\n public triggerNavigation(options: {\n params?: Params;\n queryParams?: Params;\n fragment?: string | null;\n data?: Data | null;\n title?: { value: string | undefined } | null;\n url?: Array<UrlSegment> | null;\n }): void {\n // set the snapshot first\n if (options.params) {\n this.snapshot.params = options.params;\n }\n if (options.queryParams) {\n this.snapshot.queryParams = options.queryParams;\n }\n if (options.fragment !== undefined) {\n this.snapshot.fragment = options.fragment;\n }\n if (options.data) {\n this.snapshot.data = options.data;\n }\n if (options.title) {\n // @ts-expect-error the title is readonly, but we need to be able to overwrite it here\n this.snapshot.title = options.title.value;\n }\n if (options.url) {\n this.snapshot.url = options.url;\n }\n\n // then emit everything that has changed\n if (options.params) {\n this.paramsSubject.next(this.snapshot.params);\n }\n if (options.queryParams) {\n this.queryParamsSubject.next(this.snapshot.queryParams);\n }\n if (options.fragment !== undefined) {\n this.fragmentSubject.next(this.snapshot.fragment);\n }\n if (options.data) {\n this.dataSubject.next(this.snapshot.data);\n }\n if (options.title) {\n this.titleSubject.next(this.snapshot.title);\n }\n if (options.url) {\n this.urlSubject.next(this.snapshot.url);\n }\n }\n\n public toString(): string {\n return 'ActivatedRouteStub';\n }\n}\n\n/**\n * Creates a new ActivatedRouteStub, by calling its constructor.\n */\nexport function stubRoute(options?: ActivatedRouteStubOptions): ActivatedRouteStub {\n return new ActivatedRouteStub(options);\n}\n","import { TestTextArea } from './test-textarea';\nimport { TestInput } from './test-input';\nimport { TestElement } from './test-element';\nimport { TestSelect } from './test-select';\nimport { TestHtmlElement } from './test-html-element';\n\nconst speculoosMatchers: jasmine.CustomMatcherFactories = {\n /**\n * Checks that the receiver is a TestElement wrapping a DOM element and as the given CSS class\n */\n toHaveClass(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n if (!el) {\n return { pass: false, message: `Expected to check class '${expected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestElement)) {\n return { pass: false, message: `Expected to check class '${expected}' on element, but element was not a TestElement` };\n }\n const actual = el.classes;\n const pass = actual.indexOf(expected) !== -1;\n const message =\n `Expected element to ${isNegative ? 'not ' : ''}have class '${expected}', ` +\n `but had ${actual.length ? \"'\" + actual.join(', ') + \"'\" : 'none'}`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestInput or a TestTextArea and has the given value\n */\n toHaveValue(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n if (!el) {\n return { pass: false, message: `Expected to check value '${expected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestInput) && !(el instanceof TestTextArea)) {\n return {\n pass: false,\n message: `Expected to check value '${expected}' on element, but element was neither a TestInput nor a TestTextArea`\n };\n }\n const actual = el.value;\n const pass = actual === expected;\n const message = `Expected element to ${isNegative ? 'not ' : ''}have value '${expected}', but had value '${actual}'`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestElement wrapping a DOM element and has the exact given textContent\n */\n toHaveText(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n if (!el) {\n return { pass: false, message: `Expected to check text '${expected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestElement)) {\n return { pass: false, message: `Expected to check text '${expected}' on element, but element was not a TestElement` };\n }\n const actual = el.textContent;\n const pass = actual === expected;\n const message = `Expected element to ${isNegative ? 'not ' : ''}have text '${expected}', but had '${actual}'`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestElement wrapping a DOM element and has the given textContent, after both have been trimmed.\n * So, An element such as\n * ```\n * <h1>\n * Some title\n * </h1>\n * ```\n * will pass the test\n * ```\n * expect(tester.title).toHaveTrimmedText('Some title')\n * ```\n */\n toHaveTrimmedText(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n const trimmedExpected = expected.trim();\n if (!el) {\n return { pass: false, message: `Expected to check trimmed text '${trimmedExpected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestElement)) {\n return {\n pass: false,\n message: `Expected to check trimmed text '${trimmedExpected}' on element, but element was not a TestElement`\n };\n }\n const actual = el.textContent?.trim();\n const pass = actual === trimmedExpected;\n const message = `Expected element to ${isNegative ? 'not ' : ''}have trimmed text '${trimmedExpected}', but had '${actual}'`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestElement wrapping a DOM element and contains the given textContent\n */\n toContainText(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n if (!el) {\n return { pass: false, message: `Expected to check text '${expected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestElement)) {\n return { pass: false, message: `Expected to check text '${expected}' on element, but element was not a TestElement` };\n }\n const actual = el.textContent;\n if (!actual) {\n return {\n pass: isNegative,\n message: `Expected element to ${isNegative ? 'not ' : ''}contain text '${expected}', but had no text`\n };\n }\n const pass = actual.indexOf(expected) !== -1;\n const message = `Expected element to ${isNegative ? 'not ' : ''}contain text '${expected}', but had text '${actual}'`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestElement wrapping a DOM element and contains the given textContent\n */\n toBeChecked(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown) => {\n if (!el) {\n return { pass: false, message: `Expected to check if element was checked, but element was falsy` };\n }\n if (!(el instanceof TestInput)) {\n return { pass: false, message: `Expected to check if element was checked, but element was not a TestInput` };\n }\n const pass = el.checked;\n const message = `Expected element to be ${isNegative ? 'not ' : ''}checked, but was${!isNegative ? ' not' : ''}`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown): jasmine.CustomMatcherResult {\n return assert(false, el);\n },\n negativeCompare(el: unknown): jasmine.CustomMatcherResult {\n return assert(true, el);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestSelect wrapping a DOM element and has the given selected index\n */\n toHaveSelectedIndex(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: number) => {\n if (!el) {\n return { pass: false, message: `Expected to check selected index ${expected} on element, but element was falsy` };\n }\n if (!(el instanceof TestSelect)) {\n return { pass: false, message: `Expected to check selected index ${expected} on element, but element was not a TestSelect` };\n }\n const actual = el.selectedIndex;\n const pass = actual === expected;\n const message = `Expected element to ${isNegative ? 'not ' : ''}have selected index ${expected}, but had ${actual}`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: number): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: number): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestSelect wrapping a DOM element with the selected option's value equal to the given value\n */\n toHaveSelectedValue(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n if (!el) {\n return { pass: false, message: `Expected to check selected value '${expected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestSelect)) {\n return { pass: false, message: `Expected to check selected value '${expected}' on element, but element was not a TestSelect` };\n }\n const actual = el.selectedValue;\n const pass = actual === expected;\n const message = `Expected element to ${isNegative ? 'not ' : ''}have selected value '${expected}', but had '${actual}'`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestSelect wrapping a DOM element with the selected option's label equal to the given label\n */\n toHaveSelectedLabel(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown, expected: string) => {\n if (!el) {\n return { pass: false, message: `Expected to check selected label '${expected}' on element, but element was falsy` };\n }\n if (!(el instanceof TestSelect)) {\n return { pass: false, message: `Expected to check selected label '${expected}' on element, but element was not a TestSelect` };\n }\n const actual = el.selectedLabel;\n const pass = actual === expected;\n const message = `Expected element to ${isNegative ? 'not ' : ''}have selected label '${expected}', but had '${actual}'`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(false, el, expected);\n },\n negativeCompare(el: unknown, expected: string): jasmine.CustomMatcherResult {\n return assert(true, el, expected);\n }\n };\n },\n\n /**\n * Checks that the receiver is a TestHtmlElement which is visible\n */\n toBeVisible(): jasmine.CustomMatcher {\n const assert = (isNegative: boolean, el: unknown) => {\n const expectedState = `${isNegative ? 'in' : ''}visible`;\n const inverseState = `${isNegative ? '' : 'in'}visible`;\n if (!el) {\n return { pass: false, message: `Expected to check if element was ${expectedState}, but element was falsy` };\n }\n if (!(el instanceof TestHtmlElement)) {\n return { pass: false, message: `Expected to check if element was ${expectedState}, but element was not a TestHtmlElement` };\n }\n const pass = el.visible;\n const message = `Expected element to be ${expectedState}, but was ${inverseState}`;\n return { pass: isNegative ? !pass : pass, message };\n };\n return {\n compare(el: unknown): jasmine.CustomMatcherResult {\n return assert(false, el);\n },\n negativeCompare(el: unknown): jasmine.CustomMatcherResult {\n return assert(true, el);\n }\n };\n }\n};\n\nexport { speculoosMatchers };\n","import { Type } from '@angular/core';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction collectMethodNames(proto: unknown): Array<string> {\n if (!proto || proto === Object.prototype) {\n return [];\n }\n const methodNames: Array<string> = [];\n for (const key of Object.getOwnPropertyNames(proto)) {\n const descriptor = Object.getOwnPropertyDescriptor(proto, key);\n if (descriptor && typeof descriptor.value === 'function' && key !== 'constructor') {\n methodNames.push(key);\n }\n }\n return [...methodNames, ...collectMethodNames(Object.getPrototypeOf(proto))];\n}\n\n/**\n * Creates a spy object for a class where all the methods of the class (and of its superclasses) are spies.\n * I.e., for a class `UserService` with methods `get()`, `create()`, `update()` and `delete()`, calling\n * `createMock(UserService)` is equivalent to calling\n * `jasmine.createSpyObj<UserService>('UserService', ['get', 'create', 'update', 'delete'])`.\n * @param type the type to mock (usually a service class)\n */\nexport function createMock<T>(type: Type<T>): jasmine.SpyObj<T> {\n return jasmine.createSpyObj<T>(type.name, collectMethodNames(type.prototype) as unknown as jasmine.SpyObjMethodNames<T>);\n}\n","/* eslint-disable */\n/*\n * Public API Surface of ngx-speculoos\n */\n/// <reference path=\"./jasmine-matchers.ts\" />\n\nexport * from './lib/component-tester';\nexport * from './lib/routing-tester';\nexport * from './lib/test-element';\nexport * from './lib/test-html-element';\nexport * from './lib/test-input';\nexport * from './lib/test-button';\nexport * from './lib/test-select';\nexport * from './lib/test-textarea';\nexport * from './lib/route';\nexport * from './lib/matchers';\nexport * from './lib/mock';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
@@ -331,4 +331,8 @@ export declare class ComponentTester<C> {
331
331
  * Triggers a change detection using the wrapped fixture
332
332
  */
333
333
  detectChanges(checkNoChanges?: boolean): void;
334
+ /**
335
+ * Delegates to the wrapped fixture whenStable and then detect changes
336
+ */
337
+ stable(): Promise<void>;
334
338
  }
@@ -0,0 +1,30 @@
1
+ import { ComponentTester } from './component-tester';
2
+ import { RouterTestingHarness } from '@angular/router/testing';
3
+ import { UrlTree } from '@angular/router';
4
+ /**
5
+ * A thin wrapper around Angular RouterTestingHarness which helps testing routed components.
6
+ * It allows, based on a configured testing module where the router is provided, to initially navigate
7
+ * to a given route, then test the routed component. It's then possible to either navigate again with
8
+ * the wrapped harness, or to use the component to trigger navigation, and test that the URL has changed
9
+ * for example.
10
+ */
11
+ export declare class RoutingTester extends ComponentTester<unknown> {
12
+ readonly harness: RouterTestingHarness;
13
+ constructor(harness: RouterTestingHarness);
14
+ /**
15
+ * Creates a RouterTestngHarness and uses it to navigate to the given URL
16
+ * @param url the URL to initially navigate to.
17
+ * @return a promise which resolves to a RoutingTester which wraps the harness
18
+ * and its fixture.
19
+ */
20
+ static forUrl(url: string): Promise<RoutingTester>;
21
+ /**
22
+ * Gets the current URL of the Router service as a string
23
+ */
24
+ get url(): string;
25
+ /**
26
+ * Gets the current URL of the Router service as an UrlTree, to be able to test its
27
+ * elements (query params, etc.)
28
+ */
29
+ get urlTree(): UrlTree;
30
+ }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "ngx-speculoos",
3
- "version": "10.0.0",
3
+ "version": "11.1.0",
4
4
  "description": "Helps writing Angular unit tests",
5
5
  "peerDependencies": {
6
- "@angular/core": "^16.0.0",
7
- "@angular/platform-browser": "^16.0.0",
8
- "@angular/router": "^16.0.0",
9
- "rxjs": "^7.5.0"
6
+ "@angular/core": "^17.0.0",
7
+ "@angular/platform-browser": "^17.0.0",
8
+ "@angular/router": "^17.0.0",
9
+ "rxjs": "^7.8.0"
10
10
  },
11
11
  "license": "MIT",
12
12
  "repository": {
@@ -25,7 +25,7 @@
25
25
  "save": "devDependencies"
26
26
  },
27
27
  "dependencies": {
28
- "tslib": "2.5.0"
28
+ "tslib": "2.6.2"
29
29
  },
30
30
  "module": "fesm2022/ngx-speculoos.mjs",
31
31
  "typings": "index.d.ts",
package/public_api.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /// <reference path="jasmine-matchers.d.ts" />
2
2
  export * from './lib/component-tester';
3
+ export * from './lib/routing-tester';
3
4
  export * from './lib/test-element';
4
5
  export * from './lib/test-html-element';
5
6
  export * from './lib/test-input';