使用原生视图封装时访问嵌套组件的DebugElement
Posted
技术标签:
【中文标题】使用原生视图封装时访问嵌套组件的DebugElement【英文标题】:Access DebugElement of nested component when using native view encapsulation 【发布时间】:2017-04-17 04:08:39 【问题描述】:我正在测试如下组件
@Component(
selector: 'my-component',
template: `
<my-nested-component [state]="state"></my-nested-component>
`,
encapsulation: ViewEncapsulation.Native
)
export class MyComponent
在对我的组件进行单元测试时,我想获得对嵌套组件MyOtherComponent
的引用。如果my-component
没有使用封装,或者如果它使用仿真封装,我可以使用:
let fixture = TestBed.createComponent(MyComponent);
let nestedComponent = fixture.debugElement.query(By.directive(MyNestedComponent))
获取对组件的引用。
但在这种情况下,query
只是查询组件的轻量级 DOM 子项(模仿 querySelector
的行为),因此在使用原生视图封装时,nestedComponent
是 null
。
您应该如何获得对嵌套组件的DebugElement
(以及组件实例)的引用?
【问题讨论】:
【参考方案1】:假设我们有以下组件:
@Component(
selector: 'my-nested-component',
template: `
<h1>Nested component - state </h1>
`,
)
export class NesterComponent
@Input() state: number;
@Component(
selector: 'my-app',
template: `
<my-nested-component [state]="state"></my-nested-component>
`,
encapsulation: ViewEncapsulation.Native
)
export class TestComponent
state = 1;
所以我会这样写测试:
let fixture = TestBed.createComponent(TestComponent);
let component = fixture.componentInstance;
const shadowRoot: DocumentFragment = fixture.debugElement.nativeElement.shadowRoot;
const nestedComponentNativeElement = shadowRoot.querySelector('my-nested-component');
const nestedComponentDebugElement = <DebugElement>getDebugNode(nestedComponentNativeElement);
var nestedComponentInstance: NesterComponent = nestedComponentDebugElement.componentInstance;
// here can be your code
component.state = 2;
fixture.detectChanges();
de = nestedComponentDebugElement.query(By.css('h1'));
expect(de.nativeElement.textContent).toBe('Nested component - 2');
您也可以在 plunker 中以 live example 的身份尝试此测试
【讨论】:
getDebugNode
来自哪里?这正是我想要的。
来自@angular/core
啊哈!非常感谢。回答被接受并获得赏金(或者更确切地说,在解锁后 5 小时内获得赏金)。
这让我找到了正确的答案,非常感谢...确保在 TestBed.configureTestModule() 声明中声明 MyNestedComponent
shadowRoot
真的有必要吗?在 Angular 6 上,我做了getDebugNode(fixture.nativeElement.querySelector('some-component')).componentInstance;
,它按预期工作。【参考方案2】:
让我根据使用的工具的较新版本更新正确答案:
这是我的工作原理,使用 "@angular/core": "^5.2.6"
、"typescript": "~2.4.2"
和 "jasmine-core": "2.5.2"
const shadowRoot: DocumentFragment = fixture.debugElement.nativeElement
const nativeElement = shadowRoot.querySelector("html-element")
const debugElement = getDebugNode(nativeElement) as DebugElement
const instance: NestedComponent = debugElement.componentInstance
expect(debugElement.query(By.css("h1")).nativeElement.textContent).toBe("ExpectedText")
【讨论】:
不使用如上所示的 .shadowRoot 在 Angular 7+ 上对我有用【参考方案3】:使用 Angular v6.1.8 和带有 Shadow root 的组件。 示例:
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance as AppComponent;
const shadowRoot: DocumentFragment = fixture.debugElement.nativeElement.shadowRoot;
app.active = true;
app.title = 'Title';
fixture.detectChanges();
expect(shadowRoot.querySelector('.bz-modal__header_title').textContent).toEqual('Title');
【讨论】:
对我来说 shadowRoot 为空 我遇到了同样的问题,需要删除上面的.shadowRoot
。请参阅@Matheus CAS 答案或我对@yurzui 答案的评论。以上是关于使用原生视图封装时访问嵌套组件的DebugElement的主要内容,如果未能解决你的问题,请参考以下文章
better-scroll中嵌套原生滚动组件,原生滚动组件失效问题
如何使用 jest+enzyme 在 react-native 中选择一个元素(文本、视图)(主要是当文本/视图嵌套在组件的深处时)?