我有这个根 AppComponent
监听服务的变化,然后在 document.body
import { Component, OnInit, Renderer2 } from '@angular/core';
import { SideMenuService } from './core/side-menu/side-menu.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
static readonly sideMenuClass: string = 'side-menu-open';
constructor(public sideMenuService: SideMenuService, private renderer2: Renderer2) { }
ngOnInit(): void {
this.sideMenuService.isOpenChange.subscribe((value: boolean) => {
if (value) {
this.renderer2.addClass(document.body, AppComponent.sideMenuClass);
} else {
this.renderer2.removeClass(document.body, AppComponent.sideMenuClass);
}
});
}
}
然后我在我的 *.spec.ts
文件中有这个,其中大部分是我从阅读 this SO answer 中获得的
import { TestBed, async, ComponentFixture, tick } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { CoreModule } from './core/core.module';
import { AppComponent } from './app.component';
import { Renderer2, Type } from '@angular/core';
describe('AppComponent', () => {
let fixture: ComponentFixture<AppComponent>;
let app: AppComponent;
let renderer2: Renderer2;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
CoreModule
],
declarations: [
AppComponent
],
providers: [Renderer2]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
app = fixture.debugElement.componentInstance;
//Spy on the renderer
renderer2 = fixture.componentRef.injector.get<Renderer2>(Renderer2 as Type<Renderer2>);
spyOn(renderer2, 'addClass').and.callThrough();
});
it(`should toggle a class on the <body> tag when opening/closing the side-menu via the side-menu service`, () => {
app.sideMenuService.open();
fixture.detectChanges();
console.log(fixture.debugElement.nativeElement, document.body)
expect(renderer2.addClass).toHaveBeenCalledWith(jasmine.any(Object), AppComponent.sideMenuClass);
});
});
但是,现在它给了我错误信息
Expected spy addClass to have been called with [ , 'side-menu-open' ] but it was never called.
我需要做什么才能正确测试这个组件?我在这里是否走在正确的轨道上?
编辑:
这是side-menu.service.ts
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class SideMenuService {
isOpen: boolean = false;
isOpenChange: Subject<boolean> = new Subject<boolean>();
constructor() {
this.isOpenChange.subscribe((value: boolean) => {
this.isOpen = value;
});
}
open(): void {
this.isOpenChange.next(true);
}
close(): void {
this.isOpenChange.next(false);
}
}
最佳答案
我最终没有使用渲染器并注入(inject)了一个我可以在测试中模拟的窗口服务。
在我的 app.module.ts
我有
@NgModule({
declarations: [
AppComponent
],
imports: [ ... ],
providers: [
{provide: 'Window', useValue: window},
...
],
bootstrap: [AppComponent]
})
export class AppModule { }
在 app.component.ts
中:
import { Component, OnInit, Inject } from '@angular/core';
import { SideMenuService } from './services/side-menu/side-menu.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
static readonly sideMenuClass: string = 'side-menu-open';
constructor(@Inject('Window') private window: Window, public sideMenuService: SideMenuService) { }
ngOnInit(): void {
this.sideMenuService.isOpen$.subscribe((value: boolean) => {
if (value) {
this.window.document.body.classList.add(AppComponent.sideMenuClass);
} else {
this.window.document.body.classList.remove(AppComponent.sideMenuClass);
}
});
}
}
神奇的是,我发现 karma-viewport
项目添加了 karma 测试修改测试窗口的能力(比如响应式屏幕尺寸等)
https://github.com/squidfunk/karma-viewport
添加这个允许我在 app.component.spec.ts
中使用 karma testig iframe 作为 window
并且测试通过!
describe('Component: App', () => {
let fixture: ComponentFixture<AppComponent>;
let app: AppComponent;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ ... ],
declarations: [
AppComponent
],
providers: [
{provide: 'Window', useValue: viewport.context.contentWindow},
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
app = fixture.debugElement.componentInstance;
});
it(`should toggle a class on the <body> tag when opening/closing the side-menu via the side-menu service`, () => {
if (viewport.context && viewport.context.contentDocument) {
const testBody = viewport.context.contentDocument.body;
fixture.detectChanges(); //do this initially to trigger `ngOnInit()`
app.sideMenuService.open();
fixture.detectChanges();
expect(testBody.className).toContain(AppComponent.sideMenuClass);
app.sideMenuService.close();
fixture.detectChanges();
expect(testBody.className).not.toContain(AppComponent.sideMenuClass);
} else {
fail('Could not locate the karma testing iframe document!');
}
});
});
关于angular - 测试在 Angular 7 中向 <body> 添加类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55165001/