我们的项目是一个React和TypeScript项目,首先使用React App Rewired制作,但现在迁移到Vite。
我一直致力于让 Jest 工作(在尝试使用 Vitest 后,我遇到了完全不同的问题)。我现在遇到的问题是它给了我这个错误消息:
Test suite failed to run
TypeError: Cannot read properties of undefined (reading 'VITE_HOST')
其中
VITE_HOST
在我们的.test.env
文件中定义如下:
VITE_HOST="http://localhost:3000"
我正在运行的脚本如下:
"test": "dotenv -e ./src/environments/.env.test jest --testResultsProcessor --detectOpenHandles --bail",
我已经通过这样做测试了
.env
文件是否正在加载:
dotenv -e ./src/environments/.env.test node -e
// Followed by:
console.log(process.env)
实际上正确记录了所有环境变量。
我的
jest.config.js
看起来像这样:
/** @type {import('ts-jest').JestConfigWithTsJest} **/
module.exports = {
testEnvironment: 'jest-environment-jsdom',
transform: {
'^.+\\.m?[tj]sx?$': [
'ts-jest',
{
moduleNameMapper: {
'\\.(css|less|scss|sass)$': '<rootDir>/__mocks__/styleMock.js',
'\\.(gif|ttf|eot|svg|png)$': '<rootDir>/__mocks__/fileMock.js',
'@testing-library/jest-dom/extend-expect':
'@testing-library/jest-dom',
},
transformIgnorePatterns: ['node_modules/(?!variables/.*)'],
useESM: true,
babelConfig: true,
diagnostics: {
ignoreCodes: [1343],
},
astTransformers: {
before: [
{
path: 'node_modules/ts-jest-mock-import-meta',
options: {
metaObjectReplacement: { url: 'https://www.url.com' },
},
},
],
},
},
],
},
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
setupFiles: ['dotenv/config'],
maxWorkers: 1,
moduleNameMapper: {
'\\.(css|less|scss|sass)$': '<rootDir>/__mocks__/styleMock.js',
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/__mocks__/fileMock.js',
'@testing-library/jest-dom/extend-expect': '@testing-library/jest-dom',
},
};
为了获取环境变量,我们有一个执行以下操作的函数:
export const getProcessEnv = (key: string): ProcessEnv =>
new ProcessEnv(key, import.meta.env[key]);
export class ProcessEnv {
constructor(public name: string, public rawValue: string | undefined) {}
然后在我们的
environment.ts
文件中使用它,如下所示:
import { getProcessEnv } from '../utils/environmentValidator';
const allowedEnvironmentTypes = [
'local',
'staging',
'production',
'test',
] as const;
export const ENV = {
HOST: getProcessEnv('VITE_HOST').asString(''),
之后我们使用导出的
ENV
const 中的环境变量。然而,即使只是做 import.meta.env.VITE_HOST
也不起作用。显然,它不应该返回“未定义”。
Vite使用
import.meta.env
访问环境变量,这些变量在构建时静态替换。
另一方面,Jest 在通常使用
Node.js
的 process.env
环境中运行。
由于您在
import.meta.env.VITE_HOST
函数中使用了 getProcessEnv
,因此它不适用于 Jest,因为 Jest 不理解 import.meta.env
。
修改
getProcessEnv
函数以同时检查 import.meta.env
和 process.env
。这样,它就可以在 Vite 和 Jest 环境中无缝运行:
export const getProcessEnv = (key: string): ProcessEnv => {
const value = import.meta.env[key] || process.env[key];
return new ProcessEnv(key, value);
};
export class ProcessEnv {
constructor(public name: string, public rawValue: string | undefined) {}
asString(defaultValue: string): string {
return this.rawValue ?? defaultValue;
}
}
通过结合对 Vite 配置的更新和调整 getProcessEnv 函数,您可以确保在 Vite 和 Jest 环境中一致地访问环境变量。
还可以通过添加测试用例来验证 process.env.VITE_HOST 是否可以在 Jest 中访问:
test('Environment variable VITE_HOST is defined', () => {
expect(process.env.VITE_HOST).toBeDefined();
});
如果通过,问题确实与 Jest 中无法访问 import.meta.env 有关。
要使环境变量在整个项目中可作为
process.env
访问,请更新您的 vite.config.ts,如下所示:
import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react-swc';
import checker from 'vite-plugin-checker';
import tsconfigPaths from 'vite-tsconfig-paths';
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '');
return {
plugins: [
react(),
tsconfigPaths(),
checker({
typescript: true,
eslint: {
lintCommand: 'eslint "./src/**/*.{ts,tsx}"',
},
}),
],
define: {
'process.env': JSON.stringify(env), // Makes all env variables available globally
},
build: {
outDir: 'build',
sourcemap: true,
chunkSizeWarningLimit: 1000,
},
};
});
此设置确保 process.env.VITE_HOST 和其他环境变量在 Vite 构建的代码和 Jest 测试中都可用。