Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion goldens/public-api/platform-browser/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ export const platformBrowser: (extraProviders?: StaticProvider[]) => PlatformRef
export function provideClientHydration(...features: HydrationFeature<HydrationFeatureKind>[]): EnvironmentProviders;

// @public
export function provideProtractorTestingSupport(): Provider[];
export function provideProtractorTestingSupport(options?: {
usePendingTasksForStability?: boolean;
}): Provider[];

// @public
export const REMOVE_STYLES_ON_COMPONENT_DESTROY: InjectionToken<boolean>;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/core_private_export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ export {_sanitizeUrl as ɵ_sanitizeUrl} from './sanitization/url_sanitizer';
export {
TESTABILITY as ɵTESTABILITY,
TESTABILITY_GETTER as ɵTESTABILITY_GETTER,
USE_PENDING_TASKS as ɵUSE_PENDING_TASKS,
} from './testability/testability';
export {booleanAttribute, numberAttribute} from './util/coercion';
export {devModeEqual as ɵdevModeEqual} from './util/comparison';
Expand Down
43 changes: 37 additions & 6 deletions packages/core/src/testability/testability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {inject, Inject, Injectable, InjectionToken} from '../di';
import {Inject, Injectable, InjectionToken, inject} from '../di';
import {isInInjectionContext} from '../di/contextual';
import {DestroyRef} from '../linker/destroy_ref';
import {PendingTasksInternal} from '../pending_tasks_internal';
import {NgZone} from '../zone/ng_zone';

/**
Expand Down Expand Up @@ -61,6 +62,14 @@ export const TESTABILITY = new InjectionToken<Testability>('');
*/
export const TESTABILITY_GETTER = new InjectionToken<GetTestability>('');

/**
* Internal injection token to signal whether to use pending tasks for stability.
*/
export const USE_PENDING_TASKS = new InjectionToken<boolean>('USE_PENDING_TASKS', {
providedIn: 'root',
factory: () => typeof Zone === 'undefined',
});

/**
* The Testability service provides testing hooks that can be accessed from
* the browser.
Expand Down Expand Up @@ -90,6 +99,8 @@ export class Testability implements PublicTestability {

private _destroyRef?: DestroyRef;

private readonly pendingTasksInternal = inject(PendingTasksInternal);
private readonly _usePendingTasks = inject(USE_PENDING_TASKS);
constructor(
private _ngZone: NgZone,
private registry: TestabilityRegistry,
Expand Down Expand Up @@ -121,20 +132,36 @@ export class Testability implements PublicTestability {
},
});

const onStableSubscription = this._ngZone.runOutsideAngular(() =>
this._ngZone.onStable.subscribe({
let pendingTasksSubscription: any;
let onStableSubscription: any;

this._ngZone.runOutsideAngular(() => {
if (this._usePendingTasks) {
pendingTasksSubscription = this.pendingTasksInternal.hasPendingTasksObservable.subscribe(
() => {
if (this.isStable()) {
this._ngZone.runOutsideAngular(() => {
this._runCallbacksIfReady();
});
}
},
);
}

onStableSubscription = this._ngZone.onStable.subscribe({
next: () => {
NgZone.assertNotInAngularZone();
queueMicrotask(() => {
this._isZoneStable = true;
this._runCallbacksIfReady();
});
},
}),
);
});
});

this._destroyRef?.onDestroy(() => {
onUnstableSubscription.unsubscribe();
pendingTasksSubscription?.unsubscribe();
onStableSubscription.unsubscribe();
});
}
Expand All @@ -143,7 +170,11 @@ export class Testability implements PublicTestability {
* Whether an associated application is stable
*/
isStable(): boolean {
return this._isZoneStable && !this._ngZone.hasPendingMacrotasks;
return (
this._isZoneStable &&
!this._ngZone.hasPendingMacrotasks &&
(!this._usePendingTasks || !this.pendingTasksInternal.hasPendingTasks)
);
}

private _runCallbacksIfReady(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@
"TracingAction",
"TracingService",
"UNSET",
"USE_PENDING_TASKS",
"USE_VALUE",
"UnsubscriptionError",
"VALID",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@
"TracingAction",
"TracingService",
"UNSET",
"USE_PENDING_TASKS",
"USE_VALUE",
"UnsubscriptionError",
"VALID",
Expand Down
Loading
Loading