svelte-declarative-testing 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.prettierrc ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "useTabs": false,
3
+ "singleQuote": true,
4
+ "trailingComma": "all",
5
+ "htmlWhitespaceSensitivity": "ignore",
6
+ "printWidth": 100,
7
+ "plugins": ["prettier-plugin-svelte"],
8
+ "overrides": [
9
+ {
10
+ "files": "*.svelte",
11
+ "options": {
12
+ "parser": "svelte"
13
+ }
14
+ }
15
+ ]
16
+ }
package/README.md ADDED
@@ -0,0 +1,270 @@
1
+ # svelte-declarative-testing
2
+
3
+ One of the great things about Svelte is its compiler, producing a minimal
4
+ runtime and providing a great, declarative way to build components.
5
+ Unfortunately, unlike many other JavaScript frameworks, which use jsx or tagged
6
+ template functions to render components in a declarative manner inside
7
+ JavaScript files, Svelte has no such feature. Consider the following structure
8
+ of composed components:
9
+
10
+ ```svelte
11
+ <Popover>
12
+ <PopoverTrigger>Open Menu</PopoverTrigger>
13
+ <PopoverMenu>
14
+ <PopoverMenuItem href="/account">Account</PopoverMenuItem>
15
+ <PopoverMenuItem href="/logout">Log out</PopoverMenuItem>
16
+ </PopoverMenu>
17
+ </Popover>
18
+ ```
19
+
20
+ There _are_ existing ways to render this in your tests, but none of them are
21
+ ergonomic. You can:
22
+
23
+ - create a separate `.svelte` file for each configuration of your composed
24
+ components you want to test and pass that component to `render()`; or
25
+ - create a single `.svelte` file and wrap all of your configurations in
26
+ `{#snippet <name>()}...{/snippet}`, along with a `{@render children()}`. You
27
+ export all the snippets and import them along with the default export, pass
28
+ the default export to `render(...)` and the snippet to the `children`
29
+ property; or
30
+ - Use something like [vite-plugin-svelte-inline-component][vpsic] which allows
31
+ you to use tagged template literals along with some directive comments in your
32
+ test files.
33
+
34
+ [vpsic]: https://github.com/hanielu/vite-plugin-svelte-inline-component
35
+
36
+ Using this library, you can write your tests in Svelte syntax. This gives you
37
+ much greater ergonomics and flexibility, especially for the above composition.
38
+ Your tests can look like this:
39
+
40
+ ```svelte
41
+ <!-- Popover.test.svelte -->
42
+ <script>
43
+ import { Test, Check } from 'svelte-declarative-testing/vitest-browser-svelte';
44
+ import { Popover, PopoverTrigger, PopoverMenu, PopoverMenuItem } from './';
45
+ </script>
46
+
47
+ <Test it="opens the menu when the trigger is clicked">
48
+ <!-- children of the Test are rendered automatically -->
49
+ <Popover>
50
+ <PopoverTrigger>Open Menu</PopoverTrigger>
51
+ <PopoverMenu>
52
+ <PopoverMenuItem href="/account">Account</PopoverMenuItem>
53
+ <PopoverMenuItem href="/logout">Log out</PopoverMenuItem>
54
+ </PopoverMenu>
55
+ </Popover>
56
+
57
+ <!-- one or more test functions can be provided as checks -->
58
+ {#snippet checks()}
59
+ <Check
60
+ fn={async (screen) => {
61
+ expect(screen.getByRole('menu', { includeHidden: true })).not.toBeVisible();
62
+ await screen.getByRole('button', { name: 'Open Menu' }).click();
63
+ expect(screen.getByRole('menu')).toBeVisible();
64
+ }}
65
+ />
66
+ {/snippet}
67
+ </Test>
68
+ ```
69
+
70
+ ## Installation
71
+
72
+ Install as part of your project's `devDependencies` through your preferred
73
+ package manager.
74
+
75
+ ```
76
+ npm install --save-dev svelte-declarative-testing
77
+ ```
78
+
79
+ ## Setup
80
+
81
+ There are 2 ways to activate your declarative svelte test files, using the
82
+ provided Vite plugins or by importing them directly into another test file to
83
+ mount them.
84
+
85
+ ### Using the plugins
86
+
87
+ In order to work with the VSCode Vitest extension, 2 plugins are provided to
88
+ instrument the source code. You will also need to make sure Vitest includes your
89
+ test files:
90
+
91
+ ```javascript
92
+ import svelteDeclarativeTesting from 'svelte-declarative-testing/vitest';
93
+
94
+ export default defineConfig({
95
+ plugins: [
96
+ // ...
97
+
98
+ ...svelteDeclarativeTesting(),
99
+ ],
100
+
101
+ // ...
102
+
103
+ test: {
104
+ include: [
105
+ 'src/**/*.svelte.{test,spec}.{js,ts}',
106
+
107
+ // Includes .test.svelte and .spec.svelte
108
+ 'src/**/*.{test,spec}.svelte',
109
+ ],
110
+ },
111
+ });
112
+ ```
113
+
114
+ ### Importing directly into your other tests
115
+
116
+ > [!WARNING]
117
+ > This approach will not allow you to trigger test runs using the Vitest
118
+ > extension for VSCode. There may be some other side effects also.
119
+
120
+ If you don't want to use the plugins, simply import your Svelte-syntax test
121
+ files into your existing unit tests:
122
+
123
+ ```javascript
124
+ // Popover.test.js
125
+ import PopoverIntegrationTests from './Popover.test.svelte';
126
+ import { render } from '@testing-library/svelte'; // or vitest-browser-svelte
127
+
128
+ describe('Unit tests', () => {
129
+ // ... existing unit tests
130
+ });
131
+
132
+ describe('Integration tests', () => {
133
+ render(PopoverIntegrationTests);
134
+ });
135
+ ```
136
+
137
+ ## Writing tests
138
+
139
+ Writing tests is quite intuitive. It is a similar structure to JavaScript test
140
+ files, with `describe()` and `test()` being replaced by `<Describe ...>` and
141
+ `<Test ...>` respectively. Additionally, there is a `<Check>` function that
142
+ allows you to provide the test functions.
143
+
144
+ Convenience wrappers are provided for @testing-library/svelte and
145
+ vitest-browser-svelte.
146
+
147
+ ```typescript
148
+ import { Describe, Test, Check } from 'svelte-declarative-testing/testing-library';
149
+ ```
150
+
151
+ ```typescript
152
+ import { Describe, Test, Check } from 'svelte-declarative-testing/vitest-browser-svelte';
153
+ ```
154
+
155
+ Alternatively, you can import the core functions and provide a custom `render()`
156
+ function to the `Test` component.
157
+
158
+ ```typescript
159
+ import { Describe, Test, Check } from 'svelte-declarative-testing';
160
+ ```
161
+
162
+ ### `<Describe ...>`
163
+
164
+ Wraps your tests in a suite, similare to `describe()`.
165
+
166
+ ```svelte
167
+ <Describe label="My Integration Tests">
168
+ ```
169
+
170
+ Inside `Describe`, tests go in a `tests()` snippet. Any other children will be
171
+ rendered for each test.
172
+
173
+ | Properties | Type | Description |
174
+ | ---------- | ---------- | ------------------------------------------------------------------------------------- |
175
+ | `label` | `string` | The descriptive label for the test suite |
176
+ | `children` | `Snippet` | Any component(s) that you wish to render for the tests |
177
+ | `tests` | `Snippet` | A snippet block containing one or more `<Test>` elements |
178
+ | `skip` | `any` | Skips the suite if truthy, just like `describe.skip()` |
179
+ | `only` | `any` | Only run this suite if truthy, just like `describe.only()` |
180
+ | `todo` | `any` | Mark the suite as todo if truthy, just like `describe.todo()` |
181
+ | `shuffle` | `any` | Mark the suite as todo if truthy, just like `describe.todo()` |
182
+ | `skipIf` | `function` | Skips the suite if the function returns a truthy value, just like `describe.skipIf()` |
183
+ | `runIf` | `function` | Runs the suite if the function returns a truthy value, just like `describe.runIf()` |
184
+
185
+ ```svelte
186
+ <Describe label="My Integration Tests">
187
+ <Button>My button</Button>
188
+
189
+ {#snippet tests()}
190
+ <Test it="renders an accessible button">
191
+ <!-- Test body goes here -->
192
+ </Test>
193
+
194
+ <Test it="does something when I click the button">
195
+ <!-- Test body goes here -->
196
+ </Test>
197
+ {/snippet}
198
+ </Describe>
199
+ ```
200
+
201
+ ### `<Test ...>`
202
+
203
+ Describes a test.
204
+
205
+ ```svelte
206
+ <Test it="does what I expect it to do">
207
+ ```
208
+
209
+ Inside `Test`, checks go in a `checks()` snippet. Any other children will be
210
+ rendered for each test. If no other children are provided, the children of the
211
+ parent `<Describe>` are rendered.
212
+
213
+ | Properties | Type | Description |
214
+ | ---------- | ---------- | -------------------------------------------------------------------------------- |
215
+ | `it` | `string` | The description of the test |
216
+ | `children` | `Snippet` | Any component(s) that you wish to render for the test |
217
+ | `checks` | `Snippet` | A snippet block containing one or more `<Check>` elements |
218
+ | `skip` | `any` | Skips the test if truthy, just like `test.skip()` |
219
+ | `only` | `any` | Only run this test if truthy, just like `test.only()` |
220
+ | `todo` | `any` | Mark the test as todo if truthy, just like `test.todo()` |
221
+ | `fails` | `any` | Passes the test on failure if truthy, just like `test.fails()` |
222
+ | `skipIf` | `function` | Skips the test if the function returns a truthy value, just like `test.skipIf()` |
223
+ | `runIf` | `function` | Runs the test if the function returns a truthy value, just like `test.runIf()` |
224
+ | `render()` | `function` | Provides a custom render function (not available on the wrapper components` |
225
+
226
+ ```svelte
227
+ <Test it="renders an accessible button">
228
+ <Button>My button</Button>
229
+
230
+ {#snippet checks()}
231
+ <Check fn={ /* ... */ } />
232
+ <Check fn={ /* ... */ } />
233
+ {/snippet}
234
+ </Describe>
235
+ ```
236
+
237
+ ### `<Check ...>`
238
+
239
+ Provides a test function.
240
+
241
+ ```svelte
242
+ <Check fn={() => expect(1 + 1).toBe(2)} />
243
+ ```
244
+
245
+ You can provide as many checks as you like and they will run sequentially.
246
+
247
+ | Properties | Type | Description |
248
+ | ---------- | ---------- | -------------------------------------------------- |
249
+ | `fn` | `function` | A function to be executed as part of the test body |
250
+
251
+ ```svelte
252
+ <Test it="renders an accessible button">
253
+ <Button>My button</Button>
254
+
255
+ {#snippet checks()}
256
+ <Check fn={({queryByRole}) => {
257
+ expect(queryByRole("button")).toBeIntheDocument();
258
+ }/>
259
+ {/snippet}
260
+ </Describe>
261
+ ```
262
+
263
+ ## Credits
264
+
265
+ This is not a new idea and was originally posited by [@7nik][7nik] and
266
+ [@paoloricciuti][paol] on the Svelte bug tracker. Thanks also to @sheremet-va,
267
+ who assisted with the Vitest test detection plugins.
268
+
269
+ [7nik]: https://github.com/sveltejs/svelte/issues/14791#issuecomment-3166064732
270
+ [paol]: https://github.com/sveltejs/svelte/issues/14791#issuecomment-3166186575
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "svelte-declarative-testing",
3
+ "version": "0.1.0",
4
+ "description": "A way to mount your Svelte test components declaratively",
5
+ "type": "module",
6
+ "module": "src/index.js",
7
+ "main": "src/index.js",
8
+ "exports": {
9
+ "./testing-library": {
10
+ "types": "./src/components/testing-library/index.d.ts",
11
+ "default": "./src/components/testing-library/index.js"
12
+ },
13
+ "./vitest-browser-svelte": {
14
+ "types": "./src/components/vitest-browser-svelte/index.d.ts",
15
+ "default": "./src/components/vitest-browser-svelte/index.js"
16
+ },
17
+ "./internal": {
18
+ "types": "./src/components/internal/index.d.ts",
19
+ "default": "./src/components/internal/index.js"
20
+ },
21
+ "./vitest": {
22
+ "types": "./src/plugins/index.d.ts",
23
+ "default": "./src/plugins/vitest.js"
24
+ }
25
+ },
26
+ "scripts": {
27
+ "test": "echo \"Error: no test specified\" && exit 1"
28
+ },
29
+ "keywords": [
30
+ "svelte",
31
+ "vitest",
32
+ "test",
33
+ "testing-library"
34
+ ],
35
+ "author": "Andy Earnshaw",
36
+ "license": "ISC",
37
+ "dependencies": {
38
+ "magic-string": "^0.30.21",
39
+ "ts-essentials": "^10.1.1",
40
+ "zimmerframe": "^1.1.4"
41
+ },
42
+ "devDependencies": {
43
+ "eslint": "^9.39.2",
44
+ "prettier": "^3.8.1",
45
+ "prettier-plugin-svelte": "^3.4.1"
46
+ },
47
+ "peerDependencies": {
48
+ "@testing-library/svelte": "^5.3.1",
49
+ "svelte": "^5.49.0",
50
+ "vitest": "^4.0.18",
51
+ "vitest-browser-svelte": "^2.0.2"
52
+ },
53
+ "peerDependenciesMeta": {
54
+ "@testing-library/svelte": {
55
+ "optional": true
56
+ },
57
+ "vitest-browser-svelte": {
58
+ "optional": true
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ /**@import { CheckProps } from './' */
3
+ import { getAddCheck } from './context.js';
4
+
5
+ /**@type {CheckProps} */
6
+ const { fn } = $props();
7
+
8
+ $effect(() => {
9
+ getAddCheck()?.(fn);
10
+ });
11
+ </script>
@@ -0,0 +1,37 @@
1
+ <script>
2
+ /** @import { DescribeProps } from './' */
3
+ import { describe } from 'vitest';
4
+ import { setAddTest, setSuiteRenderSnippet } from './context.js';
5
+
6
+ /**@type {DescribeProps}*/
7
+ const { label, todo, only, skip, skipIf, runIf, children, tests } = $props();
8
+
9
+ /**@type {((result: unknown) => void | Promise<void>)[]} */
10
+ const testFns = [];
11
+
12
+ setAddTest((fn) => {
13
+ testFns.push(fn);
14
+ });
15
+
16
+ // svelte-ignore state_referenced_locally
17
+ setSuiteRenderSnippet(children);
18
+
19
+ $effect(() => {
20
+ const describeFn = () => {
21
+ if (skip) return describe.skip;
22
+ if (skipIf) return describe.skipIf(skipIf());
23
+ if (todo) return describe.todo;
24
+ if (only) return describe.only;
25
+ if (runIf) return describe.runIf(runIf());
26
+ return describe;
27
+ };
28
+
29
+ describeFn()(label, async () => {
30
+ for (const test of testFns) {
31
+ await test();
32
+ }
33
+ });
34
+ });
35
+ </script>
36
+
37
+ {@render tests()}
@@ -0,0 +1,56 @@
1
+ <script>
2
+ /**@import { TestProps } from './index.js' */
3
+ import { test } from 'vitest';
4
+ import { getAddTest, setAddCheck, getSuiteRenderSnippet } from './context.js';
5
+ import Wrapper from './Wrapper.svelte';
6
+
7
+ /**@type {TestProps} */
8
+ const { it, fails, todo, only, skip, skipIf, runIf, children, checks, render } = $props();
9
+
10
+ /**@type {((result: unknown) => void | Promise<void>)[]} */
11
+ const checkFns = [];
12
+
13
+ const addTest = getAddTest();
14
+
15
+ const suiteRenderSnippet = getSuiteRenderSnippet();
16
+
17
+ setAddCheck((fn) => {
18
+ checkFns.push(fn);
19
+ });
20
+
21
+ const setupTest = () => {
22
+ const testFn = () => {
23
+ if (skip) return test.skip;
24
+ if (skipIf) return test.skipIf(skipIf());
25
+ if (todo) return test.todo;
26
+ if (only) return test.only;
27
+ if (fails) return test.fails;
28
+ if (runIf) return test.runIf(runIf());
29
+ return test;
30
+ };
31
+
32
+ testFn()(it, async () => {
33
+ const result = await render(Wrapper, { children: children ?? suiteRenderSnippet });
34
+
35
+ try {
36
+ if (!checkFns.length) {
37
+ throw new Error(`No checks were registered for test: "${it}"`);
38
+ }
39
+
40
+ for (const check of checkFns) {
41
+ await check(result);
42
+ }
43
+ } finally {
44
+ result.unmount();
45
+ }
46
+ });
47
+ };
48
+
49
+ addTest?.(setupTest);
50
+
51
+ $effect(() => {
52
+ if (!addTest) setupTest();
53
+ });
54
+ </script>
55
+
56
+ {@render checks()}
@@ -0,0 +1,8 @@
1
+ <script>
2
+ /**@import type { Snippet } from 'svelte';*/
3
+
4
+ /**@type {{ children: Snippet }}*/
5
+ const { children } = $props();
6
+ </script>
7
+
8
+ {@render children()}
@@ -0,0 +1,7 @@
1
+ import { createContext, Snippet } from 'svelte';
2
+
3
+ export const [getAddTest, setAddTest] = createContext<(fn: () => void | Promise<void>) => void>();
4
+
5
+ export const [getAddCheck, setAddCheck] = createContext<(fn: () => void | Promise<void>) => void>();
6
+
7
+ export const [getSuiteRenderSnippet, setSuiteRenderSnippet] = createContext<Snippet | undefined>();
@@ -0,0 +1,39 @@
1
+ import type { Snippet, Component } from 'svelte';
2
+ import { XOR } from 'ts-essentials';
3
+
4
+ export type ModifierProps = XOR<
5
+ /* These are all mutually exclusive */
6
+ { only: boolean },
7
+ { todo: boolean },
8
+ { skip: boolean },
9
+ { skipIf: () => unknown },
10
+ { runIf: () => unknown }
11
+ >;
12
+
13
+ export type DescribeProps =
14
+ | {
15
+ label: string;
16
+ children?: Snippet;
17
+ tests: Snippet;
18
+ }
19
+ | ModifierProps;
20
+
21
+ export type BaseTestProps =
22
+ | {
23
+ it: string;
24
+ children?: Snippet;
25
+ checks: Snippet;
26
+ }
27
+ | XOR<ModifierProps, { fails: boolean }>;
28
+
29
+ export type TestProps = BaseTestProps & {
30
+ render: (result: unknown) => void | Promise<void>;
31
+ };
32
+
33
+ export type CheckProps = {
34
+ fn: (result: unknown) => void | Promise<void>;
35
+ };
36
+
37
+ export declare const Describe: Component<DescribeProps>;
38
+ export declare const Test: Component<TestProps>;
39
+ export declare const Check: Component<CheckProps>;
@@ -0,0 +1,3 @@
1
+ export { default as Describe } from './Describe.svelte';
2
+ export { default as Test } from './Test.svelte';
3
+ export { default as Check } from './Check.svelte';
@@ -0,0 +1,9 @@
1
+ <script>
2
+ /** @import { CheckProps } from './' */
3
+ import { Check as CoreCheck } from '../core';
4
+
5
+ /**@type {CheckProps}*/
6
+ const props = $props();
7
+ </script>
8
+
9
+ <CoreCheck {...props} />
@@ -0,0 +1,11 @@
1
+ <script>
2
+ /**@import { BaseTestProps } from '../core' */
3
+
4
+ import { Test as CoreTest } from '../core';
5
+ import { render } from '@testing-library/svelte';
6
+
7
+ /**@type {BaseTestProps}*/
8
+ const props = $props();
9
+ </script>
10
+
11
+ <CoreTest {render} {...props} />
@@ -0,0 +1,14 @@
1
+ import { RenderResult } from '@testing-library/svelte';
2
+ import { Component } from 'svelte';
3
+ import type { BaseTestProps, DescribeProps } from '../core';
4
+
5
+ export type CheckFn = (result: RenderResult<Component<any, any>>) => void | Promise<void>;
6
+
7
+ export type CheckProps = {
8
+ fn: CheckFn;
9
+ };
10
+
11
+ export { DescribeProps };
12
+ export declare const Describe: Component<DescribeProps>;
13
+ export declare const Test: Component<BaseTestProps>;
14
+ export declare const Check: Component<CheckProps>;
@@ -0,0 +1,3 @@
1
+ export { Describe } from '../core';
2
+ export { default as Test } from './Test.svelte';
3
+ export { default as Check } from './Check.svelte';
@@ -0,0 +1,9 @@
1
+ <script>
2
+ /**@import { CheckProps } from './' */
3
+ import { Check as CoreCheck } from '../core';
4
+
5
+ /**@type {CheckProps}*/
6
+ const props = $props();
7
+ </script>
8
+
9
+ <CoreCheck {...props} />
@@ -0,0 +1,11 @@
1
+ <script>
2
+ /**@import { BaseTestProps } from '../core' */
3
+
4
+ import { Test as CoreTest } from '../core';
5
+ import { render } from 'vitest-browser-svelte';
6
+
7
+ /**@type {BaseTestProps}*/
8
+ const props = $props();
9
+ </script>
10
+
11
+ <CoreTest {render} {...props} />
@@ -0,0 +1,14 @@
1
+ import { RenderResult } from 'vitest-browser-svelte';
2
+ import { Component } from 'svelte';
3
+ import type { BaseTestProps, DescribeProps } from '../core';
4
+
5
+ export type CheckFn = (result: RenderResult<Component<any, any>>) => void | Promise<void>;
6
+
7
+ export type CheckProps = {
8
+ fn: CheckFn;
9
+ };
10
+
11
+ export { DescribeProps };
12
+ export declare const Test: Component<BaseTestProps>;
13
+ export declare const Check: Component<CheckProps>;
14
+ export declare const Describe: Component<DescribeProps>;
@@ -0,0 +1,3 @@
1
+ export { Describe } from '../core';
2
+ export { default as Test } from './Test.svelte';
3
+ export { default as Check } from './Check.svelte';
package/src/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { default as Test } from './core';
2
+ export { default as Check } from './core';
@@ -0,0 +1,3 @@
1
+ // TODO fix type
2
+ declare const getPlugins: () => any[];
3
+ export default getPlugins;
@@ -0,0 +1,93 @@
1
+ /** @import type { Plugin } from 'vitest/config' */
2
+ import { parse } from 'svelte/compiler';
3
+ import { walk } from 'zimmerframe';
4
+ import MagicString from 'magic-string';
5
+
6
+ const pre = () =>
7
+ /**@type {Plugin}*/ ({
8
+ name: 'transform-svelte-declarative-test',
9
+ enforce: 'pre',
10
+ transform(code, id) {
11
+ if (!/\.(?:test|spec)\.svelte$/.test(id)) {
12
+ return;
13
+ }
14
+
15
+ const s = new MagicString(code);
16
+ const ast = parse(code);
17
+ walk(
18
+ ast.html,
19
+ {},
20
+ {
21
+ InlineComponent(node, { visit }) {
22
+ if (node.name === 'Test') {
23
+ for (const attr of node.attributes) {
24
+ if (attr.name === 'it') {
25
+ const name =
26
+ attr.value?.[0]?.data?.replace(/"/g, '\\"') ?? '(dynamically named test)';
27
+
28
+ s.appendLeft(
29
+ attr.start,
30
+ `data-test-code={function () { test("${name}", () => {}) }} `,
31
+ );
32
+ }
33
+ }
34
+
35
+ return;
36
+ } else if (node.name === 'Describe') {
37
+ for (const attr of node.attributes) {
38
+ if (attr.name === 'label') {
39
+ const name =
40
+ attr.value?.[0]?.data?.replace(/"/g, '\\"') ?? '(dynamically named test suite)';
41
+
42
+ s.appendLeft(
43
+ attr.start,
44
+ `data-describe-code={function () { describe("${name}", () => {}) }} `,
45
+ );
46
+ }
47
+ }
48
+
49
+ for (const child of node.children) {
50
+ if (child.type === 'SnippetBlock') {
51
+ visit(child);
52
+ }
53
+ }
54
+ }
55
+ },
56
+ SnippetBlock(node, { visit }) {
57
+ for (const child of node.children) {
58
+ if (child.type === 'InlineComponent') {
59
+ visit(child);
60
+ }
61
+ }
62
+ },
63
+ },
64
+ );
65
+
66
+ console.log(s.toString());
67
+ return { code: s.toString(), map: s.generateMap({ hires: true }) };
68
+ },
69
+ });
70
+
71
+ const post = () =>
72
+ /**@type {Plugin}*/ ({
73
+ name: 'transform-svelte-declarative-test',
74
+ enforce: 'post',
75
+ transform(code, id) {
76
+ if (!/\.(?:test|spec)\.svelte$/.test(id)) {
77
+ return;
78
+ }
79
+
80
+ const s = new MagicString(code);
81
+ const componentName = id.split('/').pop()?.split('.').slice(0, -1).join('_');
82
+ s.append(`
83
+ import { mount } from 'svelte';
84
+ mount(${componentName}, { target: document.body });
85
+ `);
86
+
87
+ return { code: s.toString(), map: s.generateMap({ hires: true }) };
88
+ },
89
+ });
90
+
91
+ export default function getPlugins() {
92
+ return [pre(), post()];
93
+ }