2

I'm trying to test the child component, but it requires a parent component for its main functionalities.

How can I test the child component with a "mock" parent?

(Using Jest, Angular 14, TypeScript)

parent.component.ts

@Component({...})
export class ParentComponent {
    onChildClicked(child: ChildComponent) {
        // ...
    }
}

child.component.ts

@Component({...})
export class ChildComponent {
  constructor(private parent: ParentComponent) {}

  onClick() {
    this.parent.onChildClicked(this);
  }
}

child.component.spec.ts

describe("ChildComponent", () => {
  it("should be rendered", async () => {
    const { container } = await render(ChildComponent, {
      declarations: [ParentComponent],
    });
    expect(container).toBeTruthy();
  });
});

page.component.html

<app-parent>
  <app-child></app-child>
</app-parent>

Test output:

ChildComponent › should be rendered

    NullInjectorError: R3InjectorError(DynamicTestModule)[ParentComponent -> ParentComponent]:
      NullInjectorError: No provider for ParentComponent!
Doug
  • 129
  • 1
  • 12
  • Yikes.. that is some tight coupling there. I’d just mock the function on the parent and call it a day. – MikeOne Aug 26 '22 at 16:20
  • I know what you mean but in this case is tight coupling what I need in this specific case. And I even would implement to throw error is the child component is not the type the parent is expecting. – Doug Aug 26 '22 at 17:39

2 Answers2

1

I found a solution. Make the parent component avaible as a provider for the child component.

child.component.spec.ts


describe("ChildComponent", () => {
  it("should be rendered", async () => {
    const { container } = await render(ChildComponent, {
      declarations: [ParentComponent],
      providers: [ParentComponent]
    });
    expect(container).toBeTruthy();
  });
});

Doug
  • 129
  • 1
  • 12
0

Why you are calling parent function like this in child component, and you should not inject Parent component as dependency in child component.

If you want to call parent function based on some event click inside child component then use @Output() event emitter.

Like below

Parent Component

 onChildClicked(value) {
            console.log(value);
 }





<app-parent>
  <app-child (childClicked)='onChildClicked($event)'></app-child>
</app-parent>

Child component

@Output() childClicked = new EventEmitter()

onClick() {  
        this.childClicked.emit(value_you_want_to_pass);
    }
Passionate Coder
  • 7,154
  • 2
  • 19
  • 44
  • 1
    Even though I fully agree with what you’re saying (very bad practice this) - this is not an answer to the question. – MikeOne Aug 26 '22 at 16:32
  • 1
    Exactly Mike. I'm just needing to register specific components in a design system project. I want the child component to be used only within this specific parent component. It would be complex to explain the reasons in a few words. – Doug Aug 26 '22 at 17:36