Vite test error cannot be imported in a CommonJS module using require()
sbland opened this issue · comments
Describe the bug
I'm trying to create a setup test files for vite in a custom react environment with some mocked modules. Unfortunately when running the tests I get an error related to Vitest cannot be imported in a CommonJS module using require()
Full error:
FAIL myorg/node-search.spec.tsx [ myorg/node-search.spec.tsx ]
Error: Vitest cannot be imported in a CommonJS module using require(). Please use "import" instead.
If you are using "import" in your source code, then it's possible it was bundled into require() automatically by your bundler. In that case, do not bundle CommonJS output since it will never work with Vitest, or use dynamic import() which is available in all CommonJS modules.
❯ Object.<anonymous> node_modules/.pnpm/vitest@1.4.0_@types+node@18.19.26_jsdom@23.2.0_sass@1.72.0/node_modules/vitest/index.cjs:1:7
❯ vi myorg/envs/react-env-custom/setup/setup-tests.tsx:1:1
❯ myorg/envs/react-env-custom/setup/setup-tests.tsx:6:1
Steps to Reproduce
react-env-custom.bit-env.ts
tester(): EnvHandler<Tester> {
return VitestTester.from({
config: require.resolve('./config/vitest.config.mjs'),
});
}
vitetest.config.mjs
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const setupPathName = require.resolve('../setup/setup-tests.js');
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: [setupPathName],
},
});
setup-tests.ts
import { vi } from 'vitest'
import '@testing-library/jest-dom'
vi.mock('@my-org.mockme', () => ({
__esModule: true,
default: () => ({
get: (k) =>
({
port: 100
}[k]),
}),
}));
Running a test with the above setup results in the error below:
FAIL cam/collect-and-map/core/node-search/node-search.spec.tsx [ cam/collect-and-map/core/node-search/node-search.spec.tsx ]
Error: Vitest cannot be imported in a CommonJS module using require(). Please use "import" instead.
If you are using "import" in your source code, then it's possible it was bundled into require() automatically by your bundler. In that case, do not bundle CommonJS output since it will never work with Vitest, or use dynamic import() which is available in all CommonJS modules.
❯ Object.<anonymous> node_modules/.pnpm/vitest@1.4.0_@types+node@18.19.26_jsdom@23.2.0_sass@1.72.0/node_modules/vitest/index.cjs:1:7
❯ vi cam/envs/react-env-custom/setup/setup-tests.tsx:1:1
❯ cam/envs/react-env-custom/setup/setup-tests.tsx:6:1
Specifications
- Bit version:
1.6.2
- Workspace type: harmony
- Node version:
v18.19.1
- npm / yarn version:
v10.2.4
- Platform:
ubuntu
for harmony workspace
- relevant env: custom env from
@teambit/react.react-env
this is likely a CJS<>ESM issue, as the compilation type from teambit/react
is CJS.
i recommend basing your custom env on @bitdev/react.react-env
instead (just add that depenency, and change you import statement). this env adds type:module
and such, so target is esm.
https://bit.cloud/bitdev/react/react-env
Thanks @itaymendel but no luck. I also tried adding esm: true
to the compiler. Full env file below:
/**
* this env uses bitdev.react/react-env
* to inspect its config @see https://bit.cloud/bitdev/react/react-env
*/
import { ReactEnv } from '@bitdev/react.react-env';
import typescript from 'typescript';
import { TypeScriptExtractor } from '@teambit/typescript';
import { SchemaExtractor } from '@teambit/schema';
import { Compiler } from '@teambit/compiler';
import { ReactPreview } from '@teambit/preview.react-preview';
import { EnvHandler } from '@teambit/envs';
import { Pipeline } from '@teambit/builder';
import { ESLint as ESLintLib } from 'eslint';
import {
TypescriptCompiler,
resolveTypes,
TypescriptTask,
} from '@teambit/typescript.typescript-compiler';
import { ESLintLinter, EslintTask } from '@teambit/defender.eslint-linter';
// import { JestTester, JestTask } from '@teambit/defender.jest-tester';
import { VitestTester, VitestTask } from '@teambit/vite.vitest-tester';
import { PrettierFormatter } from '@teambit/defender.prettier-formatter';
import { Tester } from '@teambit/tester';
import { Preview } from '@teambit/preview';
import hostDependencies from './preview/host-dependencies.js';
import { webpackTransformer } from './config/webpack.config.js';
export class ReactEnvCustom extends ReactEnv {
/**
* name of the environment. used for friendly mentions across bit.
*/
name = 'react-env-custom';
/**
* create an instance of a Bit Component Compiler.
* Learn more: https://bit.dev/reference/compiling/set-up-compiler
*/
compiler(): EnvHandler<Compiler> {
return TypescriptCompiler.from({
esm: true,
tsconfig: this.tsconfigPath,
types: resolveTypes(__dirname, [this.tsTypesPath]),
typescript,
});
}
/**
* returns an instance of the default TypeScript extractor.
* used by default for type inference for both JS and TS.
*/
schemaExtractor(): EnvHandler<SchemaExtractor> {
return TypeScriptExtractor.from({
tsconfig: this.tsconfigPath,
});
}
/**
* create an instance of the Bit Tester plugin.
* learn more: https://bit.dev/reference/testing/set-up-tester
*/
// Vitetest not working
tester(): EnvHandler<Tester> {
return VitestTester.from({
config: require.resolve('./config/vitest.config.mjs'),
});
}
// tester(): EnvHandler<Tester> {
// return JestTester.from({
// config: require.resolve('./config/jest.config.js'),
// });
// }
/**
* add a Bit Linter plugin.
* learn more: https://bit.dev/reference/testing/set-up-tester
*/
linter() {
return ESLintLinter.from({
tsconfig: this.tsconfigPath,
eslint: ESLintLib,
configPath: this.eslintConfigPath,
pluginsPath: __dirname,
extensions: this.eslintExtensions,
});
}
/**
* create a formatter instance.
* learn more: https://bit.dev/reference/formatting/set-up-formatter
*/
formatter() {
return PrettierFormatter.from({
configPath: require.resolve('./config/prettier.config.js'),
});
}
/**
* create an instance for Bit Preview.
*/
preview(): EnvHandler<Preview> {
return ReactPreview.from({
// TODO: Add webpack here
transformers: [
webpackTransformer,
],
mounter: this.previewMounter,
hostDependencies,
});
}
/**
* Add your build pipeline.
* learn more: https://bit.dev/docs/react-env/build-pipelines
*/
build() {
return Pipeline.from([
TypescriptTask.from({
tsconfig: this.tsconfigPath,
types: resolveTypes(__dirname, [this.tsTypesPath]),
typescript,
}),
EslintTask.from({
eslint: ESLintLib,
tsconfig: this.tsconfigPath,
configPath: this.eslintConfigPath,
pluginsPath: __dirname,
extensions: this.eslintExtensions,
}),
VitestTask.from({
config: require.resolve('./config/vitest.config.mjs'),
}),
// JestTask.from({
// config: this.jestConfigPath,
// }),
]);
}
protected tsconfigPath = require.resolve('./config/tsconfig.json');
protected tsTypesPath = './types';
protected jestConfigPath = require.resolve('./config/jest.config');
protected eslintConfigPath = require.resolve('./config/eslintrc.js');
protected eslintExtensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs'];
protected prettierConfigPath = require.resolve('./config/prettier.config.js');
protected prettierExtensions = [
'.js',
'.jsx',
'.ts',
'.tsx',
'.mjs',
'.cjs',
'.json',
'.css',
'.scss',
'.md',
'.mdx',
'.html',
'.yml',
'.yaml',
];
protected previewMounter = require.resolve('./preview/mounter');
}
export default new ReactEnvCustom();
@sbland sorry for the trouble. You can try to rename the setup-tests.ts
into setup-tests.mjs
to keep it in ESM. Then it would work. The reason behind is all the ts files in an env will be transpiled into CJS by default. So by renaming it into .mjs
, you can bypass it. I've tried it locally, it worked as expected after that. Thanks.