Jasmine 测试中 AfterViewInit 的生命周期钩子
Posted
技术标签:
【中文标题】Jasmine 测试中 AfterViewInit 的生命周期钩子【英文标题】:Lifecycle hook of AfterViewInit in Jasmine test 【发布时间】:2017-12-15 18:11:37 【问题描述】:我对与 Jasmine 测试相关的生命周期挂钩感到困惑。 LifeCycle Angular 文档没有提到测试https://angular.io/guide/lifecycle-hooks。测试文档仅提及 OnChange https://angular.io/guide/testing。 我有一个示例组件如下:
import Component, OnInit, AfterViewInit, OnDestroy, ElementRef from '@angular/core';
...
@Component(
selector: 'app-prod-category-detail',
templateUrl: './prod-category-detail.component.html',
styleUrls: ['./prod-category-detail.component.css']
)
//
export class ProdCategoryDetailComponent implements OnInit, AfterViewInit, OnDestroy
...
nav: HTMLSelectElement;
//
constructor(
...
private _elementRef: ElementRef )
...
ngAfterViewInit()
console.log( 'ProdCategoryDetailComponent: ngAfterViewInit' );
this.nav = this._elementRef.nativeElement.querySelector('#nav');
...
请注意,这是一个 Angular CLI 应用程序,具有最新下载。在 Karma 中,我看不到控制台日志,因此永远不会设置 nav。我目前在我的规范中调用它如下:
beforeEach(() =>
fixture = TestBed.createComponent(ProdCategoryDetailComponent);
sut = fixture.componentInstance;
sut.ngAfterViewInit( );
fixture.detectChanges( );
);
这是正确的处理方式吗?
对于 shusson,这是很久以前的,我已经有一段时间没有看这个了。希望它会有所帮助。请注意,我使用的是 Primeface primeng 库:
describe('ProdCategoryDetailComponent', () =>
let sut: ProdCategoryDetailComponent;
let fixture: ComponentFixture< ProdCategoryDetailComponent >;
let alertService: AlertsService;
let prodCatService: ProdCategoryServiceMock;
let confirmService: ConfirmationServiceMock;
let elementRef: MockElementRef;
//
beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [
FormsModule,
ButtonModule,
BrowserAnimationsModule
],
declarations: [
ProdCategoryDetailComponent,
AlertsComponent,
ConfirmDialog
],
providers: [
AlertsService,
provide: ProdCategoryService, useClass: ProdCategoryServiceMock ,
provide: MockBackend, useClass: MockBackend ,
provide: BaseRequestOptions, useClass: BaseRequestOptions ,
provide: ConfirmationService, useClass: ConfirmationServiceMock ,
provide: ElementRef, useClass: MockElementRef
]
)
.compileComponents();
));
//
beforeEach(inject([AlertsService, ProdCategoryService,
ConfirmationService, ElementRef],
(srvc: AlertsService, pcsm: ProdCategoryServiceMock,
cs: ConfirmationServiceMock, er: MockElementRef) =>
alertService = srvc;
prodCatService = pcsm;
confirmService = cs;
elementRef = er;
));
//
beforeEach(() =>
fixture = TestBed.createComponent(ProdCategoryDetailComponent);
sut = fixture.componentInstance;
sut.ngAfterViewInit( );
fixture.detectChanges( );
);
//
【问题讨论】:
ngAfterViewInit 应该使用第一个 fixture.detectChanges( ) 调用一次; 您能告诉我们您是如何配置 TestBed 的吗?例如TestBed.configureTestingModule(...)
。另外你真的有任何测试吗?如果没有 it
测试,beforeEach
将不会被调用。
【参考方案1】:
我经常在必要时直接从每个规范中调用生命周期钩子。这有效。
因为这提供了在调用ngAfterViewInit()
或ngOnInit()
之前操作任何数据的灵活性。
我还看到很少有角度库测试规范以相同的方式使用它。例如,检查这个videogular 规范文件。所以手动调用这些方法并没有什么坏处。
这里也复制相同的代码,以免以后链接被破坏。
it('Should hide controls after view init', () =>
spyOn(controls, 'hide').and.callFake(() => );
controls.vgAutohide = true;
controls.ngAfterViewInit();
expect(controls.hide).toHaveBeenCalled();
);
【讨论】:
【参考方案2】:我们不能直接从规范调用生命周期钩子,但我们可以调用自定义方法。因为要调用生命周期书籍,我们需要使用夹具创建组件的实例。
示例:在我的示例中,我需要将 padding-left 和 right 设置为 0,因为 bootstrap 默认情况下会左右提供一些填充,所以我需要将其删除。
HTML 文件 - app.component.ts
import Component, ViewChild, ElementRef, Renderer2 from '@angular/core';
@Component(
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
)
export class AppComponent
@ViewChild('navCol', static: true ) navCol: ElementRef;
constructor(private renderer: Renderer2)
ngAfterViewInit()
this.renderer.setStyle(this.navCol.nativeElement, 'padding-left', '0px');
this.renderer.setStyle(this.navCol.nativeElement, 'padding-right', '0px');
app.component.spec.ts
import TestBed, async from '@angular/core/testing';
describe('AppComponent', () =>
it('should load page and remove padding', () =>
const fixture = TestBed.createComponent(AppComponent);
fixture.componentInstance.ngAfterViewInit();
const styles = window.getComputedStyle(fixture.nativeElement);
expect(styles.paddingLeft).toBe('0px');
expect(styles.paddingRight).toBe('0px');
);
);
【讨论】:
嗨 Sahil Shikalgar,在这种情况下,view child 如何没有给你带来问题,你说你不必调用 fixture.ngAfterViewInit(); 谢谢@Sahil Shikalgar,我想我正在使用fixture.detectChanges(),即使我的测试没有断言HTML。我认为也许大多数人使用fixture.detectChanges() 的频率比他们必须的要多。 谢谢Girum,我也会用fixture.detectChanges()检查而不是手动调用。以上是关于Jasmine 测试中 AfterViewInit 的生命周期钩子的主要内容,如果未能解决你的问题,请参考以下文章
将代码放在 Jasmine 测试 + Meteor 的正确目录中
在 Jasmine 中访问 Meteor 模板辅助函数以进行集成测试
在Visual Studio 2013中使用Jasmine + Karma进行AngularJS测试