testing.mjs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /**
  2. * @license Angular v16.0.4
  3. * (c) 2010-2022 Google LLC. https://angular.io/
  4. * License: MIT
  5. */
  6. import { Location } from '@angular/common';
  7. import { provideLocationMocks } from '@angular/common/testing';
  8. import * as i0 from '@angular/core';
  9. import { inject, Compiler, Injector, NgModule, Injectable, Component, ViewChild } from '@angular/core';
  10. import { UrlSerializer, ChildrenOutletContexts, ROUTES, UrlHandlingStrategy, ROUTER_CONFIGURATION, RouteReuseStrategy, TitleStrategy, Router, RouterModule, ɵROUTER_PROVIDERS, withPreloading, NoPreloading, RouterOutlet, ɵafterNextNavigation } from '@angular/router';
  11. import { TestBed } from '@angular/core/testing';
  12. function isUrlHandlingStrategy(opts) {
  13. // This property check is needed because UrlHandlingStrategy is an interface and doesn't exist at
  14. // runtime.
  15. return 'shouldProcessUrl' in opts;
  16. }
  17. function throwInvalidConfigError(parameter) {
  18. throw new Error(`Parameter ${parameter} does not match the one available in the injector. ` +
  19. '`setupTestingRouter` is meant to be used as a factory function with dependencies coming from DI.');
  20. }
  21. /**
  22. * Router setup factory function used for testing.
  23. *
  24. * @publicApi
  25. * @deprecated Use `provideRouter` or `RouterModule` instead.
  26. */
  27. function setupTestingRouter(urlSerializer, contexts, location, compiler, injector, routes, opts, urlHandlingStrategy, routeReuseStrategy, titleStrategy) {
  28. // Note: The checks below are to detect misconfigured providers and invalid uses of
  29. // `setupTestingRouter`. This function is not used internally (neither in router code or anywhere
  30. // in g3). It appears this function was exposed as publicApi by mistake and should not be used
  31. // externally either. However, if it is, the documented intent is to be used as a factory function
  32. // and parameter values should always match what's available in DI.
  33. if (urlSerializer !== inject(UrlSerializer)) {
  34. throwInvalidConfigError('urlSerializer');
  35. }
  36. if (contexts !== inject(ChildrenOutletContexts)) {
  37. throwInvalidConfigError('contexts');
  38. }
  39. if (location !== inject(Location)) {
  40. throwInvalidConfigError('location');
  41. }
  42. if (compiler !== inject(Compiler)) {
  43. throwInvalidConfigError('compiler');
  44. }
  45. if (injector !== inject(Injector)) {
  46. throwInvalidConfigError('injector');
  47. }
  48. if (routes !== inject(ROUTES)) {
  49. throwInvalidConfigError('routes');
  50. }
  51. if (opts) {
  52. // Handle deprecated argument ordering.
  53. if (isUrlHandlingStrategy(opts)) {
  54. if (opts !== inject(UrlHandlingStrategy)) {
  55. throwInvalidConfigError('opts (UrlHandlingStrategy)');
  56. }
  57. }
  58. else {
  59. if (opts !== inject(ROUTER_CONFIGURATION)) {
  60. throwInvalidConfigError('opts (ROUTER_CONFIGURATION)');
  61. }
  62. }
  63. }
  64. if (urlHandlingStrategy !== inject(UrlHandlingStrategy)) {
  65. throwInvalidConfigError('urlHandlingStrategy');
  66. }
  67. if (routeReuseStrategy !== inject(RouteReuseStrategy)) {
  68. throwInvalidConfigError('routeReuseStrategy');
  69. }
  70. if (titleStrategy !== inject(TitleStrategy)) {
  71. throwInvalidConfigError('titleStrategy');
  72. }
  73. return new Router();
  74. }
  75. /**
  76. * @description
  77. *
  78. * Sets up the router to be used for testing.
  79. *
  80. * The modules sets up the router to be used for testing.
  81. * It provides spy implementations of `Location` and `LocationStrategy`.
  82. *
  83. * @usageNotes
  84. * ### Example
  85. *
  86. * ```
  87. * beforeEach(() => {
  88. * TestBed.configureTestingModule({
  89. * imports: [
  90. * RouterModule.forRoot(
  91. * [{path: '', component: BlankCmp}, {path: 'simple', component: SimpleCmp}]
  92. * )
  93. * ]
  94. * });
  95. * });
  96. * ```
  97. *
  98. * @publicApi
  99. */
  100. class RouterTestingModule {
  101. static withRoutes(routes, config) {
  102. return {
  103. ngModule: RouterTestingModule,
  104. providers: [
  105. { provide: ROUTES, multi: true, useValue: routes },
  106. { provide: ROUTER_CONFIGURATION, useValue: config ? config : {} },
  107. ]
  108. };
  109. }
  110. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.4", ngImport: i0, type: RouterTestingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
  111. static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.4", ngImport: i0, type: RouterTestingModule, exports: [RouterModule] }); }
  112. static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.4", ngImport: i0, type: RouterTestingModule, providers: [
  113. ɵROUTER_PROVIDERS,
  114. provideLocationMocks(),
  115. withPreloading(NoPreloading).ɵproviders,
  116. { provide: ROUTES, multi: true, useValue: [] },
  117. ], imports: [RouterModule] }); }
  118. }
  119. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.4", ngImport: i0, type: RouterTestingModule, decorators: [{
  120. type: NgModule,
  121. args: [{
  122. exports: [RouterModule],
  123. providers: [
  124. ɵROUTER_PROVIDERS,
  125. provideLocationMocks(),
  126. withPreloading(NoPreloading).ɵproviders,
  127. { provide: ROUTES, multi: true, useValue: [] },
  128. ]
  129. }]
  130. }] });
  131. class RootFixtureService {
  132. createHarness() {
  133. if (this.harness) {
  134. throw new Error('Only one harness should be created per test.');
  135. }
  136. this.harness = new RouterTestingHarness(this.getRootFixture());
  137. return this.harness;
  138. }
  139. getRootFixture() {
  140. if (this.fixture !== undefined) {
  141. return this.fixture;
  142. }
  143. this.fixture = TestBed.createComponent(RootCmp);
  144. this.fixture.detectChanges();
  145. return this.fixture;
  146. }
  147. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.4", ngImport: i0, type: RootFixtureService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
  148. static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.4", ngImport: i0, type: RootFixtureService, providedIn: 'root' }); }
  149. }
  150. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.4", ngImport: i0, type: RootFixtureService, decorators: [{
  151. type: Injectable,
  152. args: [{ providedIn: 'root' }]
  153. }] });
  154. class RootCmp {
  155. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.4", ngImport: i0, type: RootCmp, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  156. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.4", type: RootCmp, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "outlet", first: true, predicate: RouterOutlet, descendants: true }], ngImport: i0, template: '<router-outlet></router-outlet>', isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] }); }
  157. }
  158. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.4", ngImport: i0, type: RootCmp, decorators: [{
  159. type: Component,
  160. args: [{
  161. standalone: true,
  162. template: '<router-outlet></router-outlet>',
  163. imports: [RouterOutlet],
  164. }]
  165. }], propDecorators: { outlet: [{
  166. type: ViewChild,
  167. args: [RouterOutlet]
  168. }] } });
  169. /**
  170. * A testing harness for the `Router` to reduce the boilerplate needed to test routes and routed
  171. * components.
  172. *
  173. * @publicApi
  174. */
  175. class RouterTestingHarness {
  176. /**
  177. * Creates a `RouterTestingHarness` instance.
  178. *
  179. * The `RouterTestingHarness` also creates its own root component with a `RouterOutlet` for the
  180. * purposes of rendering route components.
  181. *
  182. * Throws an error if an instance has already been created.
  183. * Use of this harness also requires `destroyAfterEach: true` in the `ModuleTeardownOptions`
  184. *
  185. * @param initialUrl The target of navigation to trigger before returning the harness.
  186. */
  187. static async create(initialUrl) {
  188. const harness = TestBed.inject(RootFixtureService).createHarness();
  189. if (initialUrl !== undefined) {
  190. await harness.navigateByUrl(initialUrl);
  191. }
  192. return harness;
  193. }
  194. /** @internal */
  195. constructor(fixture) {
  196. this.fixture = fixture;
  197. }
  198. /** Instructs the root fixture to run change detection. */
  199. detectChanges() {
  200. this.fixture.detectChanges();
  201. }
  202. /** The `DebugElement` of the `RouterOutlet` component. `null` if the outlet is not activated. */
  203. get routeDebugElement() {
  204. const outlet = this.fixture.componentInstance.outlet;
  205. if (!outlet || !outlet.isActivated) {
  206. return null;
  207. }
  208. return this.fixture.debugElement.query(v => v.componentInstance === outlet.component);
  209. }
  210. /** The native element of the `RouterOutlet` component. `null` if the outlet is not activated. */
  211. get routeNativeElement() {
  212. return this.routeDebugElement?.nativeElement ?? null;
  213. }
  214. async navigateByUrl(url, requiredRoutedComponentType) {
  215. const router = TestBed.inject(Router);
  216. let resolveFn;
  217. const redirectTrackingPromise = new Promise(resolve => {
  218. resolveFn = resolve;
  219. });
  220. ɵafterNextNavigation(TestBed.inject(Router), resolveFn);
  221. await router.navigateByUrl(url);
  222. await redirectTrackingPromise;
  223. this.fixture.detectChanges();
  224. const outlet = this.fixture.componentInstance.outlet;
  225. // The outlet might not be activated if the user is testing a navigation for a guard that
  226. // rejects
  227. if (outlet && outlet.isActivated && outlet.activatedRoute.component) {
  228. const activatedComponent = outlet.component;
  229. if (requiredRoutedComponentType !== undefined &&
  230. !(activatedComponent instanceof requiredRoutedComponentType)) {
  231. throw new Error(`Unexpected routed component type. Expected ${requiredRoutedComponentType.name} but got ${activatedComponent.constructor.name}`);
  232. }
  233. return activatedComponent;
  234. }
  235. else {
  236. return null;
  237. }
  238. }
  239. }
  240. /**
  241. * @module
  242. * @description
  243. * Entry point for all public APIs of the router/testing package.
  244. */
  245. /**
  246. * @module
  247. * @description
  248. * Entry point for all public APIs of this package.
  249. */
  250. // This file only reexports content of the `src` folder. Keep it that way.
  251. // This file is not used to build this module. It is only used during editing
  252. /**
  253. * Generated bundle index. Do not edit.
  254. */
  255. export { RouterTestingHarness, RouterTestingModule, setupTestingRouter };
  256. //# sourceMappingURL=testing.mjs.map