如何在测试中访问未挂载到DOM的组件CSS?
我是一名组件库实习生,所在项目没有app.component,因此不会生成应用实例,要测试的组件并未挂载到DOM中。在Karma-Jasmine测试中调用getComputedStyle()时返回undefined,请问是否有办法将该组件加入DOM并获取CSS用于测试?
相关组件代码:
export class CheckboxComponent implements ControlValueAccessor { @Input() size: 'large' | 'small' | 'tablet' = 'large'; @Input() label: string = 'test check box'; @Input() checked: boolean = false; @Input() colorTheme: 'dark' | 'light' = 'light'; @Input() disabled: boolean = false; constructor() {} public get classes(): string[] { let cls:string[] = []; cls.push(this.size) if (this.colorTheme==='dark') { cls.push('dark') } if (this.error){ cls.push('error') } if (this.disabled){ cls.push('disabled') } return cls } }
我希望测试修改size、theme等输入属性时组件是否具有正确样式,示例测试代码如下:
it('should have 24px width for small', () => { component.size = 'small'; fixture.detectChanges(); // add the component to DOM to retireve css, else getComputedStyled() returns undefined expect(getComputedStyle(fixture.nativeElement).width).toEqual('24px'); })
在Karma-Jasmine的Angular组件测试中,即使没有AppComponent,也可以通过以下步骤将组件手动挂载到测试DOM中:
确保测试模块配置正确
在组件的.spec.ts文件里,TestBed.configureTestingModule的declarations数组必须包含CheckboxComponent;如果组件依赖全局样式或自身样式文件,要在测试模块中通过styles或styleUrls引入,或者在测试全局配置中导入样式资源。手动挂载组件到DOM
Angular测试夹具的nativeElement默认不会自动加入DOM,你可以在测试中手动把它追加到document.body里,这样getComputedStyle就能正常获取样式。测试后清理DOM
为避免测试用例间的干扰,测试完成后要从DOM中移除组件元素。
修改后的测试代码示例
it('should have 24px width for small', () => { component.size = 'small'; fixture.detectChanges(); // 将组件元素添加到测试DOM document.body.appendChild(fixture.nativeElement); // 获取计算样式并断言 const computedStyle = getComputedStyle(fixture.nativeElement); expect(computedStyle.width).toEqual('24px'); // 测试完成后清理DOM document.body.removeChild(fixture.nativeElement); });
优化:复用挂载/清理逻辑
如果多个测试用例都需要挂载DOM,可以把逻辑放到beforeEach和afterEach中减少重复代码:
let fixture: ComponentFixture<CheckboxComponent>; let component: CheckboxComponent; beforeEach(() => { TestBed.configureTestingModule({ declarations: [CheckboxComponent], // 若组件依赖样式,在此引入 // styles: [require('./checkbox.component.scss').toString()] }); fixture = TestBed.createComponent(CheckboxComponent); component = fixture.componentInstance; }); beforeEach(() => { // 每个测试前挂载组件到DOM document.body.appendChild(fixture.nativeElement); }); afterEach(() => { // 每个测试后清理DOM document.body.removeChild(fixture.nativeElement); }); it('should have 24px width for small', () => { component.size = 'small'; fixture.detectChanges(); const computedStyle = getComputedStyle(fixture.nativeElement); expect(computedStyle.width).toEqual('24px'); });
注意:原组件代码的
classesgetter存在语法错误,let cls:string = [];应改为let cls:string[] = [];,否则会导致编译失败。
内容的提问来源于stack exchange,提问作者Ashutosh Shinde

