@angular/core 19.2.0 → 19.2.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 +317 -1646
- 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 -12
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +387 -241
- 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 +14138 -14924
- package/navigation_types.d-u4EOrrdZ.d.ts +121 -0
- package/package.json +5 -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 +73 -92
- package/schematics/bundles/{apply_import_manager-a4e62ded.js → apply_import_manager-C8MABThs.js} +13 -17
- package/schematics/bundles/{checker-2eecc677.js → checker-DP-zos5Q.js} +2961 -1060
- package/schematics/bundles/cleanup-unused-imports.js +22 -28
- package/schematics/bundles/{compiler_host-f313eac9.js → compiler_host-DzM2hemp.js} +20 -24
- package/schematics/bundles/control-flow-migration.js +82 -39
- package/schematics/bundles/explicit-standalone-flag.js +27 -33
- package/schematics/bundles/{imports-31a38653.js → imports-CIX-JgAN.js} +10 -15
- package/schematics/bundles/{index-afc3f749.js → index-CEdDCtp8.js} +56 -60
- package/schematics/bundles/{index-3891dd55.js → index-CrKEaRj_.js} +5 -5
- 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-1abf1f5f.js → migrate_ts_type_references-C0325A9V.js} +107 -112
- 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/pending-tasks.js +14 -20
- package/schematics/bundles/{program-24da9092.js → program-CRYsSwIq.js} +769 -2634
- package/schematics/bundles/{project_paths-64bc3947.js → project_paths-BoRVJPjW.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/provide-initializer.js +14 -20
- 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/testing/index.d.ts +309 -471
- package/weak_ref.d-ttyj86RV.d.ts +9 -0
package/fesm2022/testing.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v19.2.
|
|
3
|
-
* (c) 2010-
|
|
2
|
+
* @license Angular v19.2.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, ɵMicrotaskEffectScheduler as _MicrotaskEffectScheduler, 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, ɵconvertToBitFlags as _convertToBitFlags, InjectFlags, ɵ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,12 @@ 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(
|
|
229
|
+
zonelessEnabled = inject$1(_ZONELESS_ENABLED);
|
|
230
|
+
scheduler = inject$1(_ChangeDetectionScheduler);
|
|
231
|
+
rootEffectScheduler = inject$1(_EffectScheduler);
|
|
232
|
+
microtaskEffectScheduler = inject$1(_MicrotaskEffectScheduler);
|
|
233
233
|
autoDetectDefault = this.zonelessEnabled ? true : false;
|
|
234
234
|
autoDetect = inject$1(ComponentFixtureAutoDetect, { optional: true }) ?? this.autoDetectDefault;
|
|
235
235
|
subscriptions = new Subscription();
|
|
@@ -358,7 +358,7 @@ class ComponentFixture {
|
|
|
358
358
|
getDeferBlocks() {
|
|
359
359
|
const deferBlocks = [];
|
|
360
360
|
const lView = this.componentRef.hostView['_lView'];
|
|
361
|
-
|
|
361
|
+
_getDeferBlocks(lView, deferBlocks);
|
|
362
362
|
const deferBlockFixtures = [];
|
|
363
363
|
for (const block of deferBlocks) {
|
|
364
364
|
deferBlockFixtures.push(new DeferBlockFixture(block, this));
|
|
@@ -571,7 +571,7 @@ class MetadataOverrider {
|
|
|
571
571
|
}
|
|
572
572
|
if (override.set) {
|
|
573
573
|
if (override.remove || override.add) {
|
|
574
|
-
throw new Error(`Cannot set and add/remove ${
|
|
574
|
+
throw new Error(`Cannot set and add/remove ${_stringify(metadataClass)} at the same time!`);
|
|
575
575
|
}
|
|
576
576
|
setMetadata(props, override.set);
|
|
577
577
|
}
|
|
@@ -650,7 +650,7 @@ function _propHashKey(propName, propValue, references) {
|
|
|
650
650
|
function _serializeReference(ref, references) {
|
|
651
651
|
let id = references.get(ref);
|
|
652
652
|
if (!id) {
|
|
653
|
-
id = `${
|
|
653
|
+
id = `${_stringify(ref)}${_nextReferenceId++}`;
|
|
654
654
|
references.set(ref, id);
|
|
655
655
|
}
|
|
656
656
|
return id;
|
|
@@ -676,7 +676,7 @@ function _valueProps(obj) {
|
|
|
676
676
|
return props;
|
|
677
677
|
}
|
|
678
678
|
|
|
679
|
-
const reflection = new
|
|
679
|
+
const reflection = new _ReflectionCapabilities();
|
|
680
680
|
/**
|
|
681
681
|
* Allows to override ivy metadata for tests (via the `TestBed`).
|
|
682
682
|
*/
|
|
@@ -763,10 +763,10 @@ function isTestingModuleOverride(value) {
|
|
|
763
763
|
}
|
|
764
764
|
function assertNoStandaloneComponents(types, resolver, location) {
|
|
765
765
|
types.forEach((type) => {
|
|
766
|
-
if (
|
|
766
|
+
if (!_getAsyncClassMetadataFn(type)) {
|
|
767
767
|
const component = resolver.resolve(type);
|
|
768
768
|
if (component && (component.standalone == null || component.standalone)) {
|
|
769
|
-
throw new Error(
|
|
769
|
+
throw new Error(_generateStandaloneInDeclarationsError(type, location));
|
|
770
770
|
}
|
|
771
771
|
}
|
|
772
772
|
});
|
|
@@ -861,8 +861,8 @@ class TestBedCompiler {
|
|
|
861
861
|
moduleDef.rethrowApplicationErrors ?? RETHROW_APPLICATION_ERRORS_DEFAULT;
|
|
862
862
|
}
|
|
863
863
|
overrideModule(ngModule, override) {
|
|
864
|
-
if (
|
|
865
|
-
|
|
864
|
+
if (_USE_RUNTIME_DEPS_TRACKER_FOR_JIT) {
|
|
865
|
+
_depsTracker.clearScopeCacheFor(ngModule);
|
|
866
866
|
}
|
|
867
867
|
this.overriddenModules.add(ngModule);
|
|
868
868
|
// Compile the module right away.
|
|
@@ -919,7 +919,7 @@ class TestBedCompiler {
|
|
|
919
919
|
else {
|
|
920
920
|
providerDef = { provide: token };
|
|
921
921
|
}
|
|
922
|
-
const injectableDef = typeof token !== 'string' ?
|
|
922
|
+
const injectableDef = typeof token !== 'string' ? _getInjectableDef(token) : null;
|
|
923
923
|
const providedIn = injectableDef === null ? null : resolveForwardRef(injectableDef.providedIn);
|
|
924
924
|
const overridesBucket = providedIn === 'root' ? this.rootProviderOverrides : this.providerOverrides;
|
|
925
925
|
overridesBucket.push(providerDef);
|
|
@@ -936,12 +936,12 @@ class TestBedCompiler {
|
|
|
936
936
|
}
|
|
937
937
|
}
|
|
938
938
|
overrideTemplateUsingTestingModule(type, template) {
|
|
939
|
-
const def = type[
|
|
939
|
+
const def = type[_NG_COMP_DEF];
|
|
940
940
|
const hasStyleUrls = () => {
|
|
941
941
|
const metadata = this.resolvers.component.resolve(type);
|
|
942
942
|
return !!metadata.styleUrl || !!metadata.styleUrls?.length;
|
|
943
943
|
};
|
|
944
|
-
const overrideStyleUrls = !!def &&
|
|
944
|
+
const overrideStyleUrls = !!def && !_isComponentDefPendingResolution(type) && hasStyleUrls();
|
|
945
945
|
// In Ivy, compiling a component does not require knowing the module providing the
|
|
946
946
|
// component's scope, so overrideTemplateUsingTestingModule can be implemented purely via
|
|
947
947
|
// overrideComponent. Important: overriding template requires full Component re-compilation,
|
|
@@ -964,7 +964,7 @@ class TestBedCompiler {
|
|
|
964
964
|
return;
|
|
965
965
|
const promises = [];
|
|
966
966
|
for (const component of this.componentsWithAsyncMetadata) {
|
|
967
|
-
const asyncMetadataFn =
|
|
967
|
+
const asyncMetadataFn = _getAsyncClassMetadataFn(component);
|
|
968
968
|
if (asyncMetadataFn) {
|
|
969
969
|
promises.push(asyncMetadataFn());
|
|
970
970
|
}
|
|
@@ -1001,7 +1001,7 @@ class TestBedCompiler {
|
|
|
1001
1001
|
}
|
|
1002
1002
|
return Promise.resolve(resourceLoader.get(url));
|
|
1003
1003
|
};
|
|
1004
|
-
await
|
|
1004
|
+
await _resolveComponentResources(resolver);
|
|
1005
1005
|
}
|
|
1006
1006
|
}
|
|
1007
1007
|
finalize() {
|
|
@@ -1018,15 +1018,15 @@ class TestBedCompiler {
|
|
|
1018
1018
|
// every component.
|
|
1019
1019
|
this.componentToModuleScope.clear();
|
|
1020
1020
|
const parentInjector = this.platform.injector;
|
|
1021
|
-
this.testModuleRef = new
|
|
1021
|
+
this.testModuleRef = new _Render3NgModuleRef(this.testModuleType, parentInjector, []);
|
|
1022
1022
|
// ApplicationInitStatus.runInitializers() is marked @internal to core.
|
|
1023
1023
|
// Cast it to any before accessing it.
|
|
1024
1024
|
this.testModuleRef.injector.get(ApplicationInitStatus).runInitializers();
|
|
1025
1025
|
// Set locale ID after running app initializers, since locale information might be updated while
|
|
1026
1026
|
// running initializers. This is also consistent with the execution order while bootstrapping an
|
|
1027
1027
|
// app (see `packages/core/src/application_ref.ts` file).
|
|
1028
|
-
const localeId = this.testModuleRef.injector.get(LOCALE_ID,
|
|
1029
|
-
|
|
1028
|
+
const localeId = this.testModuleRef.injector.get(LOCALE_ID, _DEFAULT_LOCALE_ID);
|
|
1029
|
+
_setLocaleId(localeId);
|
|
1030
1030
|
return this.testModuleRef;
|
|
1031
1031
|
}
|
|
1032
1032
|
/**
|
|
@@ -1061,7 +1061,7 @@ class TestBedCompiler {
|
|
|
1061
1061
|
_getComponentFactories(moduleType) {
|
|
1062
1062
|
return maybeUnwrapFn(moduleType.ɵmod.declarations).reduce((factories, declaration) => {
|
|
1063
1063
|
const componentDef = declaration.ɵcmp;
|
|
1064
|
-
componentDef && factories.push(new
|
|
1064
|
+
componentDef && factories.push(new _Render3ComponentFactory(componentDef, this.testModuleRef));
|
|
1065
1065
|
return factories;
|
|
1066
1066
|
}, []);
|
|
1067
1067
|
}
|
|
@@ -1069,20 +1069,20 @@ class TestBedCompiler {
|
|
|
1069
1069
|
// Compile all queued components, directives, pipes.
|
|
1070
1070
|
let needsAsyncResources = false;
|
|
1071
1071
|
this.pendingComponents.forEach((declaration) => {
|
|
1072
|
-
if (
|
|
1072
|
+
if (_getAsyncClassMetadataFn(declaration)) {
|
|
1073
1073
|
throw new Error(`Component '${declaration.name}' has unresolved metadata. ` +
|
|
1074
1074
|
`Please call \`await TestBed.compileComponents()\` before running this test.`);
|
|
1075
1075
|
}
|
|
1076
|
-
needsAsyncResources = needsAsyncResources ||
|
|
1076
|
+
needsAsyncResources = needsAsyncResources || _isComponentDefPendingResolution(declaration);
|
|
1077
1077
|
const metadata = this.resolvers.component.resolve(declaration);
|
|
1078
1078
|
if (metadata === null) {
|
|
1079
1079
|
throw invalidTypeError(declaration.name, 'Component');
|
|
1080
1080
|
}
|
|
1081
|
-
this.maybeStoreNgDef(
|
|
1082
|
-
if (
|
|
1083
|
-
|
|
1081
|
+
this.maybeStoreNgDef(_NG_COMP_DEF, declaration);
|
|
1082
|
+
if (_USE_RUNTIME_DEPS_TRACKER_FOR_JIT) {
|
|
1083
|
+
_depsTracker.clearScopeCacheFor(declaration);
|
|
1084
1084
|
}
|
|
1085
|
-
|
|
1085
|
+
_compileComponent(declaration, metadata);
|
|
1086
1086
|
});
|
|
1087
1087
|
this.pendingComponents.clear();
|
|
1088
1088
|
this.pendingDirectives.forEach((declaration) => {
|
|
@@ -1090,8 +1090,8 @@ class TestBedCompiler {
|
|
|
1090
1090
|
if (metadata === null) {
|
|
1091
1091
|
throw invalidTypeError(declaration.name, 'Directive');
|
|
1092
1092
|
}
|
|
1093
|
-
this.maybeStoreNgDef(
|
|
1094
|
-
|
|
1093
|
+
this.maybeStoreNgDef(_NG_DIR_DEF, declaration);
|
|
1094
|
+
_compileDirective(declaration, metadata);
|
|
1095
1095
|
});
|
|
1096
1096
|
this.pendingDirectives.clear();
|
|
1097
1097
|
this.pendingPipes.forEach((declaration) => {
|
|
@@ -1099,8 +1099,8 @@ class TestBedCompiler {
|
|
|
1099
1099
|
if (metadata === null) {
|
|
1100
1100
|
throw invalidTypeError(declaration.name, 'Pipe');
|
|
1101
1101
|
}
|
|
1102
|
-
this.maybeStoreNgDef(
|
|
1103
|
-
|
|
1102
|
+
this.maybeStoreNgDef(_NG_PIPE_DEF, declaration);
|
|
1103
|
+
_compilePipe(declaration, metadata);
|
|
1104
1104
|
});
|
|
1105
1105
|
this.pendingPipes.clear();
|
|
1106
1106
|
return needsAsyncResources;
|
|
@@ -1110,16 +1110,16 @@ class TestBedCompiler {
|
|
|
1110
1110
|
// Module overrides (via `TestBed.overrideModule`) might affect scopes that were previously
|
|
1111
1111
|
// calculated and stored in `transitiveCompileScopes`. If module overrides are present,
|
|
1112
1112
|
// collect all affected modules and reset scopes to force their re-calculation.
|
|
1113
|
-
const testingModuleDef = this.testModuleType[
|
|
1113
|
+
const testingModuleDef = this.testModuleType[_NG_MOD_DEF];
|
|
1114
1114
|
const affectedModules = this.collectModulesAffectedByOverrides(testingModuleDef.imports);
|
|
1115
1115
|
if (affectedModules.size > 0) {
|
|
1116
1116
|
affectedModules.forEach((moduleType) => {
|
|
1117
|
-
if (
|
|
1118
|
-
this.storeFieldOfDefOnType(moduleType,
|
|
1119
|
-
moduleType[
|
|
1117
|
+
if (!_USE_RUNTIME_DEPS_TRACKER_FOR_JIT) {
|
|
1118
|
+
this.storeFieldOfDefOnType(moduleType, _NG_MOD_DEF, 'transitiveCompileScopes');
|
|
1119
|
+
moduleType[_NG_MOD_DEF].transitiveCompileScopes = null;
|
|
1120
1120
|
}
|
|
1121
1121
|
else {
|
|
1122
|
-
|
|
1122
|
+
_depsTracker.clearScopeCacheFor(moduleType);
|
|
1123
1123
|
}
|
|
1124
1124
|
});
|
|
1125
1125
|
}
|
|
@@ -1129,16 +1129,16 @@ class TestBedCompiler {
|
|
|
1129
1129
|
if (!moduleToScope.has(moduleType)) {
|
|
1130
1130
|
const isTestingModule = isTestingModuleOverride(moduleType);
|
|
1131
1131
|
const realType = isTestingModule ? this.testModuleType : moduleType;
|
|
1132
|
-
moduleToScope.set(moduleType,
|
|
1132
|
+
moduleToScope.set(moduleType, _transitiveScopesFor(realType));
|
|
1133
1133
|
}
|
|
1134
1134
|
return moduleToScope.get(moduleType);
|
|
1135
1135
|
};
|
|
1136
1136
|
this.componentToModuleScope.forEach((moduleType, componentType) => {
|
|
1137
1137
|
if (moduleType !== null) {
|
|
1138
1138
|
const moduleScope = getScopeOfModule(moduleType);
|
|
1139
|
-
this.storeFieldOfDefOnType(componentType,
|
|
1140
|
-
this.storeFieldOfDefOnType(componentType,
|
|
1141
|
-
|
|
1139
|
+
this.storeFieldOfDefOnType(componentType, _NG_COMP_DEF, 'directiveDefs');
|
|
1140
|
+
this.storeFieldOfDefOnType(componentType, _NG_COMP_DEF, 'pipeDefs');
|
|
1141
|
+
_patchComponentDefWithScope(getComponentDef(componentType), moduleScope);
|
|
1142
1142
|
}
|
|
1143
1143
|
// `tView` that is stored on component def contains information about directives and pipes
|
|
1144
1144
|
// that are in the scope of this component. Patching component scope will cause `tView` to be
|
|
@@ -1147,20 +1147,20 @@ class TestBedCompiler {
|
|
|
1147
1147
|
// Resetting `tView` is also needed for cases when we apply provider overrides and those
|
|
1148
1148
|
// providers are defined on component's level, in which case they may end up included into
|
|
1149
1149
|
// `tView.blueprint`.
|
|
1150
|
-
this.storeFieldOfDefOnType(componentType,
|
|
1150
|
+
this.storeFieldOfDefOnType(componentType, _NG_COMP_DEF, 'tView');
|
|
1151
1151
|
});
|
|
1152
1152
|
this.componentToModuleScope.clear();
|
|
1153
1153
|
}
|
|
1154
1154
|
applyProviderOverrides() {
|
|
1155
1155
|
const maybeApplyOverrides = (field) => (type) => {
|
|
1156
|
-
const resolver = field ===
|
|
1156
|
+
const resolver = field === _NG_COMP_DEF ? this.resolvers.component : this.resolvers.directive;
|
|
1157
1157
|
const metadata = resolver.resolve(type);
|
|
1158
1158
|
if (this.hasProviderOverrides(metadata.providers)) {
|
|
1159
1159
|
this.patchDefWithProviderOverrides(type, field);
|
|
1160
1160
|
}
|
|
1161
1161
|
};
|
|
1162
|
-
this.seenComponents.forEach(maybeApplyOverrides(
|
|
1163
|
-
this.seenDirectives.forEach(maybeApplyOverrides(
|
|
1162
|
+
this.seenComponents.forEach(maybeApplyOverrides(_NG_COMP_DEF));
|
|
1163
|
+
this.seenDirectives.forEach(maybeApplyOverrides(_NG_DIR_DEF));
|
|
1164
1164
|
this.seenComponents.clear();
|
|
1165
1165
|
this.seenDirectives.clear();
|
|
1166
1166
|
}
|
|
@@ -1183,7 +1183,7 @@ class TestBedCompiler {
|
|
|
1183
1183
|
// detailed error messages. The fact that the code relies on this line being
|
|
1184
1184
|
// present here is suspicious and should be refactored in a way that the line
|
|
1185
1185
|
// below can be moved (for ex. after an early exit check below).
|
|
1186
|
-
const injectorDef = type[
|
|
1186
|
+
const injectorDef = type[_NG_INJ_DEF];
|
|
1187
1187
|
// No provider overrides, exit early.
|
|
1188
1188
|
if (this.providerOverridesByToken.size === 0)
|
|
1189
1189
|
return;
|
|
@@ -1201,12 +1201,12 @@ class TestBedCompiler {
|
|
|
1201
1201
|
...(this.providerOverridesByModule.get(type) || []),
|
|
1202
1202
|
];
|
|
1203
1203
|
if (this.hasProviderOverrides(providers)) {
|
|
1204
|
-
this.maybeStoreNgDef(
|
|
1205
|
-
this.storeFieldOfDefOnType(type,
|
|
1204
|
+
this.maybeStoreNgDef(_NG_INJ_DEF, type);
|
|
1205
|
+
this.storeFieldOfDefOnType(type, _NG_INJ_DEF, 'providers');
|
|
1206
1206
|
injectorDef.providers = this.getOverriddenProviders(providers);
|
|
1207
1207
|
}
|
|
1208
1208
|
// Apply provider overrides to imported modules recursively
|
|
1209
|
-
const moduleDef = type[
|
|
1209
|
+
const moduleDef = type[_NG_MOD_DEF];
|
|
1210
1210
|
const imports = maybeUnwrapFn(moduleDef.imports);
|
|
1211
1211
|
for (const importedModule of imports) {
|
|
1212
1212
|
this.applyProviderOverridesInScope(importedModule);
|
|
@@ -1226,7 +1226,7 @@ class TestBedCompiler {
|
|
|
1226
1226
|
}
|
|
1227
1227
|
}
|
|
1228
1228
|
patchComponentsWithExistingStyles() {
|
|
1229
|
-
this.existingComponentStyles.forEach((styles, type) => (type[
|
|
1229
|
+
this.existingComponentStyles.forEach((styles, type) => (type[_NG_COMP_DEF].styles = styles));
|
|
1230
1230
|
this.existingComponentStyles.clear();
|
|
1231
1231
|
}
|
|
1232
1232
|
queueTypeArray(arr, moduleType) {
|
|
@@ -1241,12 +1241,12 @@ class TestBedCompiler {
|
|
|
1241
1241
|
}
|
|
1242
1242
|
recompileNgModule(ngModule, metadata) {
|
|
1243
1243
|
// Cache the initial ngModuleDef as it will be overwritten.
|
|
1244
|
-
this.maybeStoreNgDef(
|
|
1245
|
-
this.maybeStoreNgDef(
|
|
1246
|
-
|
|
1244
|
+
this.maybeStoreNgDef(_NG_MOD_DEF, ngModule);
|
|
1245
|
+
this.maybeStoreNgDef(_NG_INJ_DEF, ngModule);
|
|
1246
|
+
_compileNgModuleDefs(ngModule, metadata);
|
|
1247
1247
|
}
|
|
1248
1248
|
maybeRegisterComponentWithAsyncMetadata(type) {
|
|
1249
|
-
const asyncMetadataFn =
|
|
1249
|
+
const asyncMetadataFn = _getAsyncClassMetadataFn(type);
|
|
1250
1250
|
if (asyncMetadataFn) {
|
|
1251
1251
|
this.componentsWithAsyncMetadata.add(type);
|
|
1252
1252
|
}
|
|
@@ -1260,7 +1260,7 @@ class TestBedCompiler {
|
|
|
1260
1260
|
// Check whether a give Type has respective NG def (ɵcmp) and compile if def is
|
|
1261
1261
|
// missing. That might happen in case a class without any Angular decorators extends another
|
|
1262
1262
|
// class where Component/Directive/Pipe decorator is defined.
|
|
1263
|
-
if (
|
|
1263
|
+
if (_isComponentDefPendingResolution(type) || !type.hasOwnProperty(_NG_COMP_DEF)) {
|
|
1264
1264
|
this.pendingComponents.add(type);
|
|
1265
1265
|
}
|
|
1266
1266
|
this.seenComponents.add(type);
|
|
@@ -1287,14 +1287,14 @@ class TestBedCompiler {
|
|
|
1287
1287
|
}
|
|
1288
1288
|
const directive = this.resolvers.directive.resolve(type);
|
|
1289
1289
|
if (directive) {
|
|
1290
|
-
if (!type.hasOwnProperty(
|
|
1290
|
+
if (!type.hasOwnProperty(_NG_DIR_DEF)) {
|
|
1291
1291
|
this.pendingDirectives.add(type);
|
|
1292
1292
|
}
|
|
1293
1293
|
this.seenDirectives.add(type);
|
|
1294
1294
|
return;
|
|
1295
1295
|
}
|
|
1296
1296
|
const pipe = this.resolvers.pipe.resolve(type);
|
|
1297
|
-
if (pipe && !type.hasOwnProperty(
|
|
1297
|
+
if (pipe && !type.hasOwnProperty(_NG_PIPE_DEF)) {
|
|
1298
1298
|
this.pendingPipes.add(type);
|
|
1299
1299
|
return;
|
|
1300
1300
|
}
|
|
@@ -1382,7 +1382,7 @@ class TestBedCompiler {
|
|
|
1382
1382
|
path.forEach((item) => affectedModules.add(item));
|
|
1383
1383
|
}
|
|
1384
1384
|
// Examine module imports recursively to look for overridden modules.
|
|
1385
|
-
const moduleDef = value[
|
|
1385
|
+
const moduleDef = value[_NG_MOD_DEF];
|
|
1386
1386
|
calcAffectedModulesRecur(maybeUnwrapFn(moduleDef.imports), path.concat(value));
|
|
1387
1387
|
}
|
|
1388
1388
|
}
|
|
@@ -1420,7 +1420,7 @@ class TestBedCompiler {
|
|
|
1420
1420
|
if (this.originalComponentResolutionQueue === null) {
|
|
1421
1421
|
this.originalComponentResolutionQueue = new Map();
|
|
1422
1422
|
}
|
|
1423
|
-
|
|
1423
|
+
_clearResolutionOfComponentResourcesQueue().forEach((value, key) => this.originalComponentResolutionQueue.set(key, value));
|
|
1424
1424
|
}
|
|
1425
1425
|
/*
|
|
1426
1426
|
* Restores component resolution queue to the previously saved state. This operation is performed
|
|
@@ -1429,7 +1429,7 @@ class TestBedCompiler {
|
|
|
1429
1429
|
*/
|
|
1430
1430
|
restoreComponentResolutionQueue() {
|
|
1431
1431
|
if (this.originalComponentResolutionQueue !== null) {
|
|
1432
|
-
|
|
1432
|
+
_restoreComponentResolutionQueue(this.originalComponentResolutionQueue);
|
|
1433
1433
|
this.originalComponentResolutionQueue = null;
|
|
1434
1434
|
}
|
|
1435
1435
|
}
|
|
@@ -1441,8 +1441,8 @@ class TestBedCompiler {
|
|
|
1441
1441
|
});
|
|
1442
1442
|
// Restore initial component/directive/pipe defs
|
|
1443
1443
|
this.initialNgDefs.forEach((defs, type) => {
|
|
1444
|
-
if (
|
|
1445
|
-
|
|
1444
|
+
if (_USE_RUNTIME_DEPS_TRACKER_FOR_JIT) {
|
|
1445
|
+
_depsTracker.clearScopeCacheFor(type);
|
|
1446
1446
|
}
|
|
1447
1447
|
defs.forEach((descriptor, prop) => {
|
|
1448
1448
|
if (!descriptor) {
|
|
@@ -1463,24 +1463,24 @@ class TestBedCompiler {
|
|
|
1463
1463
|
this.scopesWithOverriddenProviders.clear();
|
|
1464
1464
|
this.restoreComponentResolutionQueue();
|
|
1465
1465
|
// Restore the locale ID to the default value, this shouldn't be necessary but we never know
|
|
1466
|
-
|
|
1466
|
+
_setLocaleId(_DEFAULT_LOCALE_ID);
|
|
1467
1467
|
}
|
|
1468
1468
|
compileTestModule() {
|
|
1469
1469
|
class RootScopeModule {
|
|
1470
1470
|
}
|
|
1471
|
-
|
|
1471
|
+
_compileNgModuleDefs(RootScopeModule, {
|
|
1472
1472
|
providers: [
|
|
1473
1473
|
...this.rootProviderOverrides,
|
|
1474
|
-
|
|
1474
|
+
_internalProvideZoneChangeDetection({}),
|
|
1475
1475
|
TestBedApplicationErrorHandler,
|
|
1476
|
-
{ provide:
|
|
1476
|
+
{ provide: _ChangeDetectionScheduler, useExisting: _ChangeDetectionSchedulerImpl },
|
|
1477
1477
|
],
|
|
1478
1478
|
});
|
|
1479
1479
|
const providers = [
|
|
1480
1480
|
{ provide: Compiler, useFactory: () => new R3TestCompiler(this) },
|
|
1481
|
-
{ provide:
|
|
1481
|
+
{ provide: _DEFER_BLOCK_CONFIG, useValue: { behavior: this.deferBlockBehavior } },
|
|
1482
1482
|
{
|
|
1483
|
-
provide:
|
|
1483
|
+
provide: _INTERNAL_APPLICATION_ERROR_HANDLER,
|
|
1484
1484
|
useFactory: () => {
|
|
1485
1485
|
if (this.rethrowApplicationTickErrors) {
|
|
1486
1486
|
const handler = inject$1(TestBedApplicationErrorHandler);
|
|
@@ -1499,7 +1499,7 @@ class TestBedCompiler {
|
|
|
1499
1499
|
...this.providerOverrides,
|
|
1500
1500
|
];
|
|
1501
1501
|
const imports = [RootScopeModule, this.additionalModuleTypes, this.imports || []];
|
|
1502
|
-
|
|
1502
|
+
_compileNgModuleDefs(this.testModuleType, {
|
|
1503
1503
|
declarations: this.declarations,
|
|
1504
1504
|
imports,
|
|
1505
1505
|
schemas: this.schemas,
|
|
@@ -1625,7 +1625,7 @@ function identityFn(value) {
|
|
|
1625
1625
|
function flattenProviders(providers, mapFn = identityFn) {
|
|
1626
1626
|
const out = [];
|
|
1627
1627
|
for (let provider of providers) {
|
|
1628
|
-
if (
|
|
1628
|
+
if (_isEnvironmentProviders(provider)) {
|
|
1629
1629
|
provider = provider.ɵproviders;
|
|
1630
1630
|
}
|
|
1631
1631
|
if (Array.isArray(provider)) {
|
|
@@ -1661,11 +1661,11 @@ class R3TestCompiler {
|
|
|
1661
1661
|
}
|
|
1662
1662
|
compileModuleSync(moduleType) {
|
|
1663
1663
|
this.testBed._compileNgModuleSync(moduleType);
|
|
1664
|
-
return new
|
|
1664
|
+
return new _NgModuleFactory(moduleType);
|
|
1665
1665
|
}
|
|
1666
1666
|
async compileModuleAsync(moduleType) {
|
|
1667
1667
|
await this.testBed._compileNgModuleAsync(moduleType);
|
|
1668
|
-
return new
|
|
1668
|
+
return new _NgModuleFactory(moduleType);
|
|
1669
1669
|
}
|
|
1670
1670
|
compileModuleAndAllComponentsSync(moduleType) {
|
|
1671
1671
|
const ngModuleFactory = this.compileModuleSync(moduleType);
|
|
@@ -1686,6 +1686,8 @@ class R3TestCompiler {
|
|
|
1686
1686
|
}
|
|
1687
1687
|
|
|
1688
1688
|
// The formatter and CI disagree on how this import statement should be formatted. Both try to keep
|
|
1689
|
+
// it on one line, too, which has gotten very hard to read & manage. So disable the formatter for
|
|
1690
|
+
// this statement only.
|
|
1689
1691
|
let _nextRootElementId = 0;
|
|
1690
1692
|
/**
|
|
1691
1693
|
* Returns a singleton of the `TestBed` class.
|
|
@@ -1824,7 +1826,7 @@ class TestBedImpl {
|
|
|
1824
1826
|
return TestBedImpl.INSTANCE.overrideProvider(token, provider);
|
|
1825
1827
|
}
|
|
1826
1828
|
static inject(token, notFoundValue, flags) {
|
|
1827
|
-
return TestBedImpl.INSTANCE.inject(token, notFoundValue,
|
|
1829
|
+
return TestBedImpl.INSTANCE.inject(token, notFoundValue, _convertToBitFlags(flags));
|
|
1828
1830
|
}
|
|
1829
1831
|
/** @deprecated from v9.0.0 use TestBed.inject */
|
|
1830
1832
|
static get(token, notFoundValue = Injector.THROW_IF_NOT_FOUND, flags = InjectFlags.Default) {
|
|
@@ -1895,7 +1897,7 @@ class TestBedImpl {
|
|
|
1895
1897
|
// used to track the state of the NgModule registry and reset it correctly. Instead, when we
|
|
1896
1898
|
// know we're in a testing scenario, we disable the check for duplicate NgModule registration
|
|
1897
1899
|
// completely.
|
|
1898
|
-
|
|
1900
|
+
_setAllowDuplicateNgModuleIdsForTest(true);
|
|
1899
1901
|
}
|
|
1900
1902
|
/**
|
|
1901
1903
|
* Reset the providers for the test injector.
|
|
@@ -1908,19 +1910,19 @@ class TestBedImpl {
|
|
|
1908
1910
|
this.platform = null;
|
|
1909
1911
|
this.ngModule = null;
|
|
1910
1912
|
TestBedImpl._environmentTeardownOptions = undefined;
|
|
1911
|
-
|
|
1913
|
+
_setAllowDuplicateNgModuleIdsForTest(false);
|
|
1912
1914
|
}
|
|
1913
1915
|
resetTestingModule() {
|
|
1914
1916
|
this.checkGlobalCompilationFinished();
|
|
1915
|
-
|
|
1917
|
+
_resetCompiledComponents();
|
|
1916
1918
|
if (this._compiler !== null) {
|
|
1917
1919
|
this.compiler.restoreOriginalState();
|
|
1918
1920
|
}
|
|
1919
1921
|
this._compiler = new TestBedCompiler(this.platform, this.ngModule);
|
|
1920
1922
|
// Restore the previous value of the "error on unknown elements" option
|
|
1921
|
-
|
|
1923
|
+
_setUnknownElementStrictMode(this._previousErrorOnUnknownElementsOption ?? THROW_ON_UNKNOWN_ELEMENTS_DEFAULT);
|
|
1922
1924
|
// Restore the previous value of the "error on unknown properties" option
|
|
1923
|
-
|
|
1925
|
+
_setUnknownPropertyStrictMode(this._previousErrorOnUnknownPropertiesOption ?? THROW_ON_UNKNOWN_PROPERTIES_DEFAULT);
|
|
1924
1926
|
// We have to chain a couple of try/finally blocks, because each step can
|
|
1925
1927
|
// throw errors and we don't want it to interrupt the next step and we also
|
|
1926
1928
|
// want an error to be thrown at the end.
|
|
@@ -1967,10 +1969,10 @@ class TestBedImpl {
|
|
|
1967
1969
|
this._instanceDeferBlockBehavior = moduleDef.deferBlockBehavior ?? DEFER_BLOCK_DEFAULT_BEHAVIOR;
|
|
1968
1970
|
// Store the current value of the strict mode option,
|
|
1969
1971
|
// so we can restore it later
|
|
1970
|
-
this._previousErrorOnUnknownElementsOption =
|
|
1971
|
-
|
|
1972
|
-
this._previousErrorOnUnknownPropertiesOption =
|
|
1973
|
-
|
|
1972
|
+
this._previousErrorOnUnknownElementsOption = _getUnknownElementStrictMode();
|
|
1973
|
+
_setUnknownElementStrictMode(this.shouldThrowErrorOnUnknownElements());
|
|
1974
|
+
this._previousErrorOnUnknownPropertiesOption = _getUnknownPropertyStrictMode();
|
|
1975
|
+
_setUnknownPropertyStrictMode(this.shouldThrowErrorOnUnknownProperties());
|
|
1974
1976
|
this.compiler.configureTestingModule(moduleDef);
|
|
1975
1977
|
return this;
|
|
1976
1978
|
}
|
|
@@ -1982,7 +1984,7 @@ class TestBedImpl {
|
|
|
1982
1984
|
return this;
|
|
1983
1985
|
}
|
|
1984
1986
|
const UNDEFINED = {};
|
|
1985
|
-
const result = this.testModuleRef.injector.get(token, UNDEFINED,
|
|
1987
|
+
const result = this.testModuleRef.injector.get(token, UNDEFINED, _convertToBitFlags(flags));
|
|
1986
1988
|
return result === UNDEFINED
|
|
1987
1989
|
? this.compiler.injector.get(token, notFoundValue, flags)
|
|
1988
1990
|
: result;
|
|
@@ -2038,15 +2040,15 @@ class TestBedImpl {
|
|
|
2038
2040
|
const testComponentRenderer = this.inject(TestComponentRenderer);
|
|
2039
2041
|
const rootElId = `root${_nextRootElementId++}`;
|
|
2040
2042
|
testComponentRenderer.insertRootElement(rootElId);
|
|
2041
|
-
if (
|
|
2043
|
+
if (_getAsyncClassMetadataFn(type)) {
|
|
2042
2044
|
throw new Error(`Component '${type.name}' has unresolved metadata. ` +
|
|
2043
2045
|
`Please call \`await TestBed.compileComponents()\` before running this test.`);
|
|
2044
2046
|
}
|
|
2045
2047
|
const componentDef = type.ɵcmp;
|
|
2046
2048
|
if (!componentDef) {
|
|
2047
|
-
throw new Error(`It looks like '${
|
|
2049
|
+
throw new Error(`It looks like '${_stringify(type)}' has not been compiled.`);
|
|
2048
2050
|
}
|
|
2049
|
-
const componentFactory = new
|
|
2051
|
+
const componentFactory = new _Render3ComponentFactory(componentDef);
|
|
2050
2052
|
const initComponent = () => {
|
|
2051
2053
|
const componentRef = componentFactory.create(Injector.NULL, [], `#${rootElId}`, this.testModuleRef);
|
|
2052
2054
|
return this.runInInjectionContext(() => new ComponentFixture(componentRef));
|
|
@@ -2099,7 +2101,7 @@ class TestBedImpl {
|
|
|
2099
2101
|
// Checking _testNgModuleRef is null should not be necessary, but is left in as an additional
|
|
2100
2102
|
// guard that compilations queued in tests (after instantiation) are never flushed accidentally.
|
|
2101
2103
|
if (!this.globalCompilationChecked && this._testModuleRef === null) {
|
|
2102
|
-
|
|
2104
|
+
_flushModuleScopingQueueAsMuchAsPossible();
|
|
2103
2105
|
}
|
|
2104
2106
|
this.globalCompilationChecked = true;
|
|
2105
2107
|
}
|
|
@@ -2187,8 +2189,8 @@ class TestBedImpl {
|
|
|
2187
2189
|
* @developerPreview
|
|
2188
2190
|
*/
|
|
2189
2191
|
flushEffects() {
|
|
2190
|
-
this.inject(
|
|
2191
|
-
this.inject(
|
|
2192
|
+
this.inject(_MicrotaskEffectScheduler).flush();
|
|
2193
|
+
this.inject(_EffectScheduler).flush();
|
|
2192
2194
|
}
|
|
2193
2195
|
}
|
|
2194
2196
|
/**
|
|
@@ -2302,12 +2304,6 @@ function getCleanupHook(expectedTeardownValue) {
|
|
|
2302
2304
|
// TODO(iminar): Remove this code in a safe way.
|
|
2303
2305
|
const __core_private_testing_placeholder__ = '';
|
|
2304
2306
|
|
|
2305
|
-
/**
|
|
2306
|
-
* @module
|
|
2307
|
-
* @description
|
|
2308
|
-
* Entry point for all public APIs of the core/testing package.
|
|
2309
|
-
*/
|
|
2310
|
-
|
|
2311
2307
|
/**
|
|
2312
2308
|
* Fake implementation of user agent history and navigation behavior. This is a
|
|
2313
2309
|
* high-fidelity implementation of browser behavior that attempts to emulate
|
|
@@ -2326,8 +2322,9 @@ class FakeNavigation {
|
|
|
2326
2322
|
currentEntryIndex = 0;
|
|
2327
2323
|
/**
|
|
2328
2324
|
* The current navigate event.
|
|
2325
|
+
* @internal
|
|
2329
2326
|
*/
|
|
2330
|
-
navigateEvent =
|
|
2327
|
+
navigateEvent = null;
|
|
2331
2328
|
/**
|
|
2332
2329
|
* A Map of pending traversals, so that traversals to the same entry can be
|
|
2333
2330
|
* re-used.
|
|
@@ -2350,7 +2347,10 @@ class FakeNavigation {
|
|
|
2350
2347
|
synchronousTraversals = false;
|
|
2351
2348
|
/** Whether to allow a call to setInitialEntryForTesting. */
|
|
2352
2349
|
canSetInitialEntry = true;
|
|
2353
|
-
/**
|
|
2350
|
+
/**
|
|
2351
|
+
* `EventTarget` to dispatch events.
|
|
2352
|
+
* @internal
|
|
2353
|
+
*/
|
|
2354
2354
|
eventTarget;
|
|
2355
2355
|
/** The next unique id for created entries. Replace recreates this id. */
|
|
2356
2356
|
nextId = 0;
|
|
@@ -2382,7 +2382,7 @@ class FakeNavigation {
|
|
|
2382
2382
|
throw new Error('setInitialEntryForTesting can only be called before any ' + 'navigation has occurred');
|
|
2383
2383
|
}
|
|
2384
2384
|
const currentInitialEntry = this.entriesArr[0];
|
|
2385
|
-
this.entriesArr[0] = new FakeNavigationHistoryEntry(new URL(url).toString(), {
|
|
2385
|
+
this.entriesArr[0] = new FakeNavigationHistoryEntry(this.window.document.createElement('div'), new URL(url).toString(), {
|
|
2386
2386
|
index: 0,
|
|
2387
2387
|
key: currentInitialEntry?.key ?? String(this.nextKey++),
|
|
2388
2388
|
id: currentInitialEntry?.id ?? String(this.nextId++),
|
|
@@ -2430,7 +2430,7 @@ class FakeNavigation {
|
|
|
2430
2430
|
sameDocument: hashChange,
|
|
2431
2431
|
historyState: null,
|
|
2432
2432
|
});
|
|
2433
|
-
const result = new InternalNavigationResult();
|
|
2433
|
+
const result = new InternalNavigationResult(this);
|
|
2434
2434
|
this.userAgentNavigate(destination, result, {
|
|
2435
2435
|
navigationType,
|
|
2436
2436
|
cancelable: true,
|
|
@@ -2462,7 +2462,7 @@ class FakeNavigation {
|
|
|
2462
2462
|
sameDocument: true,
|
|
2463
2463
|
historyState: data,
|
|
2464
2464
|
});
|
|
2465
|
-
const result = new InternalNavigationResult();
|
|
2465
|
+
const result = new InternalNavigationResult(this);
|
|
2466
2466
|
this.userAgentNavigate(destination, result, {
|
|
2467
2467
|
navigationType,
|
|
2468
2468
|
cancelable: true,
|
|
@@ -2470,7 +2470,6 @@ class FakeNavigation {
|
|
|
2470
2470
|
// Always false for pushState() or replaceState().
|
|
2471
2471
|
userInitiated: false,
|
|
2472
2472
|
hashChange,
|
|
2473
|
-
skipPopState: true,
|
|
2474
2473
|
});
|
|
2475
2474
|
}
|
|
2476
2475
|
/** Equivalent to `navigation.traverseTo()`. */
|
|
@@ -2512,11 +2511,11 @@ class FakeNavigation {
|
|
|
2512
2511
|
sameDocument: entry.sameDocument,
|
|
2513
2512
|
});
|
|
2514
2513
|
this.prospectiveEntryIndex = entry.index;
|
|
2515
|
-
const result = new InternalNavigationResult();
|
|
2514
|
+
const result = new InternalNavigationResult(this);
|
|
2516
2515
|
this.traversalQueue.set(entry.key, result);
|
|
2517
2516
|
this.runTraversal(() => {
|
|
2518
2517
|
this.traversalQueue.delete(entry.key);
|
|
2519
|
-
this.userAgentNavigate(destination, result, {
|
|
2518
|
+
const event = this.userAgentNavigate(destination, result, {
|
|
2520
2519
|
navigationType: 'traverse',
|
|
2521
2520
|
cancelable: true,
|
|
2522
2521
|
canIntercept: true,
|
|
@@ -2525,6 +2524,8 @@ class FakeNavigation {
|
|
|
2525
2524
|
hashChange,
|
|
2526
2525
|
info: options?.info,
|
|
2527
2526
|
});
|
|
2527
|
+
// Note this does not pay attention at all to the commit status of the event (and thus, does not support deferred commit for traversals)
|
|
2528
|
+
this.userAgentTraverse(event);
|
|
2528
2529
|
});
|
|
2529
2530
|
return {
|
|
2530
2531
|
committed: result.committed,
|
|
@@ -2593,8 +2594,8 @@ class FakeNavigation {
|
|
|
2593
2594
|
index: entry.index,
|
|
2594
2595
|
sameDocument: entry.sameDocument,
|
|
2595
2596
|
});
|
|
2596
|
-
const result = new InternalNavigationResult();
|
|
2597
|
-
this.userAgentNavigate(destination, result, {
|
|
2597
|
+
const result = new InternalNavigationResult(this);
|
|
2598
|
+
const event = this.userAgentNavigate(destination, result, {
|
|
2598
2599
|
navigationType: 'traverse',
|
|
2599
2600
|
cancelable: true,
|
|
2600
2601
|
canIntercept: true,
|
|
@@ -2602,6 +2603,8 @@ class FakeNavigation {
|
|
|
2602
2603
|
userInitiated: false,
|
|
2603
2604
|
hashChange,
|
|
2604
2605
|
});
|
|
2606
|
+
// Note this does not pay attention at all to the commit status of the event (and thus, does not support deferred commit for traversals)
|
|
2607
|
+
this.userAgentTraverse(event);
|
|
2605
2608
|
});
|
|
2606
2609
|
}
|
|
2607
2610
|
/** Runs a traversal synchronously or asynchronously */
|
|
@@ -2652,9 +2655,9 @@ class FakeNavigation {
|
|
|
2652
2655
|
this.canSetInitialEntry = false;
|
|
2653
2656
|
if (this.navigateEvent) {
|
|
2654
2657
|
this.navigateEvent.cancel(new DOMException('Navigation was aborted', 'AbortError'));
|
|
2655
|
-
this.navigateEvent =
|
|
2658
|
+
this.navigateEvent = null;
|
|
2656
2659
|
}
|
|
2657
|
-
|
|
2660
|
+
return dispatchNavigateEvent({
|
|
2658
2661
|
navigationType: options.navigationType,
|
|
2659
2662
|
cancelable: options.cancelable,
|
|
2660
2663
|
canIntercept: options.canIntercept,
|
|
@@ -2664,79 +2667,102 @@ class FakeNavigation {
|
|
|
2664
2667
|
destination,
|
|
2665
2668
|
info: options.info,
|
|
2666
2669
|
sameDocument: destination.sameDocument,
|
|
2667
|
-
skipPopState: options.skipPopState,
|
|
2668
2670
|
result,
|
|
2669
|
-
userAgentCommit: () => {
|
|
2670
|
-
this.userAgentCommit();
|
|
2671
|
-
},
|
|
2672
2671
|
});
|
|
2673
|
-
this.navigateEvent = navigateEvent;
|
|
2674
|
-
this.eventTarget.dispatchEvent(navigateEvent);
|
|
2675
|
-
navigateEvent.dispatchedNavigateEvent();
|
|
2676
|
-
if (navigateEvent.commitOption === 'immediate') {
|
|
2677
|
-
navigateEvent.commit(/* internal= */ true);
|
|
2678
|
-
}
|
|
2679
2672
|
}
|
|
2680
|
-
/**
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2673
|
+
/**
|
|
2674
|
+
* Implementation to commit a navigation.
|
|
2675
|
+
* https://whatpr.org/html/10919/nav-history-apis.html#navigateevent-commit
|
|
2676
|
+
* @internal
|
|
2677
|
+
*/
|
|
2678
|
+
commitNavigateEvent(navigateEvent) {
|
|
2679
|
+
navigateEvent.interceptionState = 'committed';
|
|
2685
2680
|
const from = this.currentEntry;
|
|
2686
|
-
if (!
|
|
2681
|
+
if (!from) {
|
|
2682
|
+
throw new Error('cannot commit navigation when current entry is null');
|
|
2683
|
+
}
|
|
2684
|
+
if (!navigateEvent.sameDocument) {
|
|
2687
2685
|
const error = new Error('Cannot navigate to a non-same-document URL.');
|
|
2688
|
-
|
|
2686
|
+
navigateEvent.cancel(error);
|
|
2689
2687
|
throw error;
|
|
2690
2688
|
}
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
this.
|
|
2694
|
-
navigationType: this.navigateEvent.navigationType,
|
|
2695
|
-
});
|
|
2689
|
+
// "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."
|
|
2690
|
+
if (navigateEvent.navigationType === 'push' || navigateEvent.navigationType === 'replace') {
|
|
2691
|
+
this.urlAndHistoryUpdateSteps(navigateEvent);
|
|
2696
2692
|
}
|
|
2697
|
-
else if (
|
|
2698
|
-
this.
|
|
2693
|
+
else if (navigateEvent.navigationType === 'reload') {
|
|
2694
|
+
this.updateNavigationEntriesForSameDocumentNavigation(navigateEvent);
|
|
2699
2695
|
}
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2696
|
+
else ;
|
|
2697
|
+
}
|
|
2698
|
+
/**
|
|
2699
|
+
* Implementation for a push or replace navigation.
|
|
2700
|
+
* https://whatpr.org/html/10919/browsing-the-web.html#url-and-history-update-steps
|
|
2701
|
+
* https://whatpr.org/html/10919/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation
|
|
2702
|
+
*/
|
|
2703
|
+
urlAndHistoryUpdateSteps(navigateEvent) {
|
|
2704
|
+
this.updateNavigationEntriesForSameDocumentNavigation(navigateEvent);
|
|
2705
|
+
}
|
|
2706
|
+
/**
|
|
2707
|
+
* Implementation for a traverse navigation.
|
|
2708
|
+
*
|
|
2709
|
+
* https://whatpr.org/html/10919/browsing-the-web.html#apply-the-traverse-history-step
|
|
2710
|
+
* ...
|
|
2711
|
+
* > 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.
|
|
2712
|
+
* > If targetEntry's document is equal to displayedDocument, then perform updateDocument.
|
|
2713
|
+
* https://whatpr.org/html/10919/browsing-the-web.html#update-document-for-history-step-application
|
|
2714
|
+
* which then goes to https://whatpr.org/html/10919/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation
|
|
2715
|
+
*/
|
|
2716
|
+
userAgentTraverse(navigateEvent) {
|
|
2717
|
+
this.updateNavigationEntriesForSameDocumentNavigation(navigateEvent);
|
|
2718
|
+
// Happens as part of "updating the document" steps https://whatpr.org/html/10919/browsing-the-web.html#updating-the-document
|
|
2719
|
+
const popStateEvent = createPopStateEvent({
|
|
2720
|
+
state: navigateEvent.destination.getHistoryState(),
|
|
2704
2721
|
});
|
|
2705
|
-
this.
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2722
|
+
this.window.dispatchEvent(popStateEvent);
|
|
2723
|
+
// 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
|
|
2724
|
+
}
|
|
2725
|
+
/** https://whatpr.org/html/10919/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation */
|
|
2726
|
+
updateNavigationEntriesForSameDocumentNavigation({ destination, navigationType, result, }) {
|
|
2727
|
+
const oldCurrentNHE = this.currentEntry;
|
|
2728
|
+
const disposedNHEs = [];
|
|
2729
|
+
if (navigationType === 'traverse') {
|
|
2730
|
+
this.currentEntryIndex = destination.index;
|
|
2731
|
+
if (this.currentEntryIndex === -1) {
|
|
2732
|
+
throw new Error('unexpected current entry index');
|
|
2733
|
+
}
|
|
2711
2734
|
}
|
|
2712
|
-
|
|
2713
|
-
/** Implementation for a push or replace navigation. */
|
|
2714
|
-
userAgentPushOrReplace(destination, { navigationType }) {
|
|
2715
|
-
if (navigationType === 'push') {
|
|
2735
|
+
else if (navigationType === 'push') {
|
|
2716
2736
|
this.currentEntryIndex++;
|
|
2717
|
-
this.prospectiveEntryIndex = this.currentEntryIndex;
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
index
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2737
|
+
this.prospectiveEntryIndex = this.currentEntryIndex; // prospectiveEntryIndex isn't in the spec but is an implementation detail
|
|
2738
|
+
disposedNHEs.push(...this.entriesArr.splice(this.currentEntryIndex));
|
|
2739
|
+
}
|
|
2740
|
+
else if (navigationType === 'replace') {
|
|
2741
|
+
disposedNHEs.push(oldCurrentNHE);
|
|
2742
|
+
}
|
|
2743
|
+
if (navigationType === 'push' || navigationType === 'replace') {
|
|
2744
|
+
const index = this.currentEntryIndex;
|
|
2745
|
+
const key = navigationType === 'push' ? String(this.nextKey++) : this.currentEntry.key;
|
|
2746
|
+
const newNHE = new FakeNavigationHistoryEntry(this.window.document.createElement('div'), destination.url, {
|
|
2747
|
+
id: String(this.nextId++),
|
|
2748
|
+
key,
|
|
2749
|
+
index,
|
|
2750
|
+
sameDocument: true,
|
|
2751
|
+
state: destination.getState(),
|
|
2752
|
+
historyState: destination.getHistoryState(),
|
|
2753
|
+
});
|
|
2754
|
+
this.entriesArr[this.currentEntryIndex] = newNHE;
|
|
2731
2755
|
}
|
|
2732
|
-
|
|
2733
|
-
|
|
2756
|
+
result.committedResolve(this.currentEntry);
|
|
2757
|
+
const currentEntryChangeEvent = createFakeNavigationCurrentEntryChangeEvent({
|
|
2758
|
+
from: oldCurrentNHE,
|
|
2759
|
+
navigationType: navigationType,
|
|
2760
|
+
});
|
|
2761
|
+
this.eventTarget.dispatchEvent(currentEntryChangeEvent);
|
|
2762
|
+
for (const disposedNHE of disposedNHEs) {
|
|
2763
|
+
disposedNHE.dispose();
|
|
2734
2764
|
}
|
|
2735
2765
|
}
|
|
2736
|
-
/** Implementation for a traverse navigation. */
|
|
2737
|
-
userAgentTraverse(destination) {
|
|
2738
|
-
this.currentEntryIndex = destination.index;
|
|
2739
|
-
}
|
|
2740
2766
|
/** Utility method for finding entries with the given `key`. */
|
|
2741
2767
|
findEntry(key) {
|
|
2742
2768
|
for (const entry of this.entriesArr) {
|
|
@@ -2778,8 +2804,13 @@ class FakeNavigation {
|
|
|
2778
2804
|
get onnavigateerror() {
|
|
2779
2805
|
throw new Error('unimplemented');
|
|
2780
2806
|
}
|
|
2807
|
+
_transition = null;
|
|
2808
|
+
/** @internal */
|
|
2809
|
+
set transition(t) {
|
|
2810
|
+
this._transition = t;
|
|
2811
|
+
}
|
|
2781
2812
|
get transition() {
|
|
2782
|
-
|
|
2813
|
+
return this._transition;
|
|
2783
2814
|
}
|
|
2784
2815
|
updateCurrentEntry(_options) {
|
|
2785
2816
|
throw new Error('unimplemented');
|
|
@@ -2792,6 +2823,7 @@ class FakeNavigation {
|
|
|
2792
2823
|
* Fake equivalent of `NavigationHistoryEntry`.
|
|
2793
2824
|
*/
|
|
2794
2825
|
class FakeNavigationHistoryEntry {
|
|
2826
|
+
eventTarget;
|
|
2795
2827
|
url;
|
|
2796
2828
|
sameDocument;
|
|
2797
2829
|
id;
|
|
@@ -2801,7 +2833,8 @@ class FakeNavigationHistoryEntry {
|
|
|
2801
2833
|
historyState;
|
|
2802
2834
|
// tslint:disable-next-line:no-any
|
|
2803
2835
|
ondispose = null;
|
|
2804
|
-
constructor(url, { id, key, index, sameDocument, state, historyState, }) {
|
|
2836
|
+
constructor(eventTarget, url, { id, key, index, sameDocument, state, historyState, }) {
|
|
2837
|
+
this.eventTarget = eventTarget;
|
|
2805
2838
|
this.url = url;
|
|
2806
2839
|
this.id = id;
|
|
2807
2840
|
this.key = key;
|
|
@@ -2821,21 +2854,34 @@ class FakeNavigationHistoryEntry {
|
|
|
2821
2854
|
: this.historyState;
|
|
2822
2855
|
}
|
|
2823
2856
|
addEventListener(type, callback, options) {
|
|
2824
|
-
|
|
2857
|
+
this.eventTarget.addEventListener(type, callback, options);
|
|
2825
2858
|
}
|
|
2826
2859
|
removeEventListener(type, callback, options) {
|
|
2827
|
-
|
|
2860
|
+
this.eventTarget.removeEventListener(type, callback, options);
|
|
2828
2861
|
}
|
|
2829
2862
|
dispatchEvent(event) {
|
|
2830
|
-
|
|
2863
|
+
return this.eventTarget.dispatchEvent(event);
|
|
2864
|
+
}
|
|
2865
|
+
/** internal */
|
|
2866
|
+
dispose() {
|
|
2867
|
+
const disposeEvent = new Event('disposed');
|
|
2868
|
+
this.dispatchEvent(disposeEvent);
|
|
2869
|
+
// release current listeners
|
|
2870
|
+
this.eventTarget = null;
|
|
2831
2871
|
}
|
|
2832
2872
|
}
|
|
2833
2873
|
/**
|
|
2834
2874
|
* Create a fake equivalent of `NavigateEvent`. This is not a class because ES5
|
|
2835
2875
|
* transpiled JavaScript cannot extend native Event.
|
|
2876
|
+
*
|
|
2877
|
+
* https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigate-event-firing
|
|
2836
2878
|
*/
|
|
2837
|
-
function
|
|
2879
|
+
function dispatchNavigateEvent({ cancelable, canIntercept, userInitiated, hashChange, navigationType, signal, destination, info, sameDocument, result, }) {
|
|
2880
|
+
const { navigation } = result;
|
|
2838
2881
|
const event = new Event('navigate', { bubbles: false, cancelable });
|
|
2882
|
+
event.focusResetBehavior = null;
|
|
2883
|
+
event.scrollBehavior = null;
|
|
2884
|
+
event.interceptionState = 'none';
|
|
2839
2885
|
event.canIntercept = canIntercept;
|
|
2840
2886
|
event.userInitiated = userInitiated;
|
|
2841
2887
|
event.hashChange = hashChange;
|
|
@@ -2845,71 +2891,151 @@ function createFakeNavigateEvent({ cancelable, canIntercept, userInitiated, hash
|
|
|
2845
2891
|
event.info = info;
|
|
2846
2892
|
event.downloadRequest = null;
|
|
2847
2893
|
event.formData = null;
|
|
2894
|
+
event.result = result;
|
|
2848
2895
|
event.sameDocument = sameDocument;
|
|
2849
|
-
event.skipPopState = skipPopState;
|
|
2850
2896
|
event.commitOption = 'immediate';
|
|
2851
|
-
let
|
|
2852
|
-
let interceptCalled = false;
|
|
2897
|
+
let handlersFinished = [Promise.resolve()];
|
|
2853
2898
|
let dispatchedNavigateEvent = false;
|
|
2854
|
-
let commitCalled = false;
|
|
2855
2899
|
event.intercept = function (options) {
|
|
2856
|
-
|
|
2900
|
+
if (!this.canIntercept) {
|
|
2901
|
+
throw new DOMException(`Cannot intercept when canIntercept is 'false'`, 'SecurityError');
|
|
2902
|
+
}
|
|
2903
|
+
this.interceptionState = 'intercepted';
|
|
2857
2904
|
event.sameDocument = true;
|
|
2858
2905
|
const handler = options?.handler;
|
|
2859
2906
|
if (handler) {
|
|
2860
|
-
|
|
2907
|
+
handlersFinished.push(handler());
|
|
2861
2908
|
}
|
|
2862
|
-
if
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2909
|
+
// override old options with new ones. UA _may_ report a console warning if new options differ from previous
|
|
2910
|
+
event.commitOption = options?.commit ?? event.commitOption;
|
|
2911
|
+
event.scrollBehavior = options?.scroll ?? event.scrollBehavior;
|
|
2912
|
+
event.focusResetBehavior = options?.focusReset ?? event.focusResetBehavior;
|
|
2866
2913
|
};
|
|
2867
2914
|
event.scroll = function () {
|
|
2868
|
-
|
|
2915
|
+
if (event.interceptionState !== 'committed') {
|
|
2916
|
+
throw new DOMException(`Failed to execute 'scroll' on 'NavigateEvent': scroll() must be ` +
|
|
2917
|
+
`called after commit() and interception options must specify manual scroll.`, 'InvalidStateError');
|
|
2918
|
+
}
|
|
2919
|
+
processScrollBehavior(event);
|
|
2869
2920
|
};
|
|
2870
2921
|
event.commit = function (internal = false) {
|
|
2871
|
-
if (!internal &&
|
|
2922
|
+
if (!internal && this.interceptionState !== 'intercepted') {
|
|
2872
2923
|
throw new DOMException(`Failed to execute 'commit' on 'NavigateEvent': intercept() must be ` +
|
|
2873
|
-
`called before commit().`, 'InvalidStateError');
|
|
2924
|
+
`called before commit() and commit() cannot be already called.`, 'InvalidStateError');
|
|
2925
|
+
}
|
|
2926
|
+
if (!internal && event.commitOption !== 'after-transition') {
|
|
2927
|
+
throw new DOMException(`Failed to execute 'commit' on 'NavigateEvent': commit() may not be ` +
|
|
2928
|
+
`called if commit behavior is not "after-transition",.`, 'InvalidStateError');
|
|
2874
2929
|
}
|
|
2875
2930
|
if (!dispatchedNavigateEvent) {
|
|
2876
2931
|
throw new DOMException(`Failed to execute 'commit' on 'NavigateEvent': commit() may not be ` +
|
|
2877
2932
|
`called during event dispatch.`, 'InvalidStateError');
|
|
2878
2933
|
}
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
}
|
|
2882
|
-
commitCalled = true;
|
|
2883
|
-
userAgentCommit();
|
|
2934
|
+
this.interceptionState = 'committed';
|
|
2935
|
+
result.navigation.commitNavigateEvent(event);
|
|
2884
2936
|
};
|
|
2885
2937
|
// Internal only.
|
|
2886
2938
|
event.cancel = function (reason) {
|
|
2887
2939
|
result.committedReject(reason);
|
|
2888
2940
|
result.finishedReject(reason);
|
|
2889
2941
|
};
|
|
2890
|
-
|
|
2891
|
-
|
|
2942
|
+
function dispatch() {
|
|
2943
|
+
navigation.navigateEvent = event;
|
|
2944
|
+
navigation.eventTarget.dispatchEvent(event);
|
|
2892
2945
|
dispatchedNavigateEvent = true;
|
|
2893
|
-
if (event.
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
}
|
|
2899
|
-
}, () => { });
|
|
2946
|
+
if (event.interceptionState !== 'none') {
|
|
2947
|
+
navigation.transition = new InternalNavigationTransition(navigation.currentEntry, navigationType);
|
|
2948
|
+
if (event.commitOption !== 'after-transition') {
|
|
2949
|
+
event.commit(/** internal */ true);
|
|
2950
|
+
}
|
|
2900
2951
|
}
|
|
2901
|
-
|
|
2902
|
-
|
|
2952
|
+
else {
|
|
2953
|
+
// In the spec, this isn't really part of the navigate API. Instead, the navigate event firing returns "true" to indicate
|
|
2954
|
+
// navigation steps should "continue" (https://whatpr.org/html/10919/browsing-the-web.html#beginning-navigation)
|
|
2955
|
+
event.commit(/** internal */ true);
|
|
2956
|
+
}
|
|
2957
|
+
Promise.all(handlersFinished).then(() => {
|
|
2958
|
+
// Follows steps outlined under "Wait for all of promisesList, with the following success steps:"
|
|
2959
|
+
// in the spec https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigate-event-firing.
|
|
2960
|
+
if (result.signal.aborted) {
|
|
2961
|
+
return;
|
|
2962
|
+
}
|
|
2963
|
+
if (event !== navigation.navigateEvent) {
|
|
2964
|
+
throw new Error("Navigation's ongoing event not equal to resolved event");
|
|
2965
|
+
}
|
|
2966
|
+
navigation.navigateEvent = null;
|
|
2967
|
+
if (event.interceptionState === 'intercepted') {
|
|
2968
|
+
navigation.commitNavigateEvent(event);
|
|
2969
|
+
}
|
|
2970
|
+
finishNavigationEvent(event, true);
|
|
2971
|
+
const navigatesuccessEvent = new Event('navigatesuccess', { bubbles: false, cancelable });
|
|
2972
|
+
navigation.eventTarget.dispatchEvent(navigatesuccessEvent);
|
|
2973
|
+
result.finishedResolve();
|
|
2974
|
+
if (navigation.transition !== null) {
|
|
2975
|
+
navigation.transition.finishedResolve();
|
|
2976
|
+
}
|
|
2977
|
+
navigation.transition = null;
|
|
2903
2978
|
}, (reason) => {
|
|
2979
|
+
if (result.signal.aborted) {
|
|
2980
|
+
return;
|
|
2981
|
+
}
|
|
2982
|
+
if (event !== navigation.navigateEvent) {
|
|
2983
|
+
throw new Error("Navigation's ongoing event not equal to resolved event");
|
|
2984
|
+
}
|
|
2985
|
+
navigation.navigateEvent = null;
|
|
2986
|
+
event.interceptionState = 'rejected'; // TODO(atscott): this is not in the spec https://github.com/whatwg/html/issues/11087
|
|
2987
|
+
finishNavigationEvent(event, false);
|
|
2988
|
+
const navigateerrorEvent = new Event('navigateerror', { bubbles: false, cancelable });
|
|
2989
|
+
navigation.eventTarget.dispatchEvent(navigateerrorEvent);
|
|
2904
2990
|
result.finishedReject(reason);
|
|
2991
|
+
if (navigation.transition !== null) {
|
|
2992
|
+
navigation.transition.finishedResolve();
|
|
2993
|
+
}
|
|
2994
|
+
navigation.transition = null;
|
|
2905
2995
|
});
|
|
2906
|
-
}
|
|
2907
|
-
|
|
2908
|
-
event.userAgentNavigated = function (entry) {
|
|
2909
|
-
result.committedResolve(entry);
|
|
2910
|
-
};
|
|
2996
|
+
}
|
|
2997
|
+
dispatch();
|
|
2911
2998
|
return event;
|
|
2912
2999
|
}
|
|
3000
|
+
/** https://whatpr.org/html/10919/nav-history-apis.html#navigateevent-finish */
|
|
3001
|
+
function finishNavigationEvent(event, didFulfill) {
|
|
3002
|
+
if (event.interceptionState === 'intercepted' || event.interceptionState === 'finished') {
|
|
3003
|
+
throw new Error('Attempting to finish navigation event that was incomplete or already finished');
|
|
3004
|
+
}
|
|
3005
|
+
if (event.interceptionState === 'none') {
|
|
3006
|
+
return;
|
|
3007
|
+
}
|
|
3008
|
+
if (didFulfill) {
|
|
3009
|
+
// TODO(atscott): https://github.com/whatwg/html/issues/11087 focus reset is not guarded by didFulfill in the spec
|
|
3010
|
+
potentiallyResetFocus(event);
|
|
3011
|
+
potentiallyResetScroll(event);
|
|
3012
|
+
}
|
|
3013
|
+
event.interceptionState = 'finished';
|
|
3014
|
+
}
|
|
3015
|
+
/** https://whatpr.org/html/10919/nav-history-apis.html#potentially-reset-the-focus */
|
|
3016
|
+
function potentiallyResetFocus(event) {
|
|
3017
|
+
if (event.interceptionState !== 'committed' && event.interceptionState !== 'scrolled') {
|
|
3018
|
+
throw new Error('cannot reset focus if navigation event is not committed or scrolled');
|
|
3019
|
+
}
|
|
3020
|
+
// TODO(atscott): The rest of the steps
|
|
3021
|
+
}
|
|
3022
|
+
function potentiallyResetScroll(event) {
|
|
3023
|
+
if (event.interceptionState !== 'committed' && event.interceptionState !== 'scrolled') {
|
|
3024
|
+
throw new Error('cannot reset scroll if navigation event is not committed or scrolled');
|
|
3025
|
+
}
|
|
3026
|
+
if (event.interceptionState === 'scrolled' || event.scrollBehavior === 'manual') {
|
|
3027
|
+
return;
|
|
3028
|
+
}
|
|
3029
|
+
processScrollBehavior(event);
|
|
3030
|
+
}
|
|
3031
|
+
/* https://whatpr.org/html/10919/nav-history-apis.html#process-scroll-behavior */
|
|
3032
|
+
function processScrollBehavior(event) {
|
|
3033
|
+
if (event.interceptionState !== 'committed') {
|
|
3034
|
+
throw new Error('invalid event interception state when processing scroll behavior');
|
|
3035
|
+
}
|
|
3036
|
+
event.interceptionState = 'scrolled';
|
|
3037
|
+
// TODO(atscott): the rest of the steps
|
|
3038
|
+
}
|
|
2913
3039
|
/**
|
|
2914
3040
|
* Create a fake equivalent of `NavigationCurrentEntryChange`. This does not use
|
|
2915
3041
|
* a class because ES5 transpiled JavaScript cannot extend native Event.
|
|
@@ -2969,8 +3095,28 @@ function isHashChange(from, to) {
|
|
|
2969
3095
|
to.pathname === from.pathname &&
|
|
2970
3096
|
to.search === from.search);
|
|
2971
3097
|
}
|
|
2972
|
-
|
|
3098
|
+
class InternalNavigationTransition {
|
|
3099
|
+
from;
|
|
3100
|
+
navigationType;
|
|
3101
|
+
finished;
|
|
3102
|
+
finishedResolve;
|
|
3103
|
+
finishedReject;
|
|
3104
|
+
constructor(from, navigationType) {
|
|
3105
|
+
this.from = from;
|
|
3106
|
+
this.navigationType = navigationType;
|
|
3107
|
+
this.finished = new Promise((resolve, reject) => {
|
|
3108
|
+
this.finishedReject = reject;
|
|
3109
|
+
this.finishedResolve = resolve;
|
|
3110
|
+
});
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
/**
|
|
3114
|
+
* Internal utility class for representing the result of a navigation.
|
|
3115
|
+
* Generally equivalent to the "apiMethodTracker" in the spec.
|
|
3116
|
+
*/
|
|
2973
3117
|
class InternalNavigationResult {
|
|
3118
|
+
navigation;
|
|
3119
|
+
committedTo = null;
|
|
2974
3120
|
committedResolve;
|
|
2975
3121
|
committedReject;
|
|
2976
3122
|
finishedResolve;
|
|
@@ -2981,13 +3127,22 @@ class InternalNavigationResult {
|
|
|
2981
3127
|
return this.abortController.signal;
|
|
2982
3128
|
}
|
|
2983
3129
|
abortController = new AbortController();
|
|
2984
|
-
constructor() {
|
|
3130
|
+
constructor(navigation) {
|
|
3131
|
+
this.navigation = navigation;
|
|
2985
3132
|
this.committed = new Promise((resolve, reject) => {
|
|
2986
|
-
this.committedResolve =
|
|
3133
|
+
this.committedResolve = (entry) => {
|
|
3134
|
+
this.committedTo = entry;
|
|
3135
|
+
resolve(entry);
|
|
3136
|
+
};
|
|
2987
3137
|
this.committedReject = reject;
|
|
2988
3138
|
});
|
|
2989
3139
|
this.finished = new Promise(async (resolve, reject) => {
|
|
2990
|
-
this.finishedResolve =
|
|
3140
|
+
this.finishedResolve = () => {
|
|
3141
|
+
if (this.committedTo === null) {
|
|
3142
|
+
throw new Error('NavigateEvent should have been committed before resolving finished promise.');
|
|
3143
|
+
}
|
|
3144
|
+
resolve(this.committedTo);
|
|
3145
|
+
};
|
|
2991
3146
|
this.finishedReject = (reason) => {
|
|
2992
3147
|
reject(reason);
|
|
2993
3148
|
this.abortController.abort(reason);
|
|
@@ -2999,14 +3154,5 @@ class InternalNavigationResult {
|
|
|
2999
3154
|
}
|
|
3000
3155
|
}
|
|
3001
3156
|
|
|
3002
|
-
/// <reference types="jasmine" />
|
|
3003
|
-
// This file only reexports content of the `src` folder. Keep it that way.
|
|
3004
|
-
|
|
3005
|
-
// This file is not used to build this module. It is only used during editing
|
|
3006
|
-
|
|
3007
|
-
/**
|
|
3008
|
-
* Generated bundle index. Do not edit.
|
|
3009
|
-
*/
|
|
3010
|
-
|
|
3011
3157
|
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 };
|
|
3012
3158
|
//# sourceMappingURL=testing.mjs.map
|