svelte-declarative-testing 0.2.0 → 0.3.1
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/ast.json +1176 -1093
- package/examples/basic/Basic.test.svelte +37 -26
- package/package.json +1 -1
- package/src/components/core/Check.svelte +1 -1
- package/src/components/core/Describe.svelte +22 -11
- package/src/components/core/Test.svelte +7 -7
- package/src/components/core/Wrapper.svelte +2 -2
- package/src/components/core/context.js +14 -0
- package/src/components/core/index.d.ts +19 -16
- package/src/plugins/__snapshots__/vitest.test.ts.snap +37 -0
- package/src/plugins/vitest.js +5 -4
- package/src/plugins/vitest.test.ts +227 -1
- package/src/utils/tryFn.js +14 -0
- package/tsconfig.json +1 -0
- package/vitest.config.ts +16 -1
- package/examples/basic/Basic.test.svelte.ast.json +0 -803
- package/id-test.code +0 -44
- package/id-test.map +0 -1
- package/src/components/core/context.ts +0 -7
- package/src/plugins/index.d.ts +0 -3
|
@@ -1,35 +1,46 @@
|
|
|
1
1
|
<script>
|
|
2
|
+
import { fireEvent } from '@testing-library/svelte';
|
|
2
3
|
import { Test, Describe, Check } from '../../src/components/testing-library';
|
|
3
4
|
</script>
|
|
4
5
|
|
|
5
|
-
<
|
|
6
|
-
{#snippet
|
|
7
|
-
<
|
|
8
|
-
|
|
6
|
+
<Test it="finds the rendered component">
|
|
7
|
+
{#snippet mount()}
|
|
8
|
+
<button>Click me</button>
|
|
9
|
+
{/snippet}
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
{/snippet}
|
|
17
|
-
</Test>
|
|
11
|
+
<Check
|
|
12
|
+
fn={({ getByRole }) => {
|
|
13
|
+
expect(getByRole('button', { name: 'Click me' })).not.toBe(null);
|
|
14
|
+
}}
|
|
15
|
+
/>
|
|
16
|
+
</Test>
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
<Describe label="Basic test suite">
|
|
19
|
+
{#snippet mount()}
|
|
20
|
+
<button>Click me</button>
|
|
21
|
+
{/snippet}
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}}
|
|
29
|
-
/>
|
|
30
|
-
{/snippet}
|
|
31
|
-
</Test>
|
|
23
|
+
<Describe label="Nested describe">
|
|
24
|
+
<Test it="mounts the test's snippet instead of the describe's snippet">
|
|
25
|
+
{#snippet mount()}
|
|
26
|
+
<button>No, click me</button>
|
|
32
27
|
{/snippet}
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
|
|
29
|
+
<Check
|
|
30
|
+
fn={({ queryByRole }) => {
|
|
31
|
+
expect(queryByRole('button', { name: 'Click me' })).toBe(null);
|
|
32
|
+
expect(queryByRole('button', { name: 'No, click me' })).not.toBe(null);
|
|
33
|
+
}}
|
|
34
|
+
/>
|
|
35
|
+
</Test>
|
|
36
|
+
|
|
37
|
+
<Test it="mounts the describe's snippet if the test doesn't have its own snippet">
|
|
38
|
+
<Check
|
|
39
|
+
fn={({ queryByRole }) => {
|
|
40
|
+
expect(queryByRole('button', { name: 'Click me' })).not.toBe(null);
|
|
41
|
+
expect(queryByRole('button', { name: 'No, click me' })).toBe(null);
|
|
42
|
+
}}
|
|
43
|
+
/>
|
|
44
|
+
</Test>
|
|
45
|
+
</Describe>
|
|
35
46
|
</Describe>
|
package/package.json
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
/** @import { DescribeProps } from './' */
|
|
3
3
|
import { describe } from 'vitest';
|
|
4
|
-
import {
|
|
4
|
+
import { getAddDescribeChild, setAddDescribeChild, setSuiteRenderSnippet } from './context';
|
|
5
|
+
import tryFn from '../../utils/tryFn.js';
|
|
5
6
|
|
|
6
7
|
/**@type {DescribeProps}*/
|
|
7
|
-
const { label, todo, only, skip, skipIf, runIf, children,
|
|
8
|
+
const { label, todo, only, skip, skipIf, runIf, children, mount } = $props();
|
|
8
9
|
|
|
9
|
-
/**@type {((
|
|
10
|
-
const
|
|
10
|
+
/**@type {(() => void | Promise<void>)[]} */
|
|
11
|
+
const childFns = [];
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
const addDescribeToParent = tryFn(getAddDescribeChild);
|
|
14
|
+
|
|
15
|
+
setAddDescribeChild((fn) => {
|
|
16
|
+
childFns.push(fn);
|
|
14
17
|
});
|
|
15
18
|
|
|
16
19
|
// svelte-ignore state_referenced_locally
|
|
17
|
-
|
|
20
|
+
if (mount) {
|
|
21
|
+
setSuiteRenderSnippet(mount);
|
|
22
|
+
}
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
const setupDescribe = () => {
|
|
20
25
|
const describeFn = () => {
|
|
21
26
|
if (skip) return describe.skip;
|
|
22
27
|
if (skipIf) return describe.skipIf(skipIf());
|
|
@@ -27,11 +32,17 @@
|
|
|
27
32
|
};
|
|
28
33
|
|
|
29
34
|
describeFn()(label, async () => {
|
|
30
|
-
for (const
|
|
31
|
-
await
|
|
35
|
+
for (const child of childFns) {
|
|
36
|
+
await child();
|
|
32
37
|
}
|
|
33
38
|
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
addDescribeToParent?.(setupDescribe);
|
|
42
|
+
|
|
43
|
+
$effect(() => {
|
|
44
|
+
if (!addDescribeToParent) setupDescribe();
|
|
34
45
|
});
|
|
35
46
|
</script>
|
|
36
47
|
|
|
37
|
-
{@render
|
|
48
|
+
{@render children()}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
/**@import { TestProps } from './index.js' */
|
|
3
3
|
import { test } from 'vitest';
|
|
4
|
-
import {
|
|
4
|
+
import { setAddCheck, getSuiteRenderSnippet, getAddDescribeChild } from './context';
|
|
5
5
|
import Wrapper from './Wrapper.svelte';
|
|
6
|
+
import tryFn from '../../utils/tryFn.js';
|
|
6
7
|
|
|
7
8
|
/**@type {TestProps} */
|
|
8
|
-
const { it, fails, todo, only, skip, skipIf, runIf, children,
|
|
9
|
+
const { it, fails, todo, only, skip, skipIf, runIf, children, mount, render } = $props();
|
|
9
10
|
|
|
10
11
|
/**@type {((result: unknown) => void | Promise<void>)[]} */
|
|
11
12
|
const checkFns = [];
|
|
12
13
|
|
|
13
|
-
const addTest =
|
|
14
|
-
|
|
15
|
-
const suiteRenderSnippet = getSuiteRenderSnippet();
|
|
14
|
+
const addTest = tryFn(getAddDescribeChild);
|
|
15
|
+
const suiteRenderSnippet = tryFn(getSuiteRenderSnippet);
|
|
16
16
|
|
|
17
17
|
setAddCheck((fn) => {
|
|
18
18
|
checkFns.push(fn);
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
testFn()(it, async () => {
|
|
33
|
-
const result = await render(Wrapper, { children:
|
|
33
|
+
const result = await render(Wrapper, { children: mount ?? suiteRenderSnippet });
|
|
34
34
|
|
|
35
35
|
try {
|
|
36
36
|
if (!checkFns.length) {
|
|
@@ -53,4 +53,4 @@
|
|
|
53
53
|
});
|
|
54
54
|
</script>
|
|
55
55
|
|
|
56
|
-
{@render
|
|
56
|
+
{@render children()}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**@import { Snippet } from 'svelte' */
|
|
2
|
+
/**@typedef {(fn: () => void} AddTestOrDescribeFn */
|
|
3
|
+
/**@typedef {(fn: (renderResult: unknown) => void | Promise<void>} AddCheckFn */
|
|
4
|
+
|
|
5
|
+
import { createContext } from 'svelte';
|
|
6
|
+
|
|
7
|
+
/**@type {[() => AddTestOrDescribeFn | undefined, (fn: AddTestOrDescribeFn) => void]} */
|
|
8
|
+
export const [getAddDescribeChild, setAddDescribeChild] = createContext(null);
|
|
9
|
+
|
|
10
|
+
/**@type {[() => AddCheckFn | undefined, (fn: AddCheckFn) => void]} */
|
|
11
|
+
export const [getAddCheck, setAddCheck] = createContext();
|
|
12
|
+
|
|
13
|
+
/**@type {[() => Snippet<[]> | undefined, (snippet: Snippet<[]> | undefined) => void]} */
|
|
14
|
+
export const [getSuiteRenderSnippet, setSuiteRenderSnippet] = createContext();
|
|
@@ -10,28 +10,31 @@ export type ModifierProps = XOR<
|
|
|
10
10
|
{ runIf: () => unknown }
|
|
11
11
|
>;
|
|
12
12
|
|
|
13
|
-
export type DescribeProps =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
| ModifierProps;
|
|
13
|
+
export type DescribeProps = {
|
|
14
|
+
label: string;
|
|
15
|
+
children: Snippet;
|
|
16
|
+
mount?: Snippet;
|
|
17
|
+
} & ModifierProps;
|
|
20
18
|
|
|
21
|
-
export type BaseTestProps =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
export type BaseTestProps = {
|
|
20
|
+
it: string;
|
|
21
|
+
children: Snippet;
|
|
22
|
+
mount?: Snippet;
|
|
23
|
+
} & XOR<ModifierProps, { fails: boolean }>;
|
|
24
|
+
|
|
25
|
+
type RenderResult = {
|
|
26
|
+
unmount: () => void | Promise<void>;
|
|
27
|
+
};
|
|
28
28
|
|
|
29
29
|
export type TestProps = BaseTestProps & {
|
|
30
|
-
render: (
|
|
30
|
+
render: (
|
|
31
|
+
component: Component<any, any>, //eslint-disable-line @typescript-eslint/no-explicit-any
|
|
32
|
+
options: unknown,
|
|
33
|
+
) => RenderResult | Promise<RenderResult>;
|
|
31
34
|
};
|
|
32
35
|
|
|
33
36
|
export type CheckProps = {
|
|
34
|
-
fn: (
|
|
37
|
+
fn: (renderResult: any) => void | Promise<void>; //eslint-disable-line @typescript-eslint/no-explicit-any
|
|
35
38
|
};
|
|
36
39
|
|
|
37
40
|
export declare const Describe: Component<DescribeProps>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`vitest post plugin > produces code that mounts the component and returns a render result 1`] = `"export default function AComponent() {};import { mount } from "svelte"; mount((await import(import.meta.url)).default, { target: document.body });"`;
|
|
4
|
+
|
|
5
|
+
exports[`vitest pre plugin > produces code with a dummy test suite 1`] = `
|
|
6
|
+
"
|
|
7
|
+
<script>
|
|
8
|
+
import { Describe, Test, Check } from '../components/core';
|
|
9
|
+
</script>
|
|
10
|
+
<Describe label="A test suite">
|
|
11
|
+
<Test it="A test case">
|
|
12
|
+
<Check fn={() => {}} />
|
|
13
|
+
</Test>
|
|
14
|
+
<Describe label="A nested test suite">
|
|
15
|
+
<Test it="A nested test case">
|
|
16
|
+
<Check fn={() => {}} />
|
|
17
|
+
</Test>
|
|
18
|
+
</Describe>
|
|
19
|
+
</Describe>
|
|
20
|
+
<Describe label="Another test suite">
|
|
21
|
+
<Test it="Another test case">
|
|
22
|
+
<Check fn={() => {}} />
|
|
23
|
+
</Test>
|
|
24
|
+
</Describe>
|
|
25
|
+
|
|
26
|
+
{#if globalThis[Symbol()]}{function () {
|
|
27
|
+
describe("A test suite", () => {
|
|
28
|
+
test("A test case", () => {})
|
|
29
|
+
describe("A nested test suite", () => {
|
|
30
|
+
test("A nested test case", () => {})
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
describe("Another test suite", () => {
|
|
34
|
+
test("Another test case", () => {})
|
|
35
|
+
})
|
|
36
|
+
}}{/if}"
|
|
37
|
+
`;
|
package/src/plugins/vitest.js
CHANGED
|
@@ -18,13 +18,13 @@ import { SourceMapGenerator, SourceMapConsumer } from 'source-map';
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
const mountCode =
|
|
21
|
-
'import { mount } from "svelte"; mount((await import(import.meta.url)).default, { target: document.body });';
|
|
21
|
+
';import { mount } from "svelte"; mount((await import(import.meta.url)).default, { target: document.body });';
|
|
22
22
|
|
|
23
23
|
const testFileRegex = /\.(?:test|spec)\.svelte$/;
|
|
24
24
|
const getNameFromAttr = (node, attr) =>
|
|
25
|
-
node.attributes.find((a) => a.name === attr)?.value?.[0]?.data ?? '(unnamed
|
|
25
|
+
node.attributes.find((a) => a.name === attr)?.value?.[0]?.data ?? '(unnamed)';
|
|
26
26
|
|
|
27
|
-
const pre =
|
|
27
|
+
const pre = () => ({
|
|
28
28
|
name: 'transform-svelte-declarative-test',
|
|
29
29
|
filter: {
|
|
30
30
|
id: testFileRegex,
|
|
@@ -110,7 +110,7 @@ const pre = /**@returns {Plugin}*/ () => ({
|
|
|
110
110
|
},
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
-
const post =
|
|
113
|
+
const post = () => ({
|
|
114
114
|
name: 'transform-svelte-declarative-test',
|
|
115
115
|
filter: {
|
|
116
116
|
id: testFileRegex,
|
|
@@ -131,6 +131,7 @@ const post = /**@returns {Plugin}*/ () => ({
|
|
|
131
131
|
},
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
+
/**@returns {import('vitest/config').Plugin[]} */
|
|
134
135
|
export default function getPlugins() {
|
|
135
136
|
return [pre(), post()];
|
|
136
137
|
}
|
|
@@ -1,3 +1,229 @@
|
|
|
1
|
+
import { SourceMapConsumer } from 'source-map';
|
|
2
|
+
import getPlugins from './vitest.js';
|
|
3
|
+
|
|
4
|
+
const dummyTestFile = `
|
|
5
|
+
<script>
|
|
6
|
+
import { Describe, Test, Check } from '../components/core';
|
|
7
|
+
</script>
|
|
8
|
+
<Describe label="A test suite">
|
|
9
|
+
<Test it="A test case">
|
|
10
|
+
<Check fn={() => {}} />
|
|
11
|
+
</Test>
|
|
12
|
+
<Describe label="A nested test suite">
|
|
13
|
+
<Test it="A nested test case">
|
|
14
|
+
<Check fn={() => {}} />
|
|
15
|
+
</Test>
|
|
16
|
+
</Describe>
|
|
17
|
+
</Describe>
|
|
18
|
+
<Describe label="Another test suite">
|
|
19
|
+
<Test it="Another test case">
|
|
20
|
+
<Check fn={() => {}} />
|
|
21
|
+
</Test>
|
|
22
|
+
</Describe>
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
const findLineAndColumn = (code: string, substring: string) => {
|
|
26
|
+
const index = code.indexOf(substring);
|
|
27
|
+
if (index === -1) {
|
|
28
|
+
throw new Error(`Substring "${substring}" not found in code.`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const lines = code.slice(0, index).split('\n');
|
|
32
|
+
const line = lines.length;
|
|
33
|
+
const column = lines[lines.length - 1].length + 1;
|
|
34
|
+
|
|
35
|
+
return { line, column };
|
|
36
|
+
};
|
|
37
|
+
|
|
1
38
|
describe('vitest pre plugin', () => {
|
|
2
|
-
|
|
39
|
+
it('does not transform non-test files', async () => {
|
|
40
|
+
const [pre] = getPlugins();
|
|
41
|
+
|
|
42
|
+
expect(await pre.transform(`<h1>Not a test file</h1>`, 'AComponent.svelte')).toBeUndefined();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('transforms .test.svelte files', async () => {
|
|
46
|
+
const [pre] = getPlugins();
|
|
47
|
+
|
|
48
|
+
expect(await pre.transform(dummyTestFile, 'AComponent.test.svelte')).not.toBeUndefined();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('transforms .spec.svelte files', async () => {
|
|
52
|
+
const [pre] = getPlugins();
|
|
53
|
+
|
|
54
|
+
expect(await pre.transform(dummyTestFile, 'AComponent.spec.svelte')).not.toBeUndefined();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('produces code with a dummy test suite', async () => {
|
|
58
|
+
const [pre] = getPlugins();
|
|
59
|
+
const result = await pre.transform(dummyTestFile, 'AComponent.test.svelte');
|
|
60
|
+
|
|
61
|
+
expect(result?.code).toMatchSnapshot();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('produces a source map with mappings that point to the Describe and Test components', async () => {
|
|
65
|
+
const [pre] = getPlugins();
|
|
66
|
+
const result = (await pre.transform(dummyTestFile, 'AComponent.test.svelte')) as {
|
|
67
|
+
code: string;
|
|
68
|
+
map: string;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const map = await new SourceMapConsumer(result?.map);
|
|
72
|
+
const describePosition = findLineAndColumn(result.code, 'describe("A test suite"');
|
|
73
|
+
const testPosition = findLineAndColumn(result.code, 'test("A test case"');
|
|
74
|
+
const nestedDescribePosition = findLineAndColumn(result.code, 'describe("A nested test suite"');
|
|
75
|
+
const nestedTestPosition = findLineAndColumn(result.code, 'test("A nested test case"');
|
|
76
|
+
const anotherDescribePosition = findLineAndColumn(result.code, 'describe("Another test suite"');
|
|
77
|
+
const anotherTestPosition = findLineAndColumn(result.code, 'test("Another test case"');
|
|
78
|
+
|
|
79
|
+
expect(map.originalPositionFor(describePosition)).toEqual(
|
|
80
|
+
expect.objectContaining({
|
|
81
|
+
line: 5,
|
|
82
|
+
column: 1,
|
|
83
|
+
}),
|
|
84
|
+
);
|
|
85
|
+
expect(map.originalPositionFor(testPosition)).toEqual(
|
|
86
|
+
expect.objectContaining({
|
|
87
|
+
line: 6,
|
|
88
|
+
column: 3,
|
|
89
|
+
}),
|
|
90
|
+
);
|
|
91
|
+
expect(map.originalPositionFor(nestedDescribePosition)).toEqual(
|
|
92
|
+
expect.objectContaining({
|
|
93
|
+
line: 9,
|
|
94
|
+
column: 3,
|
|
95
|
+
}),
|
|
96
|
+
);
|
|
97
|
+
expect(map.originalPositionFor(nestedTestPosition)).toEqual(
|
|
98
|
+
expect.objectContaining({
|
|
99
|
+
line: 10,
|
|
100
|
+
column: 5,
|
|
101
|
+
}),
|
|
102
|
+
);
|
|
103
|
+
expect(map.originalPositionFor(anotherDescribePosition)).toEqual(
|
|
104
|
+
expect.objectContaining({
|
|
105
|
+
line: 15,
|
|
106
|
+
column: 1,
|
|
107
|
+
}),
|
|
108
|
+
);
|
|
109
|
+
expect(map.originalPositionFor(anotherTestPosition)).toEqual(
|
|
110
|
+
expect.objectContaining({
|
|
111
|
+
line: 16,
|
|
112
|
+
column: 3,
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('produces (unnamed) suite names for Describe', async () => {
|
|
118
|
+
const [pre] = getPlugins();
|
|
119
|
+
const result = (await pre.transform(
|
|
120
|
+
`
|
|
121
|
+
<Describe>
|
|
122
|
+
<Test it="A test case">
|
|
123
|
+
<Check fn={() => {}} />
|
|
124
|
+
</Test>
|
|
125
|
+
</Describe>
|
|
126
|
+
`,
|
|
127
|
+
'AComponent.test.svelte',
|
|
128
|
+
)) as { code: string };
|
|
129
|
+
|
|
130
|
+
expect(result.code).toContain('describe("(unnamed)"');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('produces (unnamed) test names for Test', async () => {
|
|
134
|
+
const [pre] = getPlugins();
|
|
135
|
+
const result = (await pre.transform(
|
|
136
|
+
`
|
|
137
|
+
<Describe label="A test suite">
|
|
138
|
+
<Test>
|
|
139
|
+
<Check fn={() => {}} />
|
|
140
|
+
</Test>
|
|
141
|
+
</Describe>
|
|
142
|
+
`,
|
|
143
|
+
'AComponent.test.svelte',
|
|
144
|
+
)) as { code: string };
|
|
145
|
+
|
|
146
|
+
expect(result.code).toContain('test("(unnamed)"');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('produces (unnamed) suite names when Describe has dynamic label', async () => {
|
|
150
|
+
const [pre] = getPlugins();
|
|
151
|
+
const result = (await pre.transform(
|
|
152
|
+
`
|
|
153
|
+
<Describe label={someVariable}>
|
|
154
|
+
<Test it="A test case">
|
|
155
|
+
<Check fn={() => {}} />
|
|
156
|
+
</Test>
|
|
157
|
+
</Describe>
|
|
158
|
+
`,
|
|
159
|
+
'AComponent.test.svelte',
|
|
160
|
+
)) as { code: string };
|
|
161
|
+
|
|
162
|
+
expect(result.code).toContain('describe("(unnamed)"');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('produces (unnamed) test names when Test has dynamic name', async () => {
|
|
166
|
+
const [pre] = getPlugins();
|
|
167
|
+
const result = (await pre.transform(
|
|
168
|
+
`
|
|
169
|
+
<Describe label="A test suite">
|
|
170
|
+
<Test it={someVariable}>
|
|
171
|
+
<Check fn={() => {}} />
|
|
172
|
+
</Test>
|
|
173
|
+
</Describe>
|
|
174
|
+
`,
|
|
175
|
+
'AComponent.test.svelte',
|
|
176
|
+
)) as { code: string };
|
|
177
|
+
|
|
178
|
+
expect(result.code).toContain('test("(unnamed)"');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('does not produce descibe or test calls when no Describe or Test components are present', async () => {
|
|
182
|
+
const [pre] = getPlugins();
|
|
183
|
+
const result = (await pre.transform(
|
|
184
|
+
`
|
|
185
|
+
<Header>Not a test file</Header>
|
|
186
|
+
`,
|
|
187
|
+
'AComponent.test.svelte',
|
|
188
|
+
)) as { code: string };
|
|
189
|
+
|
|
190
|
+
expect(result.code).not.toContain('describe(');
|
|
191
|
+
expect(result.code).not.toContain('test(');
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe('vitest post plugin', () => {
|
|
196
|
+
it('does not transform non-test files', async () => {
|
|
197
|
+
const [, post] = getPlugins();
|
|
198
|
+
|
|
199
|
+
expect(
|
|
200
|
+
await post.transform(`export default function AComponent() {}`, 'AComponent.svelte'),
|
|
201
|
+
).toBeUndefined();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('transforms .test.svelte files to mount the component', async () => {
|
|
205
|
+
const [, post] = getPlugins();
|
|
206
|
+
|
|
207
|
+
expect(
|
|
208
|
+
await post.transform(`export default function AComponent() {}`, 'AComponent.test.svelte'),
|
|
209
|
+
).not.toBeUndefined();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('transforms .spec.svelte files to mount the component', async () => {
|
|
213
|
+
const [, post] = getPlugins();
|
|
214
|
+
|
|
215
|
+
expect(
|
|
216
|
+
await post.transform(`export default function AComponent() {}`, 'AComponent.spec.svelte'),
|
|
217
|
+
).not.toBeUndefined();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('produces code that mounts the component and returns a render result', async () => {
|
|
221
|
+
const [, post] = getPlugins();
|
|
222
|
+
const result = await post.transform(
|
|
223
|
+
`export default function AComponent() {}`,
|
|
224
|
+
'AComponent.test.svelte',
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
expect(result?.code).toMatchSnapshot();
|
|
228
|
+
});
|
|
3
229
|
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tries to execute a function and returns its result or undefined if an error occurs.
|
|
3
|
+
* @template T
|
|
4
|
+
* @param {T extends (...args: any[]) => any} fn
|
|
5
|
+
* @returns {ReturnType<T> | undefined}
|
|
6
|
+
*/
|
|
7
|
+
export default function tryFn(fn, ...args) {
|
|
8
|
+
try {
|
|
9
|
+
return fn(...args);
|
|
10
|
+
//eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
11
|
+
} catch (error) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
}
|
package/tsconfig.json
CHANGED
package/vitest.config.ts
CHANGED
|
@@ -7,6 +7,22 @@ export default defineConfig({
|
|
|
7
7
|
logLevel: 'warn',
|
|
8
8
|
plugins: [svelte(), svelteTesting(), getPlugins()],
|
|
9
9
|
test: {
|
|
10
|
+
projects: [
|
|
11
|
+
{
|
|
12
|
+
extends: './vitest.config.ts',
|
|
13
|
+
test: {
|
|
14
|
+
name: 'unit',
|
|
15
|
+
include: ['src/**/*.{test,spec}.ts'],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
extends: './vitest.config.ts',
|
|
20
|
+
test: {
|
|
21
|
+
name: 'examples',
|
|
22
|
+
include: ['examples/**/*.{test,spec}.svelte'],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
],
|
|
10
26
|
coverage: {
|
|
11
27
|
provider: 'v8',
|
|
12
28
|
reporter: ['text', 'html'],
|
|
@@ -16,6 +32,5 @@ export default defineConfig({
|
|
|
16
32
|
requireAssertions: true,
|
|
17
33
|
},
|
|
18
34
|
globals: true,
|
|
19
|
-
include: ['examples/**/*.{test,spec}.svelte', 'src/**/*.{test,spec}.ts'],
|
|
20
35
|
},
|
|
21
36
|
});
|