【问题标题】:Access DebugElement of nested component when using native view encapsulation使用原生视图封装时访问嵌套组件的DebugElement
【发布时间】: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 的行为),因此在使用原生视图封装时,nestedComponentnull

您应该如何获得对嵌套组件的DebugElement(以及组件实例)的引用?

【问题讨论】:

    标签: unit-testing angular typescript shadow-dom


    【解决方案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 答案的评论。
    猜你喜欢
    • 2016-11-10
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2018-01-06
    • 1970-01-01
    • 2011-04-16
    • 2021-05-19
    • 2023-04-02
    相关资源
    最近更新 更多