test(TestBed): initial implementation
This commit is contained in:
parent
57e308dd46
commit
438c2b31e4
|
@ -2,6 +2,7 @@ export * from './src/core/annotations/visibility';
|
||||||
export * from './src/core/compiler/interfaces';
|
export * from './src/core/compiler/interfaces';
|
||||||
export * from './src/core/annotations/template';
|
export * from './src/core/annotations/template';
|
||||||
export * from './src/core/application';
|
export * from './src/core/application';
|
||||||
|
export * from './src/core/application_tokens';
|
||||||
export * from './src/core/annotations/di';
|
export * from './src/core/annotations/di';
|
||||||
|
|
||||||
export * from './src/core/compiler/compiler';
|
export * from './src/core/compiler/compiler';
|
||||||
|
|
|
@ -28,6 +28,13 @@ import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
|
||||||
import {Component} from 'angular2/src/core/annotations/annotations';
|
import {Component} from 'angular2/src/core/annotations/annotations';
|
||||||
import {PrivateComponentLoader} from 'angular2/src/core/compiler/private_component_loader';
|
import {PrivateComponentLoader} from 'angular2/src/core/compiler/private_component_loader';
|
||||||
import {TestabilityRegistry, Testability} from 'angular2/src/core/testability/testability';
|
import {TestabilityRegistry, Testability} from 'angular2/src/core/testability/testability';
|
||||||
|
import {
|
||||||
|
appViewToken,
|
||||||
|
appChangeDetectorToken,
|
||||||
|
appElementToken,
|
||||||
|
appComponentAnnotatedTypeToken,
|
||||||
|
appDocumentToken,
|
||||||
|
} from './application_tokens';
|
||||||
|
|
||||||
var _rootInjector: Injector;
|
var _rootInjector: Injector;
|
||||||
|
|
||||||
|
@ -37,12 +44,6 @@ var _rootBindings = [
|
||||||
TestabilityRegistry
|
TestabilityRegistry
|
||||||
];
|
];
|
||||||
|
|
||||||
export var appViewToken = new OpaqueToken('AppView');
|
|
||||||
export var appChangeDetectorToken = new OpaqueToken('AppChangeDetector');
|
|
||||||
export var appElementToken = new OpaqueToken('AppElement');
|
|
||||||
export var appComponentAnnotatedTypeToken = new OpaqueToken('AppComponentAnnotatedType');
|
|
||||||
export var appDocumentToken = new OpaqueToken('AppDocument');
|
|
||||||
|
|
||||||
function _injectorBindings(appComponentType): List<Binding> {
|
function _injectorBindings(appComponentType): List<Binding> {
|
||||||
return [
|
return [
|
||||||
bind(appDocumentToken).toValue(DOM.defaultDoc()),
|
bind(appDocumentToken).toValue(DOM.defaultDoc()),
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import {OpaqueToken} from 'angular2/di';
|
||||||
|
|
||||||
|
export var appViewToken = new OpaqueToken('AppView');
|
||||||
|
export var appChangeDetectorToken = new OpaqueToken('AppChangeDetector');
|
||||||
|
export var appElementToken = new OpaqueToken('AppElement');
|
||||||
|
export var appComponentAnnotatedTypeToken = new OpaqueToken('AppComponentAnnotatedType');
|
||||||
|
export var appDocumentToken = new OpaqueToken('AppDocument');
|
|
@ -0,0 +1,15 @@
|
||||||
|
import {VmTurnZone} from 'angular2/src/core/zone/vm_turn_zone';
|
||||||
|
|
||||||
|
export class MockVmTurnZone extends VmTurnZone {
|
||||||
|
constructor() {
|
||||||
|
super({enableLongStackTrace: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
run(fn) {
|
||||||
|
fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
runOutsideAngular(fn) {
|
||||||
|
fn();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
import 'dart:mirrors';
|
||||||
|
|
||||||
|
Type getTypeOf(instance) => instance.runtimeType;
|
||||||
|
|
||||||
|
dynamic instantiateType(Type type, [List params = const []]) {
|
||||||
|
var cm = reflectClass(type);
|
||||||
|
return cm.newInstance(new Symbol(''), params).reflectee;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
export function getTypeOf(instance) {
|
||||||
|
return instance.constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function instantiateType(type: Function, params: Array = []) {
|
||||||
|
var instance = Object.create(type.prototype);
|
||||||
|
instance.constructor.apply(instance, params);
|
||||||
|
return instance;
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
import {Injector} from 'angular2/di';
|
||||||
|
|
||||||
|
import {Type, isPresent, BaseException} from 'angular2/src/facade/lang';
|
||||||
|
import {Promise} from 'angular2/src/facade/async';
|
||||||
|
import {isBlank} from 'angular2/src/facade/lang';
|
||||||
|
import {List} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
|
import {Template} from 'angular2/src/core/annotations/template';
|
||||||
|
|
||||||
|
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||||
|
import {Compiler} from 'angular2/src/core/compiler/compiler';
|
||||||
|
import {View} from 'angular2/src/core/compiler/view';
|
||||||
|
|
||||||
|
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
||||||
|
|
||||||
|
import {queryView} from './utils';
|
||||||
|
import {instantiateType, getTypeOf} from './lang_utils';
|
||||||
|
|
||||||
|
export class TestBed {
|
||||||
|
_injector: Injector;
|
||||||
|
|
||||||
|
constructor(injector: Injector) {
|
||||||
|
this._injector = injector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the [Template] of a [Component].
|
||||||
|
*
|
||||||
|
* @see setInlineTemplate() to only override the html
|
||||||
|
*
|
||||||
|
* @param {Type} component
|
||||||
|
* @param {Template} template
|
||||||
|
*/
|
||||||
|
overrideTemplate(component: Type, template: Template): void {
|
||||||
|
this._injector.get(TemplateResolver).setTemplate(component, template);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides only the html of a [Component].
|
||||||
|
* All the other propoerties of the component's [Template] are preserved.
|
||||||
|
*
|
||||||
|
* @param {Type} component
|
||||||
|
* @param {string} html
|
||||||
|
*/
|
||||||
|
setInlineTemplate(component: Type, html: string): void {
|
||||||
|
this._injector.get(TemplateResolver).setInlineTemplate(component, html);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the directives from the component [Template].
|
||||||
|
*
|
||||||
|
* @param {Type} component
|
||||||
|
* @param {Type} from
|
||||||
|
* @param {Type} to
|
||||||
|
*/
|
||||||
|
overrideDirective(component: Type, from: Type, to: Type): void {
|
||||||
|
this._injector.get(TemplateResolver).overrideTemplateDirective(component, from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [View] for the given component.
|
||||||
|
*
|
||||||
|
* Only either a component or a context needs to be specified but both can be provided for
|
||||||
|
* advanced use cases (ie subclassing the context).
|
||||||
|
*
|
||||||
|
* @param {Type} component
|
||||||
|
* @param {*} context
|
||||||
|
* @param {string} html Use as the component template when specified (shortcut for setInlineTemplate)
|
||||||
|
* @return {Promise<ViewProxy>}
|
||||||
|
*/
|
||||||
|
createView(component: Type,
|
||||||
|
{context = null, html = null}: {context:any, html: string} = {}): Promise<View> {
|
||||||
|
|
||||||
|
if (isBlank(component) && isBlank(context)) {
|
||||||
|
throw new BaseException('You must specified at least a component or a context');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBlank(component)) {
|
||||||
|
component = getTypeOf(context);
|
||||||
|
} else if (isBlank(context)) {
|
||||||
|
context = instantiateType(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPresent(html)) {
|
||||||
|
this.setInlineTemplate(component, html);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._injector.get(Compiler).compile(component).then((pv) => {
|
||||||
|
var eventManager = this._injector.get(EventManager);
|
||||||
|
var view = pv.instantiate(null, eventManager);
|
||||||
|
view.hydrate(this._injector, null, null, context, null);
|
||||||
|
return new ViewProxy(view);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy to [View] return by [TestBed.createView] which offers a high level API for tests.
|
||||||
|
*/
|
||||||
|
export class ViewProxy {
|
||||||
|
_view: View;
|
||||||
|
|
||||||
|
constructor(view: View) {
|
||||||
|
this._view = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
get context(): any {
|
||||||
|
return this._view.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
get nodes(): List {
|
||||||
|
return this._view.nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
detectChanges(): void {
|
||||||
|
this._view.changeDetector.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
querySelector(selector) {
|
||||||
|
return queryView(this._view, selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {View} return the underlying [View].
|
||||||
|
*
|
||||||
|
* Prefer using the other methods which hide implementation details.
|
||||||
|
*/
|
||||||
|
get rawView(): View {
|
||||||
|
return this._view;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import {bind} from 'angular2/di';
|
import {bind} from 'angular2/di';
|
||||||
|
|
||||||
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
||||||
import {Reflector, reflector} from 'angular2/src/reflection/reflection';
|
import {Reflector, reflector} from 'angular2/src/reflection/reflection';
|
||||||
import {Parser, Lexer, ChangeDetection, dynamicChangeDetection} from 'angular2/change_detection';
|
import {Parser, Lexer, ChangeDetection, dynamicChangeDetection} from 'angular2/change_detection';
|
||||||
|
@ -6,13 +7,25 @@ import {ExceptionHandler} from 'angular2/src/core/exception_handler';
|
||||||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||||
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||||
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
import {ShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||||
import {XHR} from 'angular2/src/services/xhr';
|
import {XHR} from 'angular2/src/services/xhr';
|
||||||
import {XHRMock} from 'angular2/src/mock/xhr_mock';
|
|
||||||
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
|
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
|
||||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||||
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
||||||
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
|
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
|
||||||
|
import {VmTurnZone} from 'angular2/src/core/zone/vm_turn_zone';
|
||||||
|
|
||||||
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
|
import {appDocumentToken} from 'angular2/src/core/application_tokens';
|
||||||
|
|
||||||
|
import {EventManager, DomEventsPlugin} from 'angular2/src/render/dom/events/event_manager';
|
||||||
|
|
||||||
|
import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
|
||||||
|
import {XHRMock} from 'angular2/src/mock/xhr_mock';
|
||||||
|
import {MockVmTurnZone} from 'angular2/src/mock/vm_turn_zone_mock';
|
||||||
|
|
||||||
|
import {TestBed} from './test_bed';
|
||||||
|
|
||||||
import {Injector} from 'angular2/di';
|
import {Injector} from 'angular2/di';
|
||||||
|
|
||||||
|
@ -40,11 +53,23 @@ function _getRootBindings() {
|
||||||
* @returns {*[]}
|
* @returns {*[]}
|
||||||
*/
|
*/
|
||||||
function _getAppBindings() {
|
function _getAppBindings() {
|
||||||
|
var appDoc;
|
||||||
|
|
||||||
|
// The document is only available in browser environment
|
||||||
|
try {
|
||||||
|
appDoc = DOM.defaultDoc();
|
||||||
|
} catch(e) {
|
||||||
|
appDoc = null;
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
bind(ShadowDomStrategy).toClass(NativeShadowDomStrategy),
|
bind(appDocumentToken).toValue(appDoc),
|
||||||
|
bind(ShadowDomStrategy).toFactory(
|
||||||
|
(styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head),
|
||||||
|
[StyleUrlResolver, appDocumentToken]),
|
||||||
Compiler,
|
Compiler,
|
||||||
CompilerCache,
|
CompilerCache,
|
||||||
TemplateResolver,
|
bind(TemplateResolver).toClass(MockTemplateResolver),
|
||||||
bind(ChangeDetection).toValue(dynamicChangeDetection),
|
bind(ChangeDetection).toValue(dynamicChangeDetection),
|
||||||
TemplateLoader,
|
TemplateLoader,
|
||||||
DirectiveMetadataReader,
|
DirectiveMetadataReader,
|
||||||
|
@ -55,7 +80,15 @@ function _getAppBindings() {
|
||||||
ComponentUrlMapper,
|
ComponentUrlMapper,
|
||||||
UrlResolver,
|
UrlResolver,
|
||||||
StyleUrlResolver,
|
StyleUrlResolver,
|
||||||
StyleInliner
|
StyleInliner,
|
||||||
|
TestBed,
|
||||||
|
bind(VmTurnZone).toClass(MockVmTurnZone),
|
||||||
|
bind(EventManager).toFactory((zone) => {
|
||||||
|
var plugins = [
|
||||||
|
new DomEventsPlugin(),
|
||||||
|
];
|
||||||
|
return new EventManager(plugins, zone);
|
||||||
|
}, [VmTurnZone]),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ import {
|
||||||
xdescribe,
|
xdescribe,
|
||||||
xit,
|
xit,
|
||||||
} from 'angular2/test_lib';
|
} from 'angular2/test_lib';
|
||||||
import {bootstrap, appDocumentToken, appElementToken}
|
import {bootstrap} from 'angular2/src/core/application';
|
||||||
from 'angular2/src/core/application';
|
import {appDocumentToken, appElementToken} from 'angular2/src/core/application_tokens';
|
||||||
import {Component, Decorator} from 'angular2/src/core/annotations/annotations';
|
import {Component, Decorator} from 'angular2/src/core/annotations/annotations';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||||
|
|
Loading…
Reference in New Issue