Skip to content

Commit

Permalink
refactor(router): Update integration tests to cover navigation and hi…
Browse files Browse the repository at this point in the history
…story API (angular#53799)

This commit updates the router integration tests to cover both the
classic History and the new Navigation API. There is more work to be
done here, but this commit works to prove the efficacy of the
`FakeNavigation` implementation.

PR Close angular#53799
atscott committed Jan 9, 2024
1 parent 2dedc4a commit eb2e879
Showing 7 changed files with 6,028 additions and 5,896 deletions.
1 change: 1 addition & 0 deletions packages/common/src/private_export.ts
Original file line number Diff line number Diff line change
@@ -7,3 +7,4 @@
*/

export {DomAdapter as ɵDomAdapter, getDOM as ɵgetDOM, setRootDomAdapter as ɵsetRootDomAdapter} from './dom_adapter';
export {PlatformNavigation as ɵPlatformNavigation} from './navigation/platform_navigation';
85 changes: 83 additions & 2 deletions packages/common/testing/src/mock_platform_location.ts
Original file line number Diff line number Diff line change
@@ -6,10 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/

import {LocationChangeEvent, LocationChangeListener, PlatformLocation} from '@angular/common';
import {Inject, Injectable, InjectionToken, Optional} from '@angular/core';
import {DOCUMENT, LocationChangeEvent, LocationChangeListener, PlatformLocation, ɵPlatformNavigation as PlatformNavigation} from '@angular/common';
import {Inject, inject, Injectable, InjectionToken, Optional} from '@angular/core';
import {Subject} from 'rxjs';

import {FakeNavigation} from './navigation/fake_navigation';

/**
* Parser from https://tools.ietf.org/html/rfc3986#appendix-B
* ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
@@ -250,3 +252,82 @@ export class MockPlatformLocation implements PlatformLocation {
}
}
}

/**
* Mock implementation of URL state.
*/
@Injectable()
export class FakeNavigationPlatformLocation implements PlatformLocation {
private _platformNavigation = inject(PlatformNavigation) as FakeNavigation;
private window = inject(DOCUMENT).defaultView!;

constructor() {
if (!(this._platformNavigation instanceof FakeNavigation)) {
throw new Error(
'FakePlatformNavigation cannot be used without FakeNavigation. Use ' +
'`provideFakeNavigation` to have all these services provided together.',
);
}
}

private config = inject(MOCK_PLATFORM_LOCATION_CONFIG, {optional: true});
getBaseHrefFromDOM(): string {
return this.config?.appBaseHref ?? '';
}

onPopState(fn: LocationChangeListener): VoidFunction {
this.window.addEventListener('popstate', fn);
return () => this.window.removeEventListener('popstate', fn);
}

onHashChange(fn: LocationChangeListener): VoidFunction {
this.window.addEventListener('hashchange', fn as any);
return () => this.window.removeEventListener('hashchange', fn as any);
}

get href(): string {
return this._platformNavigation.currentEntry.url!;
}
get protocol(): string {
return new URL(this._platformNavigation.currentEntry.url!).protocol;
}
get hostname(): string {
return new URL(this._platformNavigation.currentEntry.url!).hostname;
}
get port(): string {
return new URL(this._platformNavigation.currentEntry.url!).port;
}
get pathname(): string {
return new URL(this._platformNavigation.currentEntry.url!).pathname;
}
get search(): string {
return new URL(this._platformNavigation.currentEntry.url!).search;
}
get hash(): string {
return new URL(this._platformNavigation.currentEntry.url!).hash;
}

pushState(state: any, title: string, url: string): void {
this._platformNavigation.pushState(state, title, url);
}

replaceState(state: any, title: string, url: string): void {
this._platformNavigation.replaceState(state, title, url);
}

forward(): void {
this._platformNavigation.forward();
}

back(): void {
this._platformNavigation.back();
}

historyGo(relativePosition: number = 0): void {
this._platformNavigation.go(relativePosition);
}

getState(): unknown {
return this._platformNavigation.currentEntry.getHistoryState();
}
}
3 changes: 0 additions & 3 deletions packages/common/testing/src/navigation/fake_navigation.ts
Original file line number Diff line number Diff line change
@@ -6,9 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/

// Prevents deletion of `Event` from `globalThis` during module loading.
const Event = globalThis.Event;

/**
* Fake implementation of user agent history and navigation behavior. This is a
* high-fidelity implementation of browser behavior that attempts to emulate
Original file line number Diff line number Diff line change
@@ -6,25 +6,29 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Provider} from '@angular/core';
import {DOCUMENT, PlatformLocation} from '@angular/common';
import {inject, Provider} from '@angular/core';

// @ng_package: ignore-cross-repo-import
import {PlatformNavigation} from '../../../src/navigation/platform_navigation';
import {FakeNavigationPlatformLocation, MOCK_PLATFORM_LOCATION_CONFIG} from '../mock_platform_location';

import {FakeNavigation} from './fake_navigation';

/**
* Return a provider for the `FakeNavigation` in place of the real Navigation API.
*
* @internal
*/
export function provideFakePlatformNavigation(): Provider[] {
return [
{
provide: PlatformNavigation,
useFactory: () => {
return new FakeNavigation(window, 'https://test.com');
const config = inject(MOCK_PLATFORM_LOCATION_CONFIG, {optional: true});
return new FakeNavigation(
inject(DOCUMENT).defaultView!,
config?.startUrl as `http${string}` ?? 'http://_empty_/');
}
},
{provide: PlatformLocation, useClass: FakeNavigationPlatformLocation},
];
}
9 changes: 9 additions & 0 deletions packages/common/testing/src/private_export.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

export {provideFakePlatformNavigation as ɵprovideFakePlatformNavigation} from './navigation/provide_fake_platform_navigation';
2 changes: 2 additions & 0 deletions packages/common/testing/src/testing.ts
Original file line number Diff line number Diff line change
@@ -11,6 +11,8 @@
* @description
* Entry point for all public APIs of the common/testing package.
*/

export * from './private_export';
export {SpyLocation} from './location_mock';
export {MockLocationStrategy} from './mock_location_strategy';
export {MOCK_PLATFORM_LOCATION_CONFIG, MockPlatformLocation, MockPlatformLocationConfig} from './mock_platform_location';
Loading
Oops, something went wrong.

0 comments on commit eb2e879

Please sign in to comment.