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/annotations/template';
|
||||
export * from './src/core/application';
|
||||
export * from './src/core/application_tokens';
|
||||
export * from './src/core/annotations/di';
|
||||
|
||||
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 {PrivateComponentLoader} from 'angular2/src/core/compiler/private_component_loader';
|
||||
import {TestabilityRegistry, Testability} from 'angular2/src/core/testability/testability';
|
||||
import {
|
||||
appViewToken,
|
||||
appChangeDetectorToken,
|
||||
appElementToken,
|
||||
appComponentAnnotatedTypeToken,
|
||||
appDocumentToken,
|
||||
} from './application_tokens';
|
||||
|
||||
var _rootInjector: Injector;
|
||||
|
||||
|
@ -37,12 +44,6 @@ var _rootBindings = [
|
|||
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> {
|
||||
return [
|
||||
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 {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
||||
import {Reflector, reflector} from 'angular2/src/reflection/reflection';
|
||||
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 {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||
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 {XHRMock} from 'angular2/src/mock/xhr_mock';
|
||||
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
|
||||
import {UrlResolver} from 'angular2/src/services/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 {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';
|
||||
|
||||
|
@ -40,11 +53,23 @@ function _getRootBindings() {
|
|||
* @returns {*[]}
|
||||
*/
|
||||
function _getAppBindings() {
|
||||
var appDoc;
|
||||
|
||||
// The document is only available in browser environment
|
||||
try {
|
||||
appDoc = DOM.defaultDoc();
|
||||
} catch(e) {
|
||||
appDoc = null;
|
||||
}
|
||||
|
||||
return [
|
||||
bind(ShadowDomStrategy).toClass(NativeShadowDomStrategy),
|
||||
bind(appDocumentToken).toValue(appDoc),
|
||||
bind(ShadowDomStrategy).toFactory(
|
||||
(styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head),
|
||||
[StyleUrlResolver, appDocumentToken]),
|
||||
Compiler,
|
||||
CompilerCache,
|
||||
TemplateResolver,
|
||||
bind(TemplateResolver).toClass(MockTemplateResolver),
|
||||
bind(ChangeDetection).toValue(dynamicChangeDetection),
|
||||
TemplateLoader,
|
||||
DirectiveMetadataReader,
|
||||
|
@ -55,7 +80,15 @@ function _getAppBindings() {
|
|||
ComponentUrlMapper,
|
||||
UrlResolver,
|
||||
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,
|
||||
xit,
|
||||
} from 'angular2/test_lib';
|
||||
import {bootstrap, appDocumentToken, appElementToken}
|
||||
from 'angular2/src/core/application';
|
||||
import {bootstrap} from 'angular2/src/core/application';
|
||||
import {appDocumentToken, appElementToken} from 'angular2/src/core/application_tokens';
|
||||
import {Component, Decorator} from 'angular2/src/core/annotations/annotations';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
|
|
Loading…
Reference in New Issue