@angular/core 19.2.0-rc.0 → 19.2.1

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.
Files changed (43) hide show
  1. package/fesm2022/core.mjs +510 -335
  2. package/fesm2022/core.mjs.map +1 -1
  3. package/fesm2022/primitives/di.mjs +45 -0
  4. package/fesm2022/primitives/di.mjs.map +1 -0
  5. package/fesm2022/primitives/event-dispatch.mjs +2 -2
  6. package/fesm2022/primitives/signals.mjs +2 -2
  7. package/fesm2022/rxjs-interop.mjs +2 -2
  8. package/fesm2022/testing.mjs +858 -6
  9. package/fesm2022/testing.mjs.map +1 -1
  10. package/index.d.ts +221 -48
  11. package/package.json +5 -1
  12. package/primitives/di/index.d.ts +99 -0
  13. package/primitives/event-dispatch/index.d.ts +2 -2
  14. package/primitives/signals/index.d.ts +2 -2
  15. package/rxjs-interop/index.d.ts +2 -2
  16. package/schematics/bundles/{apply_import_manager-a930fcf1.js → apply_import_manager-b8d6885d.js} +4 -4
  17. package/schematics/bundles/{checker-2eecc677.js → checker-89987c98.js} +11 -15
  18. package/schematics/bundles/cleanup-unused-imports.js +8 -8
  19. package/schematics/bundles/{compiler_host-c280a924.js → compiler_host-2398e4ca.js} +3 -3
  20. package/schematics/bundles/control-flow-migration.js +4 -4
  21. package/schematics/bundles/explicit-standalone-flag.js +6 -6
  22. package/schematics/bundles/{imports-abe29092.js → imports-047fbbc8.js} +2 -2
  23. package/schematics/bundles/{index-3891dd55.js → index-10911843.js} +5 -5
  24. package/schematics/bundles/{index-24a2ad1e.js → index-e0b2e4a7.js} +5 -5
  25. package/schematics/bundles/inject-migration.js +8 -8
  26. package/schematics/bundles/{leading_space-d190b83b.js → leading_space-f8944434.js} +2 -2
  27. package/schematics/bundles/{migrate_ts_type_references-71b3a951.js → migrate_ts_type_references-52508cd4.js} +7 -7
  28. package/schematics/bundles/{ng_decorators-e699c081.js → ng_decorators-b0d8b324.js} +3 -3
  29. package/schematics/bundles/{nodes-a535b2be.js → nodes-7758dbf6.js} +2 -2
  30. package/schematics/bundles/output-migration.js +8 -8
  31. package/schematics/bundles/pending-tasks.js +6 -6
  32. package/schematics/bundles/{program-24da9092.js → program-0e1d4f10.js} +13 -13
  33. package/schematics/bundles/{project_paths-b073c4d6.js → project_paths-c48796dd.js} +4 -4
  34. package/schematics/bundles/{project_tsconfig_paths-e9ccccbf.js → project_tsconfig_paths-b558633b.js} +2 -2
  35. package/schematics/bundles/{property_name-7c8433f5.js → property_name-ac18447e.js} +2 -2
  36. package/schematics/bundles/provide-initializer.js +6 -6
  37. package/schematics/bundles/route-lazy-loading.js +6 -6
  38. package/schematics/bundles/self-closing-tags-migration.js +44 -28
  39. package/schematics/bundles/signal-input-migration.js +10 -10
  40. package/schematics/bundles/signal-queries-migration.js +10 -10
  41. package/schematics/bundles/signals.js +10 -10
  42. package/schematics/bundles/standalone-migration.js +10 -10
  43. package/testing/index.d.ts +309 -2
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license Angular v19.2.0-rc.0
3
- * (c) 2010-2024 Google LLC. https://angular.io/
2
+ * @license Angular v19.2.1
3
+ * (c) 2010-2025 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
6
6
 
@@ -175,10 +175,10 @@ class TestBedApplicationErrorHandler {
175
175
  throw e;
176
176
  }
177
177
  }
178
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0-rc.0", ngImport: i0, type: TestBedApplicationErrorHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
179
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.0-rc.0", ngImport: i0, type: TestBedApplicationErrorHandler });
178
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: TestBedApplicationErrorHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
179
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: TestBedApplicationErrorHandler });
180
180
  }
181
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0-rc.0", ngImport: i0, type: TestBedApplicationErrorHandler, decorators: [{
181
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: TestBedApplicationErrorHandler, decorators: [{
182
182
  type: Injectable
183
183
  }] });
184
184
 
@@ -2308,6 +2308,858 @@ const __core_private_testing_placeholder__ = '';
2308
2308
  * Entry point for all public APIs of the core/testing package.
2309
2309
  */
2310
2310
 
2311
+ /**
2312
+ * Fake implementation of user agent history and navigation behavior. This is a
2313
+ * high-fidelity implementation of browser behavior that attempts to emulate
2314
+ * things like traversal delay.
2315
+ */
2316
+ class FakeNavigation {
2317
+ window;
2318
+ /**
2319
+ * The fake implementation of an entries array. Only same-document entries
2320
+ * allowed.
2321
+ */
2322
+ entriesArr = [];
2323
+ /**
2324
+ * The current active entry index into `entriesArr`.
2325
+ */
2326
+ currentEntryIndex = 0;
2327
+ /**
2328
+ * The current navigate event.
2329
+ * @internal
2330
+ */
2331
+ navigateEvent = null;
2332
+ /**
2333
+ * A Map of pending traversals, so that traversals to the same entry can be
2334
+ * re-used.
2335
+ */
2336
+ traversalQueue = new Map();
2337
+ /**
2338
+ * A Promise that resolves when the previous traversals have finished. Used to
2339
+ * simulate the cross-process communication necessary for traversals.
2340
+ */
2341
+ nextTraversal = Promise.resolve();
2342
+ /**
2343
+ * A prospective current active entry index, which includes unresolved
2344
+ * traversals. Used by `go` to determine where navigations are intended to go.
2345
+ */
2346
+ prospectiveEntryIndex = 0;
2347
+ /**
2348
+ * A test-only option to make traversals synchronous, rather than emulate
2349
+ * cross-process communication.
2350
+ */
2351
+ synchronousTraversals = false;
2352
+ /** Whether to allow a call to setInitialEntryForTesting. */
2353
+ canSetInitialEntry = true;
2354
+ /**
2355
+ * `EventTarget` to dispatch events.
2356
+ * @internal
2357
+ */
2358
+ eventTarget;
2359
+ /** The next unique id for created entries. Replace recreates this id. */
2360
+ nextId = 0;
2361
+ /** The next unique key for created entries. Replace inherits this id. */
2362
+ nextKey = 0;
2363
+ /** Whether this fake is disposed. */
2364
+ disposed = false;
2365
+ /** Equivalent to `navigation.currentEntry`. */
2366
+ get currentEntry() {
2367
+ return this.entriesArr[this.currentEntryIndex];
2368
+ }
2369
+ get canGoBack() {
2370
+ return this.currentEntryIndex > 0;
2371
+ }
2372
+ get canGoForward() {
2373
+ return this.currentEntryIndex < this.entriesArr.length - 1;
2374
+ }
2375
+ constructor(window, startURL) {
2376
+ this.window = window;
2377
+ this.eventTarget = this.window.document.createElement('div');
2378
+ // First entry.
2379
+ this.setInitialEntryForTesting(startURL);
2380
+ }
2381
+ /**
2382
+ * Sets the initial entry.
2383
+ */
2384
+ setInitialEntryForTesting(url, options = { historyState: null }) {
2385
+ if (!this.canSetInitialEntry) {
2386
+ throw new Error('setInitialEntryForTesting can only be called before any ' + 'navigation has occurred');
2387
+ }
2388
+ const currentInitialEntry = this.entriesArr[0];
2389
+ this.entriesArr[0] = new FakeNavigationHistoryEntry(this.window.document.createElement('div'), new URL(url).toString(), {
2390
+ index: 0,
2391
+ key: currentInitialEntry?.key ?? String(this.nextKey++),
2392
+ id: currentInitialEntry?.id ?? String(this.nextId++),
2393
+ sameDocument: true,
2394
+ historyState: options?.historyState,
2395
+ state: options.state,
2396
+ });
2397
+ }
2398
+ /** Returns whether the initial entry is still eligible to be set. */
2399
+ canSetInitialEntryForTesting() {
2400
+ return this.canSetInitialEntry;
2401
+ }
2402
+ /**
2403
+ * Sets whether to emulate traversals as synchronous rather than
2404
+ * asynchronous.
2405
+ */
2406
+ setSynchronousTraversalsForTesting(synchronousTraversals) {
2407
+ this.synchronousTraversals = synchronousTraversals;
2408
+ }
2409
+ /** Equivalent to `navigation.entries()`. */
2410
+ entries() {
2411
+ return this.entriesArr.slice();
2412
+ }
2413
+ /** Equivalent to `navigation.navigate()`. */
2414
+ navigate(url, options) {
2415
+ const fromUrl = new URL(this.currentEntry.url);
2416
+ const toUrl = new URL(url, this.currentEntry.url);
2417
+ let navigationType;
2418
+ if (!options?.history || options.history === 'auto') {
2419
+ // Auto defaults to push, but if the URLs are the same, is a replace.
2420
+ if (fromUrl.toString() === toUrl.toString()) {
2421
+ navigationType = 'replace';
2422
+ }
2423
+ else {
2424
+ navigationType = 'push';
2425
+ }
2426
+ }
2427
+ else {
2428
+ navigationType = options.history;
2429
+ }
2430
+ const hashChange = isHashChange(fromUrl, toUrl);
2431
+ const destination = new FakeNavigationDestination({
2432
+ url: toUrl.toString(),
2433
+ state: options?.state,
2434
+ sameDocument: hashChange,
2435
+ historyState: null,
2436
+ });
2437
+ const result = new InternalNavigationResult(this);
2438
+ this.userAgentNavigate(destination, result, {
2439
+ navigationType,
2440
+ cancelable: true,
2441
+ canIntercept: true,
2442
+ // Always false for navigate().
2443
+ userInitiated: false,
2444
+ hashChange,
2445
+ info: options?.info,
2446
+ });
2447
+ return {
2448
+ committed: result.committed,
2449
+ finished: result.finished,
2450
+ };
2451
+ }
2452
+ /** Equivalent to `history.pushState()`. */
2453
+ pushState(data, title, url) {
2454
+ this.pushOrReplaceState('push', data, title, url);
2455
+ }
2456
+ /** Equivalent to `history.replaceState()`. */
2457
+ replaceState(data, title, url) {
2458
+ this.pushOrReplaceState('replace', data, title, url);
2459
+ }
2460
+ pushOrReplaceState(navigationType, data, _title, url) {
2461
+ const fromUrl = new URL(this.currentEntry.url);
2462
+ const toUrl = url ? new URL(url, this.currentEntry.url) : fromUrl;
2463
+ const hashChange = isHashChange(fromUrl, toUrl);
2464
+ const destination = new FakeNavigationDestination({
2465
+ url: toUrl.toString(),
2466
+ sameDocument: true,
2467
+ historyState: data,
2468
+ });
2469
+ const result = new InternalNavigationResult(this);
2470
+ this.userAgentNavigate(destination, result, {
2471
+ navigationType,
2472
+ cancelable: true,
2473
+ canIntercept: true,
2474
+ // Always false for pushState() or replaceState().
2475
+ userInitiated: false,
2476
+ hashChange,
2477
+ });
2478
+ }
2479
+ /** Equivalent to `navigation.traverseTo()`. */
2480
+ traverseTo(key, options) {
2481
+ const fromUrl = new URL(this.currentEntry.url);
2482
+ const entry = this.findEntry(key);
2483
+ if (!entry) {
2484
+ const domException = new DOMException('Invalid key', 'InvalidStateError');
2485
+ const committed = Promise.reject(domException);
2486
+ const finished = Promise.reject(domException);
2487
+ committed.catch(() => { });
2488
+ finished.catch(() => { });
2489
+ return {
2490
+ committed,
2491
+ finished,
2492
+ };
2493
+ }
2494
+ if (entry === this.currentEntry) {
2495
+ return {
2496
+ committed: Promise.resolve(this.currentEntry),
2497
+ finished: Promise.resolve(this.currentEntry),
2498
+ };
2499
+ }
2500
+ if (this.traversalQueue.has(entry.key)) {
2501
+ const existingResult = this.traversalQueue.get(entry.key);
2502
+ return {
2503
+ committed: existingResult.committed,
2504
+ finished: existingResult.finished,
2505
+ };
2506
+ }
2507
+ const hashChange = isHashChange(fromUrl, new URL(entry.url, this.currentEntry.url));
2508
+ const destination = new FakeNavigationDestination({
2509
+ url: entry.url,
2510
+ state: entry.getState(),
2511
+ historyState: entry.getHistoryState(),
2512
+ key: entry.key,
2513
+ id: entry.id,
2514
+ index: entry.index,
2515
+ sameDocument: entry.sameDocument,
2516
+ });
2517
+ this.prospectiveEntryIndex = entry.index;
2518
+ const result = new InternalNavigationResult(this);
2519
+ this.traversalQueue.set(entry.key, result);
2520
+ this.runTraversal(() => {
2521
+ this.traversalQueue.delete(entry.key);
2522
+ const event = this.userAgentNavigate(destination, result, {
2523
+ navigationType: 'traverse',
2524
+ cancelable: true,
2525
+ canIntercept: true,
2526
+ // Always false for traverseTo().
2527
+ userInitiated: false,
2528
+ hashChange,
2529
+ info: options?.info,
2530
+ });
2531
+ // Note this does not pay attention at all to the commit status of the event (and thus, does not support deferred commit for traversals)
2532
+ this.userAgentTraverse(event);
2533
+ });
2534
+ return {
2535
+ committed: result.committed,
2536
+ finished: result.finished,
2537
+ };
2538
+ }
2539
+ /** Equivalent to `navigation.back()`. */
2540
+ back(options) {
2541
+ if (this.currentEntryIndex === 0) {
2542
+ const domException = new DOMException('Cannot go back', 'InvalidStateError');
2543
+ const committed = Promise.reject(domException);
2544
+ const finished = Promise.reject(domException);
2545
+ committed.catch(() => { });
2546
+ finished.catch(() => { });
2547
+ return {
2548
+ committed,
2549
+ finished,
2550
+ };
2551
+ }
2552
+ const entry = this.entriesArr[this.currentEntryIndex - 1];
2553
+ return this.traverseTo(entry.key, options);
2554
+ }
2555
+ /** Equivalent to `navigation.forward()`. */
2556
+ forward(options) {
2557
+ if (this.currentEntryIndex === this.entriesArr.length - 1) {
2558
+ const domException = new DOMException('Cannot go forward', 'InvalidStateError');
2559
+ const committed = Promise.reject(domException);
2560
+ const finished = Promise.reject(domException);
2561
+ committed.catch(() => { });
2562
+ finished.catch(() => { });
2563
+ return {
2564
+ committed,
2565
+ finished,
2566
+ };
2567
+ }
2568
+ const entry = this.entriesArr[this.currentEntryIndex + 1];
2569
+ return this.traverseTo(entry.key, options);
2570
+ }
2571
+ /**
2572
+ * Equivalent to `history.go()`.
2573
+ * Note that this method does not actually work precisely to how Chrome
2574
+ * does, instead choosing a simpler model with less unexpected behavior.
2575
+ * Chrome has a few edge case optimizations, for instance with repeated
2576
+ * `back(); forward()` chains it collapses certain traversals.
2577
+ */
2578
+ go(direction) {
2579
+ const targetIndex = this.prospectiveEntryIndex + direction;
2580
+ if (targetIndex >= this.entriesArr.length || targetIndex < 0) {
2581
+ return;
2582
+ }
2583
+ this.prospectiveEntryIndex = targetIndex;
2584
+ this.runTraversal(() => {
2585
+ // Check again that destination is in the entries array.
2586
+ if (targetIndex >= this.entriesArr.length || targetIndex < 0) {
2587
+ return;
2588
+ }
2589
+ const fromUrl = new URL(this.currentEntry.url);
2590
+ const entry = this.entriesArr[targetIndex];
2591
+ const hashChange = isHashChange(fromUrl, new URL(entry.url, this.currentEntry.url));
2592
+ const destination = new FakeNavigationDestination({
2593
+ url: entry.url,
2594
+ state: entry.getState(),
2595
+ historyState: entry.getHistoryState(),
2596
+ key: entry.key,
2597
+ id: entry.id,
2598
+ index: entry.index,
2599
+ sameDocument: entry.sameDocument,
2600
+ });
2601
+ const result = new InternalNavigationResult(this);
2602
+ const event = this.userAgentNavigate(destination, result, {
2603
+ navigationType: 'traverse',
2604
+ cancelable: true,
2605
+ canIntercept: true,
2606
+ // Always false for go().
2607
+ userInitiated: false,
2608
+ hashChange,
2609
+ });
2610
+ // Note this does not pay attention at all to the commit status of the event (and thus, does not support deferred commit for traversals)
2611
+ this.userAgentTraverse(event);
2612
+ });
2613
+ }
2614
+ /** Runs a traversal synchronously or asynchronously */
2615
+ runTraversal(traversal) {
2616
+ if (this.synchronousTraversals) {
2617
+ traversal();
2618
+ return;
2619
+ }
2620
+ // Each traversal occupies a single timeout resolution.
2621
+ // This means that Promises added to commit and finish should resolve
2622
+ // before the next traversal.
2623
+ this.nextTraversal = this.nextTraversal.then(() => {
2624
+ return new Promise((resolve) => {
2625
+ setTimeout(() => {
2626
+ resolve();
2627
+ traversal();
2628
+ });
2629
+ });
2630
+ });
2631
+ }
2632
+ /** Equivalent to `navigation.addEventListener()`. */
2633
+ addEventListener(type, callback, options) {
2634
+ this.eventTarget.addEventListener(type, callback, options);
2635
+ }
2636
+ /** Equivalent to `navigation.removeEventListener()`. */
2637
+ removeEventListener(type, callback, options) {
2638
+ this.eventTarget.removeEventListener(type, callback, options);
2639
+ }
2640
+ /** Equivalent to `navigation.dispatchEvent()` */
2641
+ dispatchEvent(event) {
2642
+ return this.eventTarget.dispatchEvent(event);
2643
+ }
2644
+ /** Cleans up resources. */
2645
+ dispose() {
2646
+ // Recreate eventTarget to release current listeners.
2647
+ // `document.createElement` because NodeJS `EventTarget` is incompatible with Domino's `Event`.
2648
+ this.eventTarget = this.window.document.createElement('div');
2649
+ this.disposed = true;
2650
+ }
2651
+ /** Returns whether this fake is disposed. */
2652
+ isDisposed() {
2653
+ return this.disposed;
2654
+ }
2655
+ /** Implementation for all navigations and traversals. */
2656
+ userAgentNavigate(destination, result, options) {
2657
+ // The first navigation should disallow any future calls to set the initial
2658
+ // entry.
2659
+ this.canSetInitialEntry = false;
2660
+ if (this.navigateEvent) {
2661
+ this.navigateEvent.cancel(new DOMException('Navigation was aborted', 'AbortError'));
2662
+ this.navigateEvent = null;
2663
+ }
2664
+ return dispatchNavigateEvent({
2665
+ navigationType: options.navigationType,
2666
+ cancelable: options.cancelable,
2667
+ canIntercept: options.canIntercept,
2668
+ userInitiated: options.userInitiated,
2669
+ hashChange: options.hashChange,
2670
+ signal: result.signal,
2671
+ destination,
2672
+ info: options.info,
2673
+ sameDocument: destination.sameDocument,
2674
+ result,
2675
+ });
2676
+ }
2677
+ /**
2678
+ * Implementation to commit a navigation.
2679
+ * https://whatpr.org/html/10919/nav-history-apis.html#navigateevent-commit
2680
+ * @internal
2681
+ */
2682
+ commitNavigateEvent(navigateEvent) {
2683
+ navigateEvent.interceptionState = 'committed';
2684
+ const from = this.currentEntry;
2685
+ if (!from) {
2686
+ throw new Error('cannot commit navigation when current entry is null');
2687
+ }
2688
+ if (!navigateEvent.sameDocument) {
2689
+ const error = new Error('Cannot navigate to a non-same-document URL.');
2690
+ navigateEvent.cancel(error);
2691
+ throw error;
2692
+ }
2693
+ // "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."
2694
+ if (navigateEvent.navigationType === 'push' || navigateEvent.navigationType === 'replace') {
2695
+ this.urlAndHistoryUpdateSteps(navigateEvent);
2696
+ }
2697
+ else if (navigateEvent.navigationType === 'reload') {
2698
+ this.updateNavigationEntriesForSameDocumentNavigation(navigateEvent);
2699
+ }
2700
+ else if (navigateEvent.navigationType === 'traverse') {
2701
+ // "If navigationType is "traverse", then this event firing is happening as part of the traversal process, and that process will take care of performing the appropriate session history entry updates."
2702
+ }
2703
+ }
2704
+ /**
2705
+ * Implementation for a push or replace navigation.
2706
+ * https://whatpr.org/html/10919/browsing-the-web.html#url-and-history-update-steps
2707
+ * https://whatpr.org/html/10919/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation
2708
+ */
2709
+ urlAndHistoryUpdateSteps(navigateEvent) {
2710
+ this.updateNavigationEntriesForSameDocumentNavigation(navigateEvent);
2711
+ }
2712
+ /**
2713
+ * Implementation for a traverse navigation.
2714
+ *
2715
+ * https://whatpr.org/html/10919/browsing-the-web.html#apply-the-traverse-history-step
2716
+ * ...
2717
+ * > 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.
2718
+ * > If targetEntry's document is equal to displayedDocument, then perform updateDocument.
2719
+ * https://whatpr.org/html/10919/browsing-the-web.html#update-document-for-history-step-application
2720
+ * which then goes to https://whatpr.org/html/10919/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation
2721
+ */
2722
+ userAgentTraverse(navigateEvent) {
2723
+ this.updateNavigationEntriesForSameDocumentNavigation(navigateEvent);
2724
+ // Happens as part of "updating the document" steps https://whatpr.org/html/10919/browsing-the-web.html#updating-the-document
2725
+ const popStateEvent = createPopStateEvent({
2726
+ state: navigateEvent.destination.getHistoryState(),
2727
+ });
2728
+ this.window.dispatchEvent(popStateEvent);
2729
+ // 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
2730
+ }
2731
+ /** https://whatpr.org/html/10919/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation */
2732
+ updateNavigationEntriesForSameDocumentNavigation({ destination, navigationType, result, }) {
2733
+ const oldCurrentNHE = this.currentEntry;
2734
+ const disposedNHEs = [];
2735
+ if (navigationType === 'traverse') {
2736
+ this.currentEntryIndex = destination.index;
2737
+ if (this.currentEntryIndex === -1) {
2738
+ throw new Error('unexpected current entry index');
2739
+ }
2740
+ }
2741
+ else if (navigationType === 'push') {
2742
+ this.currentEntryIndex++;
2743
+ this.prospectiveEntryIndex = this.currentEntryIndex; // prospectiveEntryIndex isn't in the spec but is an implementation detail
2744
+ disposedNHEs.push(...this.entriesArr.splice(this.currentEntryIndex));
2745
+ }
2746
+ else if (navigationType === 'replace') {
2747
+ disposedNHEs.push(oldCurrentNHE);
2748
+ }
2749
+ if (navigationType === 'push' || navigationType === 'replace') {
2750
+ const index = this.currentEntryIndex;
2751
+ const key = navigationType === 'push' ? String(this.nextKey++) : this.currentEntry.key;
2752
+ const newNHE = new FakeNavigationHistoryEntry(this.window.document.createElement('div'), destination.url, {
2753
+ id: String(this.nextId++),
2754
+ key,
2755
+ index,
2756
+ sameDocument: true,
2757
+ state: destination.getState(),
2758
+ historyState: destination.getHistoryState(),
2759
+ });
2760
+ this.entriesArr[this.currentEntryIndex] = newNHE;
2761
+ }
2762
+ result.committedResolve(this.currentEntry);
2763
+ const currentEntryChangeEvent = createFakeNavigationCurrentEntryChangeEvent({
2764
+ from: oldCurrentNHE,
2765
+ navigationType: navigationType,
2766
+ });
2767
+ this.eventTarget.dispatchEvent(currentEntryChangeEvent);
2768
+ for (const disposedNHE of disposedNHEs) {
2769
+ disposedNHE.dispose();
2770
+ }
2771
+ }
2772
+ /** Utility method for finding entries with the given `key`. */
2773
+ findEntry(key) {
2774
+ for (const entry of this.entriesArr) {
2775
+ if (entry.key === key)
2776
+ return entry;
2777
+ }
2778
+ return undefined;
2779
+ }
2780
+ set onnavigate(
2781
+ // tslint:disable-next-line:no-any
2782
+ _handler) {
2783
+ throw new Error('unimplemented');
2784
+ }
2785
+ // tslint:disable-next-line:no-any
2786
+ get onnavigate() {
2787
+ throw new Error('unimplemented');
2788
+ }
2789
+ set oncurrententrychange(_handler) {
2790
+ throw new Error('unimplemented');
2791
+ }
2792
+ get oncurrententrychange() {
2793
+ throw new Error('unimplemented');
2794
+ }
2795
+ set onnavigatesuccess(
2796
+ // tslint:disable-next-line:no-any
2797
+ _handler) {
2798
+ throw new Error('unimplemented');
2799
+ }
2800
+ // tslint:disable-next-line:no-any
2801
+ get onnavigatesuccess() {
2802
+ throw new Error('unimplemented');
2803
+ }
2804
+ set onnavigateerror(
2805
+ // tslint:disable-next-line:no-any
2806
+ _handler) {
2807
+ throw new Error('unimplemented');
2808
+ }
2809
+ // tslint:disable-next-line:no-any
2810
+ get onnavigateerror() {
2811
+ throw new Error('unimplemented');
2812
+ }
2813
+ _transition = null;
2814
+ /** @internal */
2815
+ set transition(t) {
2816
+ this._transition = t;
2817
+ }
2818
+ get transition() {
2819
+ return this._transition;
2820
+ }
2821
+ updateCurrentEntry(_options) {
2822
+ throw new Error('unimplemented');
2823
+ }
2824
+ reload(_options) {
2825
+ throw new Error('unimplemented');
2826
+ }
2827
+ }
2828
+ /**
2829
+ * Fake equivalent of `NavigationHistoryEntry`.
2830
+ */
2831
+ class FakeNavigationHistoryEntry {
2832
+ eventTarget;
2833
+ url;
2834
+ sameDocument;
2835
+ id;
2836
+ key;
2837
+ index;
2838
+ state;
2839
+ historyState;
2840
+ // tslint:disable-next-line:no-any
2841
+ ondispose = null;
2842
+ constructor(eventTarget, url, { id, key, index, sameDocument, state, historyState, }) {
2843
+ this.eventTarget = eventTarget;
2844
+ this.url = url;
2845
+ this.id = id;
2846
+ this.key = key;
2847
+ this.index = index;
2848
+ this.sameDocument = sameDocument;
2849
+ this.state = state;
2850
+ this.historyState = historyState;
2851
+ }
2852
+ getState() {
2853
+ // Budget copy.
2854
+ return this.state ? JSON.parse(JSON.stringify(this.state)) : this.state;
2855
+ }
2856
+ getHistoryState() {
2857
+ // Budget copy.
2858
+ return this.historyState
2859
+ ? JSON.parse(JSON.stringify(this.historyState))
2860
+ : this.historyState;
2861
+ }
2862
+ addEventListener(type, callback, options) {
2863
+ this.eventTarget.addEventListener(type, callback, options);
2864
+ }
2865
+ removeEventListener(type, callback, options) {
2866
+ this.eventTarget.removeEventListener(type, callback, options);
2867
+ }
2868
+ dispatchEvent(event) {
2869
+ return this.eventTarget.dispatchEvent(event);
2870
+ }
2871
+ /** internal */
2872
+ dispose() {
2873
+ const disposeEvent = new Event('disposed');
2874
+ this.dispatchEvent(disposeEvent);
2875
+ // release current listeners
2876
+ this.eventTarget = null;
2877
+ }
2878
+ }
2879
+ /**
2880
+ * Create a fake equivalent of `NavigateEvent`. This is not a class because ES5
2881
+ * transpiled JavaScript cannot extend native Event.
2882
+ *
2883
+ * https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigate-event-firing
2884
+ */
2885
+ function dispatchNavigateEvent({ cancelable, canIntercept, userInitiated, hashChange, navigationType, signal, destination, info, sameDocument, result, }) {
2886
+ const { navigation } = result;
2887
+ const event = new Event('navigate', { bubbles: false, cancelable });
2888
+ event.focusResetBehavior = null;
2889
+ event.scrollBehavior = null;
2890
+ event.interceptionState = 'none';
2891
+ event.canIntercept = canIntercept;
2892
+ event.userInitiated = userInitiated;
2893
+ event.hashChange = hashChange;
2894
+ event.navigationType = navigationType;
2895
+ event.signal = signal;
2896
+ event.destination = destination;
2897
+ event.info = info;
2898
+ event.downloadRequest = null;
2899
+ event.formData = null;
2900
+ event.result = result;
2901
+ event.sameDocument = sameDocument;
2902
+ event.commitOption = 'immediate';
2903
+ let handlersFinished = [Promise.resolve()];
2904
+ let dispatchedNavigateEvent = false;
2905
+ event.intercept = function (options) {
2906
+ if (!this.canIntercept) {
2907
+ throw new DOMException(`Cannot intercept when canIntercept is 'false'`, 'SecurityError');
2908
+ }
2909
+ this.interceptionState = 'intercepted';
2910
+ event.sameDocument = true;
2911
+ const handler = options?.handler;
2912
+ if (handler) {
2913
+ handlersFinished.push(handler());
2914
+ }
2915
+ // override old options with new ones. UA _may_ report a console warning if new options differ from previous
2916
+ event.commitOption = options?.commit ?? event.commitOption;
2917
+ event.scrollBehavior = options?.scroll ?? event.scrollBehavior;
2918
+ event.focusResetBehavior = options?.focusReset ?? event.focusResetBehavior;
2919
+ };
2920
+ event.scroll = function () {
2921
+ if (event.interceptionState !== 'committed') {
2922
+ throw new DOMException(`Failed to execute 'scroll' on 'NavigateEvent': scroll() must be ` +
2923
+ `called after commit() and interception options must specify manual scroll.`, 'InvalidStateError');
2924
+ }
2925
+ processScrollBehavior(event);
2926
+ };
2927
+ event.commit = function (internal = false) {
2928
+ if (!internal && this.interceptionState !== 'intercepted') {
2929
+ throw new DOMException(`Failed to execute 'commit' on 'NavigateEvent': intercept() must be ` +
2930
+ `called before commit() and commit() cannot be already called.`, 'InvalidStateError');
2931
+ }
2932
+ if (!internal && event.commitOption !== 'after-transition') {
2933
+ throw new DOMException(`Failed to execute 'commit' on 'NavigateEvent': commit() may not be ` +
2934
+ `called if commit behavior is not "after-transition",.`, 'InvalidStateError');
2935
+ }
2936
+ if (!dispatchedNavigateEvent) {
2937
+ throw new DOMException(`Failed to execute 'commit' on 'NavigateEvent': commit() may not be ` +
2938
+ `called during event dispatch.`, 'InvalidStateError');
2939
+ }
2940
+ this.interceptionState = 'committed';
2941
+ result.navigation.commitNavigateEvent(event);
2942
+ };
2943
+ // Internal only.
2944
+ event.cancel = function (reason) {
2945
+ result.committedReject(reason);
2946
+ result.finishedReject(reason);
2947
+ };
2948
+ function dispatch() {
2949
+ navigation.navigateEvent = event;
2950
+ navigation.eventTarget.dispatchEvent(event);
2951
+ dispatchedNavigateEvent = true;
2952
+ if (event.interceptionState !== 'none') {
2953
+ navigation.transition = new InternalNavigationTransition(navigation.currentEntry, navigationType);
2954
+ if (event.commitOption !== 'after-transition') {
2955
+ event.commit(/** internal */ true);
2956
+ }
2957
+ }
2958
+ else {
2959
+ // In the spec, this isn't really part of the navigate API. Instead, the navigate event firing returns "true" to indicate
2960
+ // navigation steps should "continue" (https://whatpr.org/html/10919/browsing-the-web.html#beginning-navigation)
2961
+ event.commit(/** internal */ true);
2962
+ }
2963
+ Promise.all(handlersFinished).then(() => {
2964
+ // Follows steps outlined under "Wait for all of promisesList, with the following success steps:"
2965
+ // in the spec https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigate-event-firing.
2966
+ if (result.signal.aborted) {
2967
+ return;
2968
+ }
2969
+ if (event !== navigation.navigateEvent) {
2970
+ throw new Error("Navigation's ongoing event not equal to resolved event");
2971
+ }
2972
+ navigation.navigateEvent = null;
2973
+ if (event.interceptionState === 'intercepted') {
2974
+ navigation.commitNavigateEvent(event);
2975
+ }
2976
+ finishNavigationEvent(event, true);
2977
+ const navigatesuccessEvent = new Event('navigatesuccess', { bubbles: false, cancelable });
2978
+ navigation.eventTarget.dispatchEvent(navigatesuccessEvent);
2979
+ result.finishedResolve();
2980
+ if (navigation.transition !== null) {
2981
+ navigation.transition.finishedResolve();
2982
+ }
2983
+ navigation.transition = null;
2984
+ }, (reason) => {
2985
+ if (result.signal.aborted) {
2986
+ return;
2987
+ }
2988
+ if (event !== navigation.navigateEvent) {
2989
+ throw new Error("Navigation's ongoing event not equal to resolved event");
2990
+ }
2991
+ navigation.navigateEvent = null;
2992
+ event.interceptionState = 'rejected'; // TODO(atscott): this is not in the spec https://github.com/whatwg/html/issues/11087
2993
+ finishNavigationEvent(event, false);
2994
+ const navigateerrorEvent = new Event('navigateerror', { bubbles: false, cancelable });
2995
+ navigation.eventTarget.dispatchEvent(navigateerrorEvent);
2996
+ result.finishedReject(reason);
2997
+ if (navigation.transition !== null) {
2998
+ navigation.transition.finishedResolve();
2999
+ }
3000
+ navigation.transition = null;
3001
+ });
3002
+ }
3003
+ dispatch();
3004
+ return event;
3005
+ }
3006
+ /** https://whatpr.org/html/10919/nav-history-apis.html#navigateevent-finish */
3007
+ function finishNavigationEvent(event, didFulfill) {
3008
+ if (event.interceptionState === 'intercepted' || event.interceptionState === 'finished') {
3009
+ throw new Error('Attempting to finish navigation event that was incomplete or already finished');
3010
+ }
3011
+ if (event.interceptionState === 'none') {
3012
+ return;
3013
+ }
3014
+ if (didFulfill) {
3015
+ // TODO(atscott): https://github.com/whatwg/html/issues/11087 focus reset is not guarded by didFulfill in the spec
3016
+ potentiallyResetFocus(event);
3017
+ potentiallyResetScroll(event);
3018
+ }
3019
+ event.interceptionState = 'finished';
3020
+ }
3021
+ /** https://whatpr.org/html/10919/nav-history-apis.html#potentially-reset-the-focus */
3022
+ function potentiallyResetFocus(event) {
3023
+ if (event.interceptionState !== 'committed' && event.interceptionState !== 'scrolled') {
3024
+ throw new Error('cannot reset focus if navigation event is not committed or scrolled');
3025
+ }
3026
+ // TODO(atscott): The rest of the steps
3027
+ }
3028
+ function potentiallyResetScroll(event) {
3029
+ if (event.interceptionState !== 'committed' && event.interceptionState !== 'scrolled') {
3030
+ throw new Error('cannot reset scroll if navigation event is not committed or scrolled');
3031
+ }
3032
+ if (event.interceptionState === 'scrolled' || event.scrollBehavior === 'manual') {
3033
+ return;
3034
+ }
3035
+ processScrollBehavior(event);
3036
+ }
3037
+ /* https://whatpr.org/html/10919/nav-history-apis.html#process-scroll-behavior */
3038
+ function processScrollBehavior(event) {
3039
+ if (event.interceptionState !== 'committed') {
3040
+ throw new Error('invalid event interception state when processing scroll behavior');
3041
+ }
3042
+ event.interceptionState = 'scrolled';
3043
+ // TODO(atscott): the rest of the steps
3044
+ }
3045
+ /**
3046
+ * Create a fake equivalent of `NavigationCurrentEntryChange`. This does not use
3047
+ * a class because ES5 transpiled JavaScript cannot extend native Event.
3048
+ */
3049
+ function createFakeNavigationCurrentEntryChangeEvent({ from, navigationType, }) {
3050
+ const event = new Event('currententrychange', {
3051
+ bubbles: false,
3052
+ cancelable: false,
3053
+ });
3054
+ event.from = from;
3055
+ event.navigationType = navigationType;
3056
+ return event;
3057
+ }
3058
+ /**
3059
+ * Create a fake equivalent of `PopStateEvent`. This does not use a class
3060
+ * because ES5 transpiled JavaScript cannot extend native Event.
3061
+ */
3062
+ function createPopStateEvent({ state }) {
3063
+ const event = new Event('popstate', {
3064
+ bubbles: false,
3065
+ cancelable: false,
3066
+ });
3067
+ event.state = state;
3068
+ return event;
3069
+ }
3070
+ /**
3071
+ * Fake equivalent of `NavigationDestination`.
3072
+ */
3073
+ class FakeNavigationDestination {
3074
+ url;
3075
+ sameDocument;
3076
+ key;
3077
+ id;
3078
+ index;
3079
+ state;
3080
+ historyState;
3081
+ constructor({ url, sameDocument, historyState, state, key = null, id = null, index = -1, }) {
3082
+ this.url = url;
3083
+ this.sameDocument = sameDocument;
3084
+ this.state = state;
3085
+ this.historyState = historyState;
3086
+ this.key = key;
3087
+ this.id = id;
3088
+ this.index = index;
3089
+ }
3090
+ getState() {
3091
+ return this.state;
3092
+ }
3093
+ getHistoryState() {
3094
+ return this.historyState;
3095
+ }
3096
+ }
3097
+ /** Utility function to determine whether two UrlLike have the same hash. */
3098
+ function isHashChange(from, to) {
3099
+ return (to.hash !== from.hash &&
3100
+ to.hostname === from.hostname &&
3101
+ to.pathname === from.pathname &&
3102
+ to.search === from.search);
3103
+ }
3104
+ class InternalNavigationTransition {
3105
+ from;
3106
+ navigationType;
3107
+ finished;
3108
+ finishedResolve;
3109
+ finishedReject;
3110
+ constructor(from, navigationType) {
3111
+ this.from = from;
3112
+ this.navigationType = navigationType;
3113
+ this.finished = new Promise((resolve, reject) => {
3114
+ this.finishedReject = reject;
3115
+ this.finishedResolve = resolve;
3116
+ });
3117
+ }
3118
+ }
3119
+ /**
3120
+ * Internal utility class for representing the result of a navigation.
3121
+ * Generally equivalent to the "apiMethodTracker" in the spec.
3122
+ */
3123
+ class InternalNavigationResult {
3124
+ navigation;
3125
+ committedTo = null;
3126
+ committedResolve;
3127
+ committedReject;
3128
+ finishedResolve;
3129
+ finishedReject;
3130
+ committed;
3131
+ finished;
3132
+ get signal() {
3133
+ return this.abortController.signal;
3134
+ }
3135
+ abortController = new AbortController();
3136
+ constructor(navigation) {
3137
+ this.navigation = navigation;
3138
+ this.committed = new Promise((resolve, reject) => {
3139
+ this.committedResolve = (entry) => {
3140
+ this.committedTo = entry;
3141
+ resolve(entry);
3142
+ };
3143
+ this.committedReject = reject;
3144
+ });
3145
+ this.finished = new Promise(async (resolve, reject) => {
3146
+ this.finishedResolve = () => {
3147
+ if (this.committedTo === null) {
3148
+ throw new Error('NavigateEvent should have been committed before resolving finished promise.');
3149
+ }
3150
+ resolve(this.committedTo);
3151
+ };
3152
+ this.finishedReject = (reason) => {
3153
+ reject(reason);
3154
+ this.abortController.abort(reason);
3155
+ };
3156
+ });
3157
+ // All rejections are handled.
3158
+ this.committed.catch(() => { });
3159
+ this.finished.catch(() => { });
3160
+ }
3161
+ }
3162
+
2311
3163
  /// <reference types="jasmine" />
2312
3164
  // This file only reexports content of the `src` folder. Keep it that way.
2313
3165
 
@@ -2317,5 +3169,5 @@ const __core_private_testing_placeholder__ = '';
2317
3169
  * Generated bundle index. Do not edit.
2318
3170
  */
2319
3171
 
2320
- export { ComponentFixture, ComponentFixtureAutoDetect, ComponentFixtureNoNgZone, DeferBlockFixture, InjectSetupWrapper, TestBed, TestComponentRenderer, __core_private_testing_placeholder__, discardPeriodicTasks, fakeAsync, flush, flushMicrotasks, getTestBed, inject, resetFakeAsyncZone, tick, waitForAsync, withModule, MetadataOverrider as ɵMetadataOverrider };
3172
+ 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 };
2321
3173
  //# sourceMappingURL=testing.mjs.map