Skip to content

Commit f7ab040

Browse files
atscottdylhunn
authored andcommitted
fix(core): errors during ApplicationRef.tick should be rethrown for zoneless tests (#56993)
The behavior of `ComponentFixture` for zoneless tests was decided somewhat through guesswork, trial, and error. In addition, working on the zoneless fixture revealed oddities in the behavior of the zone-based fixture, or behaviors that we felt were counterintuitive. The most consequential difference is how change detection works: `detectChanges` goes through ApplicationRef.tick in zoneless while it is `changeDetectorRef.detectChanges` in the zone fixture. We felt that running change detection through `ApplicationRef.tick` was important for several reasons: * Aligning application behavior more closely with the test behavior (almost all views are attached to application ref in reality) * Ensuring that afterRender* hooks are executed when calling `fixture.detectChanges` * Ensuring that the change detection runs again if render hooks update state This change, however, has some noticeable consequences that will break some tests, mostly around how errors are handled. `ApplicationRef.tick` catches errors that happen during change detection and reports them to the ErrorHandler from DI. The default error handler only logs the error to the console. This will break tests which have `expect(() => fixture.detectChanges()).toThrow()`. In addition, it allows tests to pass when there are real errors encountered during change detection. This change ensures that errors from `ApplicationRef.tick` are rethrown and will fail the test. We should also do a follow-up investigation to determine whether we can/should also do this for the zone-based `ComponentFixture`. fixes #56977 PR Close #56993
1 parent 6136700 commit f7ab040

File tree

18 files changed

+195
-44
lines changed

18 files changed

+195
-44
lines changed

packages/core/src/change_detection/scheduling/ng_zone_scheduling.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
makeEnvironmentProviders,
1919
StaticProvider,
2020
} from '../../di';
21-
import {ErrorHandler, INTERNAL_APPLICATION_ERROR_HANDLER} from '../../error_handler';
2221
import {RuntimeError, RuntimeErrorCode} from '../../errors';
2322
import {PendingTasks} from '../../pending_tasks';
2423
import {performanceMarkFeature} from '../../util/performance';
@@ -113,19 +112,12 @@ export function internalProvideZoneChangeDetection({
113112
};
114113
},
115114
},
116-
{provide: INTERNAL_APPLICATION_ERROR_HANDLER, useFactory: ngZoneApplicationErrorHandlerFactory},
117115
// Always disable scheduler whenever explicitly disabled, even if another place called
118116
// `provideZoneChangeDetection` without the 'ignore' option.
119117
ignoreChangesOutsideZone === true ? {provide: ZONELESS_SCHEDULER_DISABLED, useValue: true} : [],
120118
];
121119
}
122120

123-
export function ngZoneApplicationErrorHandlerFactory() {
124-
const zone = inject(NgZone);
125-
const userErrorHandler = inject(ErrorHandler);
126-
return (e: unknown) => zone.runOutsideAngular(() => userErrorHandler.handleError(e));
127-
}
128-
129121
/**
130122
* Provides `NgZone`-based change detection for the application bootstrapped using
131123
* `bootstrapApplication`.

packages/core/src/core_private_export.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export {
1111
detectChangesInViewIfRequired as ɵdetectChangesInViewIfRequired,
1212
whenStable as ɵwhenStable,
1313
} from './application/application_ref';
14+
export {INTERNAL_APPLICATION_ERROR_HANDLER as ɵINTERNAL_APPLICATION_ERROR_HANDLER} from './error_handler';
1415
export {
1516
IMAGE_CONFIG as ɵIMAGE_CONFIG,
1617
IMAGE_CONFIG_DEFAULTS as ɵIMAGE_CONFIG_DEFAULTS,

packages/core/src/error_handler.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import {inject, InjectionToken} from './di';
1010
import {getOriginalError} from './util/errors';
11+
import {NgZone} from './zone';
1112

1213
/**
1314
* Provides a hook for centralized exception handling.
@@ -71,8 +72,9 @@ export const INTERNAL_APPLICATION_ERROR_HANDLER = new InjectionToken<(e: any) =>
7172
{
7273
providedIn: 'root',
7374
factory: () => {
75+
const zone = inject(NgZone);
7476
const userErrorHandler = inject(ErrorHandler);
75-
return userErrorHandler.handleError.bind(this);
77+
return (e: unknown) => zone.runOutsideAngular(() => userErrorHandler.handleError(e));
7678
},
7779
},
7880
);

packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,9 +1256,6 @@
12561256
{
12571257
"name": "ngOnChangesSetInput"
12581258
},
1259-
{
1260-
"name": "ngZoneApplicationErrorHandlerFactory"
1261-
},
12621259
{
12631260
"name": "nonNull"
12641261
},

packages/core/test/bundling/animations/bundle.golden_symbols.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,9 +1319,6 @@
13191319
{
13201320
"name": "ngOnChangesSetInput"
13211321
},
1322-
{
1323-
"name": "ngZoneApplicationErrorHandlerFactory"
1324-
},
13251322
{
13261323
"name": "noSideEffects"
13271324
},

packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,9 +1061,6 @@
10611061
{
10621062
"name": "ngOnChangesSetInput"
10631063
},
1064-
{
1065-
"name": "ngZoneApplicationErrorHandlerFactory"
1066-
},
10671064
{
10681065
"name": "noSideEffects"
10691066
},

packages/core/test/bundling/defer/bundle.golden_symbols.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,9 +2285,6 @@
22852285
{
22862286
"name": "ngOnChangesSetInput"
22872287
},
2288-
{
2289-
"name": "ngZoneApplicationErrorHandlerFactory"
2290-
},
22912288
{
22922289
"name": "nonNull"
22932290
},

packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,9 +1583,6 @@
15831583
{
15841584
"name": "ngOnChangesSetInput"
15851585
},
1586-
{
1587-
"name": "ngZoneApplicationErrorHandlerFactory"
1588-
},
15891586
{
15901587
"name": "noSideEffects"
15911588
},

packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,9 +1550,6 @@
15501550
{
15511551
"name": "ngOnChangesSetInput"
15521552
},
1553-
{
1554-
"name": "ngZoneApplicationErrorHandlerFactory"
1555-
},
15561553
{
15571554
"name": "noSideEffects"
15581555
},

packages/core/test/bundling/hello_world/bundle.golden_symbols.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -836,9 +836,6 @@
836836
{
837837
"name": "ngOnChangesSetInput"
838838
},
839-
{
840-
"name": "ngZoneApplicationErrorHandlerFactory"
841-
},
842839
{
843840
"name": "noop"
844841
},

0 commit comments

Comments
 (0)