ovangle
ovangle

Reputation: 2031

Access DebugElement of nested component when using native view encapsulation

I'm testing a component like the following

@Component({
  selector: 'my-component',
  template: `
    <my-nested-component [state]="state"></my-nested-component>
  `,
  encapsulation: ViewEncapsulation.Native
})
export class MyComponent {}

When unit testing my component, I want to obtain a reference to the nested component MyOtherComponent. If my-component used no encapsulation, or if it used emulated encapsulation, I could use:

let fixture = TestBed.createComponent(MyComponent);
let nestedComponent = fixture.debugElement.query(By.directive(MyNestedComponent))

to obtain a reference to the component.

But in this case, query just queries the light DOM children of the component (mimicking the behaviour of querySelector), so nestedComponent is 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?

Upvotes: 8

Views: 7541

Answers (3)

anlijudavid
anlijudavid

Reputation: 539

With Angular v6.1.8 and component with Shadow root. Example:

  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');

Upvotes: -1

Matheus CAS
Matheus CAS

Reputation: 161

Let me update the correct answer based on newer versions of used tools:

Here's how it worked for me, using "@angular/core": "^5.2.6", "typescript": "~2.4.2" and "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")

Upvotes: 5

yurzui
yurzui

Reputation: 214085

Let's say we have the following components:

@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;
}

So i would write test like this:

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');

You can also try this test as a live example in plunker

Upvotes: 9

Related Questions