feat(debug): replace DebugElement with new Debug DOM

Now, using `ng.probe(element)` in the browser console returns
a DebugElement when in dev mode.

`ComponentFixture#debugElement` also returns a new DebugElement.

Breaking Change:

This is a breaking change for unit tests. The API for the DebugElement
has changed. Now, there is a DebugElement or DebugNode for every node
in the DOM, not only nodes with an ElementRef. `componentViewChildren` is
removed, and `childNodes` is a list of ElementNodes corresponding to every
child in the DOM. `query` no longer takes a scope parameter, since
the entire rendered DOM is included in the `childNodes`.

Before:

```
componentFixture.debugElement.componentViewChildren[0];
```

After
```
// Depending on the DOM structure of your component, the
// index may have changed or the first component child
// may be a sub-child.
componentFixture.debugElement.children[0];
```

Before:

```
debugElement.query(By.css('div'), Scope.all());
```

After:

```
debugElement.query(By.css('div'));
```

Before:

```
componentFixture.debugElement.elementRef;
```

After:

```
componentFixture.elementRef;
```
This commit is contained in:
Julie Ralph
2016-01-29 11:28:10 -08:00
committed by Alex Eagle
parent ae7d2ab515
commit e1bf3d33f8
45 changed files with 1243 additions and 1220 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ export './src/core/application_tokens.dart' show APP_ID,
export './src/core/zone.dart';
export './src/core/render.dart';
export './src/core/linker.dart';
export './src/core/debug/debug_element.dart' show DebugElement,
export './src/core/debug/debug_node.dart' show DebugElement,
Scope,
inspectElement,
asNativeElements;
+1 -6
View File
@@ -20,12 +20,7 @@ export {
export * from './src/core/zone';
export * from './src/core/render';
export * from './src/core/linker';
export {
DebugElement,
Scope,
inspectElement,
asNativeElements
} from './src/core/debug/debug_element';
export {DebugElement, asNativeElements} from './src/core/debug/debug_node';
export * from './src/core/testability/testability';
export * from './src/core/change_detection';
export * from './src/core/platform_directives_and_pipes';
@@ -1,16 +1,8 @@
import {DebugElement, Scope} from 'angular2/core';
import {DebugElement} from 'angular2/core';
var debugElement: DebugElement;
var predicate;
// #docregion scope_all
debugElement.query(predicate, Scope.all);
// #enddocregion
// #docregion scope_light
debugElement.query(predicate, Scope.light);
// #enddocregion
// #docregion scope_view
debugElement.query(predicate, Scope.view);
debugElement.query(predicate);
// #enddocregion
@@ -1,17 +1,17 @@
import {By} from 'angular2/platform/browser';
import {DebugElement, Scope} from 'angular2/core';
import {DebugElement} from 'angular2/core';
var debugElement: DebugElement;
class MyDirective {}
// #docregion by_all
debugElement.query(By.all(), Scope.all);
debugElement.query(By.all());
// #enddocregion
// #docregion by_css
debugElement.query(By.css('[attribute]'), Scope.all);
debugElement.query(By.css('[attribute]'));
// #enddocregion
// #docregion by_directive
debugElement.query(By.directive(MyDirective), Scope.all);
debugElement.query(By.directive(MyDirective));
// #enddocregion
+1 -1
View File
@@ -1,8 +1,8 @@
export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
export {
BROWSER_PROVIDERS,
ELEMENT_PROBE_BINDINGS,
ELEMENT_PROBE_PROVIDERS,
ELEMENT_PROBE_PROVIDERS_PROD_MODE,
inspectNativeElement,
BrowserDomAdapter,
By,
+1 -1
View File
@@ -1,8 +1,8 @@
export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
export {
BROWSER_PROVIDERS,
ELEMENT_PROBE_BINDINGS,
ELEMENT_PROBE_PROVIDERS,
ELEMENT_PROBE_PROVIDERS_PROD_MODE,
inspectNativeElement,
BrowserDomAdapter,
By,
+1 -1
View File
@@ -12,4 +12,4 @@ export {
EventManagerPlugin
} from 'angular2/src/platform/dom/events/event_manager';
export * from 'angular2/src/platform/dom/debug/by';
export * from 'angular2/src/platform/dom/debug/debug_element_view_listener';
export * from 'angular2/src/platform/dom/debug/ng_probe';
@@ -15,7 +15,6 @@ import {ResolvedMetadataCache} from 'angular2/src/core/linker/resolved_metadata_
import {AppViewManager} from './linker/view_manager';
import {AppViewManager_} from "./linker/view_manager";
import {ViewResolver} from './linker/view_resolver';
import {AppViewListener} from './linker/view_listener';
import {DirectiveResolver} from './linker/directive_resolver';
import {PipeResolver} from './linker/pipe_resolver';
import {Compiler} from './linker/compiler';
@@ -32,7 +31,6 @@ export const APPLICATION_COMMON_PROVIDERS: Array<Type | Provider | any[]> = CONS
APP_ID_RANDOM_PROVIDER,
ResolvedMetadataCache,
new Provider(AppViewManager, {useClass: AppViewManager_}),
AppViewListener,
ViewResolver,
new Provider(IterableDiffers, {useValue: defaultIterableDiffers}),
new Provider(KeyValueDiffers, {useValue: defaultKeyValueDiffers}),
@@ -1,248 +0,0 @@
import {Type, isPresent, isBlank} from 'angular2/src/facade/lang';
import {ListWrapper, MapWrapper, Predicate} from 'angular2/src/facade/collection';
import {unimplemented} from 'angular2/src/facade/exceptions';
import {AppElement} from 'angular2/src/core/linker/element';
import {AppView} from 'angular2/src/core/linker/view';
import {ElementRef, ElementRef_} from 'angular2/src/core/linker/element_ref';
/**
* A DebugElement contains information from the Angular compiler about an
* element and provides access to the corresponding ElementInjector and
* underlying DOM Element, as well as a way to query for children.
*
* A DebugElement can be obtained from a {@link ComponentFixture} or from an
* {@link ElementRef} via {@link inspectElement}.
*/
export abstract class DebugElement {
/**
* Return the instance of the component associated with this element, if any.
*/
get componentInstance(): any { return unimplemented(); };
/**
* Return the native HTML element for this DebugElement.
*/
get nativeElement(): any { return unimplemented(); };
/**
* Return an Angular {@link ElementRef} for this element.
*/
get elementRef(): ElementRef { return unimplemented(); };
/**
* Get the directive active for this element with the given index, if any.
*/
abstract getDirectiveInstance(directiveIndex: number): any;
/**
* Get child DebugElements from within the Light DOM.
*
* @return {DebugElement[]}
*/
get children(): DebugElement[] { return unimplemented(); };
/**
* Get the root DebugElement children of a component. Returns an empty
* list if the current DebugElement is not a component root.
*
* @return {DebugElement[]}
*/
get componentViewChildren(): DebugElement[] { return unimplemented(); };
/**
* Simulate an event from this element as if the user had caused
* this event to fire from the page.
*/
abstract triggerEventHandler(eventName: string, eventObj: Event): void;
/**
* Check whether the element has a directive with the given type.
*/
abstract hasDirective(type: Type): boolean;
/**
* Inject the given type from the element injector.
*/
abstract inject(type: Type): any;
/**
* Read a local variable from the element (e.g. one defined with `#variable`).
*/
abstract getLocal(name: string): any;
/**
* Return the first descendant TestElement matching the given predicate
* and scope.
*
* @param {Function: boolean} predicate
* @param {Scope} scope
*
* @return {DebugElement}
*/
query(predicate: Predicate<DebugElement>, scope: Function = Scope.all): DebugElement {
var results = this.queryAll(predicate, scope);
return results.length > 0 ? results[0] : null;
}
/**
* Return descendant TestElememts matching the given predicate
* and scope.
*
* @param {Function: boolean} predicate
* @param {Scope} scope
*
* @return {DebugElement[]}
*/
queryAll(predicate: Predicate<DebugElement>, scope: Function = Scope.all): DebugElement[] {
var elementsInScope: any[] = scope(this);
return elementsInScope.filter(predicate);
}
}
export class DebugElement_ extends DebugElement {
constructor(private _appElement: AppElement) { super(); }
get componentInstance(): any {
if (!isPresent(this._appElement)) {
return null;
}
return this._appElement.getComponent();
}
get nativeElement(): any { return this.elementRef.nativeElement; }
get elementRef(): ElementRef { return this._appElement.ref; }
getDirectiveInstance(directiveIndex: number): any {
return this._appElement.getDirectiveAtIndex(directiveIndex);
}
get children(): DebugElement[] {
return this._getChildElements(this._appElement.parentView, this._appElement);
}
get componentViewChildren(): DebugElement[] {
if (!isPresent(this._appElement.componentView)) {
// The current element is not a component.
return [];
}
return this._getChildElements(this._appElement.componentView, null);
}
triggerEventHandler(eventName: string, eventObj: Event): void {
this._appElement.parentView.triggerEventHandlers(eventName, eventObj,
this._appElement.proto.index);
}
hasDirective(type: Type): boolean {
if (!isPresent(this._appElement)) {
return false;
}
return this._appElement.hasDirective(type);
}
inject(type: Type): any {
if (!isPresent(this._appElement)) {
return null;
}
return this._appElement.get(type);
}
getLocal(name: string): any { return this._appElement.parentView.locals.get(name); }
/** @internal */
_getChildElements(view: AppView, parentAppElement: AppElement): DebugElement[] {
var els = [];
for (var i = 0; i < view.appElements.length; ++i) {
var appEl = view.appElements[i];
if (appEl.parent == parentAppElement) {
els.push(new DebugElement_(appEl));
var views = appEl.nestedViews;
if (isPresent(views)) {
views.forEach(
(nextView) => { els = els.concat(this._getChildElements(nextView, null)); });
}
}
}
return els;
}
}
/**
* Returns a {@link DebugElement} for an {@link ElementRef}.
*
* @param {ElementRef}: elementRef
* @return {DebugElement}
*/
export function inspectElement(elementRef: ElementRef): DebugElement {
return new DebugElement_((<ElementRef_>elementRef).internalElement);
}
/**
* Maps an array of {@link DebugElement}s to an array of native DOM elements.
*/
export function asNativeElements(arr: DebugElement[]): any[] {
return arr.map((debugEl) => debugEl.nativeElement);
}
/**
* Set of scope functions used with {@link DebugElement}'s query functionality.
*/
export class Scope {
/**
* Scope queries to both the light dom and view of an element and its
* children.
*
* ## Example
*
* {@example core/debug/ts/debug_element/debug_element.ts region='scope_all'}
*/
static all(debugElement: DebugElement): DebugElement[] {
var scope = [];
scope.push(debugElement);
debugElement.children.forEach(child => scope = scope.concat(Scope.all(child)));
debugElement.componentViewChildren.forEach(child => scope = scope.concat(Scope.all(child)));
return scope;
}
/**
* Scope queries to the light dom of an element and its children.
*
* ## Example
*
* {@example core/debug/ts/debug_element/debug_element.ts region='scope_light'}
*/
static light(debugElement: DebugElement): DebugElement[] {
var scope = [];
debugElement.children.forEach(child => {
scope.push(child);
scope = scope.concat(Scope.light(child));
});
return scope;
}
/**
* Scope queries to the view of an element of its children.
*
* ## Example
*
* {@example core/debug/ts/debug_element/debug_element.ts region='scope_view'}
*/
static view(debugElement: DebugElement): DebugElement[] {
var scope = [];
debugElement.componentViewChildren.forEach(child => {
scope.push(child);
scope = scope.concat(Scope.light(child));
});
return scope;
}
}
@@ -0,0 +1,171 @@
import {isPresent} from 'angular2/src/facade/lang';
import {Predicate} from 'angular2/src/facade/collection';
import {Injector} from 'angular2/src/core/di';
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {RenderDebugInfo} from 'angular2/src/core/render/api';
export class EventListener { constructor(public name: string, public callback: Function){}; }
export class DebugNode {
nativeNode: any;
listeners: EventListener[];
parent: DebugElement;
providerTokens: any[];
locals: Map<string, any>;
injector: Injector;
componentInstance: any;
constructor(nativeNode: any, parent: DebugNode) {
this.nativeNode = nativeNode;
if (isPresent(parent) && parent instanceof DebugElement) {
parent.addChild(this);
} else {
this.parent = null;
}
this.listeners = [];
this.providerTokens = [];
}
setDebugInfo(info: RenderDebugInfo) {
this.injector = info.injector;
this.providerTokens = info.providerTokens;
this.locals = info.locals;
this.componentInstance = info.component;
}
inject(token: any): any { return this.injector.get(token); }
getLocal(name: string): any { return this.locals.get(name); }
}
export class DebugElement extends DebugNode {
name: string;
properties: Map<string, any>;
attributes: Map<string, any>;
childNodes: DebugNode[];
nativeElement: any;
constructor(nativeNode: any, parent: any) {
super(nativeNode, parent);
this.properties = new Map<string, any>();
this.attributes = new Map<string, any>();
this.childNodes = [];
this.nativeElement = nativeNode;
}
addChild(child: DebugNode) {
if (isPresent(child)) {
this.childNodes.push(child);
child.parent = this;
}
}
removeChild(child: DebugNode) {
var childIndex = this.childNodes.indexOf(child);
if (childIndex !== -1) {
child.parent = null;
this.childNodes.splice(childIndex, 1);
}
}
insertChildrenAfter(child: DebugNode, newChildren: DebugNode[]) {
var siblingIndex = this.childNodes.indexOf(child);
if (siblingIndex !== -1) {
var previousChildren = this.childNodes.slice(0, siblingIndex + 1);
var nextChildren = this.childNodes.slice(siblingIndex + 1);
this.childNodes =
ListWrapper.concat(ListWrapper.concat(previousChildren, newChildren), nextChildren);
for (var i = 0; i < newChildren.length; ++i) {
var newChild = newChildren[i];
if (isPresent(newChild.parent)) {
newChild.parent.removeChild(newChild);
}
newChild.parent = this;
}
}
}
query(predicate: Predicate<DebugElement>): DebugElement {
var results = this.queryAll(predicate);
return results.length > 0 ? results[0] : null;
}
queryAll(predicate: Predicate<DebugElement>): DebugElement[] {
var matches = [];
_queryElementChildren(this, predicate, matches);
return matches;
}
queryAllNodes(predicate: Predicate<DebugNode>): DebugNode[] {
var matches = [];
_queryNodeChildren(this, predicate, matches);
return matches;
}
get children(): DebugElement[] {
var children = [];
this.childNodes.forEach((node) => {
if (node instanceof DebugElement) {
children.push(node);
}
});
return children;
}
triggerEventHandler(eventName: string, eventObj: Event) {
this.listeners.forEach((listener) => {
if (listener.name == eventName) {
listener.callback(eventObj);
}
});
}
}
export function asNativeElements(debugEls: DebugElement[]): any {
return debugEls.map((el) => el.nativeElement);
}
function _queryElementChildren(element: DebugElement, predicate: Predicate<DebugElement>,
matches: DebugElement[]) {
element.childNodes.forEach(node => {
if (node instanceof DebugElement) {
if (predicate(node)) {
matches.push(node);
}
_queryElementChildren(node, predicate, matches);
}
});
}
function _queryNodeChildren(parentNode: DebugNode, predicate: Predicate<DebugNode>,
matches: DebugNode[]) {
if (parentNode instanceof DebugElement) {
parentNode.childNodes.forEach(node => {
if (predicate(node)) {
matches.push(node);
}
if (node instanceof DebugElement) {
_queryNodeChildren(node, predicate, matches);
}
});
}
}
// Need to keep the nodes in a global Map so that multiple angular apps are supported.
var _nativeNodeToDebugNode = new Map<any, DebugNode>();
export function getDebugNode(nativeNode: any): DebugNode {
return _nativeNodeToDebugNode.get(nativeNode);
}
export function getAllDebugNodes(): DebugNode[] {
return MapWrapper.values(_nativeNodeToDebugNode);
}
export function indexDebugNode(node: DebugNode) {
_nativeNodeToDebugNode.set(node.nativeNode, node);
}
export function removeDebugNodeFromIndex(node: DebugNode) {
_nativeNodeToDebugNode.delete(node.nativeNode);
}
@@ -0,0 +1,157 @@
import {isPresent} from 'angular2/src/facade/lang';
import {
Renderer,
RootRenderer,
RenderComponentType,
RenderDebugInfo
} from 'angular2/src/core/render/api';
import {
DebugNode,
DebugElement,
EventListener,
getDebugNode,
indexDebugNode,
removeDebugNodeFromIndex
} from 'angular2/src/core/debug/debug_node';
export class DebugDomRootRenderer implements RootRenderer {
constructor(private _delegate: RootRenderer) {}
renderComponent(componentProto: RenderComponentType): Renderer {
return new DebugDomRenderer(this, this._delegate.renderComponent(componentProto));
}
}
export class DebugDomRenderer implements Renderer {
constructor(private _rootRenderer: DebugDomRootRenderer, private _delegate: Renderer) {}
renderComponent(componentType: RenderComponentType): Renderer {
return this._rootRenderer.renderComponent(componentType);
}
selectRootElement(selector: string): any {
var nativeEl = this._delegate.selectRootElement(selector);
var debugEl = new DebugElement(nativeEl, null);
indexDebugNode(debugEl);
return nativeEl;
}
createElement(parentElement: any, name: string): any {
var nativeEl = this._delegate.createElement(parentElement, name);
var debugEl = new DebugElement(nativeEl, getDebugNode(parentElement));
debugEl.name = name;
indexDebugNode(debugEl);
return nativeEl;
}
createViewRoot(hostElement: any): any { return this._delegate.createViewRoot(hostElement); }
createTemplateAnchor(parentElement: any): any {
var comment = this._delegate.createTemplateAnchor(parentElement);
var debugEl = new DebugNode(comment, getDebugNode(parentElement));
indexDebugNode(debugEl);
return comment;
}
createText(parentElement: any, value: string): any {
var text = this._delegate.createText(parentElement, value);
var debugEl = new DebugNode(text, getDebugNode(parentElement));
indexDebugNode(debugEl);
return text;
}
projectNodes(parentElement: any, nodes: any[]) {
var debugParent = getDebugNode(parentElement);
if (isPresent(debugParent) && debugParent instanceof DebugElement) {
nodes.forEach((node) => { debugParent.addChild(getDebugNode(node)); });
}
return this._delegate.projectNodes(parentElement, nodes);
}
attachViewAfter(node: any, viewRootNodes: any[]) {
var debugNode = getDebugNode(node);
if (isPresent(debugNode)) {
var debugParent = debugNode.parent;
if (viewRootNodes.length > 0 && isPresent(debugParent)) {
var debugViewRootNodes = [];
viewRootNodes.forEach((rootNode) => debugViewRootNodes.push(getDebugNode(rootNode)));
debugParent.insertChildrenAfter(debugNode, debugViewRootNodes);
}
}
return this._delegate.attachViewAfter(node, viewRootNodes);
}
detachView(viewRootNodes: any[]) {
viewRootNodes.forEach((node) => {
var debugNode = getDebugNode(node);
if (isPresent(debugNode) && isPresent(debugNode.parent)) {
debugNode.parent.removeChild(debugNode);
}
});
return this._delegate.detachView(viewRootNodes);
}
destroyView(hostElement: any, viewAllNodes: any[]) {
viewAllNodes.forEach((node) => { removeDebugNodeFromIndex(getDebugNode(node)); });
return this._delegate.destroyView(hostElement, viewAllNodes);
}
listen(renderElement: any, name: string, callback: Function) {
var debugEl = getDebugNode(renderElement);
if (isPresent(debugEl)) {
debugEl.listeners.push(new EventListener(name, callback));
}
return this._delegate.listen(renderElement, name, callback);
}
listenGlobal(target: string, name: string, callback: Function): Function {
return this._delegate.listenGlobal(target, name, callback);
}
setElementProperty(renderElement: any, propertyName: string, propertyValue: any) {
var debugEl = getDebugNode(renderElement);
if (isPresent(debugEl) && debugEl instanceof DebugElement) {
debugEl.properties.set(propertyName, propertyValue);
}
return this._delegate.setElementProperty(renderElement, propertyName, propertyValue);
}
setElementAttribute(renderElement: any, attributeName: string, attributeValue: string) {
var debugEl = getDebugNode(renderElement);
if (isPresent(debugEl) && debugEl instanceof DebugElement) {
debugEl.attributes.set(attributeName, attributeValue);
}
return this._delegate.setElementAttribute(renderElement, attributeName, attributeValue);
}
/**
* Used only in debug mode to serialize property changes to comment nodes,
* such as <template> placeholders.
*/
setBindingDebugInfo(renderElement: any, propertyName: string, propertyValue: string) {
return this._delegate.setBindingDebugInfo(renderElement, propertyName, propertyValue);
}
/**
* Used only in development mode to set information needed by the DebugNode for this element.
*/
setElementDebugInfo(renderElement: any, info: RenderDebugInfo) {
var debugEl = getDebugNode(renderElement);
debugEl.setDebugInfo(info);
return this._delegate.setElementDebugInfo(renderElement, info);
}
setElementClass(renderElement: any, className: string, isAdd: boolean) {
return this._delegate.setElementClass(renderElement, className, isAdd);
}
setElementStyle(renderElement: any, styleName: string, styleValue: string) {
return this._delegate.setElementStyle(renderElement, styleName, styleValue);
}
invokeElementMethod(renderElement: any, methodName: string, args: any[]) {
return this._delegate.invokeElementMethod(renderElement, methodName, args);
}
setText(renderNode: any, text: string) { return this._delegate.setText(renderNode, text); }
}
+10 -1
View File
@@ -27,7 +27,7 @@ import {
CONST_EXPR
} from 'angular2/src/facade/lang';
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
import {Renderer, RootRenderer} from 'angular2/src/core/render/api';
import {Renderer, RootRenderer, RenderDebugInfo} from 'angular2/src/core/render/api';
import {ViewRef_, HostViewFactoryRef} from './view_ref';
import {ProtoPipes} from 'angular2/src/core/pipes/pipes';
import {camelCaseToDashCase} from 'angular2/src/core/render/util';
@@ -119,6 +119,12 @@ export class AppView implements ChangeDispatcher {
(templateName, _) => { localsMap.set(templateName, null); });
for (var i = 0; i < appElements.length; i++) {
var appEl = appElements[i];
var providerTokens = [];
if (isPresent(appEl.proto.protoInjector)) {
for (var j = 0; j < appEl.proto.protoInjector.numberOfProviders; j++) {
providerTokens.push(appEl.proto.protoInjector.getProviderAtIndex(j).key.token);
}
}
StringMapWrapper.forEach(appEl.proto.directiveVariableBindings, (directiveIndex, name) => {
if (isBlank(directiveIndex)) {
localsMap.set(name, appEl.nativeElement);
@@ -126,6 +132,9 @@ export class AppView implements ChangeDispatcher {
localsMap.set(name, appEl.getDirectiveAtIndex(directiveIndex));
}
});
this.renderer.setElementDebugInfo(
appEl.nativeElement, new RenderDebugInfo(appEl.getInjector(), appEl.getComponent(),
providerTokens, localsMap));
}
var parentLocals = null;
if (this.proto.type !== ViewType.COMPONENT) {
@@ -1,11 +0,0 @@
import {Injectable} from 'angular2/src/core/di';
import * as viewModule from './view';
/**
* Listener for view creation / destruction.
*/
@Injectable()
export class AppViewListener {
onViewCreated(view: viewModule.AppView) {}
onViewDestroyed(view: viewModule.AppView) {}
}
@@ -22,7 +22,6 @@ import {
} from './view_ref';
import {ViewContainerRef} from './view_container_ref';
import {TemplateRef, TemplateRef_} from './template_ref';
import {AppViewListener} from './view_listener';
import {RootRenderer, RenderComponentType} from 'angular2/src/core/render/api';
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
import {APP_ID} from 'angular2/src/core/application_tokens';
@@ -185,10 +184,7 @@ export abstract class AppViewManager {
export class AppViewManager_ extends AppViewManager {
private _nextCompTypeId: number = 0;
constructor(private _renderer: RootRenderer, private _viewListener: AppViewListener,
@Inject(APP_ID) private _appId: string) {
super();
}
constructor(private _renderer: RootRenderer, @Inject(APP_ID) private _appId: string) { super(); }
getViewContainer(location: ElementRef): ViewContainerRef {
return (<ElementRef_>location).internalElement.getViewContainerRef();
@@ -316,10 +312,10 @@ export class AppViewManager_ extends AppViewManager {
}
/** @internal */
onViewCreated(view: AppView) { this._viewListener.onViewCreated(view); }
onViewCreated(view: AppView) {}
/** @internal */
onViewDestroyed(view: AppView) { this._viewListener.onViewDestroyed(view); }
onViewDestroyed(view: AppView) {}
/** @internal */
createRenderComponentType(encapsulation: ViewEncapsulation,
+8
View File
@@ -1,10 +1,16 @@
import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
import {Injector} from 'angular2/src/core/di/injector';
export class RenderComponentType {
constructor(public id: string, public encapsulation: ViewEncapsulation,
public styles: Array<string | any[]>) {}
}
export class RenderDebugInfo {
constructor(public injector: Injector, public component: any, public providerTokens: any[],
public locals: Map<string, any>) {}
}
export interface ParentRenderer { renderComponent(componentType: RenderComponentType): Renderer; }
export abstract class Renderer implements ParentRenderer {
@@ -42,6 +48,8 @@ export abstract class Renderer implements ParentRenderer {
*/
abstract setBindingDebugInfo(renderElement: any, propertyName: string, propertyValue: string);
abstract setElementDebugInfo(renderElement: any, info: RenderDebugInfo);
abstract setElementClass(renderElement: any, className: string, isAdd: boolean);
abstract setElementStyle(renderElement: any, styleName: string, styleValue: string);
@@ -30,12 +30,12 @@ import {BrowserDomAdapter} from './browser/browser_adapter';
import {BrowserGetTestability} from 'angular2/src/platform/browser/testability';
import {wtfInit} from 'angular2/src/core/profile/wtf_init';
import {EventManager, EVENT_MANAGER_PLUGINS} from "angular2/src/platform/dom/events/event_manager";
import {ELEMENT_PROBE_PROVIDERS} from 'angular2/platform/common_dom';
export {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens';
export {Title} from 'angular2/src/platform/browser/title';
export {
DebugElementViewListener,
ELEMENT_PROBE_PROVIDERS,
ELEMENT_PROBE_BINDINGS,
ELEMENT_PROBE_PROVIDERS_PROD_MODE,
inspectNativeElement,
By
} from 'angular2/platform/common_dom';
@@ -84,7 +84,8 @@ export const BROWSER_APP_COMMON_PROVIDERS: Array<any /*Type | Provider | any[]*/
Testability,
BrowserDetails,
AnimationBuilder,
EventManager
EventManager,
ELEMENT_PROBE_PROVIDERS
]);
export function initDomAdapter() {
@@ -39,6 +39,6 @@ export class By {
* {@example platform/dom/debug/ts/by/by.ts region='by_directive'}
*/
static directive(type: Type): Predicate<DebugElement> {
return (debugElement) => { return debugElement.hasDirective(type); };
return (debugElement) => { return debugElement.providerTokens.indexOf(type) !== -1; };
}
}
@@ -1,89 +0,0 @@
import {CONST_EXPR, isPresent, NumberWrapper, StringWrapper} from 'angular2/src/facade/lang';
import {MapWrapper, Map, ListWrapper} from 'angular2/src/facade/collection';
import {Injectable, provide, Provider} from 'angular2/src/core/di';
import {AppViewListener} from 'angular2/src/core/linker/view_listener';
import {AppView} from 'angular2/src/core/linker/view';
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {DebugElement, DebugElement_} from 'angular2/src/core/debug/debug_element';
const NG_ID_PROPERTY = 'ngid';
const INSPECT_GLOBAL_NAME = 'ng.probe';
const NG_ID_SEPARATOR = '#';
// Need to keep the views in a global Map so that multiple angular apps are supported
var _allIdsByView = new Map<AppView, number>();
var _allViewsById = new Map<number, AppView>();
var _nextId = 0;
function _setElementId(element, indices: number[]) {
if (isPresent(element) && DOM.isElementNode(element)) {
DOM.setData(element, NG_ID_PROPERTY, indices.join(NG_ID_SEPARATOR));
}
}
function _getElementId(element): number[] {
var elId = DOM.getData(element, NG_ID_PROPERTY);
if (isPresent(elId)) {
return elId.split(NG_ID_SEPARATOR).map(partStr => NumberWrapper.parseInt(partStr, 10));
} else {
return null;
}
}
/**
* Returns a {@link DebugElement} for the given native DOM element, or
* null if the given native element does not have an Angular view associated
* with it.
*/
export function inspectNativeElement(element): DebugElement {
var elId = _getElementId(element);
if (isPresent(elId)) {
var view = _allViewsById.get(elId[0]);
if (isPresent(view)) {
return new DebugElement_(view.appElements[elId[1]]);
}
}
return null;
}
@Injectable()
export class DebugElementViewListener implements AppViewListener {
constructor() { DOM.setGlobalVar(INSPECT_GLOBAL_NAME, inspectNativeElement); }
onViewCreated(view: AppView) {
var viewId = _nextId++;
_allViewsById.set(viewId, view);
_allIdsByView.set(view, viewId);
for (var i = 0; i < view.appElements.length; i++) {
var el = view.appElements[i];
_setElementId(el.nativeElement, [viewId, i]);
}
}
onViewDestroyed(view: AppView) {
var viewId = _allIdsByView.get(view);
_allIdsByView.delete(view);
_allViewsById.delete(viewId);
}
}
/**
* Providers which support debugging Angular applications (e.g. via `ng.probe`).
*
* ## Example
*
* {@example platform/dom/debug/ts/debug_element_view_listener/providers.ts region='providers'}
*/
export const ELEMENT_PROBE_PROVIDERS: any[] = CONST_EXPR([
DebugElementViewListener,
CONST_EXPR(new Provider(AppViewListener, {useExisting: DebugElementViewListener})),
]);
/**
* Use {@link ELEMENT_PROBE_PROVIDERS}.
*
* @deprecated
*/
export const ELEMENT_PROBE_BINDINGS = ELEMENT_PROBE_PROVIDERS;
@@ -0,0 +1,42 @@
import {CONST_EXPR, assertionsEnabled, isPresent} from 'angular2/src/facade/lang';
import {Injectable, provide, Provider} from 'angular2/src/core/di';
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {DebugNode, getDebugNode} from 'angular2/src/core/debug/debug_node';
import {DomRootRenderer} from 'angular2/src/platform/dom/dom_renderer';
import {RootRenderer} from 'angular2/core';
import {DebugDomRootRenderer} from 'angular2/src/core/debug/debug_renderer';
const INSPECT_GLOBAL_NAME = 'ng.probe';
/**
* Returns a {@link DebugElement} for the given native DOM element, or
* null if the given native element does not have an Angular view associated
* with it.
*/
export function inspectNativeElement(element): DebugNode {
return getDebugNode(element);
}
function _createConditionalRootRenderer(rootRenderer) {
if (assertionsEnabled()) {
return _createRootRenderer(rootRenderer);
}
return rootRenderer;
}
function _createRootRenderer(rootRenderer) {
DOM.setGlobalVar(INSPECT_GLOBAL_NAME, inspectNativeElement);
return new DebugDomRootRenderer(rootRenderer);
}
/**
* Providers which support debugging Angular applications (e.g. via `ng.probe`).
*/
export const ELEMENT_PROBE_PROVIDERS: any[] = CONST_EXPR([
new Provider(RootRenderer,
{useFactory: _createConditionalRootRenderer, deps: [DomRootRenderer]})
]);
export const ELEMENT_PROBE_PROVIDERS_PROD_MODE: any[] = CONST_EXPR(
[new Provider(RootRenderer, {useFactory: _createRootRenderer, deps: [DomRootRenderer]})]);
@@ -14,7 +14,12 @@ import {
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
import {DomSharedStylesHost} from './shared_styles_host';
import {Renderer, RootRenderer, RenderComponentType} from 'angular2/core';
import {
Renderer,
RootRenderer,
RenderComponentType,
RenderDebugInfo
} from 'angular2/src/core/render/api';
import {EventManager} from './events/event_manager';
@@ -201,6 +206,8 @@ export class DomRenderer implements Renderer {
}
}
setElementDebugInfo(renderElement: any, info: RenderDebugInfo) {}
setElementClass(renderElement: any, className: string, isAdd: boolean): void {
if (isAdd) {
DOM.addClass(renderElement, className);
@@ -1,11 +1,11 @@
import {
ComponentRef,
DebugElement,
DirectiveResolver,
DynamicComponentLoader,
Injector,
Injectable,
ViewMetadata,
ElementRef,
EmbeddedViewRef,
ViewResolver,
provide
@@ -23,7 +23,7 @@ import {el} from './utils';
import {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens';
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {DebugElement_} from 'angular2/src/core/debug/debug_element';
import {DebugNode, DebugElement, getDebugNode} from 'angular2/src/core/debug/debug_node';
/**
@@ -45,6 +45,11 @@ export abstract class ComponentFixture {
*/
nativeElement: any;
/**
* The ElementRef for the element at the root of the component.
*/
elementRef: ElementRef;
/**
* Trigger a change detection cycle for the component.
*/
@@ -66,7 +71,9 @@ export class ComponentFixture_ extends ComponentFixture {
constructor(componentRef: ComponentRef) {
super();
this._componentParentView = (<ViewRef_>componentRef.hostView).internalView;
this.debugElement = new DebugElement_(this._componentParentView.appElements[0]);
this.elementRef = this._componentParentView.appElements[0].ref;
this.debugElement = <DebugElement>getDebugNode(
this._componentParentView.rootNodesOrAppElements[0].nativeElement);
this.componentInstance = this.debugElement.componentInstance;
this.nativeElement = this.debugElement.nativeElement;
this._componentRef = componentRef;
@@ -1,4 +1,9 @@
import {Renderer, RootRenderer, RenderComponentType} from 'angular2/src/core/render/api';
import {
Renderer,
RootRenderer,
RenderComponentType,
RenderDebugInfo
} from 'angular2/src/core/render/api';
import {
ClientMessageBroker,
ClientMessageBrokerFactory,
@@ -186,6 +191,8 @@ export class WebWorkerRenderer implements Renderer, RenderStoreObject {
]);
}
setElementDebugInfo(renderElement: any, info: RenderDebugInfo) {}
setElementClass(renderElement: any, className: string, isAdd: boolean) {
this._runOnService('setElementClass', [
new FnArg(renderElement, RenderStoreObject),
@@ -19,10 +19,9 @@ import {Component, View, provide} from 'angular2/core';
import {NgFor} from 'angular2/common';
import {NgClass} from 'angular2/src/common/directives/ng_class';
function detectChangesAndCheck(fixture: ComponentFixture, classes: string, elIndex: number = 0) {
function detectChangesAndCheck(fixture: ComponentFixture, classes: string) {
fixture.detectChanges();
expect(fixture.debugElement.componentViewChildren[elIndex].nativeElement.className)
.toEqual(classes);
expect(fixture.debugElement.children[0].nativeElement.className).toEqual(classes);
}
export function main() {
@@ -39,7 +38,7 @@ export function main() {
fixture.detectChanges();
fixture.debugElement.componentInstance.items = [['1']];
detectChangesAndCheck(fixture, '1', 1);
detectChangesAndCheck(fixture, '1');
async.done();
});
@@ -318,7 +318,7 @@ export function main() {
'<test-cmp><li template="#item #i=index">{{i}}: {{item}};</li></test-cmp>')
.createAsync(ComponentUsingTestComponent)
.then((fixture) => {
var testComponent = fixture.debugElement.componentViewChildren[0];
var testComponent = fixture.debugElement.children[0];
testComponent.componentInstance.items = ['a', 'b', 'c'];
fixture.detectChanges();
expect(testComponent.nativeElement).toHaveText('0: a;1: b;2: c;');
@@ -334,7 +334,7 @@ export function main() {
.overrideTemplate(ComponentUsingTestComponent, '<test-cmp></test-cmp>')
.createAsync(ComponentUsingTestComponent)
.then((fixture) => {
var testComponent = fixture.debugElement.componentViewChildren[0];
var testComponent = fixture.debugElement.children[0];
testComponent.componentInstance.items = ['a', 'b', 'c'];
fixture.detectChanges();
expect(testComponent.nativeElement).toHaveText('0: a;1: b;2: c;');
@@ -352,7 +352,7 @@ export function main() {
'<test-cmp><li template="#item #i=index">{{i}}: {{item}};</li></test-cmp>')
.createAsync(ComponentUsingTestComponent)
.then((fixture) => {
var testComponent = fixture.debugElement.componentViewChildren[0];
var testComponent = fixture.debugElement.children[0];
testComponent.componentInstance.items = ['a', 'b', 'c'];
fixture.detectChanges();
expect(testComponent.nativeElement).toHaveText('0: a;1: b;2: c;');
@@ -32,8 +32,7 @@ export function main() {
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
async.done();
@@ -51,15 +50,13 @@ export function main() {
fixture.debugElement.componentInstance.expr = {'max-width': '40px'};
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
expr = fixture.debugElement.componentInstance.expr;
expr['max-width'] = '30%';
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('30%');
async.done();
@@ -75,14 +72,12 @@ export function main() {
.then((fixture) => {
fixture.debugElement.componentInstance.expr = {'max-width': '40px'};
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
StringMapWrapper.delete(fixture.debugElement.componentInstance.expr, 'max-width');
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('');
async.done();
@@ -98,20 +93,16 @@ export function main() {
.then((fixture) => {
fixture.debugElement.componentInstance.expr = {'max-width': '40px'};
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'font-size'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'font-size'))
.toEqual('12px');
StringMapWrapper.delete(fixture.debugElement.componentInstance.expr, 'max-width');
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('');
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'font-size'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'font-size'))
.toEqual('12px');
async.done();
@@ -127,21 +118,17 @@ export function main() {
.then((fixture) => {
fixture.debugElement.componentInstance.expr = {'max-width': '40px'};
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'font-size'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'font-size'))
.toEqual('12px');
StringMapWrapper.delete(fixture.debugElement.componentInstance.expr, 'max-width');
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'font-size'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'font-size'))
.toEqual('12px');
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(DOM.getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('');
async.done();
@@ -673,7 +673,7 @@ export function main() {
fixture.debugElement.componentInstance.name = null;
fixture.detectChanges();
var form = fixture.debugElement.componentViewChildren[0].inject(NgForm);
var form = fixture.debugElement.children[0].inject(NgForm);
expect(form.controls['user']).not.toBeDefined();
tick();
@@ -708,7 +708,7 @@ export function main() {
fixture.debugElement.componentInstance.name = null;
fixture.detectChanges();
expect(fixture.debugElement.componentViewChildren.length).toEqual(0);
expect(fixture.debugElement.children[0].providerTokens.length).toEqual(0);
async.done();
});
}));
@@ -728,7 +728,7 @@ export function main() {
fixture.debugElement.componentInstance.name = 'show';
fixture.detectChanges();
tick();
var form = fixture.debugElement.componentViewChildren[0].inject(NgForm);
var form = fixture.debugElement.children[0].inject(NgForm);
expect(form.controls['login']).toBeDefined();
@@ -756,7 +756,7 @@ export function main() {
fixture.debugElement.componentInstance.name = 'show';
fixture.detectChanges();
tick();
var form = fixture.debugElement.componentViewChildren[0].inject(NgForm);
var form = fixture.debugElement.children[0].inject(NgForm);
expect(form.controls['user']).toBeDefined();
@@ -1,294 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
xdescribe,
describe,
dispatchEvent,
expect,
iit,
inject,
beforeEachProviders,
it,
xit,
TestComponentBuilder
} from 'angular2/testing_internal';
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {PromiseWrapper, EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
import {Injectable} from 'angular2/core';
import {NgFor, NgIf} from 'angular2/common';
import {Scope} from 'angular2/core';
import {By} from 'angular2/platform/common_dom';
import {
Directive,
Component,
View,
} from 'angular2/src/core/metadata';
@Injectable()
class Logger {
log: string[];
constructor() { this.log = []; }
add(thing: string) { this.log.push(thing); }
}
@Directive({selector: '[message]', inputs: ['message']})
@Injectable()
class MessageDir {
logger: Logger;
constructor(logger: Logger) { this.logger = logger; }
set message(newMessage) { this.logger.add(newMessage); }
}
@Component({selector: 'child-comp'})
@View({
template: `<div class="child" message="child">
<span class="childnested" message="nestedchild">Child</span>
</div>
<span class="child" [innerHtml]="childBinding"></span>`,
directives: [MessageDir],
})
@Injectable()
class ChildComp {
childBinding: string;
constructor() { this.childBinding = 'Original'; }
}
@Component({selector: 'cond-content-comp', viewProviders: [Logger]})
@View({
template: `<div class="child" message="child" *ngIf="false"><ng-content></ng-content></div>`,
directives: [NgIf, MessageDir],
})
@Injectable()
class ConditionalContentComp {
}
@Component({selector: 'parent-comp', viewProviders: [Logger]})
@View({
template: `<div class="parent" message="parent">
<span class="parentnested" message="nestedparent">Parent</span>
</div>
<span class="parent" [innerHtml]="parentBinding"></span>
<child-comp class="child-comp-class"></child-comp>
<cond-content-comp class="cond-content-comp-class"></cond-content-comp>`,
directives: [ChildComp, MessageDir, ConditionalContentComp],
})
@Injectable()
class ParentComp {
parentBinding: string;
constructor() { this.parentBinding = 'OriginalParent'; }
}
@Directive({selector: 'custom-emitter', outputs: ['myevent']})
@Injectable()
class CustomEmitter {
myevent: EventEmitter<any>;
constructor() { this.myevent = new EventEmitter(); }
}
@Component({selector: 'events-comp'})
@View({
template: `<button (click)="handleClick()"></button>
<custom-emitter (myevent)="handleCustom()"></custom-emitter>`,
directives: [CustomEmitter],
})
@Injectable()
class EventsComp {
clicked: boolean;
customed: boolean;
constructor() {
this.clicked = false;
this.customed = false;
}
handleClick() { this.clicked = true; }
handleCustom() { this.customed = true; }
}
@Component({selector: 'using-for', viewProviders: [Logger]})
@View({
template: `<span *ngFor="#thing of stuff" [innerHtml]="thing"></span>
<ul message="list">
<li *ngFor="#item of stuff" [innerHtml]="item"></li>
</ul>`,
directives: [NgFor, MessageDir],
})
@Injectable()
class UsingFor {
stuff: string[];
constructor() { this.stuff = ['one', 'two', 'three']; }
}
export function main() {
describe('debug element', function() {
it('should list component child elements',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.createAsync(ParentComp)
.then((componentFixture) => {
componentFixture.detectChanges();
var childEls = componentFixture.debugElement.children;
// The root is a lone component, and has no children in the light dom.
expect(childEls.length).toEqual(0);
var rootCompChildren = componentFixture.debugElement.componentViewChildren;
// The root component has 4 elements in its shadow view.
expect(rootCompChildren.length).toEqual(4);
expect(DOM.hasClass(rootCompChildren[0].nativeElement, 'parent')).toBe(true);
expect(DOM.hasClass(rootCompChildren[1].nativeElement, 'parent')).toBe(true);
expect(DOM.hasClass(rootCompChildren[2].nativeElement, 'child-comp-class'))
.toBe(true);
expect(DOM.hasClass(rootCompChildren[3].nativeElement, 'cond-content-comp-class'))
.toBe(true);
var nested = rootCompChildren[0].children;
expect(nested.length).toEqual(1);
expect(DOM.hasClass(nested[0].nativeElement, 'parentnested')).toBe(true);
var childComponent = rootCompChildren[2];
expect(childComponent.children.length).toEqual(0);
var childCompChildren = childComponent.componentViewChildren;
expect(childCompChildren.length).toEqual(2);
expect(DOM.hasClass(childCompChildren[0].nativeElement, 'child')).toBe(true);
expect(DOM.hasClass(childCompChildren[1].nativeElement, 'child')).toBe(true);
var childNested = childCompChildren[0].children;
expect(childNested.length).toEqual(1);
expect(DOM.hasClass(childNested[0].nativeElement, 'childnested')).toBe(true);
var conditionalContentComp = rootCompChildren[3];
expect(conditionalContentComp.children.length).toEqual(0);
expect(conditionalContentComp.componentViewChildren.length).toEqual(1);
var ngIfWithProjectedNgContent = conditionalContentComp.componentViewChildren[0];
expect(ngIfWithProjectedNgContent.children.length).toBe(0);
expect(ngIfWithProjectedNgContent.componentViewChildren.length).toBe(0);
async.done();
});
}));
it('should list child elements within viewports',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.createAsync(UsingFor).then((componentFixture) => {
componentFixture.detectChanges();
var childEls = componentFixture.debugElement.componentViewChildren;
// TODO should this count include the <template> element?
expect(childEls.length).toEqual(5);
var list = childEls[4];
expect(list.children.length).toEqual(4);
async.done();
});
}));
it('should query child elements',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.createAsync(ParentComp)
.then((componentFixture) => {
componentFixture.detectChanges();
var childTestEls = componentFixture.debugElement.queryAll(By.directive(MessageDir));
expect(childTestEls.length).toBe(4);
expect(DOM.hasClass(childTestEls[0].nativeElement, 'parent')).toBe(true);
expect(DOM.hasClass(childTestEls[1].nativeElement, 'parentnested')).toBe(true);
expect(DOM.hasClass(childTestEls[2].nativeElement, 'child')).toBe(true);
expect(DOM.hasClass(childTestEls[3].nativeElement, 'childnested')).toBe(true);
async.done();
});
}));
it('should query child elements in the light DOM',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.createAsync(ParentComp)
.then((componentFixture) => {
componentFixture.detectChanges();
var parentEl = componentFixture.debugElement.componentViewChildren[0];
var childTestEls = parentEl.queryAll(By.directive(MessageDir), Scope.light);
expect(childTestEls.length).toBe(1);
expect(DOM.hasClass(childTestEls[0].nativeElement, 'parentnested')).toBe(true);
async.done();
});
}));
it('should query child elements in the current component view DOM',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.createAsync(ParentComp)
.then((componentFixture) => {
componentFixture.detectChanges();
var childTestEls =
componentFixture.debugElement.queryAll(By.directive(MessageDir), Scope.view);
expect(childTestEls.length).toBe(2);
expect(DOM.hasClass(childTestEls[0].nativeElement, 'parent')).toBe(true);
expect(DOM.hasClass(childTestEls[1].nativeElement, 'parentnested')).toBe(true);
async.done();
});
}));
it('should allow injecting from the element injector',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.createAsync(ParentComp)
.then((componentFixture) => {
componentFixture.detectChanges();
expect(componentFixture.debugElement.componentViewChildren[0].inject(Logger).log)
.toEqual(['parent', 'nestedparent', 'child', 'nestedchild']);
async.done();
});
}));
it('should trigger event handlers',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.createAsync(EventsComp)
.then((componentFixture) => {
componentFixture.detectChanges();
expect(componentFixture.debugElement.componentInstance.clicked).toBe(false);
expect(componentFixture.debugElement.componentInstance.customed).toBe(false);
componentFixture.debugElement.componentViewChildren[0].triggerEventHandler(
'click', <Event>{});
expect(componentFixture.debugElement.componentInstance.clicked).toBe(true);
componentFixture.debugElement.componentViewChildren[1].triggerEventHandler(
'myevent', <Event>{});
expect(componentFixture.debugElement.componentInstance.customed).toBe(true);
async.done();
});
}));
});
}
File diff suppressed because it is too large Load Diff
@@ -32,8 +32,7 @@ export function main() {
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.createAsync(App).then((tc) => {
tc.detectChanges();
expect(asNativeElements(tc.debugElement.componentViewChildren))
.toHaveText('frame(lock)');
expect(asNativeElements(tc.debugElement.children)).toHaveText('frame(lock)');
async.done();
});
}));
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More