Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 5 testing: how to get a reference to the child component

I'm trying to test the interaction between a host component and a child component in an Angular application. I don't know how to get a reference to the child component created when the parent gets created. Here is the setup:

child.component.spec.ts

@Component({template: `<child [data]="model"></child>`})
class HostComponent {
  public model:any;
}

describe('ChildComponent', () => {
  let hostFixture: ComponentFixture<HostComponent>;
  let childFixture: ComponentFixture<ChildComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ChildComponent, HostComponent]
    });
  }));

  beforeEach(() => {
    // this creates the child component as well, but how to get to it?
    hostFixture = TestBed.createComponent(HostComponent);

    // this creates a NEW instance of child component, not the one from the Host template
    // so it's not the instance I actually want to test
    childFixture = TestBed.createComponent(ChildComponent);
  });
});

Changing the model value in hostFixture.componentInstance doesn't actually change the data input value of childFixture.componentInstance; that's how I realized that there are two instances of child component.

My question is simple, how can I get childFixture to refer to the component fixture found in the HostComponent template, instead of a different instance as I currently have it?

The docs haven't been helpful.

like image 619
BeetleJuice Avatar asked Sep 26 '22 10:09

BeetleJuice


People also ask

How do you find the value of a child component in the parent component?

We can get child component values in the parent component by creating a reference to the child component using the @ref directive in the Parent component. Using the reference instance, you can access the child component values in the parent.


2 Answers

As explained in the guide, host component instance is created with TestBed.createComponent, and child component instance can be selected from debugElement with By helper:

childDebugElement = hostFixture.debugElement.query(By.directive(ChildComponent));

Or:

childDebugElement = hostFixture.debugElement.query(By.css('child'));
like image 102
Estus Flask Avatar answered Oct 17 '22 20:10

Estus Flask


The answer above is good, answers the body's question, but the header/title of the question asks something else. I wanted to answer the question posed by the header as well. Estus's answer is correct for the specific use case, but Google brings you here based on the question in the title.

To get the child Component not the native element:

Test Component (called HostComponent in the question): <child [data]="model" #child></child>

Then in the class definition:

@Component({template: `<child #child [data]="model"></child>`})
class HostComponent {
    public model:any;
    @ViewChild('child') child;
}

Finally, when testing, on a spec:

it('should do something', () => {
    component.child.value
    component.child.method
    // etc.
}

You could use this in a test case, and I do, to find the child component that you're really trying to test.


The rest is to satisfy a debatable aspect brought up in the comments.

There's also a strong case for making things private when possible. I'm not sure how I feel about it if you want to unit test it. If you want to test a private member you have to let the typescript compiler that you want object with private members publicly accessible by casting it as and wrapping it in parentheses to make it clear what you're casting.

In the component:

...
    @ViewChild('child') private child;
...

In the test:

...
    (<any>component).child.value
    (<any>component).child.method
...
like image 13
Steven Lacks Avatar answered Oct 17 '22 21:10

Steven Lacks