表格单元格中的锚标记附加有 [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");
});
});
我只需在虚拟父组件中获取指令的 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");
});