Angular 15集成Jest Preset Angular报组件未解析问题求助
问题描述
之前Jest在Angular 11环境下运行完全正常,7个月前不小心重建了package-lock.json,导致依赖更新出了问题,当时就暂时放一边没管。最近升级到Angular 15后,测试能跑起来,但所有用到TestBed.createComponent或TestBed.inject的测试全报错:‘Did you run and wait for 'resolveComponentResources()'?’。翻了相关Bug报告,发现这个问题从Angular 8就有记录,推测是依赖不兼容或者配置出了问题。试过把TypeScript降级到4.7,但Angular 15不支持这个版本。项目是Node+Angular分目录结构,根目录的package.json负责管理服务端和Jest运行器,相关配置片段如下:
根目录 package.json
{ ... "engineStrict": true, "engines": { "node": "18.12.1" }, "scripts": { ... "test": "./test-data/test-data.sh && jest --detectOpenHandles", "test:watch": "./test-data/test-data.sh && jest --detectOpenHandles --watch" }, "jest": { "verbose": true, "collectCoverage": true, "collectCoverageFrom": [ "**/*.{js,ts}", "!**/*.spec.{js,ts}", "!**/serviceWorker.js", "!**/node_modules/**", "!**/data/**", "!**/environments/**", "!**/migrations/**", "!**/server/config/**", "!**/vendors/**", "!**/coverage/**", "!**/models/**", "!**/test-data/**", "!**/migration.js", "!**/app.module.ts", "!**/*webpack.config.js", "!**/*main.ts", "!**/*polyfills.ts" ], "testPathIgnorePatterns": [ "<rootDir>/*/node_modules/", "<rootDir>/client/dist/" ], "projects": [ { "displayName": "backend", "testEnvironment": "node", "testMatch": [ "<rootDir>/server/**/*.spec.js" ], "modulePaths": [ "<rootDir>/server/" ] }, { "displayName": "frontend", "testEnvironment": "jsdom", "preset": "<rootDir>/client/node_modules/jest-preset-angular", "setupFilesAfterEnv": [ "<rootDir>/client/setupJest.ts" ], "testMatch": [ "<rootDir>/client/src/**/*.spec.ts" ], "modulePaths": [ "<rootDir>/client/" ], "snapshotSerializers": [ "<rootDir>/client/node_modules/jest-preset-angular/build/serializers/html-comment" ], "transform": { "^.+\\.(ts|js|mjs|html|svg)$": "<rootDir>/client/node_modules/jest-preset-angular" }, "transformIgnorePatterns": ["node_modules/(?!.*\\.mjs$)"], "globals": { "ts-jest": { "tsconfig": "<rootDir>/client/tsconfig.spec.json", "stringifyContentPathRegex": "\\.html$" } }, "globalSetup": "<rootDir>/client/node_modules/jest-preset-angular/global-setup" } ] }, ... "devDependencies": { "ajv-cli": "^5.0.0", "db-migrate-mysql": "^1.1.10", "jest": "29.3.1", "jest-environment-jsdom": "29.3.1", "mysql-migrations": "^1.0.6", "node-env-run": "^4.0.2", "nodemon": "^1.19.4", "npm-run-all": "^4.1.5", "pino-colada": "^1.6.0", "ts-json-schema-generator": "^1.0.0" } }
client/package.json
{ ... "private": true, "dependencies": { "@angular-builders/custom-webpack": "^15.0.0", "@angular-devkit/build-angular": "^15.0.4", "@angular/animations": "^15.0.4", "@angular/cli": "^15.0.4", "@angular/common": "^15.0.4", "@angular/compiler": "^15.0.4", "@angular/compiler-cli": "^15.0.4", "@angular/core": "^15.0.4", "@angular/fire": "^7.5.0", "@angular/forms": "^15.0.4", "@angular/platform-browser": "^15.0.4", "@angular/platform-browser-dynamic": "^15.0.4", "@angular/router": "^15.0.4", ... "tslib": "^2.0.0", "typescript": "4.8.3", "zone.js": "~0.11.4" }, "devDependencies": { "@angular-builders/dev-server": "^7.3.1", "@angular-devkit/architect": "0.1500.4", "@angular-eslint/schematics": "^15.1.0", "@types/clone": "^2.1.1", "@types/file-saver": "^2.0.5", "@types/jest": "^29.2.5", "@types/node": "^12.20.7", "@types/string-similarity": "^4.0.0", ... "jest-preset-angular": "^12.2.3", "jsonc-parser": "^3.0.0", "open": "^7.0.3", "rxjs-watcher": "^1.1.3", "ts-node": "~8.3.0", "tslint": "~6.1.0" } }
angular.json
{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "rosterizer": { "projectType": "application", "schematics": { "@schematics/angular:component": { "style": "sass" } }, "root": "", "sourceRoot": "src", "prefix": "app", "architect": { "build": { "builder": "@angular-builders/custom-webpack:browser", "options": { "outputPath": "dist/rosterizer", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.app.json", "aot": true, "assets": [ "src/favicon.ico", "src/site.webmanifest", "src/assets" ], "styles": [ "src/css/main.sass" ], "scripts": [ "node_modules/marked/marked.min.js" ], "webWorkerTsConfig": "tsconfig.worker.json", "customWebpackConfig": { "path": "custom-webpack.config.ts", "replaceDuplicatePlugins": true } }, "configurations": { "development": { "buildOptimizer": false, "optimization": false, "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true }, "production": { "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ], "optimization": true, "outputHashing": "all", "sourceMap": false, "namedChunks": false, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true, "budgets": [ { "type": "initial", "maximumWarning": "3mb", "maximumError": "5mb" }, { "type": "anyComponentStyle", "maximumWarning": "6kb", "maximumError": "10kb" } ] } } }, "serve": { "builder": "@angular-builders/custom-webpack:dev-server", "options": { "browserTarget": "myApp:build", "proxyConfig": "src/proxy.conf.json" }, "configurations": { "development": { "browserTarget": "myApp:build:development" }, "production": { "browserTarget": "myApp:build:production" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "myApp:build" } }, "e2e": { "builder": "@angular-devkit/build-angular:protractor", "options": { "protractorConfig": "e2e/protractor.conf.js", "devServerTarget": "myApp:serve" }, "configurations": { "development": { "devServerTarget": "myApp:serve:development" }, "production": { "devServerTarget": "myApp:serve:production" } } }, "deploy": { "builder": "@angular/fire:deploy", "options": {} } } } } }
custom-webpack.config.ts
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin'); module.exports = { // Other rules... plugins: [ new NodePolyfillPlugin() ] };
tsconfig.json
{ "compileOnSave": false, "compilerOptions": { "baseUrl": "./", "outDir": "./dist/out-tsc", "sourceMap": true, "declaration": false, "downlevelIteration": true, "experimentalDecorators": true, "moduleResolution": "node", "importHelpers": true, "target": "ES2022", "module": "es2020", "lib": [ "es2020", "dom", "ESNext.String" ], "resolveJsonModule": true, "esModuleInterop": true, "useDefineForClassFields": false }, "emitDecoratorMetadata":true }
tsconfig.spec.json
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin'); module.exports = { // Other rules... plugins: [ new NodePolyfillPlugin() ] };
内容的提问来源于stack exchange,提问作者jugglervr
相关产品推荐
相关产品推荐

