Skip to content

Commit 64648fe

Browse files
committed
feat(vitest): add Vite plugin for Svelte browser import and autocleanup
1 parent cb9fc3a commit 64648fe

File tree

5 files changed

+92
-11
lines changed

5 files changed

+92
-11
lines changed

package.json

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
},
1515
"./vitest": {
1616
"default": "./src/vitest.js"
17+
},
18+
"./vite-plugin": {
19+
"types": "./src/vite-plugin.d.ts",
20+
"default": "./src/vite-plugin.js"
1721
}
1822
},
1923
"type": "module",

src/__tests__/_vitest-setup.js

-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
import '@testing-library/jest-dom/vitest'
2-
import '../vitest'

src/vite-plugin.js

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { dirname, join } from 'node:path'
2+
import { fileURLToPath } from 'node:url'
3+
4+
/**
5+
* Vite plugin to configure @testing-library/svelte.
6+
*
7+
* Ensures Svelte is imported correctly in tests
8+
* and that the DOM is cleaned up after each test.
9+
*
10+
* @param {{resolveBrowser?: boolean, autoCleanup?: boolean}} options
11+
* @returns {import('vite').Plugin}
12+
*/
13+
export const svelteTesting = ({
14+
resolveBrowser = true,
15+
autoCleanup = true,
16+
} = {}) => ({
17+
name: 'vite-plugin-svelte-testing-library',
18+
config: (config) => {
19+
if (!process.env.VITEST) {
20+
return
21+
}
22+
23+
if (resolveBrowser) {
24+
addBrowserCondition(config)
25+
}
26+
27+
if (autoCleanup) {
28+
addAutoCleanup(config)
29+
}
30+
},
31+
})
32+
33+
/**
34+
* Add `browser` to `resolve.conditions` before `node`.
35+
*
36+
* This ensures that Svelte's browser code is used in tests,
37+
* rather than its SSR code.
38+
*
39+
* @param {import('vitest/config').UserConfig} config
40+
*/
41+
const addBrowserCondition = (config) => {
42+
const resolve = config.resolve ?? {}
43+
const conditions = resolve.conditions ?? []
44+
const nodeConditionIndex = conditions.indexOf('node')
45+
const browserConditionIndex = conditions.indexOf('browser')
46+
47+
if (
48+
nodeConditionIndex >= 0 &&
49+
(nodeConditionIndex < browserConditionIndex || browserConditionIndex < 0)
50+
) {
51+
conditions.splice(nodeConditionIndex, 0, 'browser')
52+
}
53+
54+
resolve.conditions = conditions
55+
config.resolve = resolve
56+
}
57+
58+
/**
59+
* Add auto-cleanup file to Vitest's setup files.
60+
*
61+
* @param {import('vitest/config').UserConfig} config
62+
*/
63+
const addAutoCleanup = (config) => {
64+
const test = config.test ?? {}
65+
const setupFiles = test.setupFiles ?? []
66+
67+
setupFiles.push(join(dirname(fileURLToPath(import.meta.url)), './vitest.js'))
68+
69+
test.setupFiles = setupFiles
70+
config.test = test
71+
}

types/vite-plugin.d.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { Plugin } from 'vite'
2+
3+
/**
4+
* Vite plugin to configure @testing-library/svelte.
5+
*
6+
* Ensures Svelte is imported correctly in tests
7+
* and that the DOM is cleaned up after each test.
8+
*/
9+
export function svelteTesting(options?: {
10+
resolveBrowser?: boolean
11+
autoCleanup?: boolean
12+
}): Plugin

vite.config.js

+5-10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { svelte } from '@sveltejs/vite-plugin-svelte'
44
import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
55
import { defineConfig } from 'vite'
66

7+
import { svelteTesting } from './src/vite-plugin.js'
8+
79
const IS_SVELTE_5 = SVELTE_VERSION >= '5'
810

911
const alias = [
@@ -17,15 +19,8 @@ const alias = [
1719
]
1820

1921
// https://vitejs.dev/config/
20-
export default defineConfig(({ mode }) => ({
21-
plugins: [svelte({ hot: false })],
22-
resolve: {
23-
// Ensure `browser` exports are used in tests
24-
// Vitest prefers modules' `node` export by default
25-
// Svelte's `node` export is its SSR bundle, which does not have onMount
26-
// https://github.com/testing-library/svelte-testing-library/issues/222#issuecomment-1909993331
27-
conditions: mode === 'test' ? ['browser'] : [],
28-
},
22+
export default defineConfig({
23+
plugins: [svelte({ hot: false }), svelteTesting()],
2924
test: {
3025
alias,
3126
environment: 'jsdom',
@@ -37,4 +32,4 @@ export default defineConfig(({ mode }) => ({
3732
include: ['src'],
3833
},
3934
},
40-
}))
35+
})

0 commit comments

Comments
 (0)