Angular 14+Jest测试中async管道找不到的问题求助
Angular测试中async管道找不到的解决办法
我使用Angular 14、Jest 28和Spectator进行组件测试,被测SidebarComponent的模板中使用async管道处理Observable类型的sidebarCollapseState$。运行测试时触发NG0302错误,提示在SidebarComponent中找不到async管道;移除该管道则错误消失,但业务需要保留它。测试文件未直接操作模板,以下是相关代码及配置:
模板代码
<aside class="sidebar" [style.width]="(sidebarCollapseState$ | async) ? '10rem' : '25.5rem'"> <fmrs-side-menu [items]="menuItems" ></fmrs-side-menu> <p-divider></p-divider> <section class="sidebar__widget-container"> <ng-content></ng-content> </section> </aside>
报错信息
NG0302: The pipe 'async' could not be found in the 'SidebarComponent' component. Verify that it is declared or imported in this module. at getPipeDef (node_modules/@angular/core/fesm2020/core.mjs:22642:15) at ɵɵpipe (node_modules/@angular/core/fesm2020/core.mjs:22598:19) at SidebarComponent_Template (ng:/SidebarComponent.js:12:9) at executeTemplate (node_modules/@angular/core/fesm2020/core.mjs:12126:9) at renderView (node_modules/@angular/core/fesm2020/core.mjs:11948:13) at renderComponent (node_modules/@angular/core/fesm2020/core.mjs:13134:5) at renderChildComponents (node_modules/@angular/core/fesm2020/core.mjs:11807:9) at renderView (node_modules/@angular/core/fesm2020/core.mjs:11973:13) at ComponentFactory.create (node_modules/@angular/core/fesm2020/core.mjs:13913:13) at initComponent (node_modules/@angular/core/fesm2020/testing.mjs:26267:51) at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:409:30) at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:3830:43) at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:408:56) at Object.onInvoke (node_modules/@angular/core/fesm2020/core.mjs:26274:33) at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:408:56) at Zone.Object.<anonymous>.Zone.run (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:169:47) at NgZone.run (node_modules/@angular/core/fesm2020/core.mjs:26128:28) at TestBedImpl.createComponent (node_modules/@angular/core/fesm2020/testing.mjs:26270:41) at Function.createComponent (node_modules/@angular/core/fesm2020/testing.mjs:26078:37) at createSpectator (node_modules/@ngneat/spectator/fesm2020/ngneat-spectator.mjs:1533:29) at node_modules/@ngneat/spectator/fesm2020/ngneat-spectator.mjs:1525:27 at src/app/layout/components/sidebar/sidebar.component.spec.ts:36:17 at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:409:30) at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:3830:43) at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:408:56) at Zone.Object.<anonymous>.Zone.run (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:169:47) at Object.wrappedFunc (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:4330:34)
测试代码(sidebar.component.spec.ts)
describe('SidebarComponent', () => { let spectator: Spectator<SidebarComponent> const createComponent = createComponentFactory({ component: SidebarComponent, declareComponent: false, imports: [ HttpClientTestingModule, FormsModule, ReactiveFormsModule, RouterTestingModule ], providers: [ mockProvider(ReactiveFormsModule), mockProvider(AuthService), mockProvider(EnvironmentConfigurationService), provideMockStore({ initialState }) ], schemas: [NO_ERRORS_SCHEMA] }); beforeEach(() => { spectator = createComponent(); }); it('should create', () => { expect(spectator.component).toBeTruthy(); }); });
Jest配置(jest.config.js)
module.exports = { preset: "jest-preset-angular", globalSetup: "jest-preset-angular/global-setup", moduleNameMapper: { "@shared/(.*)": "<rootDir>/src/app/shared/$1", "@core/(.*)": "<rootDir>/src/app/core/$1", '^src/(.*)': '<rootDir>/src/$1', }, setupFilesAfterEnv: ["<rootDir>/src/setup-jest.ts"], testMatch: ["**/+(*.)+(spec).+(ts|js)?(x)"], transformIgnorePatterns: [ "<rootDir>/node_modules/(?!.*.mjs$)" ], transform: { "^.+\.(ts|js|html)$": "jest-preset-angular", }, collectCoverage: true, collectCoverageFrom: [ "<rootDir>/src/app/**/*.component.ts", "!<rootDir>/src/app/**/*.component.html", "<rootDir>/src/app/**/*.service.ts", "!<rootDir>/src/app/**/*.pipe.ts", "!<rootDir>/src/app/**/*.directive.ts", "!<rootDir>/src/app/**/*.module.ts", "!<rootDir>/src/app/core/**", "!<rootDir>/dist/**", "!<rootDir>/src/app/shared/**", "!<rootDir>/src/app/auth/**" ], coverageReporters: ["html", "cobertura", "lcov", "text"], reporters: ["jest-junit", "default"], testPathIgnorePatterns: ["<rootDir>/node_modules/", "<rootDir>/dist/"], testRunner: "jest-jasmine2", };
解决办法
问题原因
async管道属于Angular的CommonModule,实际应用中根模块或共享模块通常会导入这个模块,所以组件能正常使用。但测试环境是完全孤立的,Spectator基于TestBed构建测试环境,如果没有显式导入CommonModule,测试时就找不到async管道。
另外,测试代码里的mockProvider(ReactiveFormsModule)是错误用法——模块不能用mockProvider,应该放在imports数组里,这个配置可以直接删除。
修改后的测试代码
import { CommonModule } from '@angular/common'; // ...其他导入 describe('SidebarComponent', () => { let spectator: Spectator<SidebarComponent> const createComponent = createComponentFactory({ component: SidebarComponent, declareComponent: false, imports: [ CommonModule, // 新增:导入CommonModule HttpClientTestingModule, FormsModule, ReactiveFormsModule, RouterTestingModule ], providers: [ // 移除错误的mockProvider(ReactiveFormsModule) mockProvider(AuthService), mockProvider(EnvironmentConfigurationService), provideMockStore({ initialState }) ], schemas: [NO_ERRORS_SCHEMA] }); beforeEach(() => { spectator = createComponent(); }); it('should create', () => { expect(spectator.component).toBeTruthy(); }); });
额外说明
如果SidebarComponent所在的业务模块已经导入了CommonModule,测试时也可以直接导入该业务模块,替代单独导入CommonModule。保持测试环境的依赖与实际组件运行环境一致,就能避免这类找不到内置管道/指令的问题。
内容的提问来源于stack exchange,提问作者David Khvedelidze
相关产品推荐
相关产品推荐

