【问题标题】:Mock @Input value for Angular component with Jest使用 Jest 模拟 Angular 组件的 @Input 值
【发布时间】:2021-08-18 20:02:44
【问题描述】:

在我们的 Angular 项目中,我们正在将 jasmine 测试迁移到 jest。 当我们尝试在测试中模拟组件的 @Input 值时,我们遇到了一些问题。 例如,在 jamsine 中,我们习惯于这样写:

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

使用 jasmine,这些测试总是通过,并且 Message 的实例总是在测试中这样设置。但是开玩笑的是,每次调用 fixture.detectChanges() 时,都会重置组件,并且所有 @Input 值都设置为未定义,我不知道如何处理它。 然后我尝试另一种方式来做这件事,灵感来自(Angular Unit-Test) How to mock input property in Jasmin?,我现在使用 HostComponent 来调用我的模板,比如

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

如果我只有 1 个测试,它可以正常工作,但我不知道如何在每个测试中动态更改“消息”的值。我觉得我错过了什么或做错了什么。我应该为我的每个测试创建一个 FakeHostComponent 吗?
所以我需要帮助来使这些测试更漂亮和更有活力。另外我想了解为什么 fixture.detectChanges() 重置我的组件输入值
作为一种解决方法,我将 message 的值放在全局变量“testMessage”中并创建在每个测试中调用的这个方法,但我确信有一种方法可以更正确地做到这一点

const createComponent = (message: Message) => {
    testMessage = message;
    fixture = TestBed.createComponent(FakeHostComponent);
    component = fixture.debugElement.children[0].componentInstance;
  };

【问题讨论】:

    标签: angular jestjs


    【解决方案1】:

    奇怪的是@Input 的值被fixture.detectChanges() 重置。

    使用FakeHostComponent,要获取消息值的句柄,您可以执行以下操作:

    import { By } from '@angular/platform-browser';
    ....
    let component: FakeHostComponent;
    let messageComponent: MessageComponent;
    
    beforeEach(() => {
        TestBed.configureTestingModule({
          imports: [// some imports],
          declarations: [MessageComponent, FakeHostComponent]
        }).compileComponents();
      });
    
    beforeEach(() => {
        fixture = TestBed.createComponent(FakeHostComponent);
        component = fixture.componentInstance;
        messageComponent = fixture.debugElement.query(By.directive(MessageComponent)).componentInstance;
        // now you have a handle on FakeHostComponent and MessageComponent
        component.message = 'Hello'; // will change from FakeHostComponent
        fixture.detectChanges();
        console.log(messageComponent.message); // should output the message
      });
    
    

    【讨论】:

    • 您好,感谢您的回答。我试过你的主意!然而这会产生相同的结果:如果我在fixture.detectChanges() 之前console.log(messageComponent.message),它会打印“Hello”,但如果我在之后打印它,它会打印 undefined。如果我在创建组件模板时设置了一个输入值:&lt;app-message [message]="message"&gt;&lt;/app-message&gt;,那么此消息将在fixture.detectChanges() 之后打印。似乎它完全将组件重置为初始输入值....
    猜你喜欢
    • 1970-01-01
    • 2021-06-19
    • 2021-12-21
    • 2021-01-03
    • 2021-12-10
    • 1970-01-01
    • 1970-01-01
    • 2017-11-08
    • 1970-01-01
    相关资源
    最近更新 更多