Skip to content

Commit c0c7efa

Browse files
AndrewKushnirthePunderWoman
authored andcommitted
feat(common): add provideLocationMocks() function to provide Location mocks (#47674)
This commit adds the `provideLocationMocks()` function that returns mocks for the `Location` and `LocationStrategy` classes. This function can be used in tests to configure an environment where it's possible to fire simulated location events (helpful when testing Router configuration). PR Close #47674
1 parent 4fde292 commit c0c7efa

File tree

11 files changed

+166
-126
lines changed

11 files changed

+166
-126
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Location as Location_2 } from '@angular/common';
1010
import { LocationChangeListener } from '@angular/common';
1111
import { LocationStrategy } from '@angular/common';
1212
import { PlatformLocation } from '@angular/common';
13+
import { Provider } from '@angular/core';
1314
import { SubscriptionLike } from 'rxjs';
1415

1516
// @public
@@ -105,6 +106,9 @@ export interface MockPlatformLocationConfig {
105106
startUrl?: string;
106107
}
107108

109+
// @public
110+
export function provideLocationMocks(): Provider[];
111+
108112
// @public
109113
export class SpyLocation implements Location_2 {
110114
// (undocumented)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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.io/license
7+
*/
8+
9+
import {Location, LocationStrategy} from '@angular/common';
10+
import {MockLocationStrategy, provideLocationMocks, SpyLocation} from '@angular/common/testing';
11+
import {TestBed} from '@angular/core/testing';
12+
13+
14+
describe('provideLocationMocks() function', () => {
15+
it('should mock Location and LocationStrategy classes', () => {
16+
TestBed.configureTestingModule({providers: [provideLocationMocks()]});
17+
const location = TestBed.inject(Location);
18+
const locationStrategy = TestBed.inject(LocationStrategy);
19+
20+
expect(location).toBeInstanceOf(SpyLocation);
21+
expect(locationStrategy).toBeInstanceOf(MockLocationStrategy);
22+
});
23+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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.io/license
7+
*/
8+
9+
import {Location, LocationStrategy} from '@angular/common';
10+
import {Provider} from '@angular/core';
11+
12+
import {SpyLocation} from './location_mock';
13+
import {MockLocationStrategy} from './mock_location_strategy';
14+
15+
/**
16+
* Returns mock providers for the `Location` and `LocationStrategy` classes.
17+
* The mocks are helpful in tests to fire simulated location events.
18+
*
19+
* @developerPreview
20+
* @publicApi
21+
*/
22+
export function provideLocationMocks(): Provider[] {
23+
return [
24+
{provide: Location, useClass: SpyLocation},
25+
{provide: LocationStrategy, useClass: MockLocationStrategy},
26+
];
27+
}

packages/common/testing/src/testing.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
export {SpyLocation} from './location_mock';
1515
export {MockLocationStrategy} from './mock_location_strategy';
1616
export {MOCK_PLATFORM_LOCATION_CONFIG, MockPlatformLocation, MockPlatformLocationConfig} from './mock_platform_location';
17+
export {provideLocationMocks} from './provide_location_mocks';

packages/router/test/computed_state_restoration.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
*/
88

99
import {CommonModule, Location} from '@angular/common';
10-
import {SpyLocation} from '@angular/common/testing';
10+
import {provideLocationMocks, SpyLocation} from '@angular/common/testing';
1111
import {Component, Injectable, NgModule} from '@angular/core';
1212
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
1313
import {expect} from '@angular/platform-browser/testing/src/matchers';
1414
import {CanActivate, CanDeactivate, Resolve, Router, RouterModule, RouterOutlet, UrlTree, withRouterConfig} from '@angular/router';
1515
import {EMPTY, Observable, of} from 'rxjs';
1616

17+
import {provideRouter} from '../src/provide_router';
1718
import {isUrlTree} from '../src/url_tree';
18-
import {provideRouterForTesting} from '../testing/src/provide_router_for_testing';
1919

2020
describe('`restoredState#ɵrouterPageId`', () => {
2121
@Injectable({providedIn: 'root'})
@@ -490,7 +490,8 @@ function advance(fixture: ComponentFixture<any>, millis?: number): void {
490490
CommonModule,
491491
],
492492
providers: [
493-
provideRouterForTesting([], withRouterConfig({canceledNavigationResolution: 'computed'})),
493+
provideLocationMocks(),
494+
provideRouter([], withRouterConfig({canceledNavigationResolution: 'computed'})),
494495
],
495496
exports: [SimpleCmp, RootCmp, ThrowingCmp],
496497
declarations: [SimpleCmp, RootCmp, ThrowingCmp]

packages/router/test/integration.spec.ts

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,19 @@
77
*/
88

99
import {CommonModule, HashLocationStrategy, Location, LocationStrategy} from '@angular/common';
10-
import {SpyLocation} from '@angular/common/testing';
10+
import {provideLocationMocks, SpyLocation} from '@angular/common/testing';
1111
import {ChangeDetectionStrategy, Component, EnvironmentInjector, inject as coreInject, Inject, Injectable, InjectionToken, NgModule, NgModuleRef, NgZone, OnDestroy, QueryList, ViewChild, ViewChildren, ɵConsole as Console, ɵNoopNgZone as NoopNgZone} from '@angular/core';
1212
import {ComponentFixture, fakeAsync, inject, TestBed, tick} from '@angular/core/testing';
1313
import {By} from '@angular/platform-browser/src/dom/debug/by';
1414
import {expect} from '@angular/platform-browser/testing/src/matchers';
1515
import {ActivatedRoute, ActivatedRouteSnapshot, ActivationEnd, ActivationStart, CanActivate, CanDeactivate, ChildActivationEnd, ChildActivationStart, DefaultUrlSerializer, DetachedRouteHandle, Event, GuardsCheckEnd, GuardsCheckStart, Navigation, NavigationCancel, NavigationCancellationCode, NavigationEnd, NavigationError, NavigationStart, ParamMap, Params, PreloadAllModules, PreloadingStrategy, PRIMARY_OUTLET, Resolve, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, Router, RouteReuseStrategy, RouterEvent, RouterLink, RouterLinkActive, RouterModule, RouterOutlet, RouterPreloader, RouterStateSnapshot, RoutesRecognized, RunGuardsAndResolvers, UrlHandlingStrategy, UrlSegmentGroup, UrlSerializer, UrlTree} from '@angular/router';
16-
import {concat, defer, EMPTY, from, Observable, Observer, of, Subscription} from 'rxjs';
16+
import {concat, EMPTY, Observable, Observer, of, Subscription} from 'rxjs';
1717
import {delay, filter, first, last, map, mapTo, takeWhile, tap} from 'rxjs/operators';
1818

1919
import {CanActivateChildFn, CanActivateFn, CanMatch, CanMatchFn, ResolveFn} from '../src/models';
20-
import {withRouterConfig} from '../src/provide_router';
20+
import {provideRouter, withRouterConfig} from '../src/provide_router';
2121
import {forEach, wrapIntoObservable} from '../src/utils/collection';
2222
import {getLoadedRoutes} from '../src/utils/config';
23-
import {provideRouterForTesting} from '../testing/src/provide_router_for_testing';
2423

2524
const ROUTER_DIRECTIVES = [RouterLink, RouterLinkActive, RouterOutlet];
2625

@@ -32,7 +31,8 @@ describe('Integration', () => {
3231
imports: [...ROUTER_DIRECTIVES, TestModule],
3332
providers: [
3433
{provide: Console, useValue: noopConsole},
35-
provideRouterForTesting([{path: 'simple', component: SimpleCmp}])
34+
provideLocationMocks(),
35+
provideRouter([{path: 'simple', component: SimpleCmp}]),
3636
]
3737
});
3838
});
@@ -5451,7 +5451,8 @@ describe('Integration', () => {
54515451
...ROUTER_DIRECTIVES,
54525452
],
54535453
providers: [
5454-
provideRouterForTesting([{path: '', component: SimpleComponent}]),
5454+
provideLocationMocks(),
5455+
provideRouter([{path: '', component: SimpleComponent}]),
54555456
],
54565457
declarations: [LinkComponent, SimpleComponent]
54575458
});
@@ -6532,7 +6533,8 @@ describe('Integration', () => {
65326533
TestBed.configureTestingModule({
65336534
providers: [
65346535
{provide: RouteReuseStrategy, useClass: AttachDetachReuseStrategy},
6535-
provideRouterForTesting()
6536+
provideLocationMocks(),
6537+
provideRouter([]),
65366538
]
65376539
});
65386540

@@ -6698,10 +6700,13 @@ describe('Integration', () => {
66986700
@NgModule({
66996701
declarations: [RootCmpWithCondOutlet, Tool1Component, Tool2Component],
67006702
imports: [CommonModule, ...ROUTER_DIRECTIVES],
6701-
providers: [provideRouterForTesting([
6702-
{path: 'a', outlet: 'toolpanel', component: Tool1Component},
6703-
{path: 'b', outlet: 'toolpanel', component: Tool2Component},
6704-
])]
6703+
providers: [
6704+
provideLocationMocks(),
6705+
provideRouter([
6706+
{path: 'a', outlet: 'toolpanel', component: Tool1Component},
6707+
{path: 'b', outlet: 'toolpanel', component: Tool2Component},
6708+
]),
6709+
]
67056710
})
67066711
class TestModule {
67076712
}
@@ -6756,7 +6761,8 @@ describe('Integration', () => {
67566761
],
67576762
providers: [
67586763
{provide: RouteReuseStrategy, useClass: AttachDetachReuseStrategy},
6759-
provideRouterForTesting([
6764+
provideLocationMocks(),
6765+
provideRouter([
67606766
{path: 'a', component: SimpleCmp},
67616767
{path: 'b', component: BlankCmp},
67626768
]),
@@ -6825,7 +6831,8 @@ describe('Integration', () => {
68256831
providers: [
68266832
{provide: RouteReuseStrategy, useClass: AttachDetachReuseStrategy},
68276833
{provide: CREATED_COMPS, useValue: []},
6828-
provideRouterForTesting([
6834+
provideLocationMocks(),
6835+
provideRouter([
68296836
{path: 'a', component: Parent, children: [{path: 'b', component: Child}]},
68306837
{path: 'c', component: SimpleCmp}
68316838
]),
@@ -6882,9 +6889,10 @@ describe('Integration', () => {
68826889
imports: [ROUTER_DIRECTIVES],
68836890
providers: [
68846891
{provide: RouteReuseStrategy, useClass: AttachDetachReuseStrategy},
6885-
provideRouterForTesting([
6892+
provideLocationMocks(),
6893+
provideRouter([
68866894
{path: 'a', loadChildren: () => LoadedModule}, {path: 'b', component: ComponentB}
6887-
])
6895+
]),
68886896
]
68896897
})
68906898
class TestModule {
@@ -6914,24 +6922,32 @@ describe('Testing router options', () => {
69146922
describe('should configure the router', () => {
69156923
it('assigns onSameUrlNavigation', () => {
69166924
TestBed.configureTestingModule({
6917-
providers: [provideRouterForTesting([], withRouterConfig({onSameUrlNavigation: 'reload'}))]
6925+
providers: [
6926+
provideLocationMocks(),
6927+
provideRouter([], withRouterConfig({onSameUrlNavigation: 'reload'})),
6928+
]
69186929
});
69196930
const router: Router = TestBed.inject(Router);
69206931
expect(router.onSameUrlNavigation).toBe('reload');
69216932
});
69226933

69236934
it('assigns paramsInheritanceStrategy', () => {
69246935
TestBed.configureTestingModule({
6925-
providers:
6926-
[provideRouterForTesting([], withRouterConfig({paramsInheritanceStrategy: 'always'}))]
6936+
providers: [
6937+
provideLocationMocks(),
6938+
provideRouter([], withRouterConfig({paramsInheritanceStrategy: 'always'})),
6939+
]
69276940
});
69286941
const router: Router = TestBed.inject(Router);
69296942
expect(router.paramsInheritanceStrategy).toBe('always');
69306943
});
69316944

69326945
it('assigns urlUpdateStrategy', () => {
69336946
TestBed.configureTestingModule({
6934-
providers: [provideRouterForTesting([], withRouterConfig({urlUpdateStrategy: 'eager'}))]
6947+
providers: [
6948+
provideLocationMocks(),
6949+
provideRouter([], withRouterConfig({urlUpdateStrategy: 'eager'})),
6950+
]
69356951
});
69366952
const router: Router = TestBed.inject(Router);
69376953
expect(router.urlUpdateStrategy).toBe('eager');

packages/router/test/page_title_strategy_spec.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
*/
88

99
import {DOCUMENT} from '@angular/common';
10+
import {provideLocationMocks} from '@angular/common/testing';
1011
import {Component, Inject, Injectable, NgModule} from '@angular/core';
1112
import {fakeAsync, TestBed, tick} from '@angular/core/testing';
12-
import {NavigationEnd, Router, RouterModule, RouterStateSnapshot, TitleStrategy} from '@angular/router';
13+
import {Router, RouterModule, RouterStateSnapshot, TitleStrategy} from '@angular/router';
1314

14-
import {provideRouterForTesting} from '../testing/src/provide_router_for_testing';
15+
import {provideRouter} from '../src/provide_router';
1516

1617
describe('title strategy', () => {
1718
describe('DefaultTitleStrategy', () => {
@@ -23,7 +24,10 @@ describe('title strategy', () => {
2324
imports: [
2425
TestModule,
2526
],
26-
providers: [provideRouterForTesting()]
27+
providers: [
28+
provideLocationMocks(),
29+
provideRouter([]),
30+
]
2731
});
2832
router = TestBed.inject(Router);
2933
document = TestBed.inject(DOCUMENT);
@@ -133,8 +137,9 @@ describe('title strategy', () => {
133137
TestModule,
134138
],
135139
providers: [
136-
provideRouterForTesting(),
137-
{provide: TitleStrategy, useClass: TemplatePageTitleStrategy}
140+
provideLocationMocks(),
141+
provideRouter([]),
142+
{provide: TitleStrategy, useClass: TemplatePageTitleStrategy},
138143
]
139144
});
140145
const router = TestBed.inject(Router);

packages/router/test/regression_integration.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
*/
88

99
import {CommonModule, HashLocationStrategy, Location, LocationStrategy} from '@angular/common';
10-
import {SpyLocation} from '@angular/common/testing';
10+
import {provideLocationMocks, SpyLocation} from '@angular/common/testing';
1111
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Injectable, NgModule, TemplateRef, Type, ViewChild, ViewContainerRef} from '@angular/core';
1212
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
1313
import {ChildrenOutletContexts, Resolve, Router, RouterOutlet} from '@angular/router';
1414
import {RouterTestingModule} from '@angular/router/testing';
1515
import {of} from 'rxjs';
1616
import {delay, mapTo} from 'rxjs/operators';
1717

18-
import {provideRouterForTesting} from '../testing/src/provide_router_for_testing';
18+
import {provideRouter} from '../src/provide_router';
1919

2020
describe('Integration', () => {
2121
describe('routerLinkActive', () => {
@@ -304,7 +304,8 @@ describe('Integration', () => {
304304
imports: [RouterOutlet],
305305
providers: [
306306
DelayedResolve,
307-
provideRouterForTesting(
307+
provideLocationMocks(),
308+
provideRouter(
308309
[
309310
{path: '', component: SimpleCmp},
310311
{path: 'one', component: OneCmp, resolve: {x: DelayedResolve}}

0 commit comments

Comments
 (0)