From 64648fec9d12083a83e6181fae8dd5aafc37a19a Mon Sep 17 00:00:00 2001 From: Michael Cousins Date: Mon, 22 Apr 2024 10:32:04 -0400 Subject: [PATCH 1/6] feat(vitest): add Vite plugin for Svelte browser import and autocleanup --- package.json | 4 ++ src/__tests__/_vitest-setup.js | 1 - src/vite-plugin.js | 71 ++++++++++++++++++++++++++++++++++ types/vite-plugin.d.ts | 12 ++++++ vite.config.js | 15 +++---- 5 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 src/vite-plugin.js create mode 100644 types/vite-plugin.d.ts diff --git a/package.json b/package.json index 1948cfc..edbcdf8 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,10 @@ }, "./vitest": { "default": "./src/vitest.js" + }, + "./vite-plugin": { + "types": "./src/vite-plugin.d.ts", + "default": "./src/vite-plugin.js" } }, "type": "module", diff --git a/src/__tests__/_vitest-setup.js b/src/__tests__/_vitest-setup.js index 13ed819..a9d0dd3 100644 --- a/src/__tests__/_vitest-setup.js +++ b/src/__tests__/_vitest-setup.js @@ -1,2 +1 @@ import '@testing-library/jest-dom/vitest' -import '../vitest' diff --git a/src/vite-plugin.js b/src/vite-plugin.js new file mode 100644 index 0000000..242cdb9 --- /dev/null +++ b/src/vite-plugin.js @@ -0,0 +1,71 @@ +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 ?? {} + const setupFiles = test.setupFiles ?? [] + + setupFiles.push(join(dirname(fileURLToPath(import.meta.url)), './vitest.js')) + + test.setupFiles = setupFiles + config.test = test +} diff --git a/types/vite-plugin.d.ts b/types/vite-plugin.d.ts new file mode 100644 index 0000000..470e487 --- /dev/null +++ b/types/vite-plugin.d.ts @@ -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 diff --git a/vite.config.js b/vite.config.js index d9085ef..5d57707 100644 --- a/vite.config.js +++ b/vite.config.js @@ -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-plugin.js' + const IS_SVELTE_5 = SVELTE_VERSION >= '5' const alias = [ @@ -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', @@ -37,4 +32,4 @@ export default defineConfig(({ mode }) => ({ include: ['src'], }, }, -})) +}) From fe2e387848efd82c0f6a436c701f4804df2e1f35 Mon Sep 17 00:00:00 2001 From: Michael Cousins Date: Tue, 23 Apr 2024 09:45:50 -0400 Subject: [PATCH 2/6] fixup: review feedback + README --- README.md | 37 ++++++++++++++++++++++----- package.json | 6 ++--- src/{vite-plugin.js => vite.js} | 0 types/{vite-plugin.d.ts => vite.d.ts} | 0 4 files changed, 33 insertions(+), 10 deletions(-) rename src/{vite-plugin.js => vite.js} (100%) rename types/{vite-plugin.d.ts => vite.d.ts} (100%) diff --git a/README.md b/README.md index 0a39429..51ca77a 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@

Simple and complete Svelte testing utilities that encourage good testing practices.

[**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) [![Build Status][build-badge]][build] @@ -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 diff --git a/package.json b/package.json index edbcdf8..f3327c7 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,9 @@ "./vitest": { "default": "./src/vitest.js" }, - "./vite-plugin": { - "types": "./src/vite-plugin.d.ts", - "default": "./src/vite-plugin.js" + "./vite": { + "types": "./src/vite.d.ts", + "default": "./src/vite.js" } }, "type": "module", diff --git a/src/vite-plugin.js b/src/vite.js similarity index 100% rename from src/vite-plugin.js rename to src/vite.js diff --git a/types/vite-plugin.d.ts b/types/vite.d.ts similarity index 100% rename from types/vite-plugin.d.ts rename to types/vite.d.ts From a5e362aa3c8fa35718edfd027726f884878f6018 Mon Sep 17 00:00:00 2001 From: Michael Cousins Date: Tue, 23 Apr 2024 09:47:41 -0400 Subject: [PATCH 3/6] fixup: s/vite-plugin/vite/ --- vite.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vite.config.js b/vite.config.js index 5d57707..293d426 100644 --- a/vite.config.js +++ b/vite.config.js @@ -4,7 +4,7 @@ import { svelte } from '@sveltejs/vite-plugin-svelte' import { VERSION as SVELTE_VERSION } from 'svelte/compiler' import { defineConfig } from 'vite' -import { svelteTesting } from './src/vite-plugin.js' +import { svelteTesting } from './src/vite.js' const IS_SVELTE_5 = SVELTE_VERSION >= '5' From 023882bde43340e242b1e400d09c7f64ea0e3066 Mon Sep 17 00:00:00 2001 From: Michael Cousins Date: Tue, 23 Apr 2024 13:49:03 -0400 Subject: [PATCH 4/6] fixup: fix type exports and peer dependencies --- package.json | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index f3327c7..307e6ba 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "default": "./src/vitest.js" }, "./vite": { - "types": "./src/vite.d.ts", + "types": "./types/vite.d.ts", "default": "./src/vite.js" } }, @@ -47,8 +47,10 @@ "e2e" ], "files": [ - "src/", - "types/index.d.ts" + "src", + "types", + "!*.test-d.ts", + "!__tests__" ], "scripts": { "toc": "doctoc README.md", @@ -72,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" From 6961573346cf229afe5d23d8a7080d5df8cdafcb Mon Sep 17 00:00:00 2001 From: Michael Cousins Date: Tue, 23 Apr 2024 13:56:36 -0400 Subject: [PATCH 5/6] fixup: ensure `setupFiles` is an array --- src/vite.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vite.js b/src/vite.js index 242cdb9..a907cdb 100644 --- a/src/vite.js +++ b/src/vite.js @@ -62,7 +62,8 @@ const addBrowserCondition = (config) => { */ const addAutoCleanup = (config) => { const test = config.test ?? {} - const setupFiles = test.setupFiles ?? [] + const setupFiles = + test.setupFiles !== undefined ? [test.setupFiles].flat() : [] setupFiles.push(join(dirname(fileURLToPath(import.meta.url)), './vitest.js')) From 15a997b2d04e1e27d8e6e943cb4db6e51a324114 Mon Sep 17 00:00:00 2001 From: Michael Cousins Date: Tue, 23 Apr 2024 13:57:43 -0400 Subject: [PATCH 6/6] fixup: do something a little more obvious --- src/vite.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vite.js b/src/vite.js index a907cdb..0062b89 100644 --- a/src/vite.js +++ b/src/vite.js @@ -62,8 +62,11 @@ const addBrowserCondition = (config) => { */ const addAutoCleanup = (config) => { const test = config.test ?? {} - const setupFiles = - test.setupFiles !== undefined ? [test.setupFiles].flat() : [] + let setupFiles = test.setupFiles ?? [] + + if (typeof setupFiles === 'string') { + setupFiles = [setupFiles] + } setupFiles.push(join(dirname(fileURLToPath(import.meta.url)), './vitest.js'))