155

Trying to setup vitest on an already existing vite (vue 3, typescript) project.

My vite.config.ts looks like this:

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  test: {
    globals: true,
    environment: 'jsdom',
  },
  plugins: [vue()],
});

But in VS code it complains:

vscode red lines under test prop

On hover I see:

Argument of type '{ test: { globals: boolean; environment: string; }; plugins: Plugin[]; }' is not assignable to parameter of type 'UserConfigExport'. Object literal may only specify known properties, and 'test' does not exist in type 'UserConfigExport'.ts(2345)

I can make it go away if I change this line:

import { defineConfig } from 'vite';

To:

import { defineConfig } from 'vitest/config';

But why? What's up with this? Why should I have to import defineConfig from vitest in order to get it to support the test property?

20 Answers 20

203

Short answer:

Because this is how TypeScript works. Vite config interface does not know anything about Vitest and TS does not allow excessive properties (properties not defined by the type/interface)

So Vitest must extend Vite config (defined as TS interface). In order to use this extended interface instead of the original one, you must first import it.

Instead of doing this (importing pure Vite config):

import { defineConfig } from 'vite';

do this (importing Vite config extended by Vitest):

import { defineConfig } from 'vitest/config';

Alternatively you can also use a TS triple slash command as documented in Configuring Vitest

/// <reference types="vitest/config" />
import { defineConfig } from 'vite'

export default defineConfig({
  test: {
    // ...
  },
})

If you are using Vitest version older than 2.1:

/// <reference types="vitest" />
Sign up to request clarification or add additional context in comments.

13 Comments

not working for me
Neither for me, but this answer did: stackoverflow.com/a/73106019/1408053
This worked for me after I upgraded vite to 4.0.4, and vitest to 0.26.3
I was already using the triple slash but didn't work. as @DavidHorm mentioned upgrading vite to 4.0.4 solved the issue for me :D
If it doesn't work, It's probably because vite and vitest are incompatible with each other. To verify this you can upgrade both libs to the latest version and see if the tsc error disappears. If that's the case you need to either upgrade vite or downgrade vitest
|
28

I separated the files because i got the from this question and if i changed the import to vitest i got another error in the plugin react line.

  • vite.config.ts
  • vitest.config.ts

vitest:

import { defineConfig } from 'vitest/config';

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

vite:

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

export default defineConfig({
  plugins: [react()],
  server: {
    port: 3000,
  },
})

3 Comments

This feels like the most elegant solution of the ones posted here.
Be aware that this means all options in your vite.config will be ignored by vitest.
I've tried this solution and besides the documentation says the vite.config options would be ignored everything is working properly here
26

We can use mergeConfig method from vite or vitest/config entries to merge Vite config with Vitest config:

import { defineConfig as defineViteConfig, mergeConfig } from 'vite';
import { defineConfig as defineVitestConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';

const viteConfig = defineViteConfig({
  plugins: [react()],
});

const vitestConfig = defineVitestConfig({
  test: {
    // ...
  },
});

export default mergeConfig(viteConfig, vitestConfig);

3 Comments

This works, makes sense, really wish we didn't have to do it, thanks for sharing!
This is the way, most elegant solution 👏
Thank you! This is indeed the most elegant approach.
24

Here is what I did in case someone is still looking for a solution. I created my own type and extended to UserConfig.

...
import type { InlineConfig } from 'vitest';
import type { UserConfig } from 'vite';

interface VitestConfigExport extends UserConfig {
  test: InlineConfig;
}
...

Then I casted the type of config object to my custom interface -

export default defineConfig({
  plugins: [solidPlugin()],
  server: {
    port: 3000,
  },
  test: {
    environment: 'jsdom',
    globals: true,
    transformMode: {
      web: [/\.[jt]sx?$/],
    },
    setupFiles: './setupVitest.ts',
  },
  build: {
    target: 'esnext',
  },
} as VitestConfigExport);

This also enabled intellisense for new test property. Also, you don't need to declare /// <reference types="vitest" />. It might help.

4 Comments

works with nuxt3, thanks
Note that using as means that type-checking is entirely circumvented and you won't get type errors if anything in your object structure is incorrect. Ideally, use satisfies.
So the documentation saying to use /// <reference ... is wrong?
stackoverflow.com/a/77229505/179332 seems much cleaner to me and works beautifully.
16

I was in a similar situation, asking me the same thing and end up doing this:

/// <reference types="vitest" />
import { defineConfig } from 'vite';
import type { UserConfig as VitestUserConfigInterface } from 'vitest/config';

const vitestConfig: VitestUserConfigInterface = {
  test: {
    // vitest config, with helpful vitest typing :)
  }
};

export default defineConfig({
  test: vitestConfig.test,
  // and now: just vite config
});

It may be helpful.

2 Comments

This fails for me with typescript 5.6.2, vite 4.2.0, vitest 2.1.1. Gives error on the test: vitestConfig.test line.
7

sunny prakash solution is quite good, but it allow wrong type in config due to as VitestConfigExport construction.

Better way is to move config to separate constant and use it

import type { InlineConfig } from 'vitest';
import type { UserConfig } from 'vite';

type ViteConfig = UserConfig & { test: InlineConfig };
const config: ViteConfig = {
  // other config
  test: {
    environment: 'jsdom',
  },
};
export default defineConfig(config);

1 Comment

In new version import the InlineConfig from 'vitest/node'
7

I had a similar issue that was resolved by using a version of vitest and vite that were compatible. In my case the latest version of each. I assume using versions that were released around the same time frame would work as well.

yarn install -D vitest vite

Comments

7

as 2024 you can just import vitest/config which pulls the extended types automatically

import {defineConfig} from "vite";
import "vitest/config" // <-- just dummy import

export default defineConfig({
  test: {
    // your stuff here
  }
})

8 Comments

If this is legit then why isn't it documented in vitest.dev/guide/#adding-vitest-to-your-project ?
It literally is The <reference types="vitest" /> will stop working in Vitest 3, but you can start migrating to vitest/config in Vitest 2.1:
No, I'm referring to the fact that the import "vitest/config" dummy import is not mentioned anywhere in that guide.
Also I tried it, and it didn't work for me.
thats what I'm refering to start migrating to vitest/config. If you post a question with your configuration I can help you make it work. Include TS version, Vite version and Vetest version too please
|
5

Replacing the function with an arrow function worked for me. Mentioned at https://github.com/vitest-dev/vitest/discussions/1106#discussioncomment-2531279

export default defineConfig(() => ({
  build: {
    // ...
  },
  test: {
    // ...
  },
}));

Comments

4

None of the options listed above helped me. Eventually, I've managed to solve this issue using the type augmentation feature:

import type { UserConfig as VitestUserConfig } from 'vitest/config';
import { defineConfig } from 'vite';

declare module 'vite' {
  export interface UserConfig {
    test: VitestUserConfig['test'];
  }
}

export default defineConfig({
  // add your vite configuration here

  test: {
    // add your vitest configuration here
  },
});

Comments

2

TLDR

Assert your config object's type as UserConfig (see last line):

import { defineConfig, UserConfig } from 'vite'

export default defineConfig({
    // your vite config
    test: {
        environment: 'jsdom',
        setupFiles: 'src/setup-tests.tsx',
        coverage: {...},
    },
} as UserConfig)

Explaination

The other answers here either did not work, or were to complex for me to want to even try.

Eventually, after extending UserConfig in a few variations of this:

declare module 'vite' { interface UserConfig... }

I realized that the error wasn't complaining about UserConfig, but UserConfigExport:

Object literal may only specify known properties, and test does not exist in type 'UserConfigExport'

So that's why it wasn't taking - defineConfig is overloaded with 4 signatures, and typescript for some reason was matching my invocation to the fourth option shown here, rather than the first.

declare function defineConfig(config: UserConfig): UserConfig;
declare function defineConfig(config: Promise<UserConfig>): Promise<UserConfig>;
declare function defineConfig(config: UserConfigFnObject): UserConfigFnObject;
declare function defineConfig(config: UserConfigExport): UserConfigExport;

That is, it didn't matter how I extended UserConfig through a global module definition, or how or where I included the triple-slash reference directive suggested in the docs (which as far as I understand it basically does the same thing), because my config object wasn't being typed as a UserConfig at all!

Once I realized that, I tried the type assertion and all was well. No custom module declarations, not triple-slash reference at the top of the file - just the type assertion.

Comments

2

Short Answer:

If you're encountering type errors when using vite and vitest in your vite.config.ts file, it's likely due to incompatible types between the defineConfig functions from vite and vitest/config.

Here's how I resolved the issue:

import { defineConfig as testConfig } from "vitest/config";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// Vite configuration
const config = defineConfig({
  plugins: [vue()],
});

// Vitest configuration
const tstConfig = testConfig({
  test: {
    environment: "jsdom",
  },
});

// Merge configurations
export default {
  ...config,
  ...tstConfig,
};

  • Separate Configurations: By defining config and tstConfig separately and then merging them, you avoid type conflicts between vite and vitest.

This approach should resolve the type errors and allow you to use both vite and vitest configurations.

1 Comment

this worked for me - the accepted answer did not
1

The above method doesn't work for me, then I try this, It work.

/// <reference types="vitest" />
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx'; // 支持jsx语法

// https://vitejs.dev/config/
export default defineConfig(() => {
  return {
    plugins: [vue(), vueJsx()],
    test: {
      globals: true,
      environment: 'jsdom',
      transformMode: { web: [/.[tj]sx$/] },
    },
  };
});

Comments

1

You have to update your tsconfig.json file so that it:

  1. includes the vite.config.ts file
  2. included types from vite even if not imported in any file

tsconfig.json

{
   "compilerOptions": {
      "types": [
         "vitest"
     ],  
  },
  "include": [
    "src",
    "vite.config.ts"
  ]
}

vite.config.ts

import { defineConfig } from 'vite';

export default defineConfig({
  ...
  test: {
     ...
  },
});

1 Comment

December 2024: with vite v6.0.1, vitest: v2.1.8, with TS. I can confirm that's working.
1

My solution

vite.config.ts

import { defineConfig } from "vitest/config"
import tsConfigPaths from "vitest-tsconfig-paths"

export default defineConfig({
  plugins: [tsConfigPaths()],
  test: {
    globals: true,
  },
})

update your file tsconfig.json inserting following lines below.

tsconfig.json

{
  "baseUrl": "./",
  "paths": {
    "@/*": ["./src/*"]
  },
  "types": ["vitest/globals"]
}

Comments

0

It might be because you have multiple versions of vite installed. Search in your package-lock or yarn-lock file to find the entries for vite, and make sure there's only one of them. After that, I got it to work using the triple-slash.

Comments

0

This works for me and it's clean imo.

import { defineConfig } from 'vite';
import type { UserConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';

const config: UserConfig = {
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
  },
};

// https://vitejs.dev/config/
export default defineConfig(config);

2 Comments

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
Fails for me with vite 4.2.0, vitest 2.1.1.
0

Here's a more minimal approach than existing answers (using typescript 5.7.2, vite 6.0.3, and vitest 2.1.8/3.0.0-beta.2):

import type { UserConfig } from 'vite'
import type { UserConfig as VitestConfig } from 'vitest/node'

export default {
    // ...vite config...
    test: {
        // ...vitest config...
    }
} as UserConfig & { test: VitestConfig }

(Note: vite's UserConfig is documented, but vitest's UserConfig doesn't seem to be documented -- so possibly this may not continue to work in later releases of vitest)

2 Comments

Vitest 2.1.7 reverted support for Vite 6: github.com/vitest-dev/vitest/releases/tag/v2.1.7. The first version of Vitest to support Vite 6 will be Vitest 3: github.com/vitest-dev/vitest/releases/tag/v3.0.0-beta.1
Ah yes good point. Though it does actually still work, at least in my case. Updating the answer, thanks.
0

As someone mentioned, what worked for me was to install compatible versions of vite and vitest. When I typed the npm ls vite command, I realized there were different versions of vite, so I installed the specific version that vitest installed and I no longer get the error. If this is not a good solution, please let me know.

Comments

-2

I had a similar issue with my project, but after adding /// <reference types="vitest" /> this line at the top of the file, the error is gone.

/// <reference types="vitest" />
import { defineConfig } from 'vite';

export default defineConfig({
  ...
  test: {
   ...
  },
});

1 Comment

This comment brings no value. It's the same as what the previous post states as an alternative option, and it is apparent from the comments bellow it that for some it works and for some, it doesn't.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.