首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何用Jest和NgMocks模拟包装组件

如何用Jest和NgMocks模拟包装组件
EN

Stack Overflow用户
提问于 2021-03-22 10:38:45
回答 1查看 1.3K关注 0票数 1

在我们的项目中,我们可以在整个应用程序中将用户角色分配给多个元素,在缺少所需角色时禁用这些元素。但是,由于对某些按钮应用了其他条件,即使角色检查,也可能禁用组件,因此我们的组件也会接管它,并在必要时禁用它的子组件。这个设计背后的原因是,如果元素被禁用,我们可以很容易地显示工具提示。

代码语言:javascript
代码运行次数:0
运行
复制
// app-role-element
<div matTooltip="{{ tooltipMessage | translate }}" [matTooltipDisabled]="!isDisabled">
  <ng-content> </ng-content>
</div>
// .ts
export class AppRoleElement implements AfterConentInit {
  @Input('roles') roles: string[];
  @ContentChild('roleElement') roleElement: MatButton;

  constructor(...){}    

  ngAfterContentInit(): void {
    ...
    this.setDisabled();
  }

  setDisabled(): void {
    if (this.roleElement) {
      if (this.isDisabled) {
        this.roleElement.disabled = true; // disable if no role
      } else {
        this.roleElement.disabled = this.disableCondition; // disable if other condition
      }
    }
  }
}

// usage
<app-role-component
  [role]="['required-role']"
  [disableCondition]= "isRunning || isUnstable"
  [id]="startButtonRoleElem"
>
  <button mat-raised-button id="startBtnId" (click)="start()">Start</button>
</app-role-component>

这种方法工作得很好,但是很难进行单元测试。在上面的代码中,如果我要编写一个单元测试,点击开始按钮,按ID选择它,绕过角色元素并调用远程服务,即使它不应该。按ID选择角色元素并不会传播对按钮的单击。

代码语言:javascript
代码运行次数:0
运行
复制
test('to prevent click on a start btn when form is invalid', () => {
  spectator.component.runEnabled$ = of(false);
  spectator.detectComponentChanges();

  const checkExportFolderSpy = jest.spyOn(spectator.component, 'checkExportFolder');
  spectator.inject(PreferencesService).validateCurrentExportPath.andReturn(of(VALIDATION_RESULT_OK));
  spectator.detectChanges();

  spectator.click('#startBtnId');
  spectator.detectChanges();

  expect(checkExportFolderSpy).not.toHaveBeenCalled();
  expect(dispatchSpy).not.toHaveBeenCalled();
});

我们和Spectator以及NgMocks一起使用JEST,我希望利用这个功能并模拟这个组件,但我不知道如何使用。我不太确定我应该在多大程度上去模仿它,我是否应该把点击事件传递给孩子,禁用孩子?有什么想法或建议如何处理这件事?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-03-23 19:37:06

你的案子很复杂。

这很复杂,因为:

  • 该按钮通过MatButton禁用,因此不能对其进行模拟。
  • 因为我们想测试AppRoleElement,所以也不能对它进行模拟。
  • triggerEventHandler不尊重disabled属性,总是触发单击

因此,在测试中,我们需要:

  • 保持AppRoleElementMatButton的原样
  • 为残疾人和启用的案例创建特殊的环境
  • 通过nativeElement单击按钮

下面的代码只使用五模,角色检测已经简化。

代码语言:javascript
代码运行次数:0
运行
复制
import {AfterContentInit, Component, ContentChild, Input, NgModule,} from '@angular/core';
import {MatButton, MatButtonModule} from '@angular/material/button';
import {MockBuilder, MockRender, ngMocks} from 'ng-mocks';

@Component({
  selector: 'app-role-component',
  template: `
    <div>
      <ng-content></ng-content>
    </div>
  `,
})
class AppRoleElement implements AfterContentInit {
  @Input() public disable: boolean | null = null;
  @ContentChild(MatButton) public roleElement?: MatButton;

  public ngAfterContentInit(): void {
    this.setDisabled();
  }

  public setDisabled(): void {
    if (this.roleElement) {
      this.roleElement.disabled = this.disable;
    }
  }
}

@NgModule({
  declarations: [AppRoleElement],
  imports: [MatButtonModule],
})
class AppModule {}

fdescribe('ng-mocks-click', () => {
  // Keeping AppRoleElement and MatButton
  beforeEach(() => MockBuilder(AppRoleElement, AppModule).keep(MatButton));

  it('is not able to click the disabled button', () => {
    // specific params for the render
    const params = {
      disabled: true,
      start: jasmine.createSpy('start'),
    };

    // rendering custom template
    MockRender(
      `
      <app-role-component
        [disable]="disabled"
      >
        <button mat-raised-button id="startBtnId" (click)="start()">Start</button>
      </app-role-component>
    `,
      params,
    );

    // click on a disable element isn't propagandized
    ngMocks.find('button').nativeElement.click();

    // asserting
    expect(params.start).not.toHaveBeenCalled();
  });

  // checking the enabled case
  it('is able to click the button', () => {
    const params = {
      disabled: false,
      start: jasmine.createSpy('start'),
    };

    MockRender(
      `
      <app-role-component
        [disable]="disabled"
      >
        <button mat-raised-button id="startBtnId" (click)="start()">Start</button>
      </app-role-component>
    `,
      params,
    );

    ngMocks.find('button').nativeElement.click();
    expect(params.start).toHaveBeenCalled();
  });
});
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66744417

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档