You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jest测试Angular共享库时遇组件引入错误问题

Angular Jest测试引入项目内UI组件时出现LocaleData未定义错误

项目结构

projects/
   |..... app/
       |..... src/
          |..... app/       
              |..... app.component.spec.ts
              |..... app.component.ts
              |..... app.module.ts    
   |..... lib/
       |..... sso/
          |...... index.ts
          |...... ng-package.json
          |...... ...
          |...... sso.service.ts
          |...... ss.module.ts
       |..... ui/
          |...... menu/
              |...... menu.component.ts
              |...... menu.service.ts
              |...... menu.module.ts
          |...... index.ts
          |...... ng-package.json
       |..... ng-package.json
       |..... package.json
   |..... jest.config.ts
   |..... package.json

AppComponent代码

// app.component.ts

import {SSOService} from "my-lib/sso";

@Component({
  selector: 'app-root',
  template: `
    <my-menu>
      <router-outlet></router-outlet>
    </my-menu>
  `,
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  constructor(protected ssoService: SSOService) { }
}

当前测试代码

// app.component.spec.ts

import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
import {SSOService} from "my-lib/sso";
import {MenuComponent} from "my-lib/ui";

describe('AppComponent', () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [
        RouterTestingModule
      ],
      declarations: [
        AppComponent, MenuComponent
      ],
      providers: [
        {
          provide: SSOService,
          useValue: {
            setRoles: jest.fn()
          }
        }
      ]
    }).compileComponents();
  });

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app).toBeTruthy();
  });
});

错误信息

● Test suite failed to run

    TypeError: Cannot read properties of undefined (reading 'toLowerCase')

      289 |         }] });
      290 |
    > 291 | registerLocaleData(FR);
          | ^
      292 | /**
      293 |  * Custom date adapter for Angular Material.
      294 |  *

      at registerLocaleData (node_modules/@angular/core/fesm2022/core.mjs:22410:25)
      at registerLocaleData (node_modules/@angular/common/fesm2022/common.mjs:2562:12)
      at Object.<anonymous> (dist/lib/fesm2022/my-lib-ui.mjs:291:1)
      at Object.<anonymous> (projects/app/src/app/app.component.spec.ts:5:1)

我不想MockMenuComponent,之前用Karma测试完全正常,换Jest后出现这个问题,请问是库本身的问题还是Jest配置有误?


相关配置文件

lib/ui/index.ts

// lib/ui/index.ts
import { CommonMenuService } from './menu/menu.service';

export * from './menu/menu.component';
export * from './menu/menu.module';
export * from './menu/menu.service';

lib/ui/ng-package.json

{
  "lib": {
    "entryFile": "index.ts"
  }
}

lib/ui/package.json

{
  "name": "my-lib",
  "version": "2.5.2",
  "peerDependencies": {
    "@angular/cdk": "^17.0.0",
    "@angular/common": "^17.0.1",
    "@angular/core": "^17.0.1",
    "@angular/material": "^17.0.0",
    "@awesome-cordova-plugins/in-app-browser": "^6.3.0",
    "@capacitor/device": "^5.0.6",
    "angular-oauth2-oidc": "^15.0.1",
    "jwt-decode": "^4.0.0"
  },
  "dependencies": {
    "tslib": "^2.6.2"
  },
  "sideEffects": false,
  "exports": {
    ".": {
      "sass": "./styles/_index.scss"
    }
  }
}

jest.config.ts

// jest.config.ts

import type { Config } from 'jest';

const config: Config = {
  clearMocks: true,
  collectCoverage: true,
  coverageDirectory: 'coverage',
  coverageProvider: 'v8',
  preset: 'jest-preset-angular',
  setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
};

export default config;

tsconfig.json

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "noImplicitReturns": true,
    "paths": {
      "my-lib/*": ["projects/lib/*"],
      "my-lib": ["projects/lib"]
    },
    "noFallthroughCasesInSwitch": true,
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "ES2022",
    "module": "ES2022",
    "useDefineForClassFields": false,
    "lib": ["ES2022", "dom"]
  },
  "angularCompilerOptions": {
    "enableI18nLegacyMessageIdFormat": false,
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}

问题分析与解决方案

这个错误的核心原因是Jest加载UI库时,registerLocaleData(FR)中的FR变量未被正确初始化或导入,导致调用toLowerCase时出现undefined错误。Karma能正常运行是因为其构建流程与Jest不同,Karma依赖Angular CLI的构建管道,而Jest直接处理ES模块时可能遗漏Locale相关的初始化逻辑。

解决方案步骤:

  1. 检查Locale导入正确性
    确认UI库中注册Locale的代码是正确导入的,比如:

    import { registerLocaleData } from '@angular/common';
    import fr from '@angular/common/locales/fr';
    
    registerLocaleData(fr);
    

    避免直接使用未导入的FR变量。

  2. 在Jest测试初始化中注册Locale
    在setup-jest.ts文件中添加Locale注册逻辑,确保测试环境中存在所需的Locale数据:

    import { registerLocaleData } from '@angular/common';
    import fr from '@angular/common/locales/fr';
    
    registerLocaleData(fr);
    
  3. 调整Jest路径映射,直接加载源码
    修改jest.config.ts,添加moduleNameMapper配置,让Jest直接加载库的源码而非编译后的dist文件:

    const config: Config = {
      // 原有配置
      moduleNameMapper: {
        'my-lib/(.*)': '<rootDir>/projects/lib/$1'
      }
    };
    

    这样可以避免编译后的库文件出现的初始化问题。

  4. 将Locale注册移到NgModule中
    不要在全局文件中直接执行registerLocaleData,而是将其移到MenuModule的构造函数或初始化逻辑中:

    @NgModule({
      imports: [CommonModule],
      declarations: [MenuComponent],
      exports: [MenuComponent]
    })
    export class MenuModule {
      constructor() {
        registerLocaleData(fr);
      }
    }
    

    这样Locale注册会在模块加载时执行,更符合Angular的生命周期。

内容的提问来源于stack exchange,提问作者Smaillns

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 00:14:53