{"version":3,"file":"testing.mjs","sources":["../../../../../../packages/router/testing/src/router_testing_module.ts","../../../../../../packages/router/testing/src/router_testing_harness.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {provideLocationMocks} from '@angular/common/testing';\nimport {ModuleWithProviders, NgModule} from '@angular/core';\nimport {\n  ExtraOptions,\n  NoPreloading,\n  ROUTER_CONFIGURATION,\n  RouterModule,\n  ROUTES,\n  Routes,\n  withPreloading,\n  ɵROUTER_PROVIDERS as ROUTER_PROVIDERS,\n} from '../../index';\n\n/**\n * @description\n *\n * Sets up the router to be used for testing.\n *\n * The modules sets up the router to be used for testing.\n * It provides spy implementations of `Location` and `LocationStrategy`.\n *\n * @usageNotes\n * ### Example\n *\n * ```ts\n * beforeEach(() => {\n *   TestBed.configureTestingModule({\n *     imports: [\n *       RouterModule.forRoot(\n *         [{path: '', component: BlankCmp}, {path: 'simple', component: SimpleCmp}]\n *       )\n *     ]\n *   });\n * });\n * ```\n *\n * @publicApi\n * @deprecated Use `provideRouter` or `RouterModule`/`RouterModule.forRoot` instead.\n * This module was previously used to provide a helpful collection of test fakes,\n * most notably those for `Location` and `LocationStrategy`.  These are generally not\n * required anymore, as `MockPlatformLocation` is provided in `TestBed` by default.\n * However, you can use them directly with `provideLocationMocks`.\n */\n@NgModule({\n  exports: [RouterModule],\n  providers: [\n    ROUTER_PROVIDERS,\n    provideLocationMocks(),\n    withPreloading(NoPreloading).ɵproviders,\n    {provide: ROUTES, multi: true, useValue: []},\n  ],\n})\nexport class RouterTestingModule {\n  static withRoutes(\n    routes: Routes,\n    config?: ExtraOptions,\n  ): ModuleWithProviders<RouterTestingModule> {\n    return {\n      ngModule: RouterTestingModule,\n      providers: [\n        {provide: ROUTES, multi: true, useValue: routes},\n        {provide: ROUTER_CONFIGURATION, useValue: config ? config : {}},\n      ],\n    };\n  }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n  Component,\n  DebugElement,\n  Injectable,\n  Type,\n  ViewChild,\n  WritableSignal,\n  signal,\n} from '@angular/core';\nimport {ComponentFixture, TestBed} from '@angular/core/testing';\nimport {Router, RouterOutlet, ɵafterNextNavigation as afterNextNavigation} from '../../index';\n\n@Injectable({providedIn: 'root'})\nexport class RootFixtureService {\n  private fixture?: ComponentFixture<RootCmp>;\n  private harness?: RouterTestingHarness;\n\n  createHarness(): RouterTestingHarness {\n    if (this.harness) {\n      throw new Error('Only one harness should be created per test.');\n    }\n    this.harness = new RouterTestingHarness(this.getRootFixture());\n    return this.harness;\n  }\n\n  private getRootFixture(): ComponentFixture<RootCmp> {\n    if (this.fixture !== undefined) {\n      return this.fixture;\n    }\n    this.fixture = TestBed.createComponent(RootCmp);\n    this.fixture.detectChanges();\n    return this.fixture;\n  }\n}\n\n@Component({\n  template: '<router-outlet [routerOutletData]=\"routerOutletData()\"></router-outlet>',\n  imports: [RouterOutlet],\n})\nexport class RootCmp {\n  @ViewChild(RouterOutlet) outlet?: RouterOutlet;\n  readonly routerOutletData = signal<unknown>(undefined);\n}\n\n/**\n * A testing harness for the `Router` to reduce the boilerplate needed to test routes and routed\n * components.\n *\n * @publicApi\n */\nexport class RouterTestingHarness {\n  /**\n   * Creates a `RouterTestingHarness` instance.\n   *\n   * The `RouterTestingHarness` also creates its own root component with a `RouterOutlet` for the\n   * purposes of rendering route components.\n   *\n   * Throws an error if an instance has already been created.\n   * Use of this harness also requires `destroyAfterEach: true` in the `ModuleTeardownOptions`\n   *\n   * @param initialUrl The target of navigation to trigger before returning the harness.\n   */\n  static async create(initialUrl?: string): Promise<RouterTestingHarness> {\n    const harness = TestBed.inject(RootFixtureService).createHarness();\n    if (initialUrl !== undefined) {\n      await harness.navigateByUrl(initialUrl);\n    }\n    return harness;\n  }\n\n  /**\n   * Fixture of the root component of the RouterTestingHarness\n   */\n  public readonly fixture: ComponentFixture<{routerOutletData: WritableSignal<unknown>}>;\n\n  /** @internal */\n  constructor(fixture: ComponentFixture<{routerOutletData: WritableSignal<unknown>}>) {\n    this.fixture = fixture;\n  }\n\n  /** Instructs the root fixture to run change detection. */\n  detectChanges(): void {\n    this.fixture.detectChanges();\n  }\n  /** The `DebugElement` of the `RouterOutlet` component. `null` if the outlet is not activated. */\n  get routeDebugElement(): DebugElement | null {\n    const outlet = (this.fixture.componentInstance as RootCmp).outlet;\n    if (!outlet || !outlet.isActivated) {\n      return null;\n    }\n    return this.fixture.debugElement.query((v) => v.componentInstance === outlet.component);\n  }\n  /** The native element of the `RouterOutlet` component. `null` if the outlet is not activated. */\n  get routeNativeElement(): HTMLElement | null {\n    return this.routeDebugElement?.nativeElement ?? null;\n  }\n\n  /**\n   * Triggers a `Router` navigation and waits for it to complete.\n   *\n   * The root component with a `RouterOutlet` created for the harness is used to render `Route`\n   * components. The root component is reused within the same test in subsequent calls to\n   * `navigateForTest`.\n   *\n   * When testing `Routes` with a guards that reject the navigation, the `RouterOutlet` might not be\n   * activated and the `activatedComponent` may be `null`.\n   *\n   * {@example router/testing/test/router_testing_harness_examples.spec.ts region='Guard'}\n   *\n   * @param url The target of the navigation. Passed to `Router.navigateByUrl`.\n   * @returns The activated component instance of the `RouterOutlet` after navigation completes\n   *     (`null` if the outlet does not get activated).\n   */\n  async navigateByUrl(url: string): Promise<null | {}>;\n  /**\n   * Triggers a router navigation and waits for it to complete.\n   *\n   * The root component with a `RouterOutlet` created for the harness is used to render `Route`\n   * components.\n   *\n   * {@example router/testing/test/router_testing_harness_examples.spec.ts region='RoutedComponent'}\n   *\n   * The root component is reused within the same test in subsequent calls to `navigateByUrl`.\n   *\n   * This function also makes it easier to test components that depend on `ActivatedRoute` data.\n   *\n   * {@example router/testing/test/router_testing_harness_examples.spec.ts region='ActivatedRoute'}\n   *\n   * @param url The target of the navigation. Passed to `Router.navigateByUrl`.\n   * @param requiredRoutedComponentType After navigation completes, the required type for the\n   *     activated component of the `RouterOutlet`. If the outlet is not activated or a different\n   *     component is activated, this function will throw an error.\n   * @returns The activated component instance of the `RouterOutlet` after navigation completes.\n   */\n  async navigateByUrl<T>(url: string, requiredRoutedComponentType: Type<T>): Promise<T>;\n  async navigateByUrl<T>(url: string, requiredRoutedComponentType?: Type<T>): Promise<T | null> {\n    const router = TestBed.inject(Router);\n    let resolveFn!: () => void;\n    const redirectTrackingPromise = new Promise<void>((resolve) => {\n      resolveFn = resolve;\n    });\n    afterNextNavigation(TestBed.inject(Router), resolveFn);\n    await router.navigateByUrl(url);\n    await redirectTrackingPromise;\n    this.fixture.detectChanges();\n    const outlet = (this.fixture.componentInstance as RootCmp).outlet;\n    // The outlet might not be activated if the user is testing a navigation for a guard that\n    // rejects\n    if (outlet && outlet.isActivated && outlet.activatedRoute.component) {\n      const activatedComponent = outlet.component;\n      if (\n        requiredRoutedComponentType !== undefined &&\n        !(activatedComponent instanceof requiredRoutedComponentType)\n      ) {\n        throw new Error(\n          `Unexpected routed component type. Expected ${requiredRoutedComponentType.name} but got ${activatedComponent.constructor.name}`,\n        );\n      }\n      return activatedComponent as T;\n    } else {\n      if (requiredRoutedComponentType !== undefined) {\n        throw new Error(\n          `Unexpected routed component type. Expected ${requiredRoutedComponentType.name} but the navigation did not activate any component.`,\n        );\n      }\n      return null;\n    }\n  }\n}\n"],"names":[],"mappings":"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"}