Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock @Input value for Angular component with Jest

Tags:

angular

jestjs

In our Angular porject, We are migrating jasmine tests to jest. We are getting some issues when we try to mock @Input values of components in the tests. For example, in jamsine we use to write something like this :

@Component({
  selector: 'app-message[message]',
  templateUrl: './message.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MessageComponent implements OnInit {
  @Input() message!: Message;
}


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

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [// some imports],
      declarations: [MessageComponent]
    }).compileComponents();
  });

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

  it('test1 with input message') {
     component.message = new Message('xxx');
     fixture.detectChanges();
     // some expectations
  }

  it('test2 with another input message') {
     component.message = new Message('yyy');
     fixture.detectChanges();
     // some expectations
  }
});

With jasmine, these tests were always passing and the instance of Message was always set like this in the tests. But with jest, everytime fixture.detectChanges() is called, the component is reset and all the @Input values are set to undefined and I do not know how to deal with it. I then try another way for doing it insprired by (Angular Unit-Test) How to mock input property in Jasmin? and I now use a HostComponent to call my template like

let testMessage: Message = generateMessage();
@Component({
  selector: 'app-testhost',
  template: `<app-message [message]="message"></app-message>`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class FakeHostComponent {
  message = testMessage;
}

It works fine if I have only 1 test but I do not know how I can change the value of "message" dynamically in each tests. I feel like I'm missing something or doing something wrong. Should I create a FakeHostComponent for each of my tests ?
So I need help to make these tests a bit prettier and more dynamics. Also I would like to understand why fixture.detectChanges() reset my component input values
As a workaround, I put the value of message in a global variable "testMessage" and create this method that I call in every test, but I am sure there is a way to do it more properly

const createComponent = (message: Message) => {
    testMessage = message;
    fixture = TestBed.createComponent(FakeHostComponent);
    component = fixture.debugElement.children[0].componentInstance;
  };
like image 538
TCH Avatar asked Sep 07 '25 22:09

TCH


1 Answers

I too was struggling with Input, as it would always be undefined. I tried mocking it in the beforeEach section, but whatever I do, the input value stays undefined and I'm unable to get into the component.

Removing fixture.detectChanges() finally removed console error and tests pass. Not really sure why, but this topic helped!

like image 191
fadingbeat Avatar answered Sep 10 '25 00:09

fadingbeat