如何模拟独立指令?

问题描述 投票:0回答:1

表格单元格中的锚标记附加有 [routerLink] 指令。我的目的是测试该表。我想嘲笑该指令。我怎样才能做到这一点?更详细的问题:如何为测试床环境提供模拟指令以便在测试中使用它?

出于学习目的,我构建了另一个更简单的组件。

import { Component, Directive, ElementRef, HostListener } from "@angular/core";
import { CommonModule } from "@angular/common";
import { RouterModule } from "@angular/router";

@Directive({
  selector: "[consolePrint]",
  standalone: true,
})
export class ConsolePrintDirective {
  customText: string;

  constructor(private el: ElementRef) {}

  ngAfterViewInit() {
    this.customText = this.el.nativeElement.textContent;
  }

  @HostListener("click")
  onClick() {
    console.log("onClick method called with text: ", this.customText);
  }
}

@Component({
  selector: "app-test-directive",
  standalone: true,
  imports: [CommonModule, RouterModule, ConsolePrintDirective],
  template: `
    <p>
      <a [routerLink]="['/staff', 100500]" data-testid="link">
        "test directive"
      </a>
      <a consolePrint>undefined</a>
    </p>
  `,
  styles: [],
})
export class TestDirectiveComponent {}

并创建了这样的模拟指令:

@Directive({
  selector: "[consolePrint]",
  standalone: true,
  host: { "(click)": "onClick()" },
})
export class ConsolePrintDirectiveStub {
  customText = "stub text";

  constructor() {}

  onClick() {
    console.log("onClick method called with text: ", this.customText);
  }
}

这里是测试,根据它可以得出结论,实际使用的 ConsolePrintDirective 是什么,而不是它的存根对应项。如果我用 ConsolePrintDirectiveStub 替换injector.get() 的参数,我只会收到有关注入器中缺少此指令的错误。

import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing";

import {
  ConsolePrintDirective,
  TestDirectiveComponent,
} from "./test-directive.component";
import { ActivatedRoute, Router, RouterLink } from "@angular/router";
import { of } from "rxjs";
import { By } from "@angular/platform-browser";
import { RouterTestingModule } from "@angular/router/testing";
import { Directive } from "@angular/core";

@Directive({
  selector: "[consolePrint]",
  standalone: true,
  host: { "(click)": "onClick()" },
})
export class ConsolePrintDirectiveStub {
  customText = "stub text";

  constructor() {}

  onClick() {
    console.log("onClick method called with text: ", this.customText);
  }
}
class DummyComponent {}

fdescribe("TestDirectiveComponent", () => {
  let component: TestDirectiveComponent;
  let fixture: ComponentFixture<TestDirectiveComponent>;
  let router: Router;
  let stubConsolePrint: ConsolePrintDirectiveStub;

  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      imports: [
        TestDirectiveComponent,
        ConsolePrintDirective,
        RouterTestingModule.withRoutes([
          { path: "staff/100500", component: DummyComponent },
        ]),
      ],
      providers: [
        {
          provide: ActivatedRoute,
          useValue: {
            params: of({}),
            queryParams: of({}),
            data: of({}),
            url: of([]),
          },
        },
        {
          provide: Router,
          useValue: {
            createUrlTree: () => {},
            navigate: () => {},
            initialNavigation: () => {},
            events: of({}),
            serializeUrl: () => "",
            navigateByUrl: () => {},
          },
        },
        { provide: ConsolePrintDirective, useClass: ConsolePrintDirectiveStub },
      ],
    }).compileComponents();
  }));

  beforeEach(async () => {
    stubConsolePrint = TestBed.inject(
      ConsolePrintDirective
    ) as ConsolePrintDirective;

    router = TestBed.inject(Router);
    await router.initialNavigation();
    spyOn(router, "createUrlTree");

    fixture = TestBed.createComponent(TestDirectiveComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  fit("#consolePrint replace directive with stub", () => {
    const linkDes = fixture.debugElement.queryAll(By.css("a"));
    const dir = linkDes[1].injector.get(ConsolePrintDirective);

    spyOn(dir, "onClick");

    linkDes[1].nativeElement.click();
    stubConsolePrint.onClick();

    // expect(dir.onClick).toHaveBeenCalled();
    expect(dir.customText).toBe("stub test");
  });
});

angular angular2-directives angular-test
1个回答
0
投票

我只需在虚拟父组件中获取指令的 ViewChild,访问它并验证状态!

@Component({
  selector: "app-test-directive",
  standalone: true,
  imports: [CommonModule, RouterModule, ConsolePrintDirective],
  template: `
    <p>
      <a [routerLink]="['/staff', 100500]" data-testid="link">
        "test directive"
      </a>
      <a consolePrint>undefined</a>
    </p>
  `,
  styles: [],
})
export class TestDirectiveComponent {
    @ViewChild(ConsolePrintDirective) directive!: ConsolePrintDirective;
}

然后测试文件即可

  fit("#consolePrint replace directive with stub", () => {
    const linkDes = fixture.debugElement.queryAll(By.css("a"));
    linkDes[1].nativeElement.click();
    expect(component.directive.customText).toBe("stub test");
  });
© www.soinside.com 2019 - 2024. All rights reserved.