From 0d55d4557f4e3dd40ec3900bbab3fb2a694f2e02 Mon Sep 17 00:00:00 2001 From: Martin Sikora Date: Sun, 10 Jan 2021 19:55:39 +0100 Subject: [PATCH] test(router): add Router regression test for hash location strategy (#40409) This situation can probably happen only when using `HashLocationStrategy` and by manually changing hash that triggers a route guard that returns a new `UrlTree`. Then hash in the browser might not match the current route because navigation was canceled, while hash in the URL remained set by the user. Related to #37048 PR Close #40409 --- .../test/regression_integration.spec.ts | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/packages/router/test/regression_integration.spec.ts b/packages/router/test/regression_integration.spec.ts index 84b5117c5e..371431b9e9 100644 --- a/packages/router/test/regression_integration.spec.ts +++ b/packages/router/test/regression_integration.spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {CommonModule} from '@angular/common'; +import {CommonModule, Location} from '@angular/common'; +import {SpyLocation} from '@angular/common/testing'; import {ChangeDetectionStrategy, ChangeDetectorRef, Component, NgModule, TemplateRef, Type, ViewChild, ViewContainerRef} from '@angular/core'; import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; import {Router} from '@angular/router'; @@ -227,6 +228,54 @@ describe('Integration', () => { expect(fixture.nativeElement.innerHTML).toContain('router-outlet'); expect(fixture.nativeElement.innerHTML).not.toContain('simple'); })); + + describe('useHash', () => { + it('should restore hash to match current route - #28561', fakeAsync(() => { + @Component({selector: 'root-cmp', template: ``}) + class RootCmp { + } + + @Component({template: 'simple'}) + class SimpleCmp { + } + + TestBed.configureTestingModule({ + imports: [RouterTestingModule.withRoutes([ + {path: '', component: SimpleCmp}, + {path: 'one', component: SimpleCmp, canActivate: ['returnRootUrlTree']} + ])], + declarations: [SimpleCmp, RootCmp], + providers: [ + { + provide: 'returnRootUrlTree', + useFactory: (router: Router) => () => { + return router.parseUrl('/'); + }, + deps: [Router] + }, + ], + }); + + const router = TestBed.inject(Router); + const location = TestBed.inject(Location) as SpyLocation; + + router.navigateByUrl('/'); + // Will setup location change listeners + const fixture = createRoot(router, RootCmp); + + location.simulateHashChange('/one'); + advance(fixture); + + const BASE_ERROR_MESSAGE = + 'This asserts current behavior, which is incorrect. When #28561 is fixed, it should be: '; + + expect(location.path()).toEqual('/one', BASE_ERROR_MESSAGE + '/'); + const urlChanges = ['replace: /', 'hash: /one']; + expect(location.urlChanges) + .toEqual( + urlChanges, BASE_ERROR_MESSAGE + JSON.stringify(urlChanges.concat('replace: /'))); + })); + }); }); function advance(fixture: ComponentFixture): void {