testing.mjs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /**
  2. * @license Angular v19.2.4
  3. * (c) 2010-2025 Google LLC. https://angular.io/
  4. * License: MIT
  5. */
  6. import * as i0 from '@angular/core';
  7. import { NgModule, signal, Injectable, ViewChild, Component } from '@angular/core';
  8. import { TestBed } from '@angular/core/testing';
  9. import { ROUTES, ROUTER_CONFIGURATION, RouterModule, ɵROUTER_PROVIDERS as _ROUTER_PROVIDERS, withPreloading, NoPreloading, Router, ɵafterNextNavigation as _afterNextNavigation, RouterOutlet } from '@angular/router';
  10. import { provideLocationMocks } from '@angular/common/testing';
  11. /**
  12. * @description
  13. *
  14. * Sets up the router to be used for testing.
  15. *
  16. * The modules sets up the router to be used for testing.
  17. * It provides spy implementations of `Location` and `LocationStrategy`.
  18. *
  19. * @usageNotes
  20. * ### Example
  21. *
  22. * ```ts
  23. * beforeEach(() => {
  24. * TestBed.configureTestingModule({
  25. * imports: [
  26. * RouterModule.forRoot(
  27. * [{path: '', component: BlankCmp}, {path: 'simple', component: SimpleCmp}]
  28. * )
  29. * ]
  30. * });
  31. * });
  32. * ```
  33. *
  34. * @publicApi
  35. * @deprecated Use `provideRouter` or `RouterModule`/`RouterModule.forRoot` instead.
  36. * This module was previously used to provide a helpful collection of test fakes,
  37. * most notably those for `Location` and `LocationStrategy`. These are generally not
  38. * required anymore, as `MockPlatformLocation` is provided in `TestBed` by default.
  39. * However, you can use them directly with `provideLocationMocks`.
  40. */
  41. class RouterTestingModule {
  42. static withRoutes(routes, config) {
  43. return {
  44. ngModule: RouterTestingModule,
  45. providers: [
  46. { provide: ROUTES, multi: true, useValue: routes },
  47. { provide: ROUTER_CONFIGURATION, useValue: config ? config : {} },
  48. ],
  49. };
  50. }
  51. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RouterTestingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
  52. static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.4", ngImport: i0, type: RouterTestingModule, exports: [RouterModule] });
  53. static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RouterTestingModule, providers: [
  54. _ROUTER_PROVIDERS,
  55. provideLocationMocks(),
  56. withPreloading(NoPreloading).ɵproviders,
  57. { provide: ROUTES, multi: true, useValue: [] },
  58. ], imports: [RouterModule] });
  59. }
  60. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RouterTestingModule, decorators: [{
  61. type: NgModule,
  62. args: [{
  63. exports: [RouterModule],
  64. providers: [
  65. _ROUTER_PROVIDERS,
  66. provideLocationMocks(),
  67. withPreloading(NoPreloading).ɵproviders,
  68. { provide: ROUTES, multi: true, useValue: [] },
  69. ],
  70. }]
  71. }] });
  72. class RootFixtureService {
  73. fixture;
  74. harness;
  75. createHarness() {
  76. if (this.harness) {
  77. throw new Error('Only one harness should be created per test.');
  78. }
  79. this.harness = new RouterTestingHarness(this.getRootFixture());
  80. return this.harness;
  81. }
  82. getRootFixture() {
  83. if (this.fixture !== undefined) {
  84. return this.fixture;
  85. }
  86. this.fixture = TestBed.createComponent(RootCmp);
  87. this.fixture.detectChanges();
  88. return this.fixture;
  89. }
  90. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RootFixtureService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
  91. static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RootFixtureService, providedIn: 'root' });
  92. }
  93. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RootFixtureService, decorators: [{
  94. type: Injectable,
  95. args: [{ providedIn: 'root' }]
  96. }] });
  97. class RootCmp {
  98. outlet;
  99. routerOutletData = signal(undefined);
  100. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RootCmp, deps: [], target: i0.ɵɵFactoryTarget.Component });
  101. static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: RootCmp, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "outlet", first: true, predicate: RouterOutlet, descendants: true }], ngImport: i0, template: '<router-outlet [routerOutletData]="routerOutletData()"></router-outlet>', isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
  102. }
  103. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RootCmp, decorators: [{
  104. type: Component,
  105. args: [{
  106. template: '<router-outlet [routerOutletData]="routerOutletData()"></router-outlet>',
  107. imports: [RouterOutlet],
  108. }]
  109. }], propDecorators: { outlet: [{
  110. type: ViewChild,
  111. args: [RouterOutlet]
  112. }] } });
  113. /**
  114. * A testing harness for the `Router` to reduce the boilerplate needed to test routes and routed
  115. * components.
  116. *
  117. * @publicApi
  118. */
  119. class RouterTestingHarness {
  120. /**
  121. * Creates a `RouterTestingHarness` instance.
  122. *
  123. * The `RouterTestingHarness` also creates its own root component with a `RouterOutlet` for the
  124. * purposes of rendering route components.
  125. *
  126. * Throws an error if an instance has already been created.
  127. * Use of this harness also requires `destroyAfterEach: true` in the `ModuleTeardownOptions`
  128. *
  129. * @param initialUrl The target of navigation to trigger before returning the harness.
  130. */
  131. static async create(initialUrl) {
  132. const harness = TestBed.inject(RootFixtureService).createHarness();
  133. if (initialUrl !== undefined) {
  134. await harness.navigateByUrl(initialUrl);
  135. }
  136. return harness;
  137. }
  138. /**
  139. * Fixture of the root component of the RouterTestingHarness
  140. */
  141. fixture;
  142. /** @internal */
  143. constructor(fixture) {
  144. this.fixture = fixture;
  145. }
  146. /** Instructs the root fixture to run change detection. */
  147. detectChanges() {
  148. this.fixture.detectChanges();
  149. }
  150. /** The `DebugElement` of the `RouterOutlet` component. `null` if the outlet is not activated. */
  151. get routeDebugElement() {
  152. const outlet = this.fixture.componentInstance.outlet;
  153. if (!outlet || !outlet.isActivated) {
  154. return null;
  155. }
  156. return this.fixture.debugElement.query((v) => v.componentInstance === outlet.component);
  157. }
  158. /** The native element of the `RouterOutlet` component. `null` if the outlet is not activated. */
  159. get routeNativeElement() {
  160. return this.routeDebugElement?.nativeElement ?? null;
  161. }
  162. async navigateByUrl(url, requiredRoutedComponentType) {
  163. const router = TestBed.inject(Router);
  164. let resolveFn;
  165. const redirectTrackingPromise = new Promise((resolve) => {
  166. resolveFn = resolve;
  167. });
  168. _afterNextNavigation(TestBed.inject(Router), resolveFn);
  169. await router.navigateByUrl(url);
  170. await redirectTrackingPromise;
  171. this.fixture.detectChanges();
  172. const outlet = this.fixture.componentInstance.outlet;
  173. // The outlet might not be activated if the user is testing a navigation for a guard that
  174. // rejects
  175. if (outlet && outlet.isActivated && outlet.activatedRoute.component) {
  176. const activatedComponent = outlet.component;
  177. if (requiredRoutedComponentType !== undefined &&
  178. !(activatedComponent instanceof requiredRoutedComponentType)) {
  179. throw new Error(`Unexpected routed component type. Expected ${requiredRoutedComponentType.name} but got ${activatedComponent.constructor.name}`);
  180. }
  181. return activatedComponent;
  182. }
  183. else {
  184. if (requiredRoutedComponentType !== undefined) {
  185. throw new Error(`Unexpected routed component type. Expected ${requiredRoutedComponentType.name} but the navigation did not activate any component.`);
  186. }
  187. return null;
  188. }
  189. }
  190. }
  191. export { RouterTestingHarness, RouterTestingModule };
  192. //# sourceMappingURL=testing.mjs.map