Angular测试中Navigator InjectionToken触发ReferenceError问题求助
问题背景
我为Navigator和Window实现了以下抽象注入令牌,以便在测试时模拟依赖:
NAVIGATOR注入令牌
export const NAVIGATOR: InjectionToken<Navigator> = new InjectionToken<Navigator>( 'An abstraction over window.navigator object', { factory: () => inject(WINDOW).navigator, }, );
WINDOW注入令牌
import { inject, InjectionToken } from '@angular/core'; import { DOCUMENT } from '@angular/common'; export const WINDOW: InjectionToken<Window> = new InjectionToken<Window>( 'An abstraction over global window object', { factory: () => { const { defaultView }: any = inject(DOCUMENT); if (!defaultView) { throw new Error('Window is not available'); } return defaultView; }, }, );
服务中注入NAVIGATOR
export class MyService { constructor( @Inject(NAVIGATOR) private navigator: Navigator, ) {} }
测试错误信息
运行单元测试时抛出如下错误:
ReferenceError: Navigator is not defined 3 | constructor( > 4 | @Inject(NAVIGATOR) private navigator: Navigator, | ^ 6 | ) {}
当前tsconfig配置
tsconfig.json
{ "compilerOptions": { "allowJs": true, "allowUnreachableCode": false, "allowUnusedLabels": false, "target": "es2015", "module": "ES2020", "moduleResolution": "node", "declaration": false, "removeComments": true, "noLib": false, "experimentalDecorators": true, "sourceMap": true, "pretty": true, "noImplicitAny": false, "noImplicitReturns": false, "noImplicitUseStrict": false, "noImplicitThis": false, "noFallthroughCasesInSwitch": true, "resolveJsonModule": true, "strictNullChecks": true, "strictPropertyInitialization": false, "strict": true, "skipLibCheck": true, "lib": [ "es6", "dom", "es2017" ], "typeRoots": [ "./src/types", "node_modules/@types" ], "types": [ "jest", "node" ], "baseUrl": "./src" }, "angularCompilerOptions": { "enableIvy": true }, "compileOnSave": true, "exclude": [ "node_modules", "dist", "assets", "translations" ] }
tsconfig.spec.json
{ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/spec", "module": "commonjs", "emitDecoratorMetadata": true, "types": [ "jest", "node" ] }, "files": [ "polyfills.ts" ], "include": [ "**/*.spec.ts", "**/*.d.ts" ] }
解决方案
1. 确保测试配置包含DOM类型库
Jest运行在Node环境,默认不提供DOM相关的全局类型。虽然主tsconfig.json包含了dom库,但测试配置可能未正确继承该设置。修改tsconfig.spec.json,在compilerOptions中显式添加dom库:
"compilerOptions": { "outDir": "../out-tsc/spec", "module": "commonjs", "emitDecoratorMetadata": true, "lib": ["es6", "dom", "es2017"], "types": [ "jest", "node" ] }
2. 在测试模块中模拟NAVIGATOR
Node环境没有真实的Navigator实例,必须在测试中提供模拟对象。示例测试代码如下:
import { TestBed } from '@angular/core/testing'; import { MyService } from './my.service'; import { NAVIGATOR } from './tokens'; describe('MyService', () => { let service: MyService; let mockNavigator: Partial<Navigator>; beforeEach(() => { // 按需模拟Navigator的属性和方法 mockNavigator = { userAgent: 'test-browser-agent', geolocation: { getCurrentPosition: jest.fn() } }; TestBed.configureTestingModule({ providers: [ MyService, { provide: NAVIGATOR, useValue: mockNavigator } ] }); service = TestBed.inject(MyService); }); it('should initialize successfully', () => { expect(service).toBeTruthy(); }); });
3. 切换到JSDOM测试环境(可选)
如果需要更完整的DOM环境支持,可以改用jest-environment-jsdom:
- 安装依赖:
npm install --save-dev jest-environment-jsdom
- 在
jest.config.js中配置测试环境:
module.exports = { testEnvironment: 'jsdom' };
内容的提问来源于stack exchange,提问作者Timothy
相关产品推荐
相关产品推荐

