Angular中Jest单元测试如何模拟__webpack_public_path__变量
问题:Angular测试中模拟__webpack_public_path__失败
场景重现
组件代码:
import { Component } from '@angular/core'; import { getImageUrl } from '../../shared/get-image-url'; @Component({ selector: 'ice-section-banner-invite-client', templateUrl: './section-banner-invite-client.component.html', styleUrls: ['./section-banner-invite-client.component.scss'], }) export class IceSectionBannerInviteClient { public loading = false; public imageUrl = `url(${getImageUrl('assets/images/banner-criar-conta.png')})`; constructor() { console.log(this.imageUrl); } public clickInviteClient(): void { window.open(`${document.location.origin}${'/br-iceberg/invitations'}`); } }
工具函数代码:
export function getImageUrl(imageName: string) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error // eslint-disable-next-line camelcase let publicPath: string = __webpack_public_path__; publicPath = publicPath.endsWith('/') ? publicPath.slice(0, -1) : publicPath; return `${publicPath}/${imageName}`; }
测试文件代码:
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { OnDashboardModule } from '@onviobr/dashboard'; import { TranslateTestingModule } from 'ngx-translate-testing'; import { IceSectionBannerInviteClient } from './section-banner-invite-client.component'; describe('IceSectionBannerInviteClient', () => { let component: IceSectionBannerInviteClient; let fixture: ComponentFixture<IceSectionBannerInviteClient>; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [IceSectionBannerInviteClient], imports: [ OnDashboardModule, TranslateTestingModule.withTranslations({}), RouterTestingModule.withRoutes([]), HttpClientTestingModule, ], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(IceSectionBannerInviteClient); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); });
运行测试时报错:
IceSectionBannerInviteClient › should create ReferenceError: __webpack_public_path__ is not defined
已尝试的无效操作:
- 在spec文件中配置
providers: [{ provide: __webpack__public__path__, useValue: 'teste' }], - 在spec文件中执行
process.env = Object.assign(process.env, { __webpack__public__path__: 'teste' }); - 在spec文件中执行
process.env.__webpack__public__path__ = 'teste'; - 在jest.config.js中执行
process.env = Object.assign(process.env, { __webpack__public__path__: 'teste' }); - 在jest.config.js中设置
globals: {__webpack__public__path__: 'value',} - 在jest.config.js中配置
jest: { setupFiles: ['<rootDir>/setup.js'] },并在setup.js中添加process.env.__webpack__public__path__ = 'value';
另外使用process.env时提示Cannot find name 'process'.,但tsconfig已配置"compilerOptions": { "types": ["node"] }。
解决方案
方案1:在测试文件中直接声明并赋值全局变量
在测试文件的所有import之后、describe之前添加以下代码:
// 声明全局变量,解决TS类型报错 declare global { var __webpack_public_path__: string; } // 给变量赋值模拟路径 __webpack_public_path__ = '/test-public-path/';
测试运行时,getImageUrl函数就能获取到这个全局变量的值,不会抛出未定义错误。
方案2:Mock工具函数绕过依赖
如果测试只需要验证组件能否正常创建,不需要测试getImageUrl的逻辑,可以直接mock这个函数:
import { getImageUrl } from '../../shared/get-image-url'; // 在describe之前mock工具函数 jest.mock('../../shared/get-image-url', () => ({ getImageUrl: jest.fn(() => '/test-path/assets/images/banner-criar-conta.png') })); describe('IceSectionBannerInviteClient', () => { // 原有测试代码保持不变 });
这种方式直接跳过__webpack_public_path__的依赖,专注于组件本身的测试逻辑。
方案3:修复process.env的TS类型问题(若坚持用环境变量方案)
- 确保
tsconfig.spec.json中也添加了node和jest类型:
{ "compilerOptions": { "types": ["node", "jest"] } }
- 创建
setup-jest.ts文件并添加:
(global as any).__webpack_public_path__ = process.env.WEBPACK_PUBLIC_PATH || '/default-path/';
- 在
jest.config.js中配置:
module.exports = { setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'], // 其他现有配置... };
内容的提问来源于stack exchange,提问作者Beatriz Rachel
相关产品推荐
相关产品推荐

