Skip to content

Commit

Permalink
feat(vitest): add Vite plugin for Svelte browser import and autoclean…
Browse files Browse the repository at this point in the history
…up (#362)

Closes #359
  • Loading branch information
mcous committed Apr 24, 2024
1 parent cb9fc3a commit ed541de
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 21 deletions.
37 changes: 30 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<p>Simple and complete Svelte testing utilities that encourage good testing practices.</p>

[**Read The Docs**](https://testing-library.com/docs/svelte-testing-library/intro) |
[Edit the docs](https://github.com/alexkrolick/testing-library-docs)
[Edit the docs](https://github.com/testing-library/testing-library-docs)

<!-- prettier-ignore-start -->
[![Build Status][build-badge]][build]
Expand Down Expand Up @@ -80,19 +80,42 @@ This library has `peerDependencies` listings for `svelte >= 3`.
You may also be interested in installing `@testing-library/jest-dom` so you can use
[the custom jest matchers](https://github.com/testing-library/jest-dom).

## Setup

We recommend using `@testing-library/svelte` with [Vitest][] as your test runner. To get started, add the `svelteTesting` plugin to your Vite or Vitest config.

```diff
// vite.config.js
import { svelte } from '@sveltejs/vite-plugin-svelte'
+ import { svelteTesting } from '@testing-library/svelte/vite'

export default defineConfig({
plugins: [
svelte(),
+ svelteTesting(),
]
});
```

See the [setup docs][] for more detailed setup instructions, including for other test runners like Jest.

[vitest]: https://vitest.dev/
[setup docs]: https://testing-library.com/docs/svelte-testing-library/setup

### Svelte 5 support

If you are riding the bleeding edge of Svelte 5, you'll need to either
import from `@testing-library/svelte/svelte5` instead of `@testing-library/svelte`, or have your `vite.config.js` contains the following alias:
import from `@testing-library/svelte/svelte5` instead of `@testing-library/svelte`, or add an alias to your `vite.config.js`:

```
export default defineConfig(({ }) => ({
```js
export default defineConfig({
plugins: [svelte(), svelteTesting()],
test: {
alias: {
'@testing-library/svelte': '@testing-library/svelte/svelte5'
}
'@testing-library/svelte': '@testing-library/svelte/svelte5',
},
},
}))
})
```

## Docs
Expand Down
22 changes: 19 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
},
"./vitest": {
"default": "./src/vitest.js"
},
"./vite": {
"types": "./types/vite.d.ts",
"default": "./src/vite.js"
}
},
"type": "module",
Expand Down Expand Up @@ -43,8 +47,10 @@
"e2e"
],
"files": [
"src/",
"types/index.d.ts"
"src",
"types",
"!*.test-d.ts",
"!__tests__"
],
"scripts": {
"toc": "doctoc README.md",
Expand All @@ -68,7 +74,17 @@
"contributors:generate": "all-contributors generate"
},
"peerDependencies": {
"svelte": "^3 || ^4 || ^5"
"svelte": "^3 || ^4 || ^5",
"vite": "*",
"vitest": "*"
},
"peerDependenciesMeta": {
"vite": {
"optional": true
},
"vitest": {
"optional": true
}
},
"dependencies": {
"@testing-library/dom": "^9.3.1"
Expand Down
1 change: 0 additions & 1 deletion src/__tests__/_vitest-setup.js
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
import '@testing-library/jest-dom/vitest'
import '../vitest'
75 changes: 75 additions & 0 deletions src/vite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'

/**
* Vite plugin to configure @testing-library/svelte.
*
* Ensures Svelte is imported correctly in tests
* and that the DOM is cleaned up after each test.
*
* @param {{resolveBrowser?: boolean, autoCleanup?: boolean}} options
* @returns {import('vite').Plugin}
*/
export const svelteTesting = ({
resolveBrowser = true,
autoCleanup = true,
} = {}) => ({
name: 'vite-plugin-svelte-testing-library',
config: (config) => {
if (!process.env.VITEST) {
return
}

if (resolveBrowser) {
addBrowserCondition(config)
}

if (autoCleanup) {
addAutoCleanup(config)
}
},
})

/**
* Add `browser` to `resolve.conditions` before `node`.
*
* This ensures that Svelte's browser code is used in tests,
* rather than its SSR code.
*
* @param {import('vitest/config').UserConfig} config
*/
const addBrowserCondition = (config) => {
const resolve = config.resolve ?? {}
const conditions = resolve.conditions ?? []
const nodeConditionIndex = conditions.indexOf('node')
const browserConditionIndex = conditions.indexOf('browser')

if (
nodeConditionIndex >= 0 &&
(nodeConditionIndex < browserConditionIndex || browserConditionIndex < 0)
) {
conditions.splice(nodeConditionIndex, 0, 'browser')
}

resolve.conditions = conditions
config.resolve = resolve
}

/**
* Add auto-cleanup file to Vitest's setup files.
*
* @param {import('vitest/config').UserConfig} config
*/
const addAutoCleanup = (config) => {
const test = config.test ?? {}
let setupFiles = test.setupFiles ?? []

if (typeof setupFiles === 'string') {
setupFiles = [setupFiles]
}

setupFiles.push(join(dirname(fileURLToPath(import.meta.url)), './vitest.js'))

test.setupFiles = setupFiles
config.test = test
}
12 changes: 12 additions & 0 deletions types/vite.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { Plugin } from 'vite'

/**
* Vite plugin to configure @testing-library/svelte.
*
* Ensures Svelte is imported correctly in tests
* and that the DOM is cleaned up after each test.
*/
export function svelteTesting(options?: {
resolveBrowser?: boolean
autoCleanup?: boolean
}): Plugin
15 changes: 5 additions & 10 deletions vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { svelte } from '@sveltejs/vite-plugin-svelte'
import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
import { defineConfig } from 'vite'

import { svelteTesting } from './src/vite.js'

const IS_SVELTE_5 = SVELTE_VERSION >= '5'

const alias = [
Expand All @@ -17,15 +19,8 @@ const alias = [
]

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
plugins: [svelte({ hot: false })],
resolve: {
// Ensure `browser` exports are used in tests
// Vitest prefers modules' `node` export by default
// Svelte's `node` export is its SSR bundle, which does not have onMount
// https://github.com/testing-library/svelte-testing-library/issues/222#issuecomment-1909993331
conditions: mode === 'test' ? ['browser'] : [],
},
export default defineConfig({
plugins: [svelte({ hot: false }), svelteTesting()],
test: {
alias,
environment: 'jsdom',
Expand All @@ -37,4 +32,4 @@ export default defineConfig(({ mode }) => ({
include: ['src'],
},
},
}))
})

0 comments on commit ed541de

Please sign in to comment.