Search code examples
node.jsvitetsconfigvitest

vitest Failed to load url using vite-tsconfig-paths


I am trying to add vitest to my frontend, but have trouble setting up the paths. The frontend runs fine when running vite, but for some reason custom paths fail when running vitest.

 FAIL  |front-admin| src/pages/admin/index.test.tsx [ frontend/apps/admin/src/pages/admin/index.test.tsx ]
Error: Failed to load url ~/schema (resolved id: ~/schema) in /..../frontend/apps/admin/src/pages/admin/Update.tsx. Does the file exist?
 ❯ loadAndTransform ../../../node_modules/vitest/node_modules/vite/dist/node/chunks/dep-R0I0XnyH.js:49376:21

I am using vite and vitest on an npm workspace, and my files look like this:
vitest.workspace.ts

import { defineWorkspace } from 'vitest/config'
// @vitest-environment node
export default defineWorkspace([
  // you can use a list of glob patterns to define your workspaces
  // Vitest expects a list of config files
  // or directories where there is a config file
  'frontend/apps/*/vite.config.ts',
  // you can even run the same tests,
  // but with different configs in the same "vitest" process
  {
    test: {
      name: 'front-admin',
      root: './frontend/apps/admin',
      environment: 'node',
      setupFiles: ['./vitest.config.ts'],
    },
  },
  {
    test: {
      name: 'front-company',
      root: './frontend/apps/company',
      environment: 'node',
      setupFiles: ['./vitest.config.ts'],
    },
  },
])

frontend/apps/admin/vite.config.ts

import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react(), tsconfigPaths()],
  server: { port: 5173 },
  optimizeDeps: {
    exclude: ['prisma/factories'],
  },
})

frontend/apps/admin/vitest.config.ts

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    globals: true,
    environment: 'node'
  },
})

frontend/apps/admin/tsconfig.json

{
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": true,
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "allowJs": false,
    "skipLibCheck": true,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "baseUrl": "./src",
    "paths": {
      "~/*": ["./*"]
    }
  },
  "include": ["src", "index.html"],
  "references": [{ "path": "./tsconfig.node.json" }],
  "exclude": ["node_modules"]
}

frontend/apps/admin/src/pages/Update.tsx

import { tokenInput } from '~/schema' // all other imports that rely on tsconfig fail as well

i tried adding and removing aliases from vite config, but it had no effect

export default defineConfig({
  ...
  resolve: {
    alias: {
      '~/': path.join(__dirname, 'src/'),
    },
  },
})

Solution

  • I am not sure if that is what caused the issue, but vitest.workspace.ts was testing the same repository twice.

      // testing the first time
      'frontend/apps/*/vite.config.ts',
    
      // testing the second time
      {
        test: {
          name: 'front-admin',
          root: './frontend/apps/admin',
          environment: 'node',
          setupFiles: ['./vitest.config.ts'],
        },
      },
    

    I didnt understand from the documentation, but the way the workspace file works is that you can either call a vitest file from vitest.workspace (first method), or directly set the settings from vitest.workspaces without having to create a vitest file in the root of the app.
    vitest.workspace.ts

    import { defineWorkspace } from 'vitest/config'
    // @vitest-environment node
    export default defineWorkspace([
      // you can use a list of glob patterns to define your workspaces
      // Vitest expects a list of config files
      // or directories where there is a config file
      'frontend/apps/*/vitest.config.ts',
      // you can even run the same tests,
      // but with different configs in the same "vitest" process
      // test: { ... } is optional
    ])
    

    frontend/apps/admin/vitest.config.ts

    import { defineConfig } from 'vitest/config'
    
    export default defineConfig({
      test: {
        globals: true,
        name: 'front-admin',
        root: './src',
        environment: 'happy-dom',
        setupFiles: ['./src/utils/vitest-setup.ts'],
      },
    })