Jeff Cross 604c8bbad5 refactor(lifecycle): prefix lifecycle methods with "ng"
BREAKING CHANGE:
Previously, components that would implement lifecycle interfaces would include methods
like "onChanges" or "afterViewInit." Given that components were at risk of using such
names without realizing that Angular would call the methods at different points of
the component lifecycle. This change adds an "ng" prefix to all lifecycle hook methods,
far reducing the risk of an accidental name collision.

To fix, just rename these methods:
 * onInit
 * onDestroy
 * doCheck
 * onChanges
 * afterContentInit
 * afterContentChecked
 * afterViewInit
 * afterViewChecked
 * _Router Hooks_
 * onActivate
 * onReuse
 * onDeactivate
 * canReuse
 * canDeactivate

To:
 * ngOnInit,
 * ngOnDestroy,
 * ngDoCheck,
 * ngOnChanges,
 * ngAfterContentInit,
 * ngAfterContentChecked,
 * ngAfterViewInit,
 * ngAfterViewChecked
 * _Router Hooks_
 * routerOnActivate
 * routerOnReuse
 * routerOnDeactivate
 * routerCanReuse
 * routerCanDeactivate

The names of lifecycle interfaces and enums have not changed, though interfaces
have been updated to reflect the new method names.

Closes #5036
2015-11-30 16:40:50 -08:00

248 lines
9.0 KiB
TypeScript

import {
AsyncTestCompleter,
describe,
proxy,
it,
iit,
ddescribe,
expect,
inject,
beforeEach,
beforeEachProviders
} from 'angular2/testing_internal';
import {SpyRouterOutlet} from './spies';
import {Type} from 'angular2/src/facade/lang';
import {Promise, PromiseWrapper, ObservableWrapper} from 'angular2/src/facade/async';
import {ListWrapper} from 'angular2/src/facade/collection';
import {Router, RootRouter} from 'angular2/src/router/router';
import {SpyLocation} from 'angular2/src/mock/location_mock';
import {Location} from 'angular2/src/router/location';
import {RouteRegistry, ROUTER_PRIMARY_COMPONENT} from 'angular2/src/router/route_registry';
import {RouteConfig, AsyncRoute, Route} from 'angular2/src/router/route_config_decorator';
import {DirectiveResolver} from 'angular2/src/core/linker/directive_resolver';
import {provide} from 'angular2/core';
export function main() {
describe('Router', () => {
var router, location;
beforeEachProviders(() => [
RouteRegistry,
DirectiveResolver,
provide(Location, {useClass: SpyLocation}),
provide(ROUTER_PRIMARY_COMPONENT, {useValue: AppCmp}),
provide(Router, {useClass: RootRouter})
]);
beforeEach(inject([Router, Location], (rtr, loc) => {
router = rtr;
location = loc;
}));
it('should navigate based on the initial URL state', inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet();
router.config([new Route({path: '/', component: DummyComponent})])
.then((_) => router.registerPrimaryOutlet(outlet))
.then((_) => {
expect(outlet.spy('activate')).toHaveBeenCalled();
expect(location.urlChanges).toEqual([]);
async.done();
});
}));
it('should activate viewports and update URL on navigate',
inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet();
router.registerPrimaryOutlet(outlet)
.then((_) => router.config([new Route({path: '/a', component: DummyComponent})]))
.then((_) => router.navigateByUrl('/a'))
.then((_) => {
expect(outlet.spy('activate')).toHaveBeenCalled();
expect(location.urlChanges).toEqual(['/a']);
async.done();
});
}));
it('should activate viewports and update URL when navigating via DSL',
inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet();
router.registerPrimaryOutlet(outlet)
.then((_) => router.config(
[new Route({path: '/a', component: DummyComponent, name: 'A'})]))
.then((_) => router.navigate(['/A']))
.then((_) => {
expect(outlet.spy('activate')).toHaveBeenCalled();
expect(location.urlChanges).toEqual(['/a']);
async.done();
});
}));
it('should not push a history change on when navigate is called with skipUrlChange',
inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet();
router.registerPrimaryOutlet(outlet)
.then((_) => router.config([new Route({path: '/b', component: DummyComponent})]))
.then((_) => router.navigateByUrl('/b', true))
.then((_) => {
expect(outlet.spy('activate')).toHaveBeenCalled();
expect(location.urlChanges).toEqual([]);
async.done();
});
}));
it('should navigate after being configured', inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet();
router.registerPrimaryOutlet(outlet)
.then((_) => router.navigateByUrl('/a'))
.then((_) => {
expect(outlet.spy('activate')).not.toHaveBeenCalled();
return router.config([new Route({path: '/a', component: DummyComponent})]);
})
.then((_) => {
expect(outlet.spy('activate')).toHaveBeenCalled();
async.done();
});
}));
it('should throw when linkParams does not include a route name', () => {
expect(() => router.generate(['./']))
.toThrowError(`Link "${ListWrapper.toJSON(['./'])}" must include a route name.`);
expect(() => router.generate(['/']))
.toThrowError(`Link "${ListWrapper.toJSON(['/'])}" must include a route name.`);
});
it('should, when subscribed to, return a disposable subscription', () => {
expect(() => {
var subscription = router.subscribe((_) => {});
ObservableWrapper.dispose(subscription);
}).not.toThrow();
});
it('should generate URLs from the root component when the path starts with /', () => {
router.config(
[new Route({path: '/first/...', component: DummyParentComp, name: 'FirstCmp'})]);
var instruction = router.generate(['/FirstCmp', 'SecondCmp']);
expect(stringifyInstruction(instruction)).toEqual('first/second');
instruction = router.generate(['/FirstCmp/SecondCmp']);
expect(stringifyInstruction(instruction)).toEqual('first/second');
});
it('should generate an instruction with terminal async routes',
inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet();
router.registerPrimaryOutlet(outlet);
router.config([new AsyncRoute({path: '/first', loader: loader, name: 'FirstCmp'})]);
var instruction = router.generate(['/FirstCmp']);
router.navigateByInstruction(instruction)
.then((_) => {
expect(outlet.spy('activate')).toHaveBeenCalled();
async.done();
});
}));
it('should return whether a given instruction is active with isRouteActive',
inject([AsyncTestCompleter], (async) => {
var outlet = makeDummyOutlet();
router.registerPrimaryOutlet(outlet)
.then((_) => router.config([
new Route({path: '/a', component: DummyComponent, name: 'A'}),
new Route({path: '/b', component: DummyComponent, name: 'B'})
]))
.then((_) => router.navigateByUrl('/a'))
.then((_) => {
var instruction = router.generate(['/A']);
var otherInstruction = router.generate(['/B']);
expect(router.isRouteActive(instruction)).toEqual(true);
expect(router.isRouteActive(otherInstruction)).toEqual(false);
async.done();
});
}));
describe('query string params', () => {
it('should use query string params for the root route', () => {
router.config(
[new Route({path: '/hi/how/are/you', component: DummyComponent, name: 'GreetingUrl'})]);
var instruction = router.generate(['/GreetingUrl', {'name': 'brad'}]);
var path = stringifyInstruction(instruction);
expect(path).toEqual('hi/how/are/you?name=brad');
});
it('should serialize parameters that are not part of the route definition as query string params',
() => {
router.config([
new Route({path: '/one/two/:three', component: DummyComponent, name: 'NumberUrl'})
]);
var instruction = router.generate(['/NumberUrl', {'three': 'three', 'four': 'four'}]);
var path = stringifyInstruction(instruction);
expect(path).toEqual('one/two/three?four=four');
});
});
describe('matrix params', () => {
it('should generate matrix params for each non-root component', () => {
router.config(
[new Route({path: '/first/...', component: DummyParentComp, name: 'FirstCmp'})]);
var instruction =
router.generate(['/FirstCmp', {'key': 'value'}, 'SecondCmp', {'project': 'angular'}]);
var path = stringifyInstruction(instruction);
expect(path).toEqual('first/second;project=angular?key=value');
});
it('should work with named params', () => {
router.config(
[new Route({path: '/first/:token/...', component: DummyParentComp, name: 'FirstCmp'})]);
var instruction =
router.generate(['/FirstCmp', {'token': 'min'}, 'SecondCmp', {'author': 'max'}]);
var path = stringifyInstruction(instruction);
expect(path).toEqual('first/min/second;author=max');
});
});
});
}
function stringifyInstruction(instruction): string {
return instruction.toRootUrl();
}
function loader(): Promise<Type> {
return PromiseWrapper.resolve(DummyComponent);
}
class DummyComponent {}
@RouteConfig([new Route({path: '/second', component: DummyComponent, name: 'SecondCmp'})])
class DummyParentComp {
}
function makeDummyOutlet() {
var ref = new SpyRouterOutlet();
ref.spy('canActivate').andCallFake((_) => PromiseWrapper.resolve(true));
ref.spy('routerCanReuse').andCallFake((_) => PromiseWrapper.resolve(false));
ref.spy('routerCanDeactivate').andCallFake((_) => PromiseWrapper.resolve(true));
ref.spy('activate').andCallFake((_) => PromiseWrapper.resolve(true));
return ref;
}
class AppCmp {}