Reputation: 6552
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:
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?
Upvotes: 136
Views: 73288
Reputation: 11
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"]
}
Upvotes: 1
Reputation: 700
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,
};
vite
and vitest
.This approach should resolve the type errors and allow you to use both vite
and vitest
configurations.
Upvotes: 2
Reputation: 1
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.
Upvotes: 0
Reputation: 2598
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)
Upvotes: 0
Reputation: 37903
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 Managing Vitest config file
/// <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" />
Upvotes: 179
Reputation: 10576
You have to update your tsconfig.json
file so that it:
vite.config.ts
filetsconfig.json
{
"compilerOptions": {
"types": [
"vitest"
],
},
"include": [
"src",
"vite.config.ts"
]
}
vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
...
test: {
...
},
});
Upvotes: 1
Reputation: 1
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);
Upvotes: 0
Reputation: 301
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)
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.
Upvotes: 1
Reputation: 2151
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
}
})
Upvotes: 7
Reputation: 892
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
Upvotes: 7
Reputation: 529
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: {
// ...
},
}));
Upvotes: 5
Reputation: 500
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
},
});
Upvotes: 3
Reputation: 3550
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);
Upvotes: 20
Reputation: 11
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$/] },
},
};
});
Upvotes: 1
Reputation: 465
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.
Upvotes: 0
Reputation: 95
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: {
...
},
});
Upvotes: -2
Reputation: 630
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);
Upvotes: 7
Reputation: 341
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.
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,
},
})
Upvotes: 26
Reputation: 870
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.
Upvotes: 23
Reputation: 367
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.
Upvotes: 16