Skip to content

Commit

Permalink
feat(common): add provideLocationMocks() function to provide Locati…
Browse files Browse the repository at this point in the history
…on 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
  • Loading branch information
AndrewKushnir authored and thePunderWoman committed Oct 10, 2022
1 parent 4fde292 commit c0c7efa
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 126 deletions.
4 changes: 4 additions & 0 deletions goldens/public-api/common/testing/index.md
Expand Up @@ -10,6 +10,7 @@ import { Location as Location_2 } from '@angular/common';
import { LocationChangeListener } from '@angular/common';
import { LocationStrategy } from '@angular/common';
import { PlatformLocation } from '@angular/common';
import { Provider } from '@angular/core';
import { SubscriptionLike } from 'rxjs';

// @public
Expand Down Expand Up @@ -105,6 +106,9 @@ export interface MockPlatformLocationConfig {
startUrl?: string;
}

// @public
export function provideLocationMocks(): Provider[];

// @public
export class SpyLocation implements Location_2 {
// (undocumented)
Expand Down
23 changes: 23 additions & 0 deletions packages/common/test/location/provide_location_mocks_spec.ts
@@ -0,0 +1,23 @@
/**
* @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
*/

import {Location, LocationStrategy} from '@angular/common';
import {MockLocationStrategy, provideLocationMocks, SpyLocation} from '@angular/common/testing';
import {TestBed} from '@angular/core/testing';


describe('provideLocationMocks() function', () => {
it('should mock Location and LocationStrategy classes', () => {
TestBed.configureTestingModule({providers: [provideLocationMocks()]});
const location = TestBed.inject(Location);
const locationStrategy = TestBed.inject(LocationStrategy);

expect(location).toBeInstanceOf(SpyLocation);
expect(locationStrategy).toBeInstanceOf(MockLocationStrategy);
});
});
27 changes: 27 additions & 0 deletions packages/common/testing/src/provide_location_mocks.ts
@@ -0,0 +1,27 @@
/**
* @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
*/

import {Location, LocationStrategy} from '@angular/common';
import {Provider} from '@angular/core';

import {SpyLocation} from './location_mock';
import {MockLocationStrategy} from './mock_location_strategy';

/**
* Returns mock providers for the `Location` and `LocationStrategy` classes.
* The mocks are helpful in tests to fire simulated location events.
*
* @developerPreview
* @publicApi
*/
export function provideLocationMocks(): Provider[] {
return [
{provide: Location, useClass: SpyLocation},
{provide: LocationStrategy, useClass: MockLocationStrategy},
];
}
1 change: 1 addition & 0 deletions packages/common/testing/src/testing.ts
Expand Up @@ -14,3 +14,4 @@
export {SpyLocation} from './location_mock';
export {MockLocationStrategy} from './mock_location_strategy';
export {MOCK_PLATFORM_LOCATION_CONFIG, MockPlatformLocation, MockPlatformLocationConfig} from './mock_platform_location';
export {provideLocationMocks} from './provide_location_mocks';
7 changes: 4 additions & 3 deletions packages/router/test/computed_state_restoration.spec.ts
Expand Up @@ -7,15 +7,15 @@
*/

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

import {provideRouter} from '../src/provide_router';
import {isUrlTree} from '../src/url_tree';
import {provideRouterForTesting} from '../testing/src/provide_router_for_testing';

describe('`restoredState#ɵrouterPageId`', () => {
@Injectable({providedIn: 'root'})
Expand Down Expand Up @@ -490,7 +490,8 @@ function advance(fixture: ComponentFixture<any>, millis?: number): void {
CommonModule,
],
providers: [
provideRouterForTesting([], withRouterConfig({canceledNavigationResolution: 'computed'})),
provideLocationMocks(),
provideRouter([], withRouterConfig({canceledNavigationResolution: 'computed'})),
],
exports: [SimpleCmp, RootCmp, ThrowingCmp],
declarations: [SimpleCmp, RootCmp, ThrowingCmp]
Expand Down
54 changes: 35 additions & 19 deletions packages/router/test/integration.spec.ts
Expand Up @@ -7,20 +7,19 @@
*/

import {CommonModule, HashLocationStrategy, Location, LocationStrategy} from '@angular/common';
import {SpyLocation} from '@angular/common/testing';
import {provideLocationMocks, SpyLocation} from '@angular/common/testing';
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';
import {ComponentFixture, fakeAsync, inject, TestBed, tick} from '@angular/core/testing';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {expect} from '@angular/platform-browser/testing/src/matchers';
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';
import {concat, defer, EMPTY, from, Observable, Observer, of, Subscription} from 'rxjs';
import {concat, EMPTY, Observable, Observer, of, Subscription} from 'rxjs';
import {delay, filter, first, last, map, mapTo, takeWhile, tap} from 'rxjs/operators';

import {CanActivateChildFn, CanActivateFn, CanMatch, CanMatchFn, ResolveFn} from '../src/models';
import {withRouterConfig} from '../src/provide_router';
import {provideRouter, withRouterConfig} from '../src/provide_router';
import {forEach, wrapIntoObservable} from '../src/utils/collection';
import {getLoadedRoutes} from '../src/utils/config';
import {provideRouterForTesting} from '../testing/src/provide_router_for_testing';

const ROUTER_DIRECTIVES = [RouterLink, RouterLinkActive, RouterOutlet];

Expand All @@ -32,7 +31,8 @@ describe('Integration', () => {
imports: [...ROUTER_DIRECTIVES, TestModule],
providers: [
{provide: Console, useValue: noopConsole},
provideRouterForTesting([{path: 'simple', component: SimpleCmp}])
provideLocationMocks(),
provideRouter([{path: 'simple', component: SimpleCmp}]),
]
});
});
Expand Down Expand Up @@ -5451,7 +5451,8 @@ describe('Integration', () => {
...ROUTER_DIRECTIVES,
],
providers: [
provideRouterForTesting([{path: '', component: SimpleComponent}]),
provideLocationMocks(),
provideRouter([{path: '', component: SimpleComponent}]),
],
declarations: [LinkComponent, SimpleComponent]
});
Expand Down Expand Up @@ -6532,7 +6533,8 @@ describe('Integration', () => {
TestBed.configureTestingModule({
providers: [
{provide: RouteReuseStrategy, useClass: AttachDetachReuseStrategy},
provideRouterForTesting()
provideLocationMocks(),
provideRouter([]),
]
});

Expand Down Expand Up @@ -6698,10 +6700,13 @@ describe('Integration', () => {
@NgModule({
declarations: [RootCmpWithCondOutlet, Tool1Component, Tool2Component],
imports: [CommonModule, ...ROUTER_DIRECTIVES],
providers: [provideRouterForTesting([
{path: 'a', outlet: 'toolpanel', component: Tool1Component},
{path: 'b', outlet: 'toolpanel', component: Tool2Component},
])]
providers: [
provideLocationMocks(),
provideRouter([
{path: 'a', outlet: 'toolpanel', component: Tool1Component},
{path: 'b', outlet: 'toolpanel', component: Tool2Component},
]),
]
})
class TestModule {
}
Expand Down Expand Up @@ -6756,7 +6761,8 @@ describe('Integration', () => {
],
providers: [
{provide: RouteReuseStrategy, useClass: AttachDetachReuseStrategy},
provideRouterForTesting([
provideLocationMocks(),
provideRouter([
{path: 'a', component: SimpleCmp},
{path: 'b', component: BlankCmp},
]),
Expand Down Expand Up @@ -6825,7 +6831,8 @@ describe('Integration', () => {
providers: [
{provide: RouteReuseStrategy, useClass: AttachDetachReuseStrategy},
{provide: CREATED_COMPS, useValue: []},
provideRouterForTesting([
provideLocationMocks(),
provideRouter([
{path: 'a', component: Parent, children: [{path: 'b', component: Child}]},
{path: 'c', component: SimpleCmp}
]),
Expand Down Expand Up @@ -6882,9 +6889,10 @@ describe('Integration', () => {
imports: [ROUTER_DIRECTIVES],
providers: [
{provide: RouteReuseStrategy, useClass: AttachDetachReuseStrategy},
provideRouterForTesting([
provideLocationMocks(),
provideRouter([
{path: 'a', loadChildren: () => LoadedModule}, {path: 'b', component: ComponentB}
])
]),
]
})
class TestModule {
Expand Down Expand Up @@ -6914,24 +6922,32 @@ describe('Testing router options', () => {
describe('should configure the router', () => {
it('assigns onSameUrlNavigation', () => {
TestBed.configureTestingModule({
providers: [provideRouterForTesting([], withRouterConfig({onSameUrlNavigation: 'reload'}))]
providers: [
provideLocationMocks(),
provideRouter([], withRouterConfig({onSameUrlNavigation: 'reload'})),
]
});
const router: Router = TestBed.inject(Router);
expect(router.onSameUrlNavigation).toBe('reload');
});

it('assigns paramsInheritanceStrategy', () => {
TestBed.configureTestingModule({
providers:
[provideRouterForTesting([], withRouterConfig({paramsInheritanceStrategy: 'always'}))]
providers: [
provideLocationMocks(),
provideRouter([], withRouterConfig({paramsInheritanceStrategy: 'always'})),
]
});
const router: Router = TestBed.inject(Router);
expect(router.paramsInheritanceStrategy).toBe('always');
});

it('assigns urlUpdateStrategy', () => {
TestBed.configureTestingModule({
providers: [provideRouterForTesting([], withRouterConfig({urlUpdateStrategy: 'eager'}))]
providers: [
provideLocationMocks(),
provideRouter([], withRouterConfig({urlUpdateStrategy: 'eager'})),
]
});
const router: Router = TestBed.inject(Router);
expect(router.urlUpdateStrategy).toBe('eager');
Expand Down
15 changes: 10 additions & 5 deletions packages/router/test/page_title_strategy_spec.ts
Expand Up @@ -7,11 +7,12 @@
*/

import {DOCUMENT} from '@angular/common';
import {provideLocationMocks} from '@angular/common/testing';
import {Component, Inject, Injectable, NgModule} from '@angular/core';
import {fakeAsync, TestBed, tick} from '@angular/core/testing';
import {NavigationEnd, Router, RouterModule, RouterStateSnapshot, TitleStrategy} from '@angular/router';
import {Router, RouterModule, RouterStateSnapshot, TitleStrategy} from '@angular/router';

import {provideRouterForTesting} from '../testing/src/provide_router_for_testing';
import {provideRouter} from '../src/provide_router';

describe('title strategy', () => {
describe('DefaultTitleStrategy', () => {
Expand All @@ -23,7 +24,10 @@ describe('title strategy', () => {
imports: [
TestModule,
],
providers: [provideRouterForTesting()]
providers: [
provideLocationMocks(),
provideRouter([]),
]
});
router = TestBed.inject(Router);
document = TestBed.inject(DOCUMENT);
Expand Down Expand Up @@ -133,8 +137,9 @@ describe('title strategy', () => {
TestModule,
],
providers: [
provideRouterForTesting(),
{provide: TitleStrategy, useClass: TemplatePageTitleStrategy}
provideLocationMocks(),
provideRouter([]),
{provide: TitleStrategy, useClass: TemplatePageTitleStrategy},
]
});
const router = TestBed.inject(Router);
Expand Down
7 changes: 4 additions & 3 deletions packages/router/test/regression_integration.spec.ts
Expand Up @@ -7,15 +7,15 @@
*/

import {CommonModule, HashLocationStrategy, Location, LocationStrategy} from '@angular/common';
import {SpyLocation} from '@angular/common/testing';
import {provideLocationMocks, SpyLocation} from '@angular/common/testing';
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Injectable, NgModule, TemplateRef, Type, ViewChild, ViewContainerRef} from '@angular/core';
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
import {ChildrenOutletContexts, Resolve, Router, RouterOutlet} from '@angular/router';
import {RouterTestingModule} from '@angular/router/testing';
import {of} from 'rxjs';
import {delay, mapTo} from 'rxjs/operators';

import {provideRouterForTesting} from '../testing/src/provide_router_for_testing';
import {provideRouter} from '../src/provide_router';

describe('Integration', () => {
describe('routerLinkActive', () => {
Expand Down Expand Up @@ -304,7 +304,8 @@ describe('Integration', () => {
imports: [RouterOutlet],
providers: [
DelayedResolve,
provideRouterForTesting(
provideLocationMocks(),
provideRouter(
[
{path: '', component: SimpleCmp},
{path: 'one', component: OneCmp, resolve: {x: DelayedResolve}}
Expand Down

0 comments on commit c0c7efa

Please sign in to comment.