feat(TestComponentBuilder): add #overrideBindings and #overrideViewBindings
Closes #4052
This commit is contained in:
parent
39a6f85e95
commit
f91c087c46
|
@ -0,0 +1,65 @@
|
|||
import {Map, MapWrapper, ListWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {
|
||||
Type,
|
||||
isPresent,
|
||||
BaseException,
|
||||
stringify,
|
||||
isBlank,
|
||||
print
|
||||
} from 'angular2/src/core/facade/lang';
|
||||
import {DirectiveMetadata, ComponentMetadata} from '../core/metadata';
|
||||
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
||||
|
||||
export class MockDirectiveResolver extends DirectiveResolver {
|
||||
private _bindingsOverrides: Map<Type, any[]> = new Map();
|
||||
private _viewBindingsOverrides: Map<Type, any[]> = new Map();
|
||||
|
||||
resolve(type: Type): DirectiveMetadata {
|
||||
var dm = super.resolve(type);
|
||||
|
||||
var bindingsOverride = this._bindingsOverrides.get(type);
|
||||
var viewBindingsOverride = this._viewBindingsOverrides.get(type);
|
||||
|
||||
var bindings = dm.bindings;
|
||||
if (isPresent(bindingsOverride)) {
|
||||
bindings = dm.bindings.concat(bindingsOverride);
|
||||
}
|
||||
|
||||
if (dm instanceof ComponentMetadata) {
|
||||
var viewBindings = dm.viewBindings;
|
||||
if (isPresent(viewBindingsOverride)) {
|
||||
viewBindings = dm.viewBindings.concat(viewBindingsOverride);
|
||||
}
|
||||
|
||||
return new ComponentMetadata({
|
||||
selector: dm.selector,
|
||||
properties: dm.properties,
|
||||
events: dm.events,
|
||||
host: dm.host,
|
||||
bindings: bindings,
|
||||
exportAs: dm.exportAs,
|
||||
compileChildren: dm.compileChildren,
|
||||
changeDetection: dm.changeDetection,
|
||||
viewBindings: viewBindings
|
||||
});
|
||||
}
|
||||
|
||||
return new DirectiveMetadata({
|
||||
selector: dm.selector,
|
||||
properties: dm.properties,
|
||||
events: dm.events,
|
||||
host: dm.host,
|
||||
bindings: bindings,
|
||||
exportAs: dm.exportAs,
|
||||
compileChildren: dm.compileChildren
|
||||
});
|
||||
}
|
||||
|
||||
setBindingsOverride(type: Type, bindings: any[]): void {
|
||||
this._bindingsOverrides.set(type, bindings);
|
||||
}
|
||||
|
||||
setViewBindingsOverride(type: Type, viewBindings: any[]): void {
|
||||
this._viewBindingsOverrides.set(type, viewBindings);
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import {ListWrapper, MapWrapper} from 'angular2/src/core/facade/collection';
|
|||
|
||||
import {ViewMetadata} from '../core/metadata';
|
||||
|
||||
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
||||
import {ViewResolver} from 'angular2/src/core/compiler/view_resolver';
|
||||
import {AppView} from 'angular2/src/core/compiler/view';
|
||||
import {internalView, ViewRef} from 'angular2/src/core/compiler/view_ref';
|
||||
|
@ -47,16 +48,19 @@ var _nextRootElementId = 0;
|
|||
*/
|
||||
@Injectable()
|
||||
export class TestComponentBuilder {
|
||||
_injector: Injector;
|
||||
_viewOverrides: Map<Type, ViewMetadata>;
|
||||
_bindingsOverrides: Map<Type, any[]>;
|
||||
_directiveOverrides: Map<Type, Map<Type, Type>>;
|
||||
_templateOverrides: Map<Type, string>;
|
||||
_viewBindingsOverrides: Map<Type, any[]>;
|
||||
_viewOverrides: Map<Type, ViewMetadata>;
|
||||
|
||||
constructor(injector: Injector) {
|
||||
this._injector = injector;
|
||||
this._viewOverrides = new Map();
|
||||
|
||||
constructor(private _injector: Injector) {
|
||||
this._bindingsOverrides = new Map();
|
||||
this._directiveOverrides = new Map();
|
||||
this._templateOverrides = new Map();
|
||||
this._viewBindingsOverrides = new Map();
|
||||
this._viewOverrides = new Map();
|
||||
}
|
||||
|
||||
_clone(): TestComponentBuilder {
|
||||
|
@ -116,12 +120,53 @@ export class TestComponentBuilder {
|
|||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides one or more injectables configured via `bindings` metadata property of a directive or
|
||||
* component.
|
||||
* Very useful when certain bindings need to be mocked out.
|
||||
*
|
||||
* The bindings specified via this method are appended to the existing `bindings` causing the
|
||||
* duplicated bindings to
|
||||
* be overridden.
|
||||
*
|
||||
* @param {Type} component
|
||||
* @param {any[]} bindings
|
||||
*
|
||||
* @return {TestComponentBuilder}
|
||||
*/
|
||||
overrideBindings(type: Type, bindings: any[]): TestComponentBuilder {
|
||||
var clone = this._clone();
|
||||
clone._bindingsOverrides.set(type, bindings);
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides one or more injectables configured via `bindings` metadata property of a directive or
|
||||
* component.
|
||||
* Very useful when certain bindings need to be mocked out.
|
||||
*
|
||||
* The bindings specified via this method are appended to the existing `bindings` causing the
|
||||
* duplicated bindings to
|
||||
* be overridden.
|
||||
*
|
||||
* @param {Type} component
|
||||
* @param {any[]} bindings
|
||||
*
|
||||
* @return {TestComponentBuilder}
|
||||
*/
|
||||
overrideViewBindings(type: Type, bindings: any[]): TestComponentBuilder {
|
||||
var clone = this._clone();
|
||||
clone._viewBindingsOverrides.set(type, bindings);
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns a RootTestComponent.
|
||||
*
|
||||
* @return {Promise<RootTestComponent>}
|
||||
*/
|
||||
createAsync(rootComponentType: Type): Promise<RootTestComponent> {
|
||||
var mockDirectiveResolver = this._injector.get(DirectiveResolver);
|
||||
var mockViewResolver = this._injector.get(ViewResolver);
|
||||
MapWrapper.forEach(this._viewOverrides,
|
||||
(view, type) => { mockViewResolver.setView(type, view); });
|
||||
|
@ -133,6 +178,11 @@ export class TestComponentBuilder {
|
|||
});
|
||||
});
|
||||
|
||||
this._bindingsOverrides.forEach((bindings, type) =>
|
||||
mockDirectiveResolver.setBindingsOverride(type, bindings));
|
||||
this._viewBindingsOverrides.forEach(
|
||||
(bindings, type) => mockDirectiveResolver.setViewBindingsOverride(type, bindings));
|
||||
|
||||
var rootElId = `root${_nextRootElementId++}`;
|
||||
var rootEl = el(`<div id="${rootElId}"></div>`);
|
||||
var doc = this._injector.get(DOCUMENT);
|
||||
|
|
|
@ -36,6 +36,7 @@ import {
|
|||
EVENT_MANAGER_PLUGINS
|
||||
} from 'angular2/src/core/render/dom/events/event_manager';
|
||||
|
||||
import {MockDirectiveResolver} from 'angular2/src/mock/directive_resolver_mock';
|
||||
import {MockViewResolver} from 'angular2/src/mock/view_resolver_mock';
|
||||
import {MockXHR} from 'angular2/src/core/render/xhr_mock';
|
||||
import {MockLocationStrategy} from 'angular2/src/mock/mock_location_strategy';
|
||||
|
@ -125,6 +126,7 @@ function _getAppBindings() {
|
|||
bind(APP_VIEW_POOL_CAPACITY).toValue(500),
|
||||
Compiler,
|
||||
CompilerCache,
|
||||
bind(DirectiveResolver).toClass(MockDirectiveResolver),
|
||||
bind(ViewResolver).toClass(MockViewResolver),
|
||||
DEFAULT_PIPES,
|
||||
bind(IterableDiffers).toValue(defaultIterableDiffers),
|
||||
|
@ -133,7 +135,6 @@ function _getAppBindings() {
|
|||
Log,
|
||||
ViewLoader,
|
||||
DynamicComponentLoader,
|
||||
DirectiveResolver,
|
||||
PipeResolver,
|
||||
Parser,
|
||||
Lexer,
|
||||
|
|
|
@ -14,8 +14,7 @@ import {
|
|||
TestComponentBuilder
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {Injectable, NgIf} from 'angular2/core';
|
||||
|
||||
import {Injectable, NgIf, bind} from 'angular2/core';
|
||||
import {Directive, Component, View, ViewMetadata} from 'angular2/src/core/metadata';
|
||||
|
||||
@Component({selector: 'child-comp'})
|
||||
|
@ -48,11 +47,14 @@ class MyIfComp {
|
|||
@Component({selector: 'child-child-comp'})
|
||||
@View({template: `<span>ChildChild</span>`})
|
||||
@Injectable()
|
||||
class ChildChildComp {}
|
||||
class ChildChildComp {
|
||||
}
|
||||
|
||||
@Component({selector: 'child-comp'})
|
||||
@View({template: `<span>Original {{childBinding}}(<child-child-comp></child-child-comp>)</span>`,
|
||||
directives: [ChildChildComp]})
|
||||
@View({
|
||||
template: `<span>Original {{childBinding}}(<child-child-comp></child-child-comp>)</span>`,
|
||||
directives: [ChildChildComp]
|
||||
})
|
||||
@Injectable()
|
||||
class ChildWithChildComp {
|
||||
childBinding: string;
|
||||
|
@ -62,7 +64,30 @@ class ChildWithChildComp {
|
|||
@Component({selector: 'child-child-comp'})
|
||||
@View({template: `<span>ChildChild Mock</span>`})
|
||||
@Injectable()
|
||||
class MockChildChildComp {}
|
||||
class MockChildChildComp {
|
||||
}
|
||||
|
||||
|
||||
|
||||
class FancyService {
|
||||
value: string = 'real value';
|
||||
}
|
||||
|
||||
class MockFancyService extends FancyService {
|
||||
value: string = 'mocked out value';
|
||||
}
|
||||
|
||||
@Component({selector: 'my-service-comp', bindings: [FancyService]})
|
||||
@View({template: `injected value: {{fancyService.value}}`})
|
||||
class TestBindingsComp {
|
||||
constructor(private fancyService: FancyService) {}
|
||||
}
|
||||
|
||||
@Component({selector: 'my-service-comp', viewBindings: [FancyService]})
|
||||
@View({template: `injected value: {{fancyService.value}}`})
|
||||
class TestViewBindingsComp {
|
||||
constructor(private fancyService: FancyService) {}
|
||||
}
|
||||
|
||||
|
||||
export function main() {
|
||||
|
@ -135,17 +160,46 @@ export function main() {
|
|||
|
||||
|
||||
it("should override child component's dependencies",
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb, async) => {
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb, async) => {
|
||||
|
||||
tcb.overrideDirective(ParentComp, ChildComp, ChildWithChildComp)
|
||||
.overrideDirective(ChildWithChildComp, ChildChildComp, MockChildChildComp)
|
||||
.createAsync(ParentComp)
|
||||
.then((rootTestComponent) => {
|
||||
rootTestComponent.detectChanges();
|
||||
expect(rootTestComponent.nativeElement).toHaveText('Parent(Original Child(ChildChild Mock))');
|
||||
tcb.overrideDirective(ParentComp, ChildComp, ChildWithChildComp)
|
||||
.overrideDirective(ChildWithChildComp, ChildChildComp, MockChildChildComp)
|
||||
.createAsync(ParentComp)
|
||||
.then((rootTestComponent) => {
|
||||
rootTestComponent.detectChanges();
|
||||
expect(rootTestComponent.nativeElement)
|
||||
.toHaveText('Parent(Original Child(ChildChild Mock))');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should override a binding',
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb, async) => {
|
||||
|
||||
tcb.overrideBindings(TestBindingsComp, [bind(FancyService).toClass(MockFancyService)])
|
||||
.createAsync(TestBindingsComp)
|
||||
.then((rootTestComponent) => {
|
||||
rootTestComponent.detectChanges();
|
||||
expect(rootTestComponent.nativeElement)
|
||||
.toHaveText('injected value: mocked out value');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
it('should override a viewBinding',
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb, async) => {
|
||||
|
||||
tcb.overrideViewBindings(TestViewBindingsComp,
|
||||
[bind(FancyService).toClass(MockFancyService)])
|
||||
.createAsync(TestViewBindingsComp)
|
||||
.then((rootTestComponent) => {
|
||||
rootTestComponent.detectChanges();
|
||||
expect(rootTestComponent.nativeElement)
|
||||
.toHaveText('injected value: mocked out value');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue