Skip to content

Commit c795960

Browse files
atscottmmalerba
authored andcommitted
feat(common): Add experimental support for the Navigation API (angular#63406)
The navigation API is part of interop 2025. You can find the implementation status for each major browser here: https://wpt.fyi/results/navigation-api?label=master&label=experimental&aligned&view=interop&q=label%3Ainterop-2025-navigation https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API BREAKING CHANGE: (test only) - `TestBed` now provides a fake `PlatformLocation` implementation that supports the Navigation API. This may break some tests, though we have not observed any failures internally. You can revert to the old default for `TestBed` by providing the `MockPlatformLocation` from `@angular/common/testing` in your providers: `{provide: PlatformLocation, useClass: MockPlatformLocation}` PR Close angular#63406
1 parent 147c743 commit c795960

File tree

8 files changed

+89
-10
lines changed

8 files changed

+89
-10
lines changed

goldens/public-api/common/index.api.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ import { TrackByFunction } from '@angular/core';
3232
import { Type } from '@angular/core';
3333
import { Version } from '@angular/core';
3434
import { ViewContainerRef } from '@angular/core';
35+
import { ɵNavigateEvent } from '@angular/core';
36+
import { ɵNavigation } from '@angular/core';
37+
import { ɵNavigationCurrentEntryChangeEvent } from '@angular/core';
38+
import { ɵNavigationHistoryEntry } from '@angular/core';
39+
import { ɵNavigationNavigateOptions } from '@angular/core';
40+
import { ɵNavigationOptions } from '@angular/core';
41+
import { ɵNavigationReloadOptions } from '@angular/core';
42+
import { ɵNavigationResult } from '@angular/core';
43+
import { ɵNavigationTransition } from '@angular/core';
44+
import { ɵNavigationUpdateCurrentEntryOptions } from '@angular/core';
3545

3646
// @public
3747
export const APP_BASE_HREF: InjectionToken<string>;
@@ -842,6 +852,50 @@ export abstract class PlatformLocation {
842852
static ɵprov: i0.ɵɵInjectableDeclaration<PlatformLocation>;
843853
}
844854

855+
// @public
856+
export abstract class PlatformNavigation implements ɵNavigation {
857+
// (undocumented)
858+
abstract addEventListener(type: unknown, listener: unknown, options?: unknown): void;
859+
// (undocumented)
860+
abstract back(options?: ɵNavigationOptions | undefined): ɵNavigationResult;
861+
// (undocumented)
862+
abstract canGoBack: boolean;
863+
// (undocumented)
864+
abstract canGoForward: boolean;
865+
// (undocumented)
866+
abstract currentEntry: ɵNavigationHistoryEntry | null;
867+
// (undocumented)
868+
abstract dispatchEvent(event: Event): boolean;
869+
// (undocumented)
870+
abstract entries(): ɵNavigationHistoryEntry[];
871+
// (undocumented)
872+
abstract forward(options?: ɵNavigationOptions | undefined): ɵNavigationResult;
873+
// (undocumented)
874+
abstract navigate(url: string, options?: ɵNavigationNavigateOptions | undefined): ɵNavigationResult;
875+
// (undocumented)
876+
abstract oncurrententrychange: ((this: ɵNavigation, ev: ɵNavigationCurrentEntryChangeEvent) => any) | null;
877+
// (undocumented)
878+
abstract onnavigate: ((this: ɵNavigation, ev: ɵNavigateEvent) => any) | null;
879+
// (undocumented)
880+
abstract onnavigateerror: ((this: ɵNavigation, ev: ErrorEvent) => any) | null;
881+
// (undocumented)
882+
abstract onnavigatesuccess: ((this: ɵNavigation, ev: Event) => any) | null;
883+
// (undocumented)
884+
abstract reload(options?: ɵNavigationReloadOptions | undefined): ɵNavigationResult;
885+
// (undocumented)
886+
abstract removeEventListener(type: unknown, listener: unknown, options?: unknown): void;
887+
// (undocumented)
888+
abstract transition: ɵNavigationTransition | null;
889+
// (undocumented)
890+
abstract traverseTo(key: string, options?: ɵNavigationOptions | undefined): ɵNavigationResult;
891+
// (undocumented)
892+
abstract updateCurrentEntry(options: ɵNavigationUpdateCurrentEntryOptions): void;
893+
// (undocumented)
894+
static ɵfac: i0.ɵɵFactoryDeclaration<PlatformNavigation, never>;
895+
// (undocumented)
896+
static ɵprov: i0.ɵɵInjectableDeclaration<PlatformNavigation>;
897+
}
898+
845899
// @public @deprecated
846900
export enum Plural {
847901
// (undocumented)

packages/common/src/common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export {formatDate} from './i18n/format_date';
1717
export {formatCurrency, formatNumber, formatPercent} from './i18n/format_number';
1818
export {NgLocaleLocalization, NgLocalization} from './i18n/localization';
1919
export {registerLocaleData} from './i18n/locale_data';
20+
export {PlatformNavigation} from './navigation/platform_navigation';
2021
export {
2122
Plural,
2223
NumberFormatStyle,

packages/common/src/navigation/platform_navigation.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ import {
2323
/**
2424
* This class wraps the platform Navigation API which allows server-specific and test
2525
* implementations.
26+
*
27+
* Browser support is limited, so this API may not be available in all environments,
28+
* may contain bugs, and is experimental.
29+
*
30+
* @experimental 21.0.0
2631
*/
2732
@Injectable({providedIn: 'platform', useFactory: () => (window as any).navigation})
2833
export abstract class PlatformNavigation implements Navigation {

packages/common/src/private_export.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,3 @@ export {
1111
getDOM as ɵgetDOM,
1212
setRootDomAdapter as ɵsetRootDomAdapter,
1313
} from './dom_adapter';
14-
export {PlatformNavigation as ɵPlatformNavigation} from './navigation/platform_navigation';
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import {ɵFakeNavigation as FakeNavigation} from '../../testing';
10+
import {PlatformNavigation} from '../../index';
11+
import {TestBed} from '@angular/core/testing';
12+
13+
describe('Navigation', () => {
14+
it('provides fake navigation by default', () => {
15+
const nav = TestBed.inject(PlatformNavigation);
16+
expect(nav).toBeInstanceOf(FakeNavigation);
17+
});
18+
19+
it('can inject and use the navigation API by default', async () => {
20+
const nav = TestBed.inject(PlatformNavigation);
21+
expect(nav.entries().length).toBe(1);
22+
await nav.navigate('/someUrl').finished;
23+
expect(nav.entries().length).toBe(2);
24+
});
25+
});

packages/common/testing/src/mock_platform_location.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
LocationChangeEvent,
1212
LocationChangeListener,
1313
PlatformLocation,
14-
ɵPlatformNavigation as PlatformNavigation,
14+
PlatformNavigation,
1515
} from '../../index';
1616
import {Inject, inject, Injectable, InjectionToken, Optional} from '@angular/core';
1717
import {Subject} from 'rxjs';

packages/common/testing/src/navigation/provide_fake_platform_navigation.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {
10-
DOCUMENT,
11-
PlatformLocation,
12-
ɵPlatformNavigation as PlatformNavigation,
13-
} from '../../../index';
9+
import {DOCUMENT, PlatformLocation, PlatformNavigation} from '../../../index';
1410
import {inject, InjectionToken, Provider} from '@angular/core';
1511

1612
import {

packages/platform-browser/testing/src/browser.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.dev/license
77
*/
8-
import {PlatformLocation} from '@angular/common';
9-
import {MockPlatformLocation} from '@angular/common/testing';
8+
import {ɵprovideFakePlatformNavigation} from '@angular/common/testing';
109
import {
1110
APP_ID,
1211
createPlatformFactory,
@@ -40,7 +39,7 @@ export const platformBrowserTesting: (extraProviders?: StaticProvider[]) => Plat
4039
{provide: APP_ID, useValue: 'a'},
4140
internalProvideZoneChangeDetection({}),
4241
{provide: ChangeDetectionScheduler, useExisting: ChangeDetectionSchedulerImpl},
43-
{provide: PlatformLocation, useClass: MockPlatformLocation},
42+
ɵprovideFakePlatformNavigation(),
4443
{provide: TestComponentRenderer, useClass: DOMTestComponentRenderer},
4544
],
4645
})

0 commit comments

Comments
 (0)