【发布时间】:2021-06-03 14:59:55
【问题描述】:
在编写单元测试时,我遇到了通过 HTML 中的async 管道渲染更新 Observables 的问题。
我的想法是,我不仅要测试组件,还要测试子组件是否都被渲染并具有正确的输入。
这是发生问题的最小示例:
<ng-container *ngFor="let plan of plans$ | async">
<child-component [plan]="plan"></child-component>
</ng-container>
Visible plans: {{ plans$ | async | json }}
Component 的最小例子:
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
}
}
此模块/组件的单元测试:
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
});
});
});
虽然单元测试中的真实代码和console.log(plans); 显示正确的数据,但出于某种原因,HTML 中的plans$ | async 始终具有默认状态。该问题仅与 HTML 有关。
我的尝试:
- 添加
fixture.detectChanges();- 在beforeEach()和it测试用例中几乎每隔一行(如此极端)都添加了这一行,但没有任何改变 - 在
it测试用例中使用component.plans$ = of([ { name: 'name' } as any ]);硬编码(我想知道这是否与 Store/MockStore 有关,但即使是硬编码的值似乎在 HTML 中也不起作用) - 在整个测试用例中使用
fixture.whenRenderingDone().then(async () => { <code> });(可能在出现console.log()行时 HTML 尚未呈现) - 和第三个类似,我也试过
setTimeout(),道理一样
我的其他想法也是:
- 我错过了
declarations、imports等中的某些内容? - MockStore/Store 无法正确触发对
async管道的更改(尽管它们适用于subscribe())
如果有什么遗漏,请告诉我。提前谢谢你。
【问题讨论】:
标签: javascript angular unit-testing jasmine