Доступ к DebugElement вложенного компонента при использовании инкапсуляции собственного представления

Я тестирую компонент, подобный следующему

@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))

to obtain a reference to the component.

Но в этом случае query just queries the light DOM children of the component (mimicking the behaviour of querySelector), так nestedComponent является null when using native view encapsulation.

How are you supposed to get a reference to the DebugElement (and therefore the component instance) of the nested component?

3 ответа

Решение

Допустим, у нас есть следующие компоненты:

@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.

Позвольте мне обновить правильный ответ, основываясь на более новых версиях используемых инструментов:

Вот как это работает для меня, используя "@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")

С Angular v6.1.8 и компонентом с корнем Shadow. Пример:

  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');
Другие вопросы по тегам