Angular:如何测试单击组件 nativeElement 会打开一个对话框 [英] Angular: How to test that clicking on a component nativeElement opens a dialog

查看:31
本文介绍了Angular:如何测试单击组件 nativeElement 会打开一个对话框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为呈现 mat-accordionmat-expansion-panel 的组件编写测试.mat-expansion-panel 有一个 div(带有 .comment 类),它具有使用 [innerHtml] 的动态 html.有时,innerHtml 可能包含 <img/> 标签.当用户点击这样的 div 时,应该会弹出一个包含该图像的对话框(但尺寸更大).

I am writing a test for a component that renders mat-accordion and mat-expansion-panel. The mat-expansion-panel has a div (with class .comment) that has dynamic html using [innerHtml]. Sometimes the innerHtml could contain an <img /> tag. When the user clicks on such a div, then a dialog should pop up containing that image (but in larger size).

在我的测试中,我想断言点击 img 应该打开这个对话框,但是,问题是当我检查 fixture.nativeElement 时,我确实看不到任何对话框元素.

In my test, I would like to assert that clicking on img should open this dialog, however, the problem is that when I inspect fixture.nativeElement, I indeed don't see any dialog element.

组件如下:

@Component({
    selector: 'app-node-history',
    templateUrl: './node-history.component.html',
    styleUrls: ['./node-history.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class NodeHistoryComponent {
    readonly data$: Observable<HistoryNode[]>;

    constructor(private readonly resultService: ResultService, private readonly route: ActivatedRoute, public dialog: MatDialog) {
        this.data$ = route.paramMap.pipe(
            map(params => Number.parseInt(params.get('id')!, 10)),
            filter(value => !!value),
            switchMap(id => resultService.getResultHistoryForNode(id))
        );
    }

    onCommentClick(event: MouseEvent) {
        if ((event.target as HTMLElement)?.tagName === 'IMG') {
            this.dialog.open(ImageDialogComponent, {
                data: (event.target as HTMLElement).outerHTML,
                maxHeight: '80vh'
            });
        }
    }
}

规范文件是:

@Component({
  template: '<router-outlet></router-outlet>'
})
class TestRootComponent {}
fdescribe('NodeHistoryComponent', () => {
  function advance() {
      tick();
      rootFixture.detectChanges();
  }

  function navigateByNodeId(id: number) {
      rootFixture.ngZone?.run(() => router.navigate(['history', 'node', id]));
  }

  let component: TestRootComponent;
  let rootFixture: ComponentFixture<TestRootComponent>;
  let router: Router;
  let loader: HarnessLoader;
  let httpTestingController: HttpTestingController;

  afterEach(() => {
      httpTestingController.verify();
  });
  beforeEach(async () => {
      const fakeService = {
          getResultHistoryForNode(id: number) {
              console.log('Came here', id);
              return of(mockResult);
          }
      } as Partial<ResultService>;

      await TestBed.configureTestingModule({
          declarations: [TestRootComponent, NodeHistoryComponent, ImageDialogComponent, DatePipe, SafePipe],
          imports: [
              MatDialogModule,
              MatExpansionModule,
              NoopAnimationsModule,
              HttpClientTestingModule,
              RouterTestingModule.withRoutes([
                  {
                      path: 'history/node/:id',
                      component: NodeHistoryComponent
                  }
              ])
          ],
          providers: [
              {
                  provide: ResultService,
                  useValue: fakeService
              }
          ],
          schemas: [NO_ERRORS_SCHEMA]
      }).compileComponents();

      rootFixture = TestBed.createComponent(TestRootComponent);
      component = rootFixture.componentInstance;
      router = TestBed.inject(Router);
      rootFixture.detectChanges();
      loader = TestbedHarnessEnvironment.loader(rootFixture);
      httpTestingController = TestBed.inject(HttpTestingController);
  });

  it('should render img tags when comment has images', fakeAsync(async () => {
      navigateByNodeId(123);
      advance();
      const panel = await loader.getAllHarnesses(MatExpansionPanelHarness);
      expect(panel.length).toEqual(mockResult.length);
      const text = await (await panel[1].host()).getCssValue;

      const imageInComment = rootFixture.nativeElement.querySelector('.comment img') as HTMLImageElement;
    expect(imageInComment).toBeDefined();

    imageInComment.click();
    advance();
    /* The next assertion fails with the following error message:

         Error: Failed to find element matching one of the following queries:
        (MatDialogHarness with host element matching selector: ".mat-dialog-container")
    */
    const dialog = await loader.getHarness(MatDialogHarness);
    expect(dialog).toBeDefined();
  }));
});

从规范文件中可能很清楚,由于组件依赖于 ActivatedRoute(这就是我需要 TestRootComponent 的原因),因此增加了复杂性.

As is probably clear from the spec file, there's an added complication because the component has a dependency on ActivatedRoute (which is why I need the TestRootComponent).

非常感谢任何帮助:)

推荐答案

OverlayContainer 中有一个用于对话框的 documentRootLoader 线束加载器.

There's a documentRootLoader harness loader for dialogs in OverlayContainer.

documentRootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture);

https:///stackblitz.com/edit/angular-harness-dialogs-3f7zju?file=src%2Fapp%2Fapp.component.spec.ts

这篇关于Angular:如何测试单击组件 nativeElement 会打开一个对话框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆