Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions packages/router/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {of } from 'rxjs/observable/of';
import {concatMap} from 'rxjs/operator/concatMap';
import {map} from 'rxjs/operator/map';
import {mergeMap} from 'rxjs/operator/mergeMap';
import {toPromise} from 'rxjs/operator/toPromise';

import {applyRedirects} from './apply_redirects';
import {LoadedRouterConfig, QueryParamsHandling, Route, Routes, validateConfig} from './config';
Expand Down Expand Up @@ -473,6 +474,22 @@ export class Router {
/** Parses a string into a {@link UrlTree} */
parseUrl(url: string): UrlTree { return this.urlSerializer.parse(url); }

/** Converts given Url to RouterStateSnapshot */
urlToRouteStateSnapshot(url: string|UrlTree): Promise<RouterStateSnapshot> {
const urlTree = url instanceof UrlTree ? url : this.parseUrl(url);
const mergedTree = this.urlHandlingStrategy.merge(urlTree, this.rawUrlTree);
const moduleInjector = this.ngModule.injector;
const redirectsApplied$ = applyRedirects(
moduleInjector, this.configLoader, this.urlSerializer, mergedTree, this.config);

let snapshot$ = mergeMap.call(redirectsApplied$, (appliedUrl: UrlTree) => {
return map.call(
recognize(this.rootComponentType, this.config, appliedUrl, this.serializeUrl(appliedUrl)),
(snapshot: any) => { return snapshot; });
});
return toPromise.call(snapshot$);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just leave it as an Observable and let the caller decide if they want to use toPromise or not?

}

/** Returns whether the url is activated */
isActive(url: string|UrlTree, exact: boolean): boolean {
if (url instanceof UrlTree) {
Expand Down
34 changes: 34 additions & 0 deletions packages/router/test/router.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,36 @@ describe('Router', () => {
}));
});

describe('urlToRouteStateSnapshot', () => {
beforeEach(() => { TestBed.configureTestingModule({imports: [RouterTestingModule]}); });

it('should return snapshot or exception', inject([Router], (r: Router) => {
r.resetConfig([
{
path: 'a',
component: ComponentA,
data: {state: 'i am A'},
children: [{path: 'b', component: ComponentB, data: {state: 'i am B'}}]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also add a test for lazy loaded modules. Even if it doesn't work (though I don't immediately see why it wouldn't), the test documents the behavior. It does seem to me like this would actually trigger the lazy loading. If that's true, this needs to be documented.

},
{path: 'c', component: ComponentC, data: {state: 'i am C'}}
]);

r.urlToRouteStateSnapshot('/a').then(
(s) => { expect(s.root.firstChild !.data).toEqual({state: 'i am A'}); });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, do these asynchronous expectations actually work reliably? I think nowadays we should use async/await instead, as doing so will return a Promise to jasmine which it will wait for.

@yelhouti yelhouti May 11, 2019 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No they don't, tested it


r.urlToRouteStateSnapshot('/a/b').then(
(s) => { expect(s.root.firstChild !.firstChild !.data).toEqual({state: 'i am B'}); });

r.urlToRouteStateSnapshot('/c').then(
(s) => { expect(s.root.firstChild !.data).toEqual({state: 'i am C'}); });

r.urlToRouteStateSnapshot('/x').catch((s => {
expect(s.toString()).toContain('Error: Cannot match any routes. URL Segment: \'x\'');
}));

}));
});

describe('PreActivation', () => {
const serializer = new DefaultUrlSerializer();
const inj = {get: (token: any) => () => `${token}_value`};
Expand Down Expand Up @@ -367,3 +397,7 @@ function checkGuards(
p.initalize(new ChildrenOutletContexts());
p.checkGuards().subscribe(check, (e) => { throw e; });
}

class ComponentA {}
class ComponentB {}
class ComponentC {}