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:
@@ -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;
|
||||
|
||||
@@ -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,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,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,
|
||||
|
||||
@@ -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); }
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user