Javascript 角度异步管道在单元测试中未正确更新
在编写单元测试时,通过HTML中的Javascript 角度异步管道在单元测试中未正确更新,javascript,angular,unit-testing,jasmine,Javascript,Angular,Unit Testing,Jasmine,在编写单元测试时,通过HTML中的async管道呈现更新可观察对象时,我面临一个问题 我的想法是,我不仅要测试组件,还要测试子组件是否都被渲染并具有正确的输入 这是出现问题的最小示例: <ng-container *ngFor="let plan of plans$ | async"> <child-component [plan]="plan"></child-component> </ng-containe
async
管道呈现更新可观察对象时,我面临一个问题
我的想法是,我不仅要测试组件,还要测试子组件是否都被渲染并具有正确的输入
这是出现问题的最小示例:
<ng-container *ngFor="let plan of plans$ | async">
<child-component [plan]="plan"></child-component>
</ng-container>
Visible plans: {{ plans$ | async | json }}
可见计划:{{plans$| async | json}
组件的最小示例:
export class RecommendationsComponent implements OnInit {
public plans$: Observable<Plan[]>;
constructor(private readonly _store: Store<State>) {
this.plans$ = this._store.pipe(select(selectRecommendationsPayload));
}
public ngOnInit(): void {
this.getRecommendations(); // Action dispatch, state is filled with data
}
}
导出类建议组件实现OnInit{
公共计划:可见;
构造函数(私有只读存储:存储){
this.plans$=this.\u store.pipe(select(selectRecommendationsPayload));
}
public ngOnInit():void{
this.getRecommensions();//动作分派,状态为数据填充
}
}
此模块/组件的单元测试:
describe('Recommendations', () => {
let component: RecommendationsComponent;
let fixture: ComponentFixture<RecommendationsComponent>;
let store: Store<any>;
let mockStore: MockStore<any>;
let actions$: ReplaySubject<any> = new ReplaySubject<any>();
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [RecommendationsComponent],
imports: [RouterTestingModule.withRoutes([]), HttpClientTestingModule],
providers: [
MockStore,
provideMockStore({ initialState: initialStateMock }),
provideMockActions(() => actions$),
],
});
store = TestBed.inject(Store);
mockStore = TestBed.inject(MockStore);
fixture = TestBed.createComponent(RecommendationsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should successfully retrieve and handle plans', () => {
recommendationsService.getRecommendations = jasmine.createSpy().and.returnValue(of(plans)); // Mock BE response with non-empty data
component.plans$.subscribe(plans => {
console.log(plans);
console.log(fixture.debugElement);
// A few expect() based on state and HTML...
// This fires since all logic starts on ngOnInit() lifecycle
});
});
});
description('建议',()=>{
let组件:推荐组件;
let夹具:组件夹具;
让店:店;
让mockStore:mockStore;
让操作$:ReplaySubject=新建ReplaySubject();
beforeach(异步()=>{
等待TestBed.configureTestingModule({
声明:[建议组件],
导入:[RouterTestingModule.withRoutes([]),HttpClientTestingModule],
供应商:[
模拟商店,
provideMockStore({initialState:initialStateMock}),
provideMockActions(()=>actions$),
],
});
store=TestBed.inject(store);
mockStore=TestBed.inject(mockStore);
fixture=TestBed.createComponent(推荐组件);
组件=fixture.componentInstance;
fixture.detectChanges();
});
它('应成功检索和处理计划',()=>{
recommendationsService.getRecommendations=jasmine.createSpy().and.returnValue(of(plan));//使用非空数据模拟BE响应
component.plans$.subscribe(计划=>{
控制台日志(计划);
console.log(fixture.debugElement);
//一些基于状态和HTML的expect()。。。
//这是因为所有逻辑都在ngOnInit()生命周期上启动
});
});
});
而真正的代码和console.log(计划)单元测试中的代码>显示正确的数据,由于某种原因,HTML中的计划$| async
始终具有默认状态。这个问题只与HTML有关
我的尝试:
添加fixture.detectChanges()
-在beforeach()
和it
测试用例中,几乎每隔一行就添加这一行(到了如此极端的程度),但没有任何更改
硬编码为component.plans$=of([{name:'name'}如有])代码>在it
测试用例中(我想知道这是否与Store/MockStore有关,但即使是硬编码的值在HTML中也似乎不起作用)
使用fixture.whenRenderingDone()。然后(async()=>{})代码>在整个测试用例中(可能在出现console.log()
行时HTML没有呈现)
与第三个类似,我也尝试了使用setTimeout()
,理由相同
我的其他想法也是:
我在声明
,导入
等方面遗漏了什么
MockStore/Store无法正确触发对异步
管道的更改(尽管它们适用于订阅()
)
如果缺少什么,请告诉我。提前谢谢。我感到奇怪的是,你对store
和mockStore
都有控制权
我想你应该只用一个。我对mockStore没有太多经验,所以我会尝试实际的商店。尝试执行集成测试,如图所示。通过集成测试,我们有实际的存储,而不是模拟存储
describe('Recommendations', () => {
let component: RecommendationsComponent;
let fixture: ComponentFixture<RecommendationsComponent>;
let store: Store<any>;
let actions$: ReplaySubject<any> = new ReplaySubject<any>();
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [RecommendationsComponent],
imports: [
RouterTestingModule.withRoutes([]),
HttpClientTestingModule,
StoreModule.forRoot({
// Pay attention here, make sure this is provided in a way
// where your selectors will work (make sure the structure is
// good)
recommendations: recommendationsReducer,
})
],
});
store = TestBed.inject(Store);
// load the recommendations into the store by dispatching
store.dispatch(new loadRecommendations([]));
fixture = TestBed.createComponent(RecommendationsComponent);
component = fixture.componentInstance;
// see your state here, make sure the selector works
store.subscribe(state => console.log(state));
// any time you want to change plans, do another dispatch
store.dispatch(new loadRecommendations([/* add stuff here */]));
// the following above should make plans$ emit every time
fixture.detectChanges();
});
// !! -- The rest is up to you from now on but what I presented above
// should help in getting new plans$ with the async pipe !!-
it('should successfully retrieve and handle plans', () => {
recommendationsService.getRecommendations = jasmine.createSpy().and.returnValue(of(plans)); // Mock BE response with non-empty data
component.plans$.subscribe(plans => {
console.log(plans);
console.log(fixture.debugElement);
// A few expect() based on state and HTML...
// This fires since all logic starts on ngOnInit() lifecycle
});
});
});
description('建议',()=>{
let组件:推荐组件;
let夹具:组件夹具;
让店:店;
让操作$:ReplaySubject=新建ReplaySubject();
beforeach(异步()=>{
等待TestBed.configureTestingModule({
声明:[建议组件],
进口:[
RouterTestingModule.withRoutes([]),
HttpClientTestingModule,
StoreModule.forRoot({
//注意这里,确保以适当的方式提供
//选择器工作的位置(确保结构正确
//好的)
建议:建议减速器,
})
],
});
store=TestBed.inject(store);
//通过调度将建议加载到存储中
存储、发送(新装载建议([]);
fixture=TestBed.createComponent(推荐组件);
组件=fixture.componentInstance;
//在此处查看您的状态,确保选择器工作正常
订阅(state=>console.log(state));
//任何时候你想改变计划,再做一次调度
store.dispatch(新加载建议([/*在此处添加内容*/]);
//下面的内容每次都应该制定$emit计划
fixture.detectChanges();
});
//!!--从现在起,剩下的由您决定,但我在上面介绍了什么
//应该有助于通过异步管道获得新计划-
它('应成功检索和处理计划',()=>{
recommendationsService.getRecommendations=jasmine.createSpy().and.returnValue(of(plan));//使用非空数据模拟BE响应
component.plans$.subscribe(计划=>{
控制台日志(计划);
console.log(fixture.debugElement);
//一些基于状态和HTML的expect()。。。
//这是因为所有逻辑都在ngOnInit()生命周期上启动
});
});
});
Hmm,似乎对我不起作用(错误:NgModule'DynamicTestModule'的提供程序无效-只允许提供程序和类型的实例
)。我使用了两个不同的商店,因为在某些情况下,效果或动作都不会被触发。我可能走错方向了。谢谢你的代码和链接,我将尝试更新和测试,看看是否我的c