teambit / bit

A build system for development of composable software.

Home Page:https://bit.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.