2015-07-02 20:38:19 -04:00
|
|
|
import {
|
|
|
|
AsyncTestCompleter,
|
|
|
|
beforeEach,
|
|
|
|
ddescribe,
|
|
|
|
xdescribe,
|
|
|
|
describe,
|
|
|
|
dispatchEvent,
|
|
|
|
expect,
|
|
|
|
iit,
|
|
|
|
inject,
|
refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
{ path: '/foo', redirectTo: '/bar' },
{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
{ path: '/foo', redirectTo: ['Bar'] },
{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
{ path: '/tab', redirectTo: '/tab/users' }
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
2015-11-23 21:07:37 -05:00
|
|
|
beforeEachProviders,
|
2015-07-02 20:38:19 -04:00
|
|
|
it,
|
|
|
|
xit,
|
2015-09-04 01:01:36 -04:00
|
|
|
TestComponentBuilder
|
2015-10-13 03:29:13 -04:00
|
|
|
} from 'angular2/testing_internal';
|
2015-07-02 20:38:19 -04:00
|
|
|
|
2016-02-09 14:12:41 -05:00
|
|
|
import {SpyRouter, SpyLocation} from '../spies';
|
2015-07-02 20:38:19 -04:00
|
|
|
|
2015-10-11 01:11:13 -04:00
|
|
|
import {provide, Component, View} from 'angular2/core';
|
2015-11-23 13:18:04 -05:00
|
|
|
import {By} from 'angular2/platform/common_dom';
|
2015-07-02 20:38:19 -04:00
|
|
|
|
2015-08-24 14:24:53 -04:00
|
|
|
import {
|
|
|
|
Location,
|
|
|
|
Router,
|
|
|
|
RouteRegistry,
|
|
|
|
RouterLink,
|
|
|
|
RouterOutlet,
|
|
|
|
Route,
|
2015-09-21 22:58:45 -04:00
|
|
|
RouteParams,
|
|
|
|
ComponentInstruction
|
2015-08-24 14:24:53 -04:00
|
|
|
} from 'angular2/router';
|
2015-07-02 20:38:19 -04:00
|
|
|
|
2015-11-19 18:09:34 -05:00
|
|
|
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
{ path: '/foo', redirectTo: '/bar' },
{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
{ path: '/foo', redirectTo: ['Bar'] },
{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
{ path: '/tab', redirectTo: '/tab/users' }
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
2015-11-23 21:07:37 -05:00
|
|
|
import {ResolvedInstruction} from 'angular2/src/router/instruction';
|
2015-07-02 20:38:19 -04:00
|
|
|
|
2015-12-18 13:05:55 -05:00
|
|
|
let dummyInstruction = new ResolvedInstruction(
|
|
|
|
new ComponentInstruction('detail', [], null, null, true, '0'), null, {});
|
2015-07-02 20:38:19 -04:00
|
|
|
|
2015-07-17 16:36:53 -04:00
|
|
|
export function main() {
|
2015-11-23 19:02:19 -05:00
|
|
|
describe('routerLink directive', function() {
|
2015-08-24 14:24:53 -04:00
|
|
|
var tcb: TestComponentBuilder;
|
2015-07-02 20:38:19 -04:00
|
|
|
|
refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
{ path: '/foo', redirectTo: '/bar' },
{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
{ path: '/foo', redirectTo: ['Bar'] },
{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
{ path: '/tab', redirectTo: '/tab/users' }
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
2015-11-23 21:07:37 -05:00
|
|
|
beforeEachProviders(() => [
|
2015-10-12 14:30:34 -04:00
|
|
|
provide(Location, {useValue: makeDummyLocation()}),
|
|
|
|
provide(Router, {useValue: makeDummyRouter()})
|
2015-10-11 01:11:13 -04:00
|
|
|
]);
|
2015-07-02 20:38:19 -04:00
|
|
|
|
2015-08-24 14:24:53 -04:00
|
|
|
beforeEach(inject([TestComponentBuilder], (tcBuilder) => { tcb = tcBuilder; }));
|
2015-07-02 20:38:19 -04:00
|
|
|
|
2015-08-24 14:24:53 -04:00
|
|
|
it('should update a[href] attribute', inject([AsyncTestCompleter], (async) => {
|
2015-07-02 20:38:19 -04:00
|
|
|
|
|
|
|
tcb.createAsync(TestComponent)
|
|
|
|
.then((testComponent) => {
|
|
|
|
testComponent.detectChanges();
|
2015-11-02 18:11:57 -05:00
|
|
|
let anchorElement =
|
|
|
|
testComponent.debugElement.query(By.css('a.detail-view')).nativeElement;
|
2015-10-26 09:57:41 -04:00
|
|
|
expect(DOM.getAttribute(anchorElement, 'href')).toEqual('detail');
|
2015-07-02 20:38:19 -04:00
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
it('should call router.navigate when a link is clicked',
|
2015-08-24 14:24:53 -04:00
|
|
|
inject([AsyncTestCompleter, Router], (async, router) => {
|
2015-07-02 20:38:19 -04:00
|
|
|
|
|
|
|
tcb.createAsync(TestComponent)
|
|
|
|
.then((testComponent) => {
|
|
|
|
testComponent.detectChanges();
|
|
|
|
// TODO: shouldn't this be just 'click' rather than '^click'?
|
2015-11-02 18:11:57 -05:00
|
|
|
testComponent.debugElement.query(By.css('a.detail-view'))
|
|
|
|
.triggerEventHandler('click', null);
|
2015-09-09 00:41:56 -04:00
|
|
|
expect(router.spy('navigateByInstruction')).toHaveBeenCalledWith(dummyInstruction);
|
2015-07-02 20:38:19 -04:00
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
}));
|
2015-11-02 18:11:57 -05:00
|
|
|
|
|
|
|
it('should call router.navigate when a link is clicked if target is _self',
|
|
|
|
inject([AsyncTestCompleter, Router], (async, router) => {
|
|
|
|
|
|
|
|
tcb.createAsync(TestComponent)
|
|
|
|
.then((testComponent) => {
|
|
|
|
testComponent.detectChanges();
|
|
|
|
testComponent.debugElement.query(By.css('a.detail-view-self'))
|
|
|
|
.triggerEventHandler('click', null);
|
|
|
|
expect(router.spy('navigateByInstruction')).toHaveBeenCalledWith(dummyInstruction);
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
it('should NOT call router.navigate when a link is clicked if target is set to other than _self',
|
|
|
|
inject([AsyncTestCompleter, Router], (async, router) => {
|
|
|
|
|
|
|
|
tcb.createAsync(TestComponent)
|
|
|
|
.then((testComponent) => {
|
|
|
|
testComponent.detectChanges();
|
|
|
|
testComponent.debugElement.query(By.css('a.detail-view-blank'))
|
|
|
|
.triggerEventHandler('click', null);
|
|
|
|
expect(router.spy('navigateByInstruction')).not.toHaveBeenCalled();
|
|
|
|
async.done();
|
|
|
|
});
|
|
|
|
}));
|
2015-07-02 20:38:19 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-08-24 14:24:53 -04:00
|
|
|
@Component({selector: 'user-cmp'})
|
|
|
|
@View({template: "hello {{user}}"})
|
|
|
|
class UserCmp {
|
|
|
|
user: string;
|
|
|
|
constructor(params: RouteParams) { this.user = params.get('name'); }
|
|
|
|
}
|
2015-07-02 20:38:19 -04:00
|
|
|
|
|
|
|
@Component({selector: 'test-component'})
|
|
|
|
@View({
|
|
|
|
template: `
|
|
|
|
<div>
|
2015-11-23 19:02:19 -05:00
|
|
|
<a [routerLink]="['/Detail']"
|
2015-11-02 18:11:57 -05:00
|
|
|
class="detail-view">
|
|
|
|
detail view
|
|
|
|
</a>
|
2015-11-23 19:02:19 -05:00
|
|
|
<a [routerLink]="['/Detail']"
|
2015-11-02 18:11:57 -05:00
|
|
|
class="detail-view-self"
|
|
|
|
target="_self">
|
|
|
|
detail view with _self target
|
|
|
|
</a>
|
2015-11-23 19:02:19 -05:00
|
|
|
<a [routerLink]="['/Detail']"
|
2015-11-02 18:11:57 -05:00
|
|
|
class="detail-view-blank"
|
|
|
|
target="_blank">
|
|
|
|
detail view with _blank target
|
|
|
|
</a>
|
2015-07-02 20:38:19 -04:00
|
|
|
</div>`,
|
|
|
|
directives: [RouterLink]
|
|
|
|
})
|
|
|
|
class TestComponent {
|
|
|
|
}
|
|
|
|
|
|
|
|
function makeDummyLocation() {
|
2015-08-26 14:41:41 -04:00
|
|
|
var dl = new SpyLocation();
|
2015-10-26 09:57:41 -04:00
|
|
|
dl.spy('prepareExternalUrl').andCallFake((url) => url);
|
2015-07-02 20:38:19 -04:00
|
|
|
return dl;
|
|
|
|
}
|
|
|
|
|
|
|
|
function makeDummyRouter() {
|
2015-08-26 14:41:41 -04:00
|
|
|
var dr = new SpyRouter();
|
2015-07-17 16:36:53 -04:00
|
|
|
dr.spy('generate').andCallFake((routeParams) => dummyInstruction);
|
2015-08-31 00:25:46 -04:00
|
|
|
dr.spy('isRouteActive').andCallFake((_) => false);
|
2015-07-17 16:36:53 -04:00
|
|
|
dr.spy('navigateInstruction');
|
2015-07-02 20:38:19 -04:00
|
|
|
return dr;
|
|
|
|
}
|