0

Here the method I want to test. It´s the ngOnInit lifecicle

ngOnInit(): void {
    this.editable.subscribe((data) => {
        this.enableEdition = data.enabled;
    });
}

Here my test:

it('ngOnInit', () => {
    const editableMock = of({ enabled: false });
    component.editable = editableMock;
    component.ngOnInit();
    expect(component.enableEdition).toBe(false);
});

I am getting this error: TypeError: Cannot read property 'subscribe' of undefined

enter image description here

Maybe the problem is coming from the way the editable is sending to .ts from another component and the setTimeout where the first emision of the observable is located:

The subject which is the source of the observable is localted on table component which is a sibling of table-action component and the observable is shared from table to table-action this way:

Parent template:

    <table-actions
      [editable]="_editableState">
    </table-actions>

    <table>
    </table>
  

parent get the subject from table component using a viewChild and then share it to table-action using an input

Parent.ts

  @ViewChild('table', { static: true })
  murTable!: MurTableComponent;

  public _editableState!: Observable<any>;

  this._editableState = this.murTable.stateEditing.asObservable();

First emision of the subject is located within a setTimeout(). Maybe this produce an asynchrony error

table.ts

 ngOnInit(): void {

  setTimeout(() => {
    this.onFirstDataRendered(null);
    this.stateEditing.next({ enabled: !!this.editType });
  }, 1500);

}

DonJuwe
  • 4,477
  • 3
  • 34
  • 59
Jmainol
  • 357
  • 4
  • 18
  • Your test works for me. You are sure this fails for you? – DonJuwe Feb 20 '23 at 12:01
  • If I move `component.ngOnInit();` up before `const editableMock = of({ enabled: false });` I am getting the same error. – DonJuwe Feb 20 '23 at 12:03
  • Yes I am getting error: what jest, angular and node version you have? – Jmainol Feb 20 '23 at 12:11
  • I have "jest": "^27.0.4", node v16.13.2 and "@angular/core": "^12.0.3", – Jmainol Feb 20 '23 at 12:13
  • I tried with the current Angular CLI versions and Node v16.13.2 – DonJuwe Feb 20 '23 at 12:13
  • How do you initiate `this.editable` in your component? – DonJuwe Feb 20 '23 at 12:15
  • Could this be triggered by a different `ngOnInit` call originating, say, in a `beforeEach` section? – 500 - Internal Server Error Feb 20 '23 at 12:21
  • this.editable is initiate like this @Input() editable!: Observable because it´s comming from sibling component table as I explained – Jmainol Feb 20 '23 at 12:26
  • ngOnInit is only called inside this test. There is nothing related with ngOnInit inside beforeEach – Jmainol Feb 20 '23 at 12:28
  • Does this answer your question? [Angular2 unit test with @Input()](https://stackoverflow.com/questions/36654834/angular2-unit-test-with-input) – DonJuwe Feb 20 '23 at 12:29
  • "ngOnInit is only called inside this test" - I believe `fixture.detectChanges()` also triggers hooks like ngOnInit and ngOnChanges. – mbojko Feb 20 '23 at 15:01
  • Calling fixture.detectChanges() tells Angular to run change-detection. Finally! Every time it is called, it updates data bindings like ng-if, and re-renders the component based on the updated data. Calling this function will cause ngOnInit to run only the first time it is called. https://medium.com/@menloinnovations/testing-asynchronous-operations-in-angular-components-45d1ebad3864 – Jmainol Feb 20 '23 at 15:26

1 Answers1

0

I found this solution:

If I place the observable mock and its assignment before the fixture.detectChanges() located on my 2º beforeEach(), it works.

describe('MurTableActionsComponent', () => {
 let component: MurTableActionsComponent;
 let fixture: ComponentFixture<MurTableActionsComponent>;


beforeEach(async () => {
  await TestBed.configureTestingModule({
    imports: [AgGridModule],
  providers:[ MurPrintService ],
  declarations: [TableActionsComponent],
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents()
});

 beforeEach(() => {
  fixture = TestBed.createComponent(TableActionsComponent);
  component = fixture.componentInstance;


  const editableMock = of({ enabled: false });
  component.editable = editableMock;

  fixture.detectChanges();
  })

Now my test has this form:

it('ngOnInit', () => {
component.ngOnInit();

expect(component.enableEdition).toBe(false);

});

Jmainol
  • 357
  • 4
  • 18