@angular/core
Version:
Angular - the core framework
1 lines • 236 kB
Source Map (JSON)
{"version":3,"file":"testing.mjs","sources":["../../../../../../packages/core/testing/src/async.ts","../../../../../../packages/core/testing/src/defer.ts","../../../../../../packages/core/testing/src/test_bed_common.ts","../../../../../../packages/core/testing/src/application_error_handler.ts","../../../../../../packages/core/testing/src/component_fixture.ts","../../../../../../packages/core/testing/src/fake_async.ts","../../../../../../packages/core/testing/src/metadata_overrider.ts","../../../../../../packages/core/testing/src/resolvers.ts","../../../../../../packages/core/testing/src/test_bed_compiler.ts","../../../../../../packages/core/testing/src/test_bed.ts","../../../../../../packages/core/testing/src/test_hooks.ts","../../../../../../packages/core/primitives/dom-navigation/testing/fake_navigation.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/**\n * Wraps a test function in an asynchronous test zone. The test will automatically\n * complete when all asynchronous calls within this zone are done. Can be used\n * to wrap an {@link inject} call.\n *\n * Example:\n *\n * ```ts\n * it('...', waitForAsync(inject([AClass], (object) => {\n * object.doSomething.then(() => {\n * expect(...);\n * })\n * })));\n * ```\n *\n * @publicApi\n */\nexport function waitForAsync(fn: Function): (done: any) => any {\n const _Zone: any = typeof Zone !== 'undefined' ? Zone : null;\n if (!_Zone) {\n return function () {\n return Promise.reject(\n 'Zone is needed for the waitForAsync() test helper but could not be found. ' +\n 'Please make sure that your environment includes zone.js',\n );\n };\n }\n const asyncTest = _Zone && _Zone[_Zone.__symbol__('asyncTest')];\n if (typeof asyncTest === 'function') {\n return asyncTest(fn);\n }\n return function () {\n return Promise.reject(\n 'zone-testing.js is needed for the async() test helper but could not be found. ' +\n 'Please make sure that your environment includes zone.js/testing',\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 ɵCONTAINER_HEADER_OFFSET as CONTAINER_HEADER_OFFSET,\n ɵDeferBlockDetails as DeferBlockDetails,\n ɵDeferBlockState as DeferBlockState,\n ɵgetDeferBlocks as getDeferBlocks,\n ɵrenderDeferBlockState as renderDeferBlockState,\n ɵtriggerResourceLoading as triggerResourceLoading,\n} from '@angular/core';\n\nimport type {ComponentFixture} from './component_fixture';\n\n/**\n * Represents an individual defer block for testing purposes.\n *\n * @publicApi\n */\nexport class DeferBlockFixture {\n /** @nodoc */\n constructor(\n private block: DeferBlockDetails,\n private componentFixture: ComponentFixture<unknown>,\n ) {}\n\n /**\n * Renders the specified state of the defer fixture.\n * @param state the defer state to render\n */\n async render(state: DeferBlockState): Promise<void> {\n if (!hasStateTemplate(state, this.block)) {\n const stateAsString = getDeferBlockStateNameFromEnum(state);\n throw new Error(\n `Tried to render this defer block in the \\`${stateAsString}\\` state, ` +\n `but there was no @${stateAsString.toLowerCase()} block defined in a template.`,\n );\n }\n if (state === DeferBlockState.Complete) {\n await triggerResourceLoading(this.block.tDetails, this.block.lView, this.block.tNode);\n }\n // If the `render` method is used explicitly - skip timer-based scheduling for\n // `@placeholder` and `@loading` blocks and render them immediately.\n const skipTimerScheduling = true;\n renderDeferBlockState(state, this.block.tNode, this.block.lContainer, skipTimerScheduling);\n this.componentFixture.detectChanges();\n }\n\n /**\n * Retrieves all nested child defer block fixtures\n * in a given defer block.\n */\n getDeferBlocks(): Promise<DeferBlockFixture[]> {\n const deferBlocks: DeferBlockDetails[] = [];\n // An LContainer that represents a defer block has at most 1 view, which is\n // located right after an LContainer header. Get a hold of that view and inspect\n // it for nested defer blocks.\n const deferBlockFixtures = [];\n if (this.block.lContainer.length >= CONTAINER_HEADER_OFFSET) {\n const lView = this.block.lContainer[CONTAINER_HEADER_OFFSET];\n getDeferBlocks(lView, deferBlocks);\n for (const block of deferBlocks) {\n deferBlockFixtures.push(new DeferBlockFixture(block, this.componentFixture));\n }\n }\n return Promise.resolve(deferBlockFixtures);\n }\n}\n\nfunction hasStateTemplate(state: DeferBlockState, block: DeferBlockDetails) {\n switch (state) {\n case DeferBlockState.Placeholder:\n return block.tDetails.placeholderTmplIndex !== null;\n case DeferBlockState.Loading:\n return block.tDetails.loadingTmplIndex !== null;\n case DeferBlockState.Error:\n return block.tDetails.errorTmplIndex !== null;\n case DeferBlockState.Complete:\n return true;\n default:\n return false;\n }\n}\n\nfunction getDeferBlockStateNameFromEnum(state: DeferBlockState) {\n switch (state) {\n case DeferBlockState.Placeholder:\n return 'Placeholder';\n case DeferBlockState.Loading:\n return 'Loading';\n case DeferBlockState.Error:\n return 'Error';\n default:\n return 'Main';\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 InjectionToken,\n SchemaMetadata,\n ɵDeferBlockBehavior as DeferBlockBehavior,\n} from '@angular/core';\n\n/** Whether test modules should be torn down by default. */\nexport const TEARDOWN_TESTING_MODULE_ON_DESTROY_DEFAULT = true;\n\n/** Whether unknown elements in templates should throw by default. */\nexport const THROW_ON_UNKNOWN_ELEMENTS_DEFAULT = false;\n\n/** Whether unknown properties in templates should throw by default. */\nexport const THROW_ON_UNKNOWN_PROPERTIES_DEFAULT = false;\n\n/** Whether defer blocks should use manual triggering or play through normally. */\nexport const DEFER_BLOCK_DEFAULT_BEHAVIOR = DeferBlockBehavior.Playthrough;\n\n/**\n * An abstract class for inserting the root test component element in a platform independent way.\n *\n * @publicApi\n */\nexport class TestComponentRenderer {\n insertRootElement(rootElementId: string) {}\n removeAllRootElements?() {}\n}\n\n/**\n * @publicApi\n */\nexport const ComponentFixtureAutoDetect = new InjectionToken<boolean>('ComponentFixtureAutoDetect');\n\n/**\n * @publicApi\n */\nexport const ComponentFixtureNoNgZone = new InjectionToken<boolean>('ComponentFixtureNoNgZone');\n\n/**\n * @publicApi\n */\nexport interface TestModuleMetadata {\n providers?: any[];\n declarations?: any[];\n imports?: any[];\n schemas?: Array<SchemaMetadata | any[]>;\n teardown?: ModuleTeardownOptions;\n /**\n * Whether NG0304 runtime errors should be thrown when unknown elements are present in component's\n * template. Defaults to `false`, where the error is simply logged. If set to `true`, the error is\n * thrown.\n * @see [NG8001](/errors/NG8001) for the description of the problem and how to fix it\n */\n errorOnUnknownElements?: boolean;\n /**\n * Whether errors should be thrown when unknown properties are present in component's template.\n * Defaults to `false`, where the error is simply logged.\n * If set to `true`, the error is thrown.\n * @see [NG8002](/errors/NG8002) for the description of the error and how to fix it\n */\n errorOnUnknownProperties?: boolean;\n\n /**\n * Whether errors that happen during application change detection should be rethrown.\n *\n * When `true`, errors that are caught during application change detection will\n * be reported to the `ErrorHandler` and rethrown to prevent them from going\n * unnoticed in tests.\n *\n * When `false`, errors are only forwarded to the `ErrorHandler`, which by default\n * simply logs them to the console.\n *\n * Defaults to `true`.\n */\n rethrowApplicationErrors?: boolean;\n\n /**\n * Whether defer blocks should behave with manual triggering or play through normally.\n * Defaults to `manual`.\n */\n deferBlockBehavior?: DeferBlockBehavior;\n}\n\n/**\n * @publicApi\n */\nexport interface TestEnvironmentOptions {\n /**\n * Configures the test module teardown behavior in `TestBed`.\n */\n teardown?: ModuleTeardownOptions;\n /**\n * Whether errors should be thrown when unknown elements are present in component's template.\n * Defaults to `false`, where the error is simply logged.\n * If set to `true`, the error is thrown.\n * @see [NG8001](/errors/NG8001) for the description of the error and how to fix it\n */\n errorOnUnknownElements?: boolean;\n /**\n * Whether errors should be thrown when unknown properties are present in component's template.\n * Defaults to `false`, where the error is simply logged.\n * If set to `true`, the error is thrown.\n * @see [NG8002](/errors/NG8002) for the description of the error and how to fix it\n */\n errorOnUnknownProperties?: boolean;\n}\n\n/**\n * Configures the test module teardown behavior in `TestBed`.\n * @publicApi\n */\nexport interface ModuleTeardownOptions {\n /** Whether the test module should be destroyed after every test. Defaults to `true`. */\n destroyAfterEach: boolean;\n\n /** Whether errors during test module destruction should be re-thrown. Defaults to `true`. */\n rethrowErrors?: boolean;\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 {ErrorHandler, inject, NgZone, Injectable} from '@angular/core';\n\nexport const RETHROW_APPLICATION_ERRORS_DEFAULT = true;\n\n@Injectable()\nexport class TestBedApplicationErrorHandler {\n private readonly zone = inject(NgZone);\n private readonly userErrorHandler = inject(ErrorHandler);\n readonly whenStableRejectFunctions: Set<(e: unknown) => void> = new Set();\n\n handleError(e: unknown) {\n try {\n this.zone.runOutsideAngular(() => this.userErrorHandler.handleError(e));\n } catch (userError: unknown) {\n e = userError;\n }\n\n // Instead of throwing the error when there are outstanding `fixture.whenStable` promises,\n // reject those promises with the error. This allows developers to write\n // expectAsync(fix.whenStable()).toBeRejected();\n if (this.whenStableRejectFunctions.size > 0) {\n for (const fn of this.whenStableRejectFunctions.values()) {\n fn(e);\n }\n this.whenStableRejectFunctions.clear();\n } else {\n throw e;\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 ApplicationRef,\n ChangeDetectorRef,\n ComponentRef,\n ɵChangeDetectionScheduler,\n ɵNotificationSource,\n DebugElement,\n ElementRef,\n getDebugNode,\n inject,\n NgZone,\n RendererFactory2,\n ViewRef,\n ɵDeferBlockDetails as DeferBlockDetails,\n ɵgetDeferBlocks as getDeferBlocks,\n ɵNoopNgZone as NoopNgZone,\n ɵZONELESS_ENABLED as ZONELESS_ENABLED,\n ɵPendingTasksInternal as PendingTasks,\n ɵEffectScheduler as EffectScheduler,\n ɵMicrotaskEffectScheduler as MicrotaskEffectScheduler,\n} from '@angular/core';\nimport {Subscription} from 'rxjs';\n\nimport {DeferBlockFixture} from './defer';\nimport {ComponentFixtureAutoDetect, ComponentFixtureNoNgZone} from './test_bed_common';\nimport {TestBedApplicationErrorHandler} from './application_error_handler';\n\ninterface TestAppRef {\n externalTestViews: Set<ViewRef>;\n skipCheckNoChangesForExternalTestViews: Set<ViewRef>;\n}\n\n/**\n * Fixture for debugging and testing a component.\n *\n * @publicApi\n */\nexport class ComponentFixture<T> {\n /**\n * The DebugElement associated with the root element of this component.\n */\n debugElement: DebugElement;\n\n /**\n * The instance of the root component class.\n */\n componentInstance: T;\n\n /**\n * The native element at the root of the component.\n */\n nativeElement: any;\n\n /**\n * The ElementRef for the element at the root of the component.\n */\n elementRef: ElementRef;\n\n /**\n * The ChangeDetectorRef for the component\n */\n changeDetectorRef: ChangeDetectorRef;\n\n private _renderer: RendererFactory2 | null | undefined;\n private _isDestroyed: boolean = false;\n /** @internal */\n protected readonly _noZoneOptionIsSet = inject(ComponentFixtureNoNgZone, {optional: true});\n /** @internal */\n protected _ngZone: NgZone = this._noZoneOptionIsSet ? new NoopNgZone() : inject(NgZone);\n // Inject ApplicationRef to ensure NgZone stableness causes after render hooks to run\n // This will likely happen as a result of fixture.detectChanges because it calls ngZone.run\n // This is a crazy way of doing things but hey, it's the world we live in.\n // The zoneless scheduler should instead do this more imperatively by attaching\n // the `ComponentRef` to `ApplicationRef` and calling `appRef.tick` as the `detectChanges`\n // behavior.\n /** @internal */\n protected readonly _appRef = inject(ApplicationRef);\n private readonly _testAppRef = this._appRef as unknown as TestAppRef;\n private readonly pendingTasks = inject(PendingTasks);\n private readonly appErrorHandler = inject(TestBedApplicationErrorHandler);\n private readonly zonelessEnabled = inject(ZONELESS_ENABLED);\n private readonly scheduler = inject(ɵChangeDetectionScheduler);\n private readonly rootEffectScheduler = inject(EffectScheduler);\n private readonly microtaskEffectScheduler = inject(MicrotaskEffectScheduler);\n private readonly autoDetectDefault = this.zonelessEnabled ? true : false;\n private autoDetect =\n inject(ComponentFixtureAutoDetect, {optional: true}) ?? this.autoDetectDefault;\n\n private subscriptions = new Subscription();\n\n // TODO(atscott): Remove this from public API\n ngZone = this._noZoneOptionIsSet ? null : this._ngZone;\n\n /** @nodoc */\n constructor(public componentRef: ComponentRef<T>) {\n this.changeDetectorRef = componentRef.changeDetectorRef;\n this.elementRef = componentRef.location;\n this.debugElement = <DebugElement>getDebugNode(this.elementRef.nativeElement);\n this.componentInstance = componentRef.instance;\n this.nativeElement = this.elementRef.nativeElement;\n this.componentRef = componentRef;\n\n if (this.autoDetect) {\n this._testAppRef.externalTestViews.add(this.componentRef.hostView);\n this.scheduler?.notify(ɵNotificationSource.ViewAttached);\n this.scheduler?.notify(ɵNotificationSource.MarkAncestorsForTraversal);\n }\n this.componentRef.hostView.onDestroy(() => {\n this._testAppRef.externalTestViews.delete(this.componentRef.hostView);\n });\n // Create subscriptions outside the NgZone so that the callbacks run outside\n // of NgZone.\n this._ngZone.runOutsideAngular(() => {\n this.subscriptions.add(\n this._ngZone.onError.subscribe({\n next: (error: any) => {\n throw error;\n },\n }),\n );\n });\n }\n\n /**\n * Trigger a change detection cycle for the component.\n */\n detectChanges(checkNoChanges = true): void {\n this.microtaskEffectScheduler.flush();\n const originalCheckNoChanges = this.componentRef.changeDetectorRef.checkNoChanges;\n try {\n if (!checkNoChanges) {\n this.componentRef.changeDetectorRef.checkNoChanges = () => {};\n }\n\n if (this.zonelessEnabled) {\n try {\n this._testAppRef.externalTestViews.add(this.componentRef.hostView);\n this._appRef.tick();\n } finally {\n if (!this.autoDetect) {\n this._testAppRef.externalTestViews.delete(this.componentRef.hostView);\n }\n }\n } else {\n // Run the change detection inside the NgZone so that any async tasks as part of the change\n // detection are captured by the zone and can be waited for in isStable.\n this._ngZone.run(() => {\n // Flush root effects before `detectChanges()`, to emulate the sequencing of `tick()`.\n this.rootEffectScheduler.flush();\n this.changeDetectorRef.detectChanges();\n this.checkNoChanges();\n });\n }\n } finally {\n this.componentRef.changeDetectorRef.checkNoChanges = originalCheckNoChanges;\n }\n this.microtaskEffectScheduler.flush();\n }\n\n /**\n * Do a change detection run to make sure there were no changes.\n */\n checkNoChanges(): void {\n this.changeDetectorRef.checkNoChanges();\n }\n\n /**\n * Set whether the fixture should autodetect changes.\n *\n * Also runs detectChanges once so that any existing change is detected.\n *\n * @param autoDetect Whether to autodetect changes. By default, `true`.\n */\n autoDetectChanges(autoDetect = true): void {\n if (this._noZoneOptionIsSet && !this.zonelessEnabled) {\n throw new Error('Cannot call autoDetectChanges when ComponentFixtureNoNgZone is set.');\n }\n\n if (autoDetect !== this.autoDetect) {\n if (autoDetect) {\n this._testAppRef.externalTestViews.add(this.componentRef.hostView);\n } else {\n this._testAppRef.externalTestViews.delete(this.componentRef.hostView);\n }\n }\n\n this.autoDetect = autoDetect;\n this.detectChanges();\n }\n\n /**\n * Return whether the fixture is currently stable or has async tasks that have not been completed\n * yet.\n */\n isStable(): boolean {\n return !this.pendingTasks.hasPendingTasks.value;\n }\n\n /**\n * Get a promise that resolves when the fixture is stable.\n *\n * This can be used to resume testing after events have triggered asynchronous activity or\n * asynchronous change detection.\n */\n whenStable(): Promise<any> {\n if (this.isStable()) {\n return Promise.resolve(false);\n }\n\n return new Promise((resolve, reject) => {\n this.appErrorHandler.whenStableRejectFunctions.add(reject);\n this._appRef.whenStable().then(() => {\n this.appErrorHandler.whenStableRejectFunctions.delete(reject);\n resolve(true);\n });\n });\n }\n\n /**\n * Retrieves all defer block fixtures in the component fixture.\n */\n getDeferBlocks(): Promise<DeferBlockFixture[]> {\n const deferBlocks: DeferBlockDetails[] = [];\n const lView = (this.componentRef.hostView as any)['_lView'];\n getDeferBlocks(lView, deferBlocks);\n\n const deferBlockFixtures = [];\n for (const block of deferBlocks) {\n deferBlockFixtures.push(new DeferBlockFixture(block, this));\n }\n\n return Promise.resolve(deferBlockFixtures);\n }\n\n private _getRenderer() {\n if (this._renderer === undefined) {\n this._renderer = this.componentRef.injector.get(RendererFactory2, null);\n }\n return this._renderer as RendererFactory2 | null;\n }\n\n /**\n * Get a promise that resolves when the ui state is stable following animations.\n */\n whenRenderingDone(): Promise<any> {\n const renderer = this._getRenderer();\n if (renderer && renderer.whenRenderingDone) {\n return renderer.whenRenderingDone();\n }\n return this.whenStable();\n }\n\n /**\n * Trigger component destruction.\n */\n destroy(): void {\n this.subscriptions.unsubscribe();\n this._testAppRef.externalTestViews.delete(this.componentRef.hostView);\n if (!this._isDestroyed) {\n this.componentRef.destroy();\n this._isDestroyed = true;\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 */\nconst _Zone: any = typeof Zone !== 'undefined' ? Zone : null;\nconst fakeAsyncTestModule = _Zone && _Zone[_Zone.__symbol__('fakeAsyncTest')];\n\nconst fakeAsyncTestModuleNotLoadedErrorMessage = `zone-testing.js is needed for the fakeAsync() test helper but could not be found.\n Please make sure that your environment includes zone.js/testing`;\n\n/**\n * Clears out the shared fake async zone for a test.\n * To be called in a global `beforeEach`.\n *\n * @publicApi\n */\nexport function resetFakeAsyncZone(): void {\n if (fakeAsyncTestModule) {\n return fakeAsyncTestModule.resetFakeAsyncZone();\n }\n throw new Error(fakeAsyncTestModuleNotLoadedErrorMessage);\n}\n\nexport function resetFakeAsyncZoneIfExists(): void {\n if (fakeAsyncTestModule) {\n fakeAsyncTestModule.resetFakeAsyncZone();\n }\n}\n\n/**\n * Wraps a function to be executed in the `fakeAsync` zone:\n * - Microtasks are manually executed by calling `flushMicrotasks()`.\n * - Timers are synchronous; `tick()` simulates the asynchronous passage of time.\n *\n * Can be used to wrap `inject()` calls.\n *\n * @param fn The function that you want to wrap in the `fakeAsync` zone.\n * @param options\n * - flush: When true, will drain the macrotask queue after the test function completes.\n * When false, will throw an exception at the end of the function if there are pending timers.\n *\n * @usageNotes\n * ### Example\n *\n * {@example core/testing/ts/fake_async.ts region='basic'}\n *\n *\n * @returns The function wrapped to be executed in the `fakeAsync` zone.\n * Any arguments passed when calling this returned function will be passed through to the `fn`\n * function in the parameters when it is called.\n *\n * @publicApi\n */\nexport function fakeAsync(fn: Function, options?: {flush?: boolean}): (...args: any[]) => any {\n if (fakeAsyncTestModule) {\n return fakeAsyncTestModule.fakeAsync(fn, options);\n }\n throw new Error(fakeAsyncTestModuleNotLoadedErrorMessage);\n}\n\n/**\n * Simulates the asynchronous passage of time for the timers in the `fakeAsync` zone.\n *\n * The microtasks queue is drained at the very start of this function and after any timer callback\n * has been executed.\n *\n * @param millis The number of milliseconds to advance the virtual timer.\n * @param tickOptions The options to pass to the `tick()` function.\n *\n * @usageNotes\n *\n * The `tick()` option is a flag called `processNewMacroTasksSynchronously`,\n * which determines whether or not to invoke new macroTasks.\n *\n * If you provide a `tickOptions` object, but do not specify a\n * `processNewMacroTasksSynchronously` property (`tick(100, {})`),\n * then `processNewMacroTasksSynchronously` defaults to true.\n *\n * If you omit the `tickOptions` parameter (`tick(100))`), then\n * `tickOptions` defaults to `{processNewMacroTasksSynchronously: true}`.\n *\n * ### Example\n *\n * {@example core/testing/ts/fake_async.ts region='basic'}\n *\n * The following example includes a nested timeout (new macroTask), and\n * the `tickOptions` parameter is allowed to default. In this case,\n * `processNewMacroTasksSynchronously` defaults to true, and the nested\n * function is executed on each tick.\n *\n * ```ts\n * it ('test with nested setTimeout', fakeAsync(() => {\n * let nestedTimeoutInvoked = false;\n * function funcWithNestedTimeout() {\n * setTimeout(() => {\n * nestedTimeoutInvoked = true;\n * });\n * };\n * setTimeout(funcWithNestedTimeout);\n * tick();\n * expect(nestedTimeoutInvoked).toBe(true);\n * }));\n * ```\n *\n * In the following case, `processNewMacroTasksSynchronously` is explicitly\n * set to false, so the nested timeout function is not invoked.\n *\n * ```ts\n * it ('test with nested setTimeout', fakeAsync(() => {\n * let nestedTimeoutInvoked = false;\n * function funcWithNestedTimeout() {\n * setTimeout(() => {\n * nestedTimeoutInvoked = true;\n * });\n * };\n * setTimeout(funcWithNestedTimeout);\n * tick(0, {processNewMacroTasksSynchronously: false});\n * expect(nestedTimeoutInvoked).toBe(false);\n * }));\n * ```\n *\n *\n * @publicApi\n */\nexport function tick(\n millis: number = 0,\n tickOptions: {processNewMacroTasksSynchronously: boolean} = {\n processNewMacroTasksSynchronously: true,\n },\n): void {\n if (fakeAsyncTestModule) {\n return fakeAsyncTestModule.tick(millis, tickOptions);\n }\n throw new Error(fakeAsyncTestModuleNotLoadedErrorMessage);\n}\n\n/**\n * Flushes any pending microtasks and simulates the asynchronous passage of time for the timers in\n * the `fakeAsync` zone by\n * draining the macrotask queue until it is empty.\n *\n * @param maxTurns The maximum number of times the scheduler attempts to clear its queue before\n * throwing an error.\n * @returns The simulated time elapsed, in milliseconds.\n *\n * @publicApi\n */\nexport function flush(maxTurns?: number): number {\n if (fakeAsyncTestModule) {\n return fakeAsyncTestModule.flush(maxTurns);\n }\n throw new Error(fakeAsyncTestModuleNotLoadedErrorMessage);\n}\n\n/**\n * Discard all remaining periodic tasks.\n *\n * @publicApi\n */\nexport function discardPeriodicTasks(): void {\n if (fakeAsyncTestModule) {\n return fakeAsyncTestModule.discardPeriodicTasks();\n }\n throw new Error(fakeAsyncTestModuleNotLoadedErrorMessage);\n}\n\n/**\n * Flush any pending microtasks.\n *\n * @publicApi\n */\nexport function flushMicrotasks(): void {\n if (fakeAsyncTestModule) {\n return fakeAsyncTestModule.flushMicrotasks();\n }\n throw new Error(fakeAsyncTestModuleNotLoadedErrorMessage);\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 {ɵstringify as stringify} from '@angular/core';\n\nimport {MetadataOverride} from './metadata_override';\n\ntype StringMap = {\n [key: string]: any;\n};\n\nlet _nextReferenceId = 0;\n\nexport class MetadataOverrider {\n private _references = new Map<any, string>();\n /**\n * Creates a new instance for the given metadata class\n * based on an old instance and overrides.\n */\n overrideMetadata<C extends T, T>(\n metadataClass: {new (options: T): C},\n oldMetadata: C,\n override: MetadataOverride<T>,\n ): C {\n const props: StringMap = {};\n if (oldMetadata) {\n _valueProps(oldMetadata).forEach((prop) => (props[prop] = (<any>oldMetadata)[prop]));\n }\n\n if (override.set) {\n if (override.remove || override.add) {\n throw new Error(`Cannot set and add/remove ${stringify(metadataClass)} at the same time!`);\n }\n setMetadata(props, override.set);\n }\n if (override.remove) {\n removeMetadata(props, override.remove, this._references);\n }\n if (override.add) {\n addMetadata(props, override.add);\n }\n return new metadataClass(<any>props);\n }\n}\n\nfunction removeMetadata(metadata: StringMap, remove: any, references: Map<any, string>) {\n const removeObjects = new Set<string>();\n for (const prop in remove) {\n const removeValue = remove[prop];\n if (Array.isArray(removeValue)) {\n removeValue.forEach((value: any) => {\n removeObjects.add(_propHashKey(prop, value, references));\n });\n } else {\n removeObjects.add(_propHashKey(prop, removeValue, references));\n }\n }\n\n for (const prop in metadata) {\n const propValue = metadata[prop];\n if (Array.isArray(propValue)) {\n metadata[prop] = propValue.filter(\n (value: any) => !removeObjects.has(_propHashKey(prop, value, references)),\n );\n } else {\n if (removeObjects.has(_propHashKey(prop, propValue, references))) {\n metadata[prop] = undefined;\n }\n }\n }\n}\n\nfunction addMetadata(metadata: StringMap, add: any) {\n for (const prop in add) {\n const addValue = add[prop];\n const propValue = metadata[prop];\n if (propValue != null && Array.isArray(propValue)) {\n metadata[prop] = propValue.concat(addValue);\n } else {\n metadata[prop] = addValue;\n }\n }\n}\n\nfunction setMetadata(metadata: StringMap, set: any) {\n for (const prop in set) {\n metadata[prop] = set[prop];\n }\n}\n\nfunction _propHashKey(propName: any, propValue: any, references: Map<any, string>): string {\n let nextObjectId = 0;\n const objectIds = new Map<object, string>();\n const replacer = (key: any, value: any) => {\n if (value !== null && typeof value === 'object') {\n if (objectIds.has(value)) {\n return objectIds.get(value);\n }\n // Record an id for this object such that any later references use the object's id instead\n // of the object itself, in order to break cyclic pointers in objects.\n objectIds.set(value, `ɵobj#${nextObjectId++}`);\n\n // The first time an object is seen the object itself is serialized.\n return value;\n } else if (typeof value === 'function') {\n value = _serializeReference(value, references);\n }\n return value;\n };\n\n return `${propName}:${JSON.stringify(propValue, replacer)}`;\n}\n\nfunction _serializeReference(ref: any, references: Map<any, string>): string {\n let id = references.get(ref);\n if (!id) {\n id = `${stringify(ref)}${_nextReferenceId++}`;\n references.set(ref, id);\n }\n return id;\n}\n\nfunction _valueProps(obj: any): string[] {\n const props: string[] = [];\n // regular public props\n Object.keys(obj).forEach((prop) => {\n if (!prop.startsWith('_')) {\n props.push(prop);\n }\n });\n\n // getters\n let proto = obj;\n while ((proto = Object.getPrototypeOf(proto))) {\n Object.keys(proto).forEach((protoProp) => {\n const desc = Object.getOwnPropertyDescriptor(proto, protoProp);\n if (!protoProp.startsWith('_') && desc && 'get' in desc) {\n props.push(protoProp);\n }\n });\n }\n return props;\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 Directive,\n NgModule,\n Pipe,\n Type,\n ɵReflectionCapabilities as ReflectionCapabilities,\n} from '@angular/core';\n\nimport {MetadataOverride} from './metadata_override';\nimport {MetadataOverrider} from './metadata_overrider';\n\nconst reflection = new ReflectionCapabilities();\n\n/**\n * Base interface to resolve `@Component`, `@Directive`, `@Pipe` and `@NgModule`.\n */\nexport interface Resolver<T> {\n addOverride(type: Type<any>, override: MetadataOverride<T>): void;\n setOverrides(overrides: Array<[Type<any>, MetadataOverride<T>]>): void;\n resolve(type: Type<any>): T | null;\n}\n\n/**\n * Allows to override ivy metadata for tests (via the `TestBed`).\n */\nabstract class OverrideResolver<T> implements Resolver<T> {\n private overrides = new Map<Type<any>, MetadataOverride<T>[]>();\n private resolved = new Map<Type<any>, T | null>();\n\n abstract get type(): any;\n\n addOverride(type: Type<any>, override: MetadataOverride<T>) {\n const overrides = this.overrides.get(type) || [];\n overrides.push(override);\n this.overrides.set(type, overrides);\n this.resolved.delete(type);\n }\n\n setOverrides(overrides: Array<[Type<any>, MetadataOverride<T>]>) {\n this.overrides.clear();\n overrides.forEach(([type, override]) => {\n this.addOverride(type, override);\n });\n }\n\n getAnnotation(type: Type<any>): T | null {\n const annotations = reflection.annotations(type);\n // Try to find the nearest known Type annotation and make sure that this annotation is an\n // instance of the type we are looking for, so we can use it for resolution. Note: there might\n // be multiple known annotations found due to the fact that Components can extend Directives (so\n // both Directive and Component annotations would be present), so we always check if the known\n // annotation has the right type.\n for (let i = annotations.length - 1; i >= 0; i--) {\n const annotation = annotations[i];\n const isKnownType =\n annotation instanceof Directive ||\n annotation instanceof Component ||\n annotation instanceof Pipe ||\n annotation instanceof NgModule;\n if (isKnownType) {\n return annotation instanceof this.type ? (annotation as unknown as T) : null;\n }\n }\n return null;\n }\n\n resolve(type: Type<any>): T | null {\n let resolved: T | null = this.resolved.get(type) || null;\n\n if (!resolved) {\n resolved = this.getAnnotation(type);\n if (resolved) {\n const overrides = this.overrides.get(type);\n if (overrides) {\n const overrider = new MetadataOverrider();\n overrides.forEach((override) => {\n resolved = overrider.overrideMetadata(this.type, resolved!, override);\n });\n }\n }\n this.resolved.set(type, resolved);\n }\n\n return resolved;\n }\n}\n\nexport class DirectiveResolver extends OverrideResolver<Directive> {\n override get type() {\n return Directive;\n }\n}\n\nexport class ComponentResolver extends OverrideResolver<Component> {\n override get type() {\n return Component;\n }\n}\n\nexport class PipeResolver extends OverrideResolver<Pipe> {\n override get type() {\n return Pipe;\n }\n}\n\nexport class NgModuleResolver extends OverrideResolver<NgModule> {\n override get type() {\n return NgModule;\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 {ResourceLoader} from '@angular/compiler';\nimport {\n ApplicationInitStatus,\n ɵINTERNAL_APPLICATION_ERROR_HANDLER as INTERNAL_APPLICATION_ERROR_HANDLER,\n ɵChangeDetectionScheduler as ChangeDetectionScheduler,\n ɵChangeDetectionSchedulerImpl as ChangeDetectionSchedulerImpl,\n Compiler,\n COMPILER_OPTIONS,\n Component,\n Directive,\n Injector,\n inject,\n InjectorType,\n LOCALE_ID,\n ModuleWithComponentFactories,\n ModuleWithProviders,\n NgModule,\n NgModuleFactory,\n Pipe,\n PlatformRef,\n Provider,\n resolveForwardRef,\n StaticProvider,\n Type,\n ɵclearResolutionOfComponentResourcesQueue,\n ɵcompileComponent as compileComponent,\n ɵcompileDirective as compileDirective,\n ɵcompileNgModuleDefs as compileNgModuleDefs,\n ɵcompilePipe as compilePipe,\n ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID,\n ɵDEFER_BLOCK_CONFIG as DEFER_BLOCK_CONFIG,\n ɵdepsTracker as depsTracker,\n ɵDirectiveDef as DirectiveDef,\n ɵgenerateStandaloneInDeclarationsError,\n ɵgetAsyncClassMetadataFn as getAsyncClassMetadataFn,\n ɵgetInjectableDef as getInjectableDef,\n ɵInternalEnvironmentProviders as InternalEnvironmentProviders,\n ɵinternalProvideZoneChangeDetection as internalProvideZoneChangeDetection,\n ɵisComponentDefPendingResolution,\n ɵisEnvironmentProviders as isEnvironmentProviders,\n ɵNG_COMP_DEF as NG_COMP_DEF,\n ɵNG_DIR_DEF as NG_DIR_DEF,\n ɵNG_INJ_DEF as NG_INJ_DEF,\n ɵNG_MOD_DEF as NG_MOD_DEF,\n ɵNG_PIPE_DEF as NG_PIPE_DEF,\n ɵNgModuleFactory as R3NgModuleFactory,\n ɵNgModuleTransitiveScopes as NgModuleTransitiveScopes,\n ɵNgModuleType as NgModuleType,\n ɵpatchComponentDefWithScope as patchComponentDefWithScope,\n ɵRender3ComponentFactory as ComponentFactory,\n ɵRender3NgModuleRef as NgModuleRef,\n ɵresolveComponentResources,\n ɵrestoreComponentResolutionQueue,\n ɵsetLocaleId as setLocaleId,\n ɵtransitiveScopesFor as transitiveScopesFor,\n ɵUSE_RUNTIME_DEPS_TRACKER_FOR_JIT as USE_RUNTIME_DEPS_TRACKER_FOR_JIT,\n ɵɵInjectableDeclaration as InjectableDeclaration,\n NgZone,\n ErrorHandler,\n} from '@angular/core';\n\nimport {ComponentDef, ComponentType} from '../../src/render3';\n\nimport {MetadataOverride} from './metadata_override';\nimport {\n ComponentResolver,\n DirectiveResolver,\n NgModuleResolver,\n PipeResolver,\n Resolver,\n} from './resolvers';\nimport {DEFER_BLOCK_DEFAULT_BEHAVIOR, TestModuleMetadata} from './test_bed_common';\nimport {\n RETHROW_APPLICATION_ERRORS_DEFAULT,\n TestBedApplicationErrorHandler,\n} from './application_error_handler';\n\nenum TestingModuleOverride {\n DECLARATION,\n OVERRIDE_TEMPLATE,\n}\n\nfunction isTestingModuleOverride(value: unknown): value is TestingModuleOverride {\n return (\n value === TestingModuleOverride.DECLARATION || value === TestingModuleOverride.OVERRIDE_TEMPLATE\n );\n}\n\nfunction assertNoStandaloneComponents(\n types: Type<any>[],\n resolver: Resolver<any>,\n location: string,\n) {\n types.forEach((type) => {\n if (!getAsyncClassMetadataFn(type)) {\n const component = resolver.resolve(type);\n if (component && (component.standalone == null || component.standalone)) {\n throw new Error(ɵgenerateStandaloneInDeclarationsError(type, location));\n }\n }\n });\n}\n\n// Resolvers for Angular decorators\ntype Resolvers = {\n module: Resolver<NgModule>;\n component: Resolver<Directive>;\n directive: Resolver<Component>;\n pipe: Resolver<Pipe>;\n};\n\ninterface CleanupOperation {\n fieldName: string;\n object: any;\n originalValue: unknown;\n}\n\nexport class TestBedCompiler {\n private originalComponentResolutionQueue: Map<Type<any>, Component> | null = null;\n\n // Testing module configuration\n private declarations: Type<any>[] = [];\n private imports: Type<any>[] = [];\n private providers: Provider[] = [];\n private schemas: any[] = [];\n\n // Queues of components/directives/pipes that should be recompiled.\n private pendingComponents = new Set<Type<any>>();\n private pendingDirectives = new Set<Type<any>>();\n private pendingPipes = new Set<Type<any>>();\n\n // Set of components with async metadata, i.e. components with `@defer` blocks\n // in their templates.\n private componentsWithAsyncMetadata = new Set<Type<unknown>>();\n\n // Keep track of all components and directives, so we can patch Providers onto defs later.\n private seenComponents = new Set<Type<any>>();\n private seenDirectives = new Set<Type<any>>();\n\n // Keep track of overridden modules, so that we can collect all affected ones in the module tree.\n private overriddenModules = new Set<NgModuleType<any>>();\n\n // Store resolved styles for Components that have template overrides present and `styleUrls`\n // defined at the same time.\n private existingComponentStyles = new Map<Type<any>, string[]>();\n\n private resolvers: Resolvers = initResolvers();\n\n // Map of component type to an NgModule that declares it.\n //\n // There are a couple special cases:\n // - for standalone components, the module scope value is `null`\n // - when a component is declared in `TestBed.configureTestingModule()` call or\n // a component's template is overridden via `TestBed.overrideTemplateUsingTestingModule()`.\n // we use a special value from the `TestingModuleOverride` enum.\n private componentToModuleScope = new Map<Type<any>, Type<any> | TestingModuleOverride | null>();\n\n // Map that keeps initial version of component/directive/pipe defs in case\n // we compile a Type again, thus overriding respective static fields. This is\n // required to make sure we restore defs to their initial states between test runs.\n // Note: one class may have multiple defs (for example: ɵmod and ɵinj in case of an\n // NgModule), store all of them in a map.\n private initialNgDefs = new Map<Type<any>, Map<string, PropertyDescriptor | undefined>>();\n\n // Array that keeps cleanup operations for initial versions of component/directive/pipe/module\n // defs in case TestBed makes changes to the originals.\n private defCleanupOps: CleanupOperation[] = [];\n\n private _injector: Injector | null = null;\n private compilerProviders: Provider[] | null = null;\n\n private providerOverrides: Provider[] = [];\n private rootProviderOverrides: Provider[] = [];\n // Overrides for injectables with `{providedIn: SomeModule}` need to be tracked and added to that\n // module's provider list.\n private providerOverridesByModule = new Map<InjectorType<any>, Provider[]>();\n private providerOverridesByToken = new Map<any, Provider>();\n private scopesWithOverriddenProviders = new Set<Type<any>>();\n\n private testModuleType: NgModuleType<any>;\n private testModuleRef: NgModuleRef<any> | null = null;\n\n private deferBlockBehavior = DEFER_BLOCK_DEFAULT_BEHAVIOR;\n private rethrowApplicationTickErrors = RETHROW_APPLICATION_ERRORS_DEFAULT;\n\n constructor(\n private platform: PlatformRef,\n private additionalModuleTypes: Type<any> | Type<any>[],\n ) {\n class DynamicTestModule {}\n this.testModuleType = DynamicTestModule as any;\n }\n\n setCompilerProviders(providers: Provider[] | null): void {\n this.compilerProviders = providers;\n this._injector = null;\n }\n\n configureTestingModule(moduleDef: TestModuleMetadata): void {\n // Enqueue any compilation tasks for the directly declared component.\n if (moduleDef.declarations !== undefined) {\n // Verify that there are no standalone components\n assertNoStandaloneComponents(\n moduleDef.declarations,\n this.resolvers.component,\n '\"TestBed.configureTestingModule\" call',\n );\n this.queueTypeArray(moduleDef.declarations, TestingModuleOverride.DECLARATION);\n this.declarations.push(...moduleDef.declarations);\n }\n\n // Enqueue any compilation tasks for imported modules.\n if (moduleDef.imports !== undefined) {\n this.queueTypesFromModulesArray(moduleDef.imports);\n this.imports.push(...moduleDef.imports);\n }\n\n if (moduleDef.providers !== undefined) {\n this.providers.push(...moduleDef.providers);\n }\n\n if (moduleDef.schemas !== undefined) {\n this.schemas.push(...moduleDef.schemas);\n }\n\n this.deferBlockBehavior = moduleDef.deferBlockBehavior ?? DEFER_BLOCK_DEFAULT_BEHAVIOR;\n this.rethrowApplicationTickErrors =\n moduleDef.rethrowApplicationErrors ?? RETHROW_APPLICATION_ERRORS_DEFAULT;\n }\n\n overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): void {\n if (USE_RUNTIME_DEPS_TRACKER_FOR_JIT) {\n depsTracker.clearScopeCacheFor(ngModule);\n }\n this.overriddenModules.add(ngModule as NgModuleType<any>);\n\n // Compile the module right away.\n this.resolvers.module.addOverride(ngModule, override);\n const metadata = this.resolvers.module.resolve(ngModule);\n if (metadata === null) {\n throw invalidTypeError(ngModule.name, 'NgModule');\n }\n\n this.recompileNgModule(ngModule, metadata);\n\n // At this point, the module has a valid module def (ɵmod), but the override may have introduced\n // new declarations or imported modules. Ingest any possible new types and add them to the\n // current queue.\n this.queueTypesFromModulesArray([ngModule]);\n }\n\n overrideComponent(component: Type<any>, override: MetadataOverride<Component>): void {\n this.verifyNoStandaloneFlagOverrides(component, override);\n this.resolvers.component.addOverride(component, override);\n this.pendingComponents.add(component);\n\n // If this is a component with async metadata (i.e. a component with a `@defer` block\n // in a template) - store it for future processing.\n this.maybeRegisterComponentWithAsyncMetadata(component);\n }\n\n overrideDirective(directive: Type<any>, override: MetadataOverride<Directive>): void {\n this.verifyNoStandaloneFlagOverrides(directive, override);\n this.resolvers.directive.addOverride(directive, override);\n this.pendingDirectives.add(directive);\n }\n\n overridePipe(pipe: Type<any>, override: MetadataOverride<Pipe>): void {\n this.verifyNoStandaloneFlagOverrides(pipe, override);\n this.resolvers.pipe.addOverride(pipe, override);\n this.pendingPipes.add(pipe);\n }\n\n private verifyNoStandaloneFlagOverrides(\n type: Type<any>,\n override: MetadataOverride<Component | Directive | Pipe>,\n ) {\n if (\n override.add?.hasOwnProperty('standalone') ||\n override.set?.hasOwnProperty('standalone') ||\n override.remove?.hasOwnProperty('standalone')\n ) {\n throw new Error(\n `An override for the ${type.name} class has the \\`standalone\\` flag. ` +\n `Changing the \\`standalone\\` flag via TestBed overrides is not supported.`,\n );\n }\n }\n\n overrideProvider(\n token: any,\n provider: {useFactory?: Function; useValue?: any; deps?: any[]; multi?: boolean},\n ): void {\n let providerDef: Provider;\n if (provider.useFactory !== undefined) {\n providerDef = {\n provide: token,\n useFactory: provider.useFactory,\n deps: provider.deps || [],\n multi: provider.multi,\n };\n } else if (provider.useValue !== undefined) {\n providerDef = {provide: token, useValue: provider.useValue, multi: provider.multi};\n } else {\n providerDef = {provide: token};\n }\n\n const injectableDef: InjectableDeclaration<any> | null =\n typeof token !== 'string' ? getInjectableDef(token) : null;\n const providedIn = injectableDef === null ? null : resolveForwardRef(injectableDef.providedIn);\n const overridesBucket =\n providedIn === 'root' ? this.rootProviderOverrides : this.providerOverrides;\n overridesBucket.push(providerDef);\n\n // Keep overrides grouped by token as well for fast lookups using token\n this.providerOverridesByToken.set(token, providerDef);\n if (injectableDef !== null && providedIn !== null && typeof providedIn !== 'string') {\n const existingOverrides = this.providerOverridesByModule.get(providedIn);\n if (existingOverrides !== undefined) {\n existingOverrides.push(providerDef);\n } else {\n this.providerOverridesByModule.set(providedIn, [providerDef]);\n }\n }\n }\n\n overrideTemplateUsingTestingModule(type: Type<any>, template: string): void {\n const def = (type as any)[NG_COMP_DEF];\n const hasStyleUrls = (): boolean => {\n const metadata = this.resolvers.component.resolve(type)! as Component;\n return !!metadata.styleUrl || !!metadata.styleUrls?.length;\n };\n const overrideStyleUrls = !!def && !ɵisComponentDefPendingResolution(type) && hasStyleUrls();\n\n // In Ivy, compiling a component does not require knowing the module providing the\n // component's scope, so overrideTemplateUsingTestingModule can be implemented purely via\n // overrideComponent. Important: overriding template requires full Component re-compilation,\n // which may fail in case styleUrls are also present (thus Component is considered as required\n // resolution). In order to avoid this, we preemptively set styleUrls to an empty array,\n // preserve current styles available on Component def and restore styles back once compilation\n // is complete.\n const override = overrideStyleUrls\n ? {template, styles: [], styleUrls: [], styleUrl: undefined}\n : {template};\n this.overrideComponent(type, {set: override});\n\n if (overrideStyleUrls && def.styles && def.styles.length > 0) {\n this.existingComponentStyles.set(type, def.styles);\n }\n\n // Set the component's scope to be the testing module.\n this.componentToModuleScope.set(type, TestingModuleOverride.OVERRIDE_TEMPLATE);\n }\n\n private async resolvePendingComponentsWithAsyncMetadata() {\n if (this.componentsWithAsyncMetadata.size === 0) return;\n\n const promises = [];\n for (const component of this.componentsWithAsyncMetadata) {\n const asyncMetadataFn = getAsyncClassMetadataFn(component);\n if (asyncMetadataFn) {\n promises.push(asyncMetadataFn());\n }\n }\n this.componentsWithAsyncMetadata.clear();\n\n const resolvedDeps = await Promise.all(promises);\n const flatResolvedDeps = resolvedDeps.flat(2);\n this.queueTypesFromModulesArray(flatResolvedDeps);\n\n // Loaded standalone components might contain imports of NgModules\n // with providers, make sure we override providers there too.\n for (const component of flatResolvedDeps) {\n this.applyProviderOverridesInScope(component);\n }\n }\n\n async compileComponents(): Promise<void> {\n this.clearComponentResolutionQueue();\n\n // Wait for all async metadata for components that were\n // overridden, we need resolved metadata to perform an override\n // and re-compile a component.\n await this.resolvePendingComponentsWithAsyncMetadata();\n\n // Verify that there were no standalone components present in the `declarations` field\n // during the `TestBed.configureTestingModule` call. We perform this check here in addition\n // to the logic in the `configureTestingModule` function, since at this point we have\n // all async metadata resolved.\n assertNoStandaloneComponents(\n this.declarations,\n this.resolvers.component,\n '\"TestBed.configureTestingModule\" call',\n );\n\n // Run compilers for all queued types.\n let needsAsyncResources = this.compileTypesSync();\n\n // compileComponents() should not be async unless it needs to be.\n if (needsAsyncResources) {\n let resourceLoader: ResourceLoader;\n let resolver = (url: string): Promise<string> => {\n if (!res