@angular/core 20.0.0-next.0 → 20.0.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/core.mjs +3307 -4479
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives/di.mjs +45 -0
- package/fesm2022/primitives/di.mjs.map +1 -0
- package/fesm2022/primitives/event-dispatch.mjs +3 -590
- package/fesm2022/primitives/event-dispatch.mjs.map +1 -1
- package/fesm2022/primitives/signals.mjs +19 -9
- package/fesm2022/primitives/signals.mjs.map +1 -1
- package/fesm2022/rxjs-interop.mjs +8 -33
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +392 -250
- package/fesm2022/testing.mjs.map +1 -1
- package/fesm2022/weak_ref-DrMdAIDh.mjs +12 -0
- package/fesm2022/weak_ref-DrMdAIDh.mjs.map +1 -0
- package/index.d.ts +14339 -15134
- package/navigation_types.d-u4EOrrdZ.d.ts +121 -0
- package/package.json +11 -1
- package/primitives/di/index.d.ts +91 -0
- package/primitives/event-dispatch/index.d.ts +206 -310
- package/primitives/signals/index.d.ts +159 -196
- package/rxjs-interop/index.d.ts +72 -92
- package/schematics/bundles/{apply_import_manager-0959b78c.js → apply_import_manager-CyRT0UvU.js} +13 -17
- package/schematics/bundles/{checker-cf6f7980.js → checker-DF8ZaFW5.js} +3363 -1289
- package/schematics/bundles/cleanup-unused-imports.js +22 -28
- package/schematics/bundles/{compiler_host-cc1379e9.js → compiler_host-Da636uJ8.js} +20 -24
- package/schematics/bundles/control-flow-migration.js +82 -39
- package/schematics/bundles/{imports-31a38653.js → imports-CIX-JgAN.js} +10 -15
- package/schematics/bundles/{index-42d84d69.js → index-DnkWgagp.js} +56 -60
- package/schematics/bundles/{index-6675d6bc.js → index-vGJcp5M7.js} +5 -5
- package/schematics/bundles/inject-flags.js +181 -0
- package/schematics/bundles/inject-migration.js +122 -128
- package/schematics/bundles/{leading_space-6e7a8ec6.js → leading_space-D9nQ8UQC.js} +2 -2
- package/schematics/bundles/{migrate_ts_type_references-5089e4ef.js → migrate_ts_type_references-DtkOnnv0.js} +113 -120
- package/schematics/bundles/{ng_decorators-6878e227.js → ng_decorators-DznZ5jMl.js} +5 -9
- package/schematics/bundles/{nodes-ffdce442.js → nodes-B16H9JUd.js} +3 -7
- package/schematics/bundles/output-migration.js +40 -46
- package/schematics/bundles/{program-362689f0.js → program-BZk27Ndu.js} +846 -2653
- package/schematics/bundles/{project_paths-7d2daa1e.js → project_paths-Jtbi76Bs.js} +26 -24
- package/schematics/bundles/{project_tsconfig_paths-6c9cde78.js → project_tsconfig_paths-CDVxT6Ov.js} +2 -2
- package/schematics/bundles/{property_name-42030525.js → property_name-BBwFuqMe.js} +4 -8
- package/schematics/bundles/route-lazy-loading.js +36 -42
- package/schematics/bundles/self-closing-tags-migration.js +55 -45
- package/schematics/bundles/signal-input-migration.js +61 -68
- package/schematics/bundles/signal-queries-migration.js +48 -55
- package/schematics/bundles/signals.js +10 -12
- package/schematics/bundles/standalone-migration.js +179 -185
- package/schematics/migrations.json +4 -15
- package/testing/index.d.ts +309 -478
- package/weak_ref.d-ttyj86RV.d.ts +9 -0
- package/schematics/bundles/explicit-standalone-flag.js +0 -184
- package/schematics/bundles/pending-tasks.js +0 -103
- package/schematics/bundles/provide-initializer.js +0 -186
package/fesm2022/testing.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v20.0.0-next.
|
|
3
|
-
* (c) 2010-
|
|
2
|
+
* @license Angular v20.0.0-next.2
|
|
3
|
+
* (c) 2010-2025 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import * as i0 from '@angular/core';
|
|
8
|
-
import { ɵDeferBlockState, ɵtriggerResourceLoading, ɵrenderDeferBlockState, ɵCONTAINER_HEADER_OFFSET, ɵgetDeferBlocks
|
|
8
|
+
import { ɵDeferBlockState as _DeferBlockState, ɵtriggerResourceLoading as _triggerResourceLoading, ɵrenderDeferBlockState as _renderDeferBlockState, ɵCONTAINER_HEADER_OFFSET as _CONTAINER_HEADER_OFFSET, ɵgetDeferBlocks as _getDeferBlocks, InjectionToken, ɵDeferBlockBehavior as _DeferBlockBehavior, inject as inject$1, NgZone, ErrorHandler, Injectable, ɵNoopNgZone as _NoopNgZone, ApplicationRef, ɵPendingTasksInternal as _PendingTasksInternal, ɵZONELESS_ENABLED as _ZONELESS_ENABLED, ɵChangeDetectionScheduler as _ChangeDetectionScheduler, ɵEffectScheduler as _EffectScheduler, getDebugNode, RendererFactory2, ɵstringify as _stringify, Pipe, Directive, Component, NgModule, ɵReflectionCapabilities as _ReflectionCapabilities, ɵUSE_RUNTIME_DEPS_TRACKER_FOR_JIT as _USE_RUNTIME_DEPS_TRACKER_FOR_JIT, ɵdepsTracker as _depsTracker, ɵgetInjectableDef as _getInjectableDef, resolveForwardRef, ɵisComponentDefPendingResolution as _isComponentDefPendingResolution, ɵgetAsyncClassMetadataFn as _getAsyncClassMetadataFn, ɵresolveComponentResources as _resolveComponentResources, ɵRender3NgModuleRef as _Render3NgModuleRef, ApplicationInitStatus, LOCALE_ID, ɵDEFAULT_LOCALE_ID as _DEFAULT_LOCALE_ID, ɵsetLocaleId as _setLocaleId, ɵRender3ComponentFactory as _Render3ComponentFactory, ɵNG_COMP_DEF as _NG_COMP_DEF, ɵcompileComponent as _compileComponent, ɵNG_DIR_DEF as _NG_DIR_DEF, ɵcompileDirective as _compileDirective, ɵNG_PIPE_DEF as _NG_PIPE_DEF, ɵcompilePipe as _compilePipe, ɵNG_MOD_DEF as _NG_MOD_DEF, ɵpatchComponentDefWithScope as _patchComponentDefWithScope, ɵNG_INJ_DEF as _NG_INJ_DEF, ɵcompileNgModuleDefs as _compileNgModuleDefs, ɵclearResolutionOfComponentResourcesQueue as _clearResolutionOfComponentResourcesQueue, ɵrestoreComponentResolutionQueue as _restoreComponentResolutionQueue, ɵinternalProvideZoneChangeDetection as _internalProvideZoneChangeDetection, ɵChangeDetectionSchedulerImpl as _ChangeDetectionSchedulerImpl, Compiler, ɵDEFER_BLOCK_CONFIG as _DEFER_BLOCK_CONFIG, ɵINTERNAL_APPLICATION_ERROR_HANDLER as _INTERNAL_APPLICATION_ERROR_HANDLER, COMPILER_OPTIONS, Injector, ɵtransitiveScopesFor as _transitiveScopesFor, ɵgenerateStandaloneInDeclarationsError as _generateStandaloneInDeclarationsError, ɵNgModuleFactory as _NgModuleFactory, ModuleWithComponentFactories, ɵisEnvironmentProviders as _isEnvironmentProviders, ɵsetAllowDuplicateNgModuleIdsForTest as _setAllowDuplicateNgModuleIdsForTest, ɵresetCompiledComponents as _resetCompiledComponents, ɵsetUnknownElementStrictMode as _setUnknownElementStrictMode, ɵsetUnknownPropertyStrictMode as _setUnknownPropertyStrictMode, ɵgetUnknownElementStrictMode as _getUnknownElementStrictMode, ɵgetUnknownPropertyStrictMode as _getUnknownPropertyStrictMode, runInInjectionContext, EnvironmentInjector, ɵflushModuleScopingQueueAsMuchAsPossible as _flushModuleScopingQueueAsMuchAsPossible } from '@angular/core';
|
|
9
9
|
export { ɵDeferBlockBehavior as DeferBlockBehavior, ɵDeferBlockState as DeferBlockState } from '@angular/core';
|
|
10
10
|
import { Subscription } from 'rxjs';
|
|
11
11
|
import { ResourceLoader } from '@angular/compiler';
|
|
@@ -68,13 +68,13 @@ class DeferBlockFixture {
|
|
|
68
68
|
throw new Error(`Tried to render this defer block in the \`${stateAsString}\` state, ` +
|
|
69
69
|
`but there was no @${stateAsString.toLowerCase()} block defined in a template.`);
|
|
70
70
|
}
|
|
71
|
-
if (state ===
|
|
72
|
-
await
|
|
71
|
+
if (state === _DeferBlockState.Complete) {
|
|
72
|
+
await _triggerResourceLoading(this.block.tDetails, this.block.lView, this.block.tNode);
|
|
73
73
|
}
|
|
74
74
|
// If the `render` method is used explicitly - skip timer-based scheduling for
|
|
75
75
|
// `@placeholder` and `@loading` blocks and render them immediately.
|
|
76
76
|
const skipTimerScheduling = true;
|
|
77
|
-
|
|
77
|
+
_renderDeferBlockState(state, this.block.tNode, this.block.lContainer, skipTimerScheduling);
|
|
78
78
|
this.componentFixture.detectChanges();
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
@@ -87,9 +87,9 @@ class DeferBlockFixture {
|
|
|
87
87
|
// located right after an LContainer header. Get a hold of that view and inspect
|
|
88
88
|
// it for nested defer blocks.
|
|
89
89
|
const deferBlockFixtures = [];
|
|
90
|
-
if (this.block.lContainer.length >=
|
|
91
|
-
const lView = this.block.lContainer[
|
|
92
|
-
|
|
90
|
+
if (this.block.lContainer.length >= _CONTAINER_HEADER_OFFSET) {
|
|
91
|
+
const lView = this.block.lContainer[_CONTAINER_HEADER_OFFSET];
|
|
92
|
+
_getDeferBlocks(lView, deferBlocks);
|
|
93
93
|
for (const block of deferBlocks) {
|
|
94
94
|
deferBlockFixtures.push(new DeferBlockFixture(block, this.componentFixture));
|
|
95
95
|
}
|
|
@@ -99,13 +99,13 @@ class DeferBlockFixture {
|
|
|
99
99
|
}
|
|
100
100
|
function hasStateTemplate(state, block) {
|
|
101
101
|
switch (state) {
|
|
102
|
-
case
|
|
102
|
+
case _DeferBlockState.Placeholder:
|
|
103
103
|
return block.tDetails.placeholderTmplIndex !== null;
|
|
104
|
-
case
|
|
104
|
+
case _DeferBlockState.Loading:
|
|
105
105
|
return block.tDetails.loadingTmplIndex !== null;
|
|
106
|
-
case
|
|
106
|
+
case _DeferBlockState.Error:
|
|
107
107
|
return block.tDetails.errorTmplIndex !== null;
|
|
108
|
-
case
|
|
108
|
+
case _DeferBlockState.Complete:
|
|
109
109
|
return true;
|
|
110
110
|
default:
|
|
111
111
|
return false;
|
|
@@ -113,11 +113,11 @@ function hasStateTemplate(state, block) {
|
|
|
113
113
|
}
|
|
114
114
|
function getDeferBlockStateNameFromEnum(state) {
|
|
115
115
|
switch (state) {
|
|
116
|
-
case
|
|
116
|
+
case _DeferBlockState.Placeholder:
|
|
117
117
|
return 'Placeholder';
|
|
118
|
-
case
|
|
118
|
+
case _DeferBlockState.Loading:
|
|
119
119
|
return 'Loading';
|
|
120
|
-
case
|
|
120
|
+
case _DeferBlockState.Error:
|
|
121
121
|
return 'Error';
|
|
122
122
|
default:
|
|
123
123
|
return 'Main';
|
|
@@ -131,7 +131,7 @@ const THROW_ON_UNKNOWN_ELEMENTS_DEFAULT = false;
|
|
|
131
131
|
/** Whether unknown properties in templates should throw by default. */
|
|
132
132
|
const THROW_ON_UNKNOWN_PROPERTIES_DEFAULT = false;
|
|
133
133
|
/** Whether defer blocks should use manual triggering or play through normally. */
|
|
134
|
-
const DEFER_BLOCK_DEFAULT_BEHAVIOR =
|
|
134
|
+
const DEFER_BLOCK_DEFAULT_BEHAVIOR = _DeferBlockBehavior.Playthrough;
|
|
135
135
|
/**
|
|
136
136
|
* An abstract class for inserting the root test component element in a platform independent way.
|
|
137
137
|
*
|
|
@@ -175,12 +175,12 @@ class TestBedApplicationErrorHandler {
|
|
|
175
175
|
throw e;
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
|
-
static ɵfac =
|
|
179
|
-
static ɵprov = i0.ɵɵ
|
|
178
|
+
static ɵfac = function TestBedApplicationErrorHandler_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TestBedApplicationErrorHandler)(); };
|
|
179
|
+
static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: TestBedApplicationErrorHandler, factory: TestBedApplicationErrorHandler.ɵfac });
|
|
180
180
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
181
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TestBedApplicationErrorHandler, [{
|
|
182
|
+
type: Injectable
|
|
183
|
+
}], null, null); })();
|
|
184
184
|
|
|
185
185
|
/**
|
|
186
186
|
* Fixture for debugging and testing a component.
|
|
@@ -214,7 +214,7 @@ class ComponentFixture {
|
|
|
214
214
|
/** @internal */
|
|
215
215
|
_noZoneOptionIsSet = inject$1(ComponentFixtureNoNgZone, { optional: true });
|
|
216
216
|
/** @internal */
|
|
217
|
-
_ngZone = this._noZoneOptionIsSet ? new
|
|
217
|
+
_ngZone = this._noZoneOptionIsSet ? new _NoopNgZone() : inject$1(NgZone);
|
|
218
218
|
// Inject ApplicationRef to ensure NgZone stableness causes after render hooks to run
|
|
219
219
|
// This will likely happen as a result of fixture.detectChanges because it calls ngZone.run
|
|
220
220
|
// This is a crazy way of doing things but hey, it's the world we live in.
|
|
@@ -224,12 +224,11 @@ class ComponentFixture {
|
|
|
224
224
|
/** @internal */
|
|
225
225
|
_appRef = inject$1(ApplicationRef);
|
|
226
226
|
_testAppRef = this._appRef;
|
|
227
|
-
pendingTasks = inject$1(
|
|
227
|
+
pendingTasks = inject$1(_PendingTasksInternal);
|
|
228
228
|
appErrorHandler = inject$1(TestBedApplicationErrorHandler);
|
|
229
|
-
zonelessEnabled = inject$1(
|
|
230
|
-
scheduler = inject$1(
|
|
231
|
-
rootEffectScheduler = inject$1(
|
|
232
|
-
microtaskEffectScheduler = inject$1(ɵMicrotaskEffectScheduler);
|
|
229
|
+
zonelessEnabled = inject$1(_ZONELESS_ENABLED);
|
|
230
|
+
scheduler = inject$1(_ChangeDetectionScheduler);
|
|
231
|
+
rootEffectScheduler = inject$1(_EffectScheduler);
|
|
233
232
|
autoDetectDefault = this.zonelessEnabled ? true : false;
|
|
234
233
|
autoDetect = inject$1(ComponentFixtureAutoDetect, { optional: true }) ?? this.autoDetectDefault;
|
|
235
234
|
subscriptions = new Subscription();
|
|
@@ -277,7 +276,6 @@ class ComponentFixture {
|
|
|
277
276
|
* Trigger a change detection cycle for the component.
|
|
278
277
|
*/
|
|
279
278
|
detectChanges(checkNoChanges = true) {
|
|
280
|
-
this.microtaskEffectScheduler.flush();
|
|
281
279
|
const originalCheckNoChanges = this.componentRef.changeDetectorRef.checkNoChanges;
|
|
282
280
|
try {
|
|
283
281
|
if (!checkNoChanges) {
|
|
@@ -308,7 +306,6 @@ class ComponentFixture {
|
|
|
308
306
|
finally {
|
|
309
307
|
this.componentRef.changeDetectorRef.checkNoChanges = originalCheckNoChanges;
|
|
310
308
|
}
|
|
311
|
-
this.microtaskEffectScheduler.flush();
|
|
312
309
|
}
|
|
313
310
|
/**
|
|
314
311
|
* Do a change detection run to make sure there were no changes.
|
|
@@ -369,7 +366,7 @@ class ComponentFixture {
|
|
|
369
366
|
getDeferBlocks() {
|
|
370
367
|
const deferBlocks = [];
|
|
371
368
|
const lView = this.componentRef.hostView['_lView'];
|
|
372
|
-
|
|
369
|
+
_getDeferBlocks(lView, deferBlocks);
|
|
373
370
|
const deferBlockFixtures = [];
|
|
374
371
|
for (const block of deferBlocks) {
|
|
375
372
|
deferBlockFixtures.push(new DeferBlockFixture(block, this));
|
|
@@ -582,7 +579,7 @@ class MetadataOverrider {
|
|
|
582
579
|
}
|
|
583
580
|
if (override.set) {
|
|
584
581
|
if (override.remove || override.add) {
|
|
585
|
-
throw new Error(`Cannot set and add/remove ${
|
|
582
|
+
throw new Error(`Cannot set and add/remove ${_stringify(metadataClass)} at the same time!`);
|
|
586
583
|
}
|
|
587
584
|
setMetadata(props, override.set);
|
|
588
585
|
}
|
|
@@ -661,7 +658,7 @@ function _propHashKey(propName, propValue, references) {
|
|
|
661
658
|
function _serializeReference(ref, references) {
|
|
662
659
|
let id = references.get(ref);
|
|
663
660
|
if (!id) {
|
|
664
|
-
id = `${
|
|
661
|
+
id = `${_stringify(ref)}${_nextReferenceId++}`;
|
|
665
662
|
references.set(ref, id);
|
|
666
663
|
}
|
|
667
664
|
return id;
|
|
@@ -687,7 +684,7 @@ function _valueProps(obj) {
|
|
|
687
684
|
return props;
|
|
688
685
|
}
|
|
689
686
|
|
|
690
|
-
const reflection = new
|
|
687
|
+
const reflection = new _ReflectionCapabilities();
|
|
691
688
|
/**
|
|
692
689
|
* Allows to override ivy metadata for tests (via the `TestBed`).
|
|
693
690
|
*/
|
|
@@ -774,10 +771,10 @@ function isTestingModuleOverride(value) {
|
|
|
774
771
|
}
|
|
775
772
|
function assertNoStandaloneComponents(types, resolver, location) {
|
|
776
773
|
types.forEach((type) => {
|
|
777
|
-
if (
|
|
774
|
+
if (!_getAsyncClassMetadataFn(type)) {
|
|
778
775
|
const component = resolver.resolve(type);
|
|
779
776
|
if (component && (component.standalone == null || component.standalone)) {
|
|
780
|
-
throw new Error(
|
|
777
|
+
throw new Error(_generateStandaloneInDeclarationsError(type, location));
|
|
781
778
|
}
|
|
782
779
|
}
|
|
783
780
|
});
|
|
@@ -872,8 +869,8 @@ class TestBedCompiler {
|
|
|
872
869
|
moduleDef.rethrowApplicationErrors ?? RETHROW_APPLICATION_ERRORS_DEFAULT;
|
|
873
870
|
}
|
|
874
871
|
overrideModule(ngModule, override) {
|
|
875
|
-
if (
|
|
876
|
-
|
|
872
|
+
if (_USE_RUNTIME_DEPS_TRACKER_FOR_JIT) {
|
|
873
|
+
_depsTracker.clearScopeCacheFor(ngModule);
|
|
877
874
|
}
|
|
878
875
|
this.overriddenModules.add(ngModule);
|
|
879
876
|
// Compile the module right away.
|
|
@@ -930,7 +927,7 @@ class TestBedCompiler {
|
|
|
930
927
|
else {
|
|
931
928
|
providerDef = { provide: token };
|
|
932
929
|
}
|
|
933
|
-
const injectableDef = typeof token !== 'string' ?
|
|
930
|
+
const injectableDef = typeof token !== 'string' ? _getInjectableDef(token) : null;
|
|
934
931
|
const providedIn = injectableDef === null ? null : resolveForwardRef(injectableDef.providedIn);
|
|
935
932
|
const overridesBucket = providedIn === 'root' ? this.rootProviderOverrides : this.providerOverrides;
|
|
936
933
|
overridesBucket.push(providerDef);
|
|
@@ -947,12 +944,12 @@ class TestBedCompiler {
|
|
|
947
944
|
}
|
|
948
945
|
}
|
|
949
946
|
overrideTemplateUsingTestingModule(type, template) {
|
|
950
|
-
const def = type[
|
|
947
|
+
const def = type[_NG_COMP_DEF];
|
|
951
948
|
const hasStyleUrls = () => {
|
|
952
949
|
const metadata = this.resolvers.component.resolve(type);
|
|
953
950
|
return !!metadata.styleUrl || !!metadata.styleUrls?.length;
|
|
954
951
|
};
|
|
955
|
-
const overrideStyleUrls = !!def &&
|
|
952
|
+
const overrideStyleUrls = !!def && !_isComponentDefPendingResolution(type) && hasStyleUrls();
|
|
956
953
|
// In Ivy, compiling a component does not require knowing the module providing the
|
|
957
954
|
// component's scope, so overrideTemplateUsingTestingModule can be implemented purely via
|
|
958
955
|
// overrideComponent. Important: overriding template requires full Component re-compilation,
|
|
@@ -975,7 +972,7 @@ class TestBedCompiler {
|
|
|
975
972
|
return;
|
|
976
973
|
const promises = [];
|
|
977
974
|
for (const component of this.componentsWithAsyncMetadata) {
|
|
978
|
-
const asyncMetadataFn =
|
|
975
|
+
const asyncMetadataFn = _getAsyncClassMetadataFn(component);
|
|
979
976
|
if (asyncMetadataFn) {
|
|
980
977
|
promises.push(asyncMetadataFn());
|
|
981
978
|
}
|
|
@@ -1012,7 +1009,7 @@ class TestBedCompiler {
|
|
|
1012
1009
|
}
|
|
1013
1010
|
return Promise.resolve(resourceLoader.get(url));
|
|
1014
1011
|
};
|
|
1015
|
-
await
|
|
1012
|
+
await _resolveComponentResources(resolver);
|
|
1016
1013
|
}
|
|
1017
1014
|
}
|
|
1018
1015
|
finalize() {
|
|
@@ -1029,15 +1026,15 @@ class TestBedCompiler {
|
|
|
1029
1026
|
// every component.
|
|
1030
1027
|
this.componentToModuleScope.clear();
|
|
1031
1028
|
const parentInjector = this.platform.injector;
|
|
1032
|
-
this.testModuleRef = new
|
|
1029
|
+
this.testModuleRef = new _Render3NgModuleRef(this.testModuleType, parentInjector, []);
|
|
1033
1030
|
// ApplicationInitStatus.runInitializers() is marked @internal to core.
|
|
1034
1031
|
// Cast it to any before accessing it.
|
|
1035
1032
|
this.testModuleRef.injector.get(ApplicationInitStatus).runInitializers();
|
|
1036
1033
|
// Set locale ID after running app initializers, since locale information might be updated while
|
|
1037
1034
|
// running initializers. This is also consistent with the execution order while bootstrapping an
|
|
1038
1035
|
// app (see `packages/core/src/application_ref.ts` file).
|
|
1039
|
-
const localeId = this.testModuleRef.injector.get(LOCALE_ID,
|
|
1040
|
-
|
|
1036
|
+
const localeId = this.testModuleRef.injector.get(LOCALE_ID, _DEFAULT_LOCALE_ID);
|
|
1037
|
+
_setLocaleId(localeId);
|
|
1041
1038
|
return this.testModuleRef;
|
|
1042
1039
|
}
|
|
1043
1040
|
/**
|
|
@@ -1072,7 +1069,7 @@ class TestBedCompiler {
|
|
|
1072
1069
|
_getComponentFactories(moduleType) {
|
|
1073
1070
|
return maybeUnwrapFn(moduleType.ɵmod.declarations).reduce((factories, declaration) => {
|
|
1074
1071
|
const componentDef = declaration.ɵcmp;
|
|
1075
|
-
componentDef && factories.push(new
|
|
1072
|
+
componentDef && factories.push(new _Render3ComponentFactory(componentDef, this.testModuleRef));
|
|
1076
1073
|
return factories;
|
|
1077
1074
|
}, []);
|
|
1078
1075
|
}
|
|
@@ -1080,20 +1077,20 @@ class TestBedCompiler {
|
|
|
1080
1077
|
// Compile all queued components, directives, pipes.
|
|
1081
1078
|
let needsAsyncResources = false;
|
|
1082
1079
|
this.pendingComponents.forEach((declaration) => {
|
|
1083
|
-
if (
|
|
1080
|
+
if (_getAsyncClassMetadataFn(declaration)) {
|
|
1084
1081
|
throw new Error(`Component '${declaration.name}' has unresolved metadata. ` +
|
|
1085
1082
|
`Please call \`await TestBed.compileComponents()\` before running this test.`);
|
|
1086
1083
|
}
|
|
1087
|
-
needsAsyncResources = needsAsyncResources ||
|
|
1084
|
+
needsAsyncResources = needsAsyncResources || _isComponentDefPendingResolution(declaration);
|
|
1088
1085
|
const metadata = this.resolvers.component.resolve(declaration);
|
|
1089
1086
|
if (metadata === null) {
|
|
1090
1087
|
throw invalidTypeError(declaration.name, 'Component');
|
|
1091
1088
|
}
|
|
1092
|
-
this.maybeStoreNgDef(
|
|
1093
|
-
if (
|
|
1094
|
-
|
|
1089
|
+
this.maybeStoreNgDef(_NG_COMP_DEF, declaration);
|
|
1090
|
+
if (_USE_RUNTIME_DEPS_TRACKER_FOR_JIT) {
|
|
1091
|
+
_depsTracker.clearScopeCacheFor(declaration);
|
|
1095
1092
|
}
|
|
1096
|
-
|
|
1093
|
+
_compileComponent(declaration, metadata);
|
|
1097
1094
|
});
|
|
1098
1095
|
this.pendingComponents.clear();
|
|
1099
1096
|
this.pendingDirectives.forEach((declaration) => {
|
|
@@ -1101,8 +1098,8 @@ class TestBedCompiler {
|
|
|
1101
1098
|
if (metadata === null) {
|
|
1102
1099
|
throw invalidTypeError(declaration.name, 'Directive');
|
|
1103
1100
|
}
|
|
1104
|
-
this.maybeStoreNgDef(
|
|
1105
|
-
|
|
1101
|
+
this.maybeStoreNgDef(_NG_DIR_DEF, declaration);
|
|
1102
|
+
_compileDirective(declaration, metadata);
|
|
1106
1103
|
});
|
|
1107
1104
|
this.pendingDirectives.clear();
|
|
1108
1105
|
this.pendingPipes.forEach((declaration) => {
|
|
@@ -1110,8 +1107,8 @@ class TestBedCompiler {
|
|
|
1110
1107
|
if (metadata === null) {
|
|
1111
1108
|
throw invalidTypeError(declaration.name, 'Pipe');
|
|
1112
1109
|
}
|
|
1113
|
-
this.maybeStoreNgDef(
|
|
1114
|
-
|
|
1110
|
+
this.maybeStoreNgDef(_NG_PIPE_DEF, declaration);
|
|
1111
|
+
_compilePipe(declaration, metadata);
|
|
1115
1112
|
});
|
|
1116
1113
|
this.pendingPipes.clear();
|
|
1117
1114
|
return needsAsyncResources;
|
|
@@ -1121,16 +1118,16 @@ class TestBedCompiler {
|
|
|
1121
1118
|
// Module overrides (via `TestBed.overrideModule`) might affect scopes that were previously
|
|
1122
1119
|
// calculated and stored in `transitiveCompileScopes`. If module overrides are present,
|
|
1123
1120
|
// collect all affected modules and reset scopes to force their re-calculation.
|
|
1124
|
-
const testingModuleDef = this.testModuleType[
|
|
1121
|
+
const testingModuleDef = this.testModuleType[_NG_MOD_DEF];
|
|
1125
1122
|
const affectedModules = this.collectModulesAffectedByOverrides(testingModuleDef.imports);
|
|
1126
1123
|
if (affectedModules.size > 0) {
|
|
1127
1124
|
affectedModules.forEach((moduleType) => {
|
|
1128
|
-
if (
|
|
1129
|
-
this.storeFieldOfDefOnType(moduleType,
|
|
1130
|
-
moduleType[
|
|
1125
|
+
if (!_USE_RUNTIME_DEPS_TRACKER_FOR_JIT) {
|
|
1126
|
+
this.storeFieldOfDefOnType(moduleType, _NG_MOD_DEF, 'transitiveCompileScopes');
|
|
1127
|
+
moduleType[_NG_MOD_DEF].transitiveCompileScopes = null;
|
|
1131
1128
|
}
|
|
1132
1129
|
else {
|
|
1133
|
-
|
|
1130
|
+
_depsTracker.clearScopeCacheFor(moduleType);
|
|
1134
1131
|
}
|
|
1135
1132
|
});
|
|
1136
1133
|
}
|
|
@@ -1140,16 +1137,16 @@ class TestBedCompiler {
|
|
|
1140
1137
|
if (!moduleToScope.has(moduleType)) {
|
|
1141
1138
|
const isTestingModule = isTestingModuleOverride(moduleType);
|
|
1142
1139
|
const realType = isTestingModule ? this.testModuleType : moduleType;
|
|
1143
|
-
moduleToScope.set(moduleType,
|
|
1140
|
+
moduleToScope.set(moduleType, _transitiveScopesFor(realType));
|
|
1144
1141
|
}
|
|
1145
1142
|
return moduleToScope.get(moduleType);
|
|
1146
1143
|
};
|
|
1147
1144
|
this.componentToModuleScope.forEach((moduleType, componentType) => {
|
|
1148
1145
|
if (moduleType !== null) {
|
|
1149
1146
|
const moduleScope = getScopeOfModule(moduleType);
|
|
1150
|
-
this.storeFieldOfDefOnType(componentType,
|
|
1151
|
-
this.storeFieldOfDefOnType(componentType,
|
|
1152
|
-
|
|
1147
|
+
this.storeFieldOfDefOnType(componentType, _NG_COMP_DEF, 'directiveDefs');
|
|
1148
|
+
this.storeFieldOfDefOnType(componentType, _NG_COMP_DEF, 'pipeDefs');
|
|
1149
|
+
_patchComponentDefWithScope(getComponentDef(componentType), moduleScope);
|
|
1153
1150
|
}
|
|
1154
1151
|
// `tView` that is stored on component def contains information about directives and pipes
|
|
1155
1152
|
// that are in the scope of this component. Patching component scope will cause `tView` to be
|
|
@@ -1158,20 +1155,20 @@ class TestBedCompiler {
|
|
|
1158
1155
|
// Resetting `tView` is also needed for cases when we apply provider overrides and those
|
|
1159
1156
|
// providers are defined on component's level, in which case they may end up included into
|
|
1160
1157
|
// `tView.blueprint`.
|
|
1161
|
-
this.storeFieldOfDefOnType(componentType,
|
|
1158
|
+
this.storeFieldOfDefOnType(componentType, _NG_COMP_DEF, 'tView');
|
|
1162
1159
|
});
|
|
1163
1160
|
this.componentToModuleScope.clear();
|
|
1164
1161
|
}
|
|
1165
1162
|
applyProviderOverrides() {
|
|
1166
1163
|
const maybeApplyOverrides = (field) => (type) => {
|
|
1167
|
-
const resolver = field ===
|
|
1164
|
+
const resolver = field === _NG_COMP_DEF ? this.resolvers.component : this.resolvers.directive;
|
|
1168
1165
|
const metadata = resolver.resolve(type);
|
|
1169
1166
|
if (this.hasProviderOverrides(metadata.providers)) {
|
|
1170
1167
|
this.patchDefWithProviderOverrides(type, field);
|
|
1171
1168
|
}
|
|
1172
1169
|
};
|
|
1173
|
-
this.seenComponents.forEach(maybeApplyOverrides(
|
|
1174
|
-
this.seenDirectives.forEach(maybeApplyOverrides(
|
|
1170
|
+
this.seenComponents.forEach(maybeApplyOverrides(_NG_COMP_DEF));
|
|
1171
|
+
this.seenDirectives.forEach(maybeApplyOverrides(_NG_DIR_DEF));
|
|
1175
1172
|
this.seenComponents.clear();
|
|
1176
1173
|
this.seenDirectives.clear();
|
|
1177
1174
|
}
|
|
@@ -1194,7 +1191,7 @@ class TestBedCompiler {
|
|
|
1194
1191
|
// detailed error messages. The fact that the code relies on this line being
|
|
1195
1192
|
// present here is suspicious and should be refactored in a way that the line
|
|
1196
1193
|
// below can be moved (for ex. after an early exit check below).
|
|
1197
|
-
const injectorDef = type[
|
|
1194
|
+
const injectorDef = type[_NG_INJ_DEF];
|
|
1198
1195
|
// No provider overrides, exit early.
|
|
1199
1196
|
if (this.providerOverridesByToken.size === 0)
|
|
1200
1197
|
return;
|
|
@@ -1212,12 +1209,12 @@ class TestBedCompiler {
|
|
|
1212
1209
|
...(this.providerOverridesByModule.get(type) || []),
|
|
1213
1210
|
];
|
|
1214
1211
|
if (this.hasProviderOverrides(providers)) {
|
|
1215
|
-
this.maybeStoreNgDef(
|
|
1216
|
-
this.storeFieldOfDefOnType(type,
|
|
1212
|
+
this.maybeStoreNgDef(_NG_INJ_DEF, type);
|
|
1213
|
+
this.storeFieldOfDefOnType(type, _NG_INJ_DEF, 'providers');
|
|
1217
1214
|
injectorDef.providers = this.getOverriddenProviders(providers);
|
|
1218
1215
|
}
|
|
1219
1216
|
// Apply provider overrides to imported modules recursively
|
|
1220
|
-
const moduleDef = type[
|
|
1217
|
+
const moduleDef = type[_NG_MOD_DEF];
|
|
1221
1218
|
const imports = maybeUnwrapFn(moduleDef.imports);
|
|
1222
1219
|
for (const importedModule of imports) {
|
|
1223
1220
|
this.applyProviderOverridesInScope(importedModule);
|
|
@@ -1237,7 +1234,7 @@ class TestBedCompiler {
|
|
|
1237
1234
|
}
|
|
1238
1235
|
}
|
|
1239
1236
|
patchComponentsWithExistingStyles() {
|
|
1240
|
-
this.existingComponentStyles.forEach((styles, type) => (type[
|
|
1237
|
+
this.existingComponentStyles.forEach((styles, type) => (type[_NG_COMP_DEF].styles = styles));
|
|
1241
1238
|
this.existingComponentStyles.clear();
|
|
1242
1239
|
}
|
|
1243
1240
|
queueTypeArray(arr, moduleType) {
|
|
@@ -1252,12 +1249,12 @@ class TestBedCompiler {
|
|
|
1252
1249
|
}
|
|
1253
1250
|
recompileNgModule(ngModule, metadata) {
|
|
1254
1251
|
// Cache the initial ngModuleDef as it will be overwritten.
|
|
1255
|
-
this.maybeStoreNgDef(
|
|
1256
|
-
this.maybeStoreNgDef(
|
|
1257
|
-
|
|
1252
|
+
this.maybeStoreNgDef(_NG_MOD_DEF, ngModule);
|
|
1253
|
+
this.maybeStoreNgDef(_NG_INJ_DEF, ngModule);
|
|
1254
|
+
_compileNgModuleDefs(ngModule, metadata);
|
|
1258
1255
|
}
|
|
1259
1256
|
maybeRegisterComponentWithAsyncMetadata(type) {
|
|
1260
|
-
const asyncMetadataFn =
|
|
1257
|
+
const asyncMetadataFn = _getAsyncClassMetadataFn(type);
|
|
1261
1258
|
if (asyncMetadataFn) {
|
|
1262
1259
|
this.componentsWithAsyncMetadata.add(type);
|
|
1263
1260
|
}
|
|
@@ -1271,7 +1268,7 @@ class TestBedCompiler {
|
|
|
1271
1268
|
// Check whether a give Type has respective NG def (ɵcmp) and compile if def is
|
|
1272
1269
|
// missing. That might happen in case a class without any Angular decorators extends another
|
|
1273
1270
|
// class where Component/Directive/Pipe decorator is defined.
|
|
1274
|
-
if (
|
|
1271
|
+
if (_isComponentDefPendingResolution(type) || !type.hasOwnProperty(_NG_COMP_DEF)) {
|
|
1275
1272
|
this.pendingComponents.add(type);
|
|
1276
1273
|
}
|
|
1277
1274
|
this.seenComponents.add(type);
|
|
@@ -1298,14 +1295,14 @@ class TestBedCompiler {
|
|
|
1298
1295
|
}
|
|
1299
1296
|
const directive = this.resolvers.directive.resolve(type);
|
|
1300
1297
|
if (directive) {
|
|
1301
|
-
if (!type.hasOwnProperty(
|
|
1298
|
+
if (!type.hasOwnProperty(_NG_DIR_DEF)) {
|
|
1302
1299
|
this.pendingDirectives.add(type);
|
|
1303
1300
|
}
|
|
1304
1301
|
this.seenDirectives.add(type);
|
|
1305
1302
|
return;
|
|
1306
1303
|
}
|
|
1307
1304
|
const pipe = this.resolvers.pipe.resolve(type);
|
|
1308
|
-
if (pipe && !type.hasOwnProperty(
|
|
1305
|
+
if (pipe && !type.hasOwnProperty(_NG_PIPE_DEF)) {
|
|
1309
1306
|
this.pendingPipes.add(type);
|
|
1310
1307
|
return;
|
|
1311
1308
|
}
|
|
@@ -1393,7 +1390,7 @@ class TestBedCompiler {
|
|
|
1393
1390
|
path.forEach((item) => affectedModules.add(item));
|
|
1394
1391
|
}
|
|
1395
1392
|
// Examine module imports recursively to look for overridden modules.
|
|
1396
|
-
const moduleDef = value[
|
|
1393
|
+
const moduleDef = value[_NG_MOD_DEF];
|
|
1397
1394
|
calcAffectedModulesRecur(maybeUnwrapFn(moduleDef.imports), path.concat(value));
|
|
1398
1395
|
}
|
|
1399
1396
|
}
|
|
@@ -1431,7 +1428,7 @@ class TestBedCompiler {
|
|
|
1431
1428
|
if (this.originalComponentResolutionQueue === null) {
|
|
1432
1429
|
this.originalComponentResolutionQueue = new Map();
|
|
1433
1430
|
}
|
|
1434
|
-
|
|
1431
|
+
_clearResolutionOfComponentResourcesQueue().forEach((value, key) => this.originalComponentResolutionQueue.set(key, value));
|
|
1435
1432
|
}
|
|
1436
1433
|
/*
|
|
1437
1434
|
* Restores component resolution queue to the previously saved state. This operation is performed
|
|
@@ -1440,7 +1437,7 @@ class TestBedCompiler {
|
|
|
1440
1437
|
*/
|
|
1441
1438
|
restoreComponentResolutionQueue() {
|
|
1442
1439
|
if (this.originalComponentResolutionQueue !== null) {
|
|
1443
|
-
|
|
1440
|
+
_restoreComponentResolutionQueue(this.originalComponentResolutionQueue);
|
|
1444
1441
|
this.originalComponentResolutionQueue = null;
|
|
1445
1442
|
}
|
|
1446
1443
|
}
|
|
@@ -1452,8 +1449,8 @@ class TestBedCompiler {
|
|
|
1452
1449
|
});
|
|
1453
1450
|
// Restore initial component/directive/pipe defs
|
|
1454
1451
|
this.initialNgDefs.forEach((defs, type) => {
|
|
1455
|
-
if (
|
|
1456
|
-
|
|
1452
|
+
if (_USE_RUNTIME_DEPS_TRACKER_FOR_JIT) {
|
|
1453
|
+
_depsTracker.clearScopeCacheFor(type);
|
|
1457
1454
|
}
|
|
1458
1455
|
defs.forEach((descriptor, prop) => {
|
|
1459
1456
|
if (!descriptor) {
|
|
@@ -1474,24 +1471,24 @@ class TestBedCompiler {
|
|
|
1474
1471
|
this.scopesWithOverriddenProviders.clear();
|
|
1475
1472
|
this.restoreComponentResolutionQueue();
|
|
1476
1473
|
// Restore the locale ID to the default value, this shouldn't be necessary but we never know
|
|
1477
|
-
|
|
1474
|
+
_setLocaleId(_DEFAULT_LOCALE_ID);
|
|
1478
1475
|
}
|
|
1479
1476
|
compileTestModule() {
|
|
1480
1477
|
class RootScopeModule {
|
|
1481
1478
|
}
|
|
1482
|
-
|
|
1479
|
+
_compileNgModuleDefs(RootScopeModule, {
|
|
1483
1480
|
providers: [
|
|
1484
1481
|
...this.rootProviderOverrides,
|
|
1485
|
-
|
|
1482
|
+
_internalProvideZoneChangeDetection({}),
|
|
1486
1483
|
TestBedApplicationErrorHandler,
|
|
1487
|
-
{ provide:
|
|
1484
|
+
{ provide: _ChangeDetectionScheduler, useExisting: _ChangeDetectionSchedulerImpl },
|
|
1488
1485
|
],
|
|
1489
1486
|
});
|
|
1490
1487
|
const providers = [
|
|
1491
1488
|
{ provide: Compiler, useFactory: () => new R3TestCompiler(this) },
|
|
1492
|
-
{ provide:
|
|
1489
|
+
{ provide: _DEFER_BLOCK_CONFIG, useValue: { behavior: this.deferBlockBehavior } },
|
|
1493
1490
|
{
|
|
1494
|
-
provide:
|
|
1491
|
+
provide: _INTERNAL_APPLICATION_ERROR_HANDLER,
|
|
1495
1492
|
useFactory: () => {
|
|
1496
1493
|
if (this.rethrowApplicationTickErrors) {
|
|
1497
1494
|
const handler = inject$1(TestBedApplicationErrorHandler);
|
|
@@ -1510,7 +1507,7 @@ class TestBedCompiler {
|
|
|
1510
1507
|
...this.providerOverrides,
|
|
1511
1508
|
];
|
|
1512
1509
|
const imports = [RootScopeModule, this.additionalModuleTypes, this.imports || []];
|
|
1513
|
-
|
|
1510
|
+
_compileNgModuleDefs(this.testModuleType, {
|
|
1514
1511
|
declarations: this.declarations,
|
|
1515
1512
|
imports,
|
|
1516
1513
|
schemas: this.schemas,
|
|
@@ -1636,7 +1633,7 @@ function identityFn(value) {
|
|
|
1636
1633
|
function flattenProviders(providers, mapFn = identityFn) {
|
|
1637
1634
|
const out = [];
|
|
1638
1635
|
for (let provider of providers) {
|
|
1639
|
-
if (
|
|
1636
|
+
if (_isEnvironmentProviders(provider)) {
|
|
1640
1637
|
provider = provider.ɵproviders;
|
|
1641
1638
|
}
|
|
1642
1639
|
if (Array.isArray(provider)) {
|
|
@@ -1672,11 +1669,11 @@ class R3TestCompiler {
|
|
|
1672
1669
|
}
|
|
1673
1670
|
compileModuleSync(moduleType) {
|
|
1674
1671
|
this.testBed._compileNgModuleSync(moduleType);
|
|
1675
|
-
return new
|
|
1672
|
+
return new _NgModuleFactory(moduleType);
|
|
1676
1673
|
}
|
|
1677
1674
|
async compileModuleAsync(moduleType) {
|
|
1678
1675
|
await this.testBed._compileNgModuleAsync(moduleType);
|
|
1679
|
-
return new
|
|
1676
|
+
return new _NgModuleFactory(moduleType);
|
|
1680
1677
|
}
|
|
1681
1678
|
compileModuleAndAllComponentsSync(moduleType) {
|
|
1682
1679
|
const ngModuleFactory = this.compileModuleSync(moduleType);
|
|
@@ -1697,6 +1694,8 @@ class R3TestCompiler {
|
|
|
1697
1694
|
}
|
|
1698
1695
|
|
|
1699
1696
|
// The formatter and CI disagree on how this import statement should be formatted. Both try to keep
|
|
1697
|
+
// it on one line, too, which has gotten very hard to read & manage. So disable the formatter for
|
|
1698
|
+
// this statement only.
|
|
1700
1699
|
let _nextRootElementId = 0;
|
|
1701
1700
|
/**
|
|
1702
1701
|
* Returns a singleton of the `TestBed` class.
|
|
@@ -1834,12 +1833,12 @@ class TestBedImpl {
|
|
|
1834
1833
|
static overrideProvider(token, provider) {
|
|
1835
1834
|
return TestBedImpl.INSTANCE.overrideProvider(token, provider);
|
|
1836
1835
|
}
|
|
1837
|
-
static inject(token, notFoundValue,
|
|
1838
|
-
return TestBedImpl.INSTANCE.inject(token, notFoundValue,
|
|
1836
|
+
static inject(token, notFoundValue, options) {
|
|
1837
|
+
return TestBedImpl.INSTANCE.inject(token, notFoundValue, options);
|
|
1839
1838
|
}
|
|
1840
1839
|
/** @deprecated from v9.0.0 use TestBed.inject */
|
|
1841
|
-
static get(token, notFoundValue = Injector.THROW_IF_NOT_FOUND,
|
|
1842
|
-
return TestBedImpl.INSTANCE.inject(token, notFoundValue,
|
|
1840
|
+
static get(token, notFoundValue = Injector.THROW_IF_NOT_FOUND, options) {
|
|
1841
|
+
return TestBedImpl.INSTANCE.inject(token, notFoundValue, options);
|
|
1843
1842
|
}
|
|
1844
1843
|
/**
|
|
1845
1844
|
* Runs the given function in the `EnvironmentInjector` context of `TestBed`.
|
|
@@ -1906,7 +1905,7 @@ class TestBedImpl {
|
|
|
1906
1905
|
// used to track the state of the NgModule registry and reset it correctly. Instead, when we
|
|
1907
1906
|
// know we're in a testing scenario, we disable the check for duplicate NgModule registration
|
|
1908
1907
|
// completely.
|
|
1909
|
-
|
|
1908
|
+
_setAllowDuplicateNgModuleIdsForTest(true);
|
|
1910
1909
|
}
|
|
1911
1910
|
/**
|
|
1912
1911
|
* Reset the providers for the test injector.
|
|
@@ -1919,19 +1918,19 @@ class TestBedImpl {
|
|
|
1919
1918
|
this.platform = null;
|
|
1920
1919
|
this.ngModule = null;
|
|
1921
1920
|
TestBedImpl._environmentTeardownOptions = undefined;
|
|
1922
|
-
|
|
1921
|
+
_setAllowDuplicateNgModuleIdsForTest(false);
|
|
1923
1922
|
}
|
|
1924
1923
|
resetTestingModule() {
|
|
1925
1924
|
this.checkGlobalCompilationFinished();
|
|
1926
|
-
|
|
1925
|
+
_resetCompiledComponents();
|
|
1927
1926
|
if (this._compiler !== null) {
|
|
1928
1927
|
this.compiler.restoreOriginalState();
|
|
1929
1928
|
}
|
|
1930
1929
|
this._compiler = new TestBedCompiler(this.platform, this.ngModule);
|
|
1931
1930
|
// Restore the previous value of the "error on unknown elements" option
|
|
1932
|
-
|
|
1931
|
+
_setUnknownElementStrictMode(this._previousErrorOnUnknownElementsOption ?? THROW_ON_UNKNOWN_ELEMENTS_DEFAULT);
|
|
1933
1932
|
// Restore the previous value of the "error on unknown properties" option
|
|
1934
|
-
|
|
1933
|
+
_setUnknownPropertyStrictMode(this._previousErrorOnUnknownPropertiesOption ?? THROW_ON_UNKNOWN_PROPERTIES_DEFAULT);
|
|
1935
1934
|
// We have to chain a couple of try/finally blocks, because each step can
|
|
1936
1935
|
// throw errors and we don't want it to interrupt the next step and we also
|
|
1937
1936
|
// want an error to be thrown at the end.
|
|
@@ -1978,29 +1977,29 @@ class TestBedImpl {
|
|
|
1978
1977
|
this._instanceDeferBlockBehavior = moduleDef.deferBlockBehavior ?? DEFER_BLOCK_DEFAULT_BEHAVIOR;
|
|
1979
1978
|
// Store the current value of the strict mode option,
|
|
1980
1979
|
// so we can restore it later
|
|
1981
|
-
this._previousErrorOnUnknownElementsOption =
|
|
1982
|
-
|
|
1983
|
-
this._previousErrorOnUnknownPropertiesOption =
|
|
1984
|
-
|
|
1980
|
+
this._previousErrorOnUnknownElementsOption = _getUnknownElementStrictMode();
|
|
1981
|
+
_setUnknownElementStrictMode(this.shouldThrowErrorOnUnknownElements());
|
|
1982
|
+
this._previousErrorOnUnknownPropertiesOption = _getUnknownPropertyStrictMode();
|
|
1983
|
+
_setUnknownPropertyStrictMode(this.shouldThrowErrorOnUnknownProperties());
|
|
1985
1984
|
this.compiler.configureTestingModule(moduleDef);
|
|
1986
1985
|
return this;
|
|
1987
1986
|
}
|
|
1988
1987
|
compileComponents() {
|
|
1989
1988
|
return this.compiler.compileComponents();
|
|
1990
1989
|
}
|
|
1991
|
-
inject(token, notFoundValue,
|
|
1990
|
+
inject(token, notFoundValue, options) {
|
|
1992
1991
|
if (token === TestBed) {
|
|
1993
1992
|
return this;
|
|
1994
1993
|
}
|
|
1995
1994
|
const UNDEFINED = {};
|
|
1996
|
-
const result = this.testModuleRef.injector.get(token, UNDEFINED,
|
|
1995
|
+
const result = this.testModuleRef.injector.get(token, UNDEFINED, options);
|
|
1997
1996
|
return result === UNDEFINED
|
|
1998
|
-
? this.compiler.injector.get(token, notFoundValue,
|
|
1997
|
+
? this.compiler.injector.get(token, notFoundValue, options)
|
|
1999
1998
|
: result;
|
|
2000
1999
|
}
|
|
2001
2000
|
/** @deprecated from v9.0.0 use TestBed.inject */
|
|
2002
|
-
get(token, notFoundValue = Injector.THROW_IF_NOT_FOUND,
|
|
2003
|
-
return this.inject(token, notFoundValue,
|
|
2001
|
+
get(token, notFoundValue = Injector.THROW_IF_NOT_FOUND, options) {
|
|
2002
|
+
return this.inject(token, notFoundValue, options);
|
|
2004
2003
|
}
|
|
2005
2004
|
runInInjectionContext(fn) {
|
|
2006
2005
|
return runInInjectionContext(this.inject(EnvironmentInjector), fn);
|
|
@@ -2049,15 +2048,15 @@ class TestBedImpl {
|
|
|
2049
2048
|
const testComponentRenderer = this.inject(TestComponentRenderer);
|
|
2050
2049
|
const rootElId = `root${_nextRootElementId++}`;
|
|
2051
2050
|
testComponentRenderer.insertRootElement(rootElId);
|
|
2052
|
-
if (
|
|
2051
|
+
if (_getAsyncClassMetadataFn(type)) {
|
|
2053
2052
|
throw new Error(`Component '${type.name}' has unresolved metadata. ` +
|
|
2054
2053
|
`Please call \`await TestBed.compileComponents()\` before running this test.`);
|
|
2055
2054
|
}
|
|
2056
2055
|
const componentDef = type.ɵcmp;
|
|
2057
2056
|
if (!componentDef) {
|
|
2058
|
-
throw new Error(`It looks like '${
|
|
2057
|
+
throw new Error(`It looks like '${_stringify(type)}' has not been compiled.`);
|
|
2059
2058
|
}
|
|
2060
|
-
const componentFactory = new
|
|
2059
|
+
const componentFactory = new _Render3ComponentFactory(componentDef);
|
|
2061
2060
|
const initComponent = () => {
|
|
2062
2061
|
const componentRef = componentFactory.create(Injector.NULL, [], `#${rootElId}`, this.testModuleRef);
|
|
2063
2062
|
return this.runInInjectionContext(() => new ComponentFixture(componentRef));
|
|
@@ -2110,7 +2109,7 @@ class TestBedImpl {
|
|
|
2110
2109
|
// Checking _testNgModuleRef is null should not be necessary, but is left in as an additional
|
|
2111
2110
|
// guard that compilations queued in tests (after instantiation) are never flushed accidentally.
|
|
2112
2111
|
if (!this.globalCompilationChecked && this._testModuleRef === null) {
|
|
2113
|
-
|
|
2112
|
+
_flushModuleScopingQueueAsMuchAsPossible();
|
|
2114
2113
|
}
|
|
2115
2114
|
this.globalCompilationChecked = true;
|
|
2116
2115
|
}
|
|
@@ -2198,8 +2197,7 @@ class TestBedImpl {
|
|
|
2198
2197
|
* @developerPreview
|
|
2199
2198
|
*/
|
|
2200
2199
|
flushEffects() {
|
|
2201
|
-
this.inject(
|
|
2202
|
-
this.inject(ɵEffectScheduler).flush();
|
|
2200
|
+
this.inject(_EffectScheduler).flush();
|
|
2203
2201
|
}
|
|
2204
2202
|
}
|
|
2205
2203
|
/**
|
|
@@ -2313,12 +2311,6 @@ function getCleanupHook(expectedTeardownValue) {
|
|
|
2313
2311
|
// TODO(iminar): Remove this code in a safe way.
|
|
2314
2312
|
const __core_private_testing_placeholder__ = '';
|
|
2315
2313
|
|
|
2316
|
-
/**
|
|
2317
|
-
* @module
|
|
2318
|
-
* @description
|
|
2319
|
-
* Entry point for all public APIs of the core/testing package.
|
|
2320
|
-
*/
|
|
2321
|
-
|
|
2322
2314
|
/**
|
|
2323
2315
|
* Fake implementation of user agent history and navigation behavior. This is a
|
|
2324
2316
|
* high-fidelity implementation of browser behavior that attempts to emulate
|
|
@@ -2337,8 +2329,9 @@ class FakeNavigation {
|
|
|
2337
2329
|
currentEntryIndex = 0;
|
|
2338
2330
|
/**
|
|
2339
2331
|
* The current navigate event.
|
|
2332
|
+
* @internal
|
|
2340
2333
|
*/
|
|
2341
|
-
navigateEvent =
|
|
2334
|
+
navigateEvent = null;
|
|
2342
2335
|
/**
|
|
2343
2336
|
* A Map of pending traversals, so that traversals to the same entry can be
|
|
2344
2337
|
* re-used.
|
|
@@ -2361,7 +2354,10 @@ class FakeNavigation {
|
|
|
2361
2354
|
synchronousTraversals = false;
|
|
2362
2355
|
/** Whether to allow a call to setInitialEntryForTesting. */
|
|
2363
2356
|
canSetInitialEntry = true;
|
|
2364
|
-
/**
|
|
2357
|
+
/**
|
|
2358
|
+
* `EventTarget` to dispatch events.
|
|
2359
|
+
* @internal
|
|
2360
|
+
*/
|
|
2365
2361
|
eventTarget;
|
|
2366
2362
|
/** The next unique id for created entries. Replace recreates this id. */
|
|
2367
2363
|
nextId = 0;
|
|
@@ -2393,7 +2389,7 @@ class FakeNavigation {
|
|
|
2393
2389
|
throw new Error('setInitialEntryForTesting can only be called before any ' + 'navigation has occurred');
|
|
2394
2390
|
}
|
|
2395
2391
|
const currentInitialEntry = this.entriesArr[0];
|
|
2396
|
-
this.entriesArr[0] = new FakeNavigationHistoryEntry(new URL(url).toString(), {
|
|
2392
|
+
this.entriesArr[0] = new FakeNavigationHistoryEntry(this.window.document.createElement('div'), new URL(url).toString(), {
|
|
2397
2393
|
index: 0,
|
|
2398
2394
|
key: currentInitialEntry?.key ?? String(this.nextKey++),
|
|
2399
2395
|
id: currentInitialEntry?.id ?? String(this.nextId++),
|
|
@@ -2441,7 +2437,7 @@ class FakeNavigation {
|
|
|
2441
2437
|
sameDocument: hashChange,
|
|
2442
2438
|
historyState: null,
|
|
2443
2439
|
});
|
|
2444
|
-
const result = new InternalNavigationResult();
|
|
2440
|
+
const result = new InternalNavigationResult(this);
|
|
2445
2441
|
this.userAgentNavigate(destination, result, {
|
|
2446
2442
|
navigationType,
|
|
2447
2443
|
cancelable: true,
|
|
@@ -2473,7 +2469,7 @@ class FakeNavigation {
|
|
|
2473
2469
|
sameDocument: true,
|
|
2474
2470
|
historyState: data,
|
|
2475
2471
|
});
|
|
2476
|
-
const result = new InternalNavigationResult();
|
|
2472
|
+
const result = new InternalNavigationResult(this);
|
|
2477
2473
|
this.userAgentNavigate(destination, result, {
|
|
2478
2474
|
navigationType,
|
|
2479
2475
|
cancelable: true,
|
|
@@ -2481,7 +2477,6 @@ class FakeNavigation {
|
|
|
2481
2477
|
// Always false for pushState() or replaceState().
|
|
2482
2478
|
userInitiated: false,
|
|
2483
2479
|
hashChange,
|
|
2484
|
-
skipPopState: true,
|
|
2485
2480
|
});
|
|
2486
2481
|
}
|
|
2487
2482
|
/** Equivalent to `navigation.traverseTo()`. */
|
|
@@ -2523,11 +2518,11 @@ class FakeNavigation {
|
|
|
2523
2518
|
sameDocument: entry.sameDocument,
|
|
2524
2519
|
});
|
|
2525
2520
|
this.prospectiveEntryIndex = entry.index;
|
|
2526
|
-
const result = new InternalNavigationResult();
|
|
2521
|
+
const result = new InternalNavigationResult(this);
|
|
2527
2522
|
this.traversalQueue.set(entry.key, result);
|
|
2528
2523
|
this.runTraversal(() => {
|
|
2529
2524
|
this.traversalQueue.delete(entry.key);
|
|
2530
|
-
this.userAgentNavigate(destination, result, {
|
|
2525
|
+
const event = this.userAgentNavigate(destination, result, {
|
|
2531
2526
|
navigationType: 'traverse',
|
|
2532
2527
|
cancelable: true,
|
|
2533
2528
|
canIntercept: true,
|
|
@@ -2536,6 +2531,8 @@ class FakeNavigation {
|
|
|
2536
2531
|
hashChange,
|
|
2537
2532
|
info: options?.info,
|
|
2538
2533
|
});
|
|
2534
|
+
// Note this does not pay attention at all to the commit status of the event (and thus, does not support deferred commit for traversals)
|
|
2535
|
+
this.userAgentTraverse(event);
|
|
2539
2536
|
});
|
|
2540
2537
|
return {
|
|
2541
2538
|
committed: result.committed,
|
|
@@ -2604,8 +2601,8 @@ class FakeNavigation {
|
|
|
2604
2601
|
index: entry.index,
|
|
2605
2602
|
sameDocument: entry.sameDocument,
|
|
2606
2603
|
});
|
|
2607
|
-
const result = new InternalNavigationResult();
|
|
2608
|
-
this.userAgentNavigate(destination, result, {
|
|
2604
|
+
const result = new InternalNavigationResult(this);
|
|
2605
|
+
const event = this.userAgentNavigate(destination, result, {
|
|
2609
2606
|
navigationType: 'traverse',
|
|
2610
2607
|
cancelable: true,
|
|
2611
2608
|
canIntercept: true,
|
|
@@ -2613,6 +2610,8 @@ class FakeNavigation {
|
|
|
2613
2610
|
userInitiated: false,
|
|
2614
2611
|
hashChange,
|
|
2615
2612
|
});
|
|
2613
|
+
// Note this does not pay attention at all to the commit status of the event (and thus, does not support deferred commit for traversals)
|
|
2614
|
+
this.userAgentTraverse(event);
|
|
2616
2615
|
});
|
|
2617
2616
|
}
|
|
2618
2617
|
/** Runs a traversal synchronously or asynchronously */
|
|
@@ -2663,9 +2662,9 @@ class FakeNavigation {
|
|
|
2663
2662
|
this.canSetInitialEntry = false;
|
|
2664
2663
|
if (this.navigateEvent) {
|
|
2665
2664
|
this.navigateEvent.cancel(new DOMException('Navigation was aborted', 'AbortError'));
|
|
2666
|
-
this.navigateEvent =
|
|
2665
|
+
this.navigateEvent = null;
|
|
2667
2666
|
}
|
|
2668
|
-
|
|
2667
|
+
return dispatchNavigateEvent({
|
|
2669
2668
|
navigationType: options.navigationType,
|
|
2670
2669
|
cancelable: options.cancelable,
|
|
2671
2670
|
canIntercept: options.canIntercept,
|
|
@@ -2675,79 +2674,102 @@ class FakeNavigation {
|
|
|
2675
2674
|
destination,
|
|
2676
2675
|
info: options.info,
|
|
2677
2676
|
sameDocument: destination.sameDocument,
|
|
2678
|
-
skipPopState: options.skipPopState,
|
|
2679
2677
|
result,
|
|
2680
|
-
userAgentCommit: () => {
|
|
2681
|
-
this.userAgentCommit();
|
|
2682
|
-
},
|
|
2683
2678
|
});
|
|
2684
|
-
this.navigateEvent = navigateEvent;
|
|
2685
|
-
this.eventTarget.dispatchEvent(navigateEvent);
|
|
2686
|
-
navigateEvent.dispatchedNavigateEvent();
|
|
2687
|
-
if (navigateEvent.commitOption === 'immediate') {
|
|
2688
|
-
navigateEvent.commit(/* internal= */ true);
|
|
2689
|
-
}
|
|
2690
2679
|
}
|
|
2691
|
-
/**
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2680
|
+
/**
|
|
2681
|
+
* Implementation to commit a navigation.
|
|
2682
|
+
* https://whatpr.org/html/10919/nav-history-apis.html#navigateevent-commit
|
|
2683
|
+
* @internal
|
|
2684
|
+
*/
|
|
2685
|
+
commitNavigateEvent(navigateEvent) {
|
|
2686
|
+
navigateEvent.interceptionState = 'committed';
|
|
2696
2687
|
const from = this.currentEntry;
|
|
2697
|
-
if (!
|
|
2688
|
+
if (!from) {
|
|
2689
|
+
throw new Error('cannot commit navigation when current entry is null');
|
|
2690
|
+
}
|
|
2691
|
+
if (!navigateEvent.sameDocument) {
|
|
2698
2692
|
const error = new Error('Cannot navigate to a non-same-document URL.');
|
|
2699
|
-
|
|
2693
|
+
navigateEvent.cancel(error);
|
|
2700
2694
|
throw error;
|
|
2701
2695
|
}
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
this.
|
|
2705
|
-
navigationType: this.navigateEvent.navigationType,
|
|
2706
|
-
});
|
|
2696
|
+
// "If navigationType is "push" or "replace", then run the URL and history update steps given document and event's destination's URL, with serialiedData set to event's classic history API state and historyHandling set to navigationType."
|
|
2697
|
+
if (navigateEvent.navigationType === 'push' || navigateEvent.navigationType === 'replace') {
|
|
2698
|
+
this.urlAndHistoryUpdateSteps(navigateEvent);
|
|
2707
2699
|
}
|
|
2708
|
-
else if (
|
|
2709
|
-
this.
|
|
2700
|
+
else if (navigateEvent.navigationType === 'reload') {
|
|
2701
|
+
this.updateNavigationEntriesForSameDocumentNavigation(navigateEvent);
|
|
2710
2702
|
}
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2703
|
+
else ;
|
|
2704
|
+
}
|
|
2705
|
+
/**
|
|
2706
|
+
* Implementation for a push or replace navigation.
|
|
2707
|
+
* https://whatpr.org/html/10919/browsing-the-web.html#url-and-history-update-steps
|
|
2708
|
+
* https://whatpr.org/html/10919/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation
|
|
2709
|
+
*/
|
|
2710
|
+
urlAndHistoryUpdateSteps(navigateEvent) {
|
|
2711
|
+
this.updateNavigationEntriesForSameDocumentNavigation(navigateEvent);
|
|
2712
|
+
}
|
|
2713
|
+
/**
|
|
2714
|
+
* Implementation for a traverse navigation.
|
|
2715
|
+
*
|
|
2716
|
+
* https://whatpr.org/html/10919/browsing-the-web.html#apply-the-traverse-history-step
|
|
2717
|
+
* ...
|
|
2718
|
+
* > Let updateDocument be an algorithm step which performs update document for history step application given targetEntry's document, targetEntry, changingNavigableContinuation's update-only, scriptHistoryLength, scriptHistoryIndex, navigationType, entriesForNavigationAPI, and previousEntry.
|
|
2719
|
+
* > If targetEntry's document is equal to displayedDocument, then perform updateDocument.
|
|
2720
|
+
* https://whatpr.org/html/10919/browsing-the-web.html#update-document-for-history-step-application
|
|
2721
|
+
* which then goes to https://whatpr.org/html/10919/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation
|
|
2722
|
+
*/
|
|
2723
|
+
userAgentTraverse(navigateEvent) {
|
|
2724
|
+
this.updateNavigationEntriesForSameDocumentNavigation(navigateEvent);
|
|
2725
|
+
// Happens as part of "updating the document" steps https://whatpr.org/html/10919/browsing-the-web.html#updating-the-document
|
|
2726
|
+
const popStateEvent = createPopStateEvent({
|
|
2727
|
+
state: navigateEvent.destination.getHistoryState(),
|
|
2715
2728
|
});
|
|
2716
|
-
this.
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2729
|
+
this.window.dispatchEvent(popStateEvent);
|
|
2730
|
+
// TODO(atscott): If oldURL's fragment is not equal to entry's URL's fragment, then queue a global task to fire an event named hashchange
|
|
2731
|
+
}
|
|
2732
|
+
/** https://whatpr.org/html/10919/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation */
|
|
2733
|
+
updateNavigationEntriesForSameDocumentNavigation({ destination, navigationType, result, }) {
|
|
2734
|
+
const oldCurrentNHE = this.currentEntry;
|
|
2735
|
+
const disposedNHEs = [];
|
|
2736
|
+
if (navigationType === 'traverse') {
|
|
2737
|
+
this.currentEntryIndex = destination.index;
|
|
2738
|
+
if (this.currentEntryIndex === -1) {
|
|
2739
|
+
throw new Error('unexpected current entry index');
|
|
2740
|
+
}
|
|
2722
2741
|
}
|
|
2723
|
-
|
|
2724
|
-
/** Implementation for a push or replace navigation. */
|
|
2725
|
-
userAgentPushOrReplace(destination, { navigationType }) {
|
|
2726
|
-
if (navigationType === 'push') {
|
|
2742
|
+
else if (navigationType === 'push') {
|
|
2727
2743
|
this.currentEntryIndex++;
|
|
2728
|
-
this.prospectiveEntryIndex = this.currentEntryIndex;
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
index
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2744
|
+
this.prospectiveEntryIndex = this.currentEntryIndex; // prospectiveEntryIndex isn't in the spec but is an implementation detail
|
|
2745
|
+
disposedNHEs.push(...this.entriesArr.splice(this.currentEntryIndex));
|
|
2746
|
+
}
|
|
2747
|
+
else if (navigationType === 'replace') {
|
|
2748
|
+
disposedNHEs.push(oldCurrentNHE);
|
|
2749
|
+
}
|
|
2750
|
+
if (navigationType === 'push' || navigationType === 'replace') {
|
|
2751
|
+
const index = this.currentEntryIndex;
|
|
2752
|
+
const key = navigationType === 'push' ? String(this.nextKey++) : this.currentEntry.key;
|
|
2753
|
+
const newNHE = new FakeNavigationHistoryEntry(this.window.document.createElement('div'), destination.url, {
|
|
2754
|
+
id: String(this.nextId++),
|
|
2755
|
+
key,
|
|
2756
|
+
index,
|
|
2757
|
+
sameDocument: true,
|
|
2758
|
+
state: destination.getState(),
|
|
2759
|
+
historyState: destination.getHistoryState(),
|
|
2760
|
+
});
|
|
2761
|
+
this.entriesArr[this.currentEntryIndex] = newNHE;
|
|
2742
2762
|
}
|
|
2743
|
-
|
|
2744
|
-
|
|
2763
|
+
result.committedResolve(this.currentEntry);
|
|
2764
|
+
const currentEntryChangeEvent = createFakeNavigationCurrentEntryChangeEvent({
|
|
2765
|
+
from: oldCurrentNHE,
|
|
2766
|
+
navigationType: navigationType,
|
|
2767
|
+
});
|
|
2768
|
+
this.eventTarget.dispatchEvent(currentEntryChangeEvent);
|
|
2769
|
+
for (const disposedNHE of disposedNHEs) {
|
|
2770
|
+
disposedNHE.dispose();
|
|
2745
2771
|
}
|
|
2746
2772
|
}
|
|
2747
|
-
/** Implementation for a traverse navigation. */
|
|
2748
|
-
userAgentTraverse(destination) {
|
|
2749
|
-
this.currentEntryIndex = destination.index;
|
|
2750
|
-
}
|
|
2751
2773
|
/** Utility method for finding entries with the given `key`. */
|
|
2752
2774
|
findEntry(key) {
|
|
2753
2775
|
for (const entry of this.entriesArr) {
|
|
@@ -2789,8 +2811,13 @@ class FakeNavigation {
|
|
|
2789
2811
|
get onnavigateerror() {
|
|
2790
2812
|
throw new Error('unimplemented');
|
|
2791
2813
|
}
|
|
2814
|
+
_transition = null;
|
|
2815
|
+
/** @internal */
|
|
2816
|
+
set transition(t) {
|
|
2817
|
+
this._transition = t;
|
|
2818
|
+
}
|
|
2792
2819
|
get transition() {
|
|
2793
|
-
|
|
2820
|
+
return this._transition;
|
|
2794
2821
|
}
|
|
2795
2822
|
updateCurrentEntry(_options) {
|
|
2796
2823
|
throw new Error('unimplemented');
|
|
@@ -2803,6 +2830,7 @@ class FakeNavigation {
|
|
|
2803
2830
|
* Fake equivalent of `NavigationHistoryEntry`.
|
|
2804
2831
|
*/
|
|
2805
2832
|
class FakeNavigationHistoryEntry {
|
|
2833
|
+
eventTarget;
|
|
2806
2834
|
url;
|
|
2807
2835
|
sameDocument;
|
|
2808
2836
|
id;
|
|
@@ -2812,7 +2840,8 @@ class FakeNavigationHistoryEntry {
|
|
|
2812
2840
|
historyState;
|
|
2813
2841
|
// tslint:disable-next-line:no-any
|
|
2814
2842
|
ondispose = null;
|
|
2815
|
-
constructor(url, { id, key, index, sameDocument, state, historyState, }) {
|
|
2843
|
+
constructor(eventTarget, url, { id, key, index, sameDocument, state, historyState, }) {
|
|
2844
|
+
this.eventTarget = eventTarget;
|
|
2816
2845
|
this.url = url;
|
|
2817
2846
|
this.id = id;
|
|
2818
2847
|
this.key = key;
|
|
@@ -2832,21 +2861,34 @@ class FakeNavigationHistoryEntry {
|
|
|
2832
2861
|
: this.historyState;
|
|
2833
2862
|
}
|
|
2834
2863
|
addEventListener(type, callback, options) {
|
|
2835
|
-
|
|
2864
|
+
this.eventTarget.addEventListener(type, callback, options);
|
|
2836
2865
|
}
|
|
2837
2866
|
removeEventListener(type, callback, options) {
|
|
2838
|
-
|
|
2867
|
+
this.eventTarget.removeEventListener(type, callback, options);
|
|
2839
2868
|
}
|
|
2840
2869
|
dispatchEvent(event) {
|
|
2841
|
-
|
|
2870
|
+
return this.eventTarget.dispatchEvent(event);
|
|
2871
|
+
}
|
|
2872
|
+
/** internal */
|
|
2873
|
+
dispose() {
|
|
2874
|
+
const disposeEvent = new Event('disposed');
|
|
2875
|
+
this.dispatchEvent(disposeEvent);
|
|
2876
|
+
// release current listeners
|
|
2877
|
+
this.eventTarget = null;
|
|
2842
2878
|
}
|
|
2843
2879
|
}
|
|
2844
2880
|
/**
|
|
2845
2881
|
* Create a fake equivalent of `NavigateEvent`. This is not a class because ES5
|
|
2846
2882
|
* transpiled JavaScript cannot extend native Event.
|
|
2883
|
+
*
|
|
2884
|
+
* https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigate-event-firing
|
|
2847
2885
|
*/
|
|
2848
|
-
function
|
|
2886
|
+
function dispatchNavigateEvent({ cancelable, canIntercept, userInitiated, hashChange, navigationType, signal, destination, info, sameDocument, result, }) {
|
|
2887
|
+
const { navigation } = result;
|
|
2849
2888
|
const event = new Event('navigate', { bubbles: false, cancelable });
|
|
2889
|
+
event.focusResetBehavior = null;
|
|
2890
|
+
event.scrollBehavior = null;
|
|
2891
|
+
event.interceptionState = 'none';
|
|
2850
2892
|
event.canIntercept = canIntercept;
|
|
2851
2893
|
event.userInitiated = userInitiated;
|
|
2852
2894
|
event.hashChange = hashChange;
|
|
@@ -2856,71 +2898,151 @@ function createFakeNavigateEvent({ cancelable, canIntercept, userInitiated, hash
|
|
|
2856
2898
|
event.info = info;
|
|
2857
2899
|
event.downloadRequest = null;
|
|
2858
2900
|
event.formData = null;
|
|
2901
|
+
event.result = result;
|
|
2859
2902
|
event.sameDocument = sameDocument;
|
|
2860
|
-
event.skipPopState = skipPopState;
|
|
2861
2903
|
event.commitOption = 'immediate';
|
|
2862
|
-
let
|
|
2863
|
-
let interceptCalled = false;
|
|
2904
|
+
let handlersFinished = [Promise.resolve()];
|
|
2864
2905
|
let dispatchedNavigateEvent = false;
|
|
2865
|
-
let commitCalled = false;
|
|
2866
2906
|
event.intercept = function (options) {
|
|
2867
|
-
|
|
2907
|
+
if (!this.canIntercept) {
|
|
2908
|
+
throw new DOMException(`Cannot intercept when canIntercept is 'false'`, 'SecurityError');
|
|
2909
|
+
}
|
|
2910
|
+
this.interceptionState = 'intercepted';
|
|
2868
2911
|
event.sameDocument = true;
|
|
2869
2912
|
const handler = options?.handler;
|
|
2870
2913
|
if (handler) {
|
|
2871
|
-
|
|
2914
|
+
handlersFinished.push(handler());
|
|
2872
2915
|
}
|
|
2873
|
-
if
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2916
|
+
// override old options with new ones. UA _may_ report a console warning if new options differ from previous
|
|
2917
|
+
event.commitOption = options?.commit ?? event.commitOption;
|
|
2918
|
+
event.scrollBehavior = options?.scroll ?? event.scrollBehavior;
|
|
2919
|
+
event.focusResetBehavior = options?.focusReset ?? event.focusResetBehavior;
|
|
2877
2920
|
};
|
|
2878
2921
|
event.scroll = function () {
|
|
2879
|
-
|
|
2922
|
+
if (event.interceptionState !== 'committed') {
|
|
2923
|
+
throw new DOMException(`Failed to execute 'scroll' on 'NavigateEvent': scroll() must be ` +
|
|
2924
|
+
`called after commit() and interception options must specify manual scroll.`, 'InvalidStateError');
|
|
2925
|
+
}
|
|
2926
|
+
processScrollBehavior(event);
|
|
2880
2927
|
};
|
|
2881
2928
|
event.commit = function (internal = false) {
|
|
2882
|
-
if (!internal &&
|
|
2929
|
+
if (!internal && this.interceptionState !== 'intercepted') {
|
|
2883
2930
|
throw new DOMException(`Failed to execute 'commit' on 'NavigateEvent': intercept() must be ` +
|
|
2884
|
-
`called before commit().`, 'InvalidStateError');
|
|
2931
|
+
`called before commit() and commit() cannot be already called.`, 'InvalidStateError');
|
|
2932
|
+
}
|
|
2933
|
+
if (!internal && event.commitOption !== 'after-transition') {
|
|
2934
|
+
throw new DOMException(`Failed to execute 'commit' on 'NavigateEvent': commit() may not be ` +
|
|
2935
|
+
`called if commit behavior is not "after-transition",.`, 'InvalidStateError');
|
|
2885
2936
|
}
|
|
2886
2937
|
if (!dispatchedNavigateEvent) {
|
|
2887
2938
|
throw new DOMException(`Failed to execute 'commit' on 'NavigateEvent': commit() may not be ` +
|
|
2888
2939
|
`called during event dispatch.`, 'InvalidStateError');
|
|
2889
2940
|
}
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
}
|
|
2893
|
-
commitCalled = true;
|
|
2894
|
-
userAgentCommit();
|
|
2941
|
+
this.interceptionState = 'committed';
|
|
2942
|
+
result.navigation.commitNavigateEvent(event);
|
|
2895
2943
|
};
|
|
2896
2944
|
// Internal only.
|
|
2897
2945
|
event.cancel = function (reason) {
|
|
2898
2946
|
result.committedReject(reason);
|
|
2899
2947
|
result.finishedReject(reason);
|
|
2900
2948
|
};
|
|
2901
|
-
|
|
2902
|
-
|
|
2949
|
+
function dispatch() {
|
|
2950
|
+
navigation.navigateEvent = event;
|
|
2951
|
+
navigation.eventTarget.dispatchEvent(event);
|
|
2903
2952
|
dispatchedNavigateEvent = true;
|
|
2904
|
-
if (event.
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
}
|
|
2910
|
-
}, () => { });
|
|
2953
|
+
if (event.interceptionState !== 'none') {
|
|
2954
|
+
navigation.transition = new InternalNavigationTransition(navigation.currentEntry, navigationType);
|
|
2955
|
+
if (event.commitOption !== 'after-transition') {
|
|
2956
|
+
event.commit(/** internal */ true);
|
|
2957
|
+
}
|
|
2911
2958
|
}
|
|
2912
|
-
|
|
2913
|
-
|
|
2959
|
+
else {
|
|
2960
|
+
// In the spec, this isn't really part of the navigate API. Instead, the navigate event firing returns "true" to indicate
|
|
2961
|
+
// navigation steps should "continue" (https://whatpr.org/html/10919/browsing-the-web.html#beginning-navigation)
|
|
2962
|
+
event.commit(/** internal */ true);
|
|
2963
|
+
}
|
|
2964
|
+
Promise.all(handlersFinished).then(() => {
|
|
2965
|
+
// Follows steps outlined under "Wait for all of promisesList, with the following success steps:"
|
|
2966
|
+
// in the spec https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigate-event-firing.
|
|
2967
|
+
if (result.signal.aborted) {
|
|
2968
|
+
return;
|
|
2969
|
+
}
|
|
2970
|
+
if (event !== navigation.navigateEvent) {
|
|
2971
|
+
throw new Error("Navigation's ongoing event not equal to resolved event");
|
|
2972
|
+
}
|
|
2973
|
+
navigation.navigateEvent = null;
|
|
2974
|
+
if (event.interceptionState === 'intercepted') {
|
|
2975
|
+
navigation.commitNavigateEvent(event);
|
|
2976
|
+
}
|
|
2977
|
+
finishNavigationEvent(event, true);
|
|
2978
|
+
const navigatesuccessEvent = new Event('navigatesuccess', { bubbles: false, cancelable });
|
|
2979
|
+
navigation.eventTarget.dispatchEvent(navigatesuccessEvent);
|
|
2980
|
+
result.finishedResolve();
|
|
2981
|
+
if (navigation.transition !== null) {
|
|
2982
|
+
navigation.transition.finishedResolve();
|
|
2983
|
+
}
|
|
2984
|
+
navigation.transition = null;
|
|
2914
2985
|
}, (reason) => {
|
|
2986
|
+
if (result.signal.aborted) {
|
|
2987
|
+
return;
|
|
2988
|
+
}
|
|
2989
|
+
if (event !== navigation.navigateEvent) {
|
|
2990
|
+
throw new Error("Navigation's ongoing event not equal to resolved event");
|
|
2991
|
+
}
|
|
2992
|
+
navigation.navigateEvent = null;
|
|
2993
|
+
event.interceptionState = 'rejected'; // TODO(atscott): this is not in the spec https://github.com/whatwg/html/issues/11087
|
|
2994
|
+
finishNavigationEvent(event, false);
|
|
2995
|
+
const navigateerrorEvent = new Event('navigateerror', { bubbles: false, cancelable });
|
|
2996
|
+
navigation.eventTarget.dispatchEvent(navigateerrorEvent);
|
|
2915
2997
|
result.finishedReject(reason);
|
|
2998
|
+
if (navigation.transition !== null) {
|
|
2999
|
+
navigation.transition.finishedResolve();
|
|
3000
|
+
}
|
|
3001
|
+
navigation.transition = null;
|
|
2916
3002
|
});
|
|
2917
|
-
}
|
|
2918
|
-
|
|
2919
|
-
event.userAgentNavigated = function (entry) {
|
|
2920
|
-
result.committedResolve(entry);
|
|
2921
|
-
};
|
|
3003
|
+
}
|
|
3004
|
+
dispatch();
|
|
2922
3005
|
return event;
|
|
2923
3006
|
}
|
|
3007
|
+
/** https://whatpr.org/html/10919/nav-history-apis.html#navigateevent-finish */
|
|
3008
|
+
function finishNavigationEvent(event, didFulfill) {
|
|
3009
|
+
if (event.interceptionState === 'intercepted' || event.interceptionState === 'finished') {
|
|
3010
|
+
throw new Error('Attempting to finish navigation event that was incomplete or already finished');
|
|
3011
|
+
}
|
|
3012
|
+
if (event.interceptionState === 'none') {
|
|
3013
|
+
return;
|
|
3014
|
+
}
|
|
3015
|
+
if (didFulfill) {
|
|
3016
|
+
// TODO(atscott): https://github.com/whatwg/html/issues/11087 focus reset is not guarded by didFulfill in the spec
|
|
3017
|
+
potentiallyResetFocus(event);
|
|
3018
|
+
potentiallyResetScroll(event);
|
|
3019
|
+
}
|
|
3020
|
+
event.interceptionState = 'finished';
|
|
3021
|
+
}
|
|
3022
|
+
/** https://whatpr.org/html/10919/nav-history-apis.html#potentially-reset-the-focus */
|
|
3023
|
+
function potentiallyResetFocus(event) {
|
|
3024
|
+
if (event.interceptionState !== 'committed' && event.interceptionState !== 'scrolled') {
|
|
3025
|
+
throw new Error('cannot reset focus if navigation event is not committed or scrolled');
|
|
3026
|
+
}
|
|
3027
|
+
// TODO(atscott): The rest of the steps
|
|
3028
|
+
}
|
|
3029
|
+
function potentiallyResetScroll(event) {
|
|
3030
|
+
if (event.interceptionState !== 'committed' && event.interceptionState !== 'scrolled') {
|
|
3031
|
+
throw new Error('cannot reset scroll if navigation event is not committed or scrolled');
|
|
3032
|
+
}
|
|
3033
|
+
if (event.interceptionState === 'scrolled' || event.scrollBehavior === 'manual') {
|
|
3034
|
+
return;
|
|
3035
|
+
}
|
|
3036
|
+
processScrollBehavior(event);
|
|
3037
|
+
}
|
|
3038
|
+
/* https://whatpr.org/html/10919/nav-history-apis.html#process-scroll-behavior */
|
|
3039
|
+
function processScrollBehavior(event) {
|
|
3040
|
+
if (event.interceptionState !== 'committed') {
|
|
3041
|
+
throw new Error('invalid event interception state when processing scroll behavior');
|
|
3042
|
+
}
|
|
3043
|
+
event.interceptionState = 'scrolled';
|
|
3044
|
+
// TODO(atscott): the rest of the steps
|
|
3045
|
+
}
|
|
2924
3046
|
/**
|
|
2925
3047
|
* Create a fake equivalent of `NavigationCurrentEntryChange`. This does not use
|
|
2926
3048
|
* a class because ES5 transpiled JavaScript cannot extend native Event.
|
|
@@ -2980,8 +3102,28 @@ function isHashChange(from, to) {
|
|
|
2980
3102
|
to.pathname === from.pathname &&
|
|
2981
3103
|
to.search === from.search);
|
|
2982
3104
|
}
|
|
2983
|
-
|
|
3105
|
+
class InternalNavigationTransition {
|
|
3106
|
+
from;
|
|
3107
|
+
navigationType;
|
|
3108
|
+
finished;
|
|
3109
|
+
finishedResolve;
|
|
3110
|
+
finishedReject;
|
|
3111
|
+
constructor(from, navigationType) {
|
|
3112
|
+
this.from = from;
|
|
3113
|
+
this.navigationType = navigationType;
|
|
3114
|
+
this.finished = new Promise((resolve, reject) => {
|
|
3115
|
+
this.finishedReject = reject;
|
|
3116
|
+
this.finishedResolve = resolve;
|
|
3117
|
+
});
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
/**
|
|
3121
|
+
* Internal utility class for representing the result of a navigation.
|
|
3122
|
+
* Generally equivalent to the "apiMethodTracker" in the spec.
|
|
3123
|
+
*/
|
|
2984
3124
|
class InternalNavigationResult {
|
|
3125
|
+
navigation;
|
|
3126
|
+
committedTo = null;
|
|
2985
3127
|
committedResolve;
|
|
2986
3128
|
committedReject;
|
|
2987
3129
|
finishedResolve;
|
|
@@ -2992,13 +3134,22 @@ class InternalNavigationResult {
|
|
|
2992
3134
|
return this.abortController.signal;
|
|
2993
3135
|
}
|
|
2994
3136
|
abortController = new AbortController();
|
|
2995
|
-
constructor() {
|
|
3137
|
+
constructor(navigation) {
|
|
3138
|
+
this.navigation = navigation;
|
|
2996
3139
|
this.committed = new Promise((resolve, reject) => {
|
|
2997
|
-
this.committedResolve =
|
|
3140
|
+
this.committedResolve = (entry) => {
|
|
3141
|
+
this.committedTo = entry;
|
|
3142
|
+
resolve(entry);
|
|
3143
|
+
};
|
|
2998
3144
|
this.committedReject = reject;
|
|
2999
3145
|
});
|
|
3000
3146
|
this.finished = new Promise(async (resolve, reject) => {
|
|
3001
|
-
this.finishedResolve =
|
|
3147
|
+
this.finishedResolve = () => {
|
|
3148
|
+
if (this.committedTo === null) {
|
|
3149
|
+
throw new Error('NavigateEvent should have been committed before resolving finished promise.');
|
|
3150
|
+
}
|
|
3151
|
+
resolve(this.committedTo);
|
|
3152
|
+
};
|
|
3002
3153
|
this.finishedReject = (reason) => {
|
|
3003
3154
|
reject(reason);
|
|
3004
3155
|
this.abortController.abort(reason);
|
|
@@ -3010,14 +3161,5 @@ class InternalNavigationResult {
|
|
|
3010
3161
|
}
|
|
3011
3162
|
}
|
|
3012
3163
|
|
|
3013
|
-
/// <reference types="jasmine" />
|
|
3014
|
-
// This file only reexports content of the `src` folder. Keep it that way.
|
|
3015
|
-
|
|
3016
|
-
// This file is not used to build this module. It is only used during editing
|
|
3017
|
-
|
|
3018
|
-
/**
|
|
3019
|
-
* Generated bundle index. Do not edit.
|
|
3020
|
-
*/
|
|
3021
|
-
|
|
3022
3164
|
export { ComponentFixture, ComponentFixtureAutoDetect, ComponentFixtureNoNgZone, DeferBlockFixture, InjectSetupWrapper, TestBed, TestComponentRenderer, __core_private_testing_placeholder__, discardPeriodicTasks, fakeAsync, flush, flushMicrotasks, getTestBed, inject, resetFakeAsyncZone, tick, waitForAsync, withModule, FakeNavigation as ɵFakeNavigation, MetadataOverrider as ɵMetadataOverrider };
|
|
3023
3165
|
//# sourceMappingURL=testing.mjs.map
|