@testing-library/svelte 4.2.1 → 4.2.2
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/package.json +2 -2
- package/src/__tests__/act.test.js +8 -31
- package/src/__tests__/auto-cleanup.test.js +1 -1
- package/src/__tests__/cleanup.test.js +3 -4
- package/src/__tests__/context.test.js +1 -1
- package/src/__tests__/debug.test.js +6 -12
- package/src/__tests__/events.test.js +6 -4
- package/src/__tests__/fixtures/Comp.svelte +2 -8
- package/src/__tests__/fixtures/Context.svelte +2 -2
- package/src/__tests__/fixtures/Simple.svelte +2 -0
- package/src/__tests__/mount.test.js +1 -1
- package/src/__tests__/multi-base.test.js +7 -7
- package/src/__tests__/render.test.js +55 -93
- package/src/__tests__/rerender.test.js +37 -28
- package/src/__tests__/transition.test.js +3 -4
- package/src/index.js +6 -1
- package/src/pure.js +83 -79
- package/src/svelte5-index.js +6 -1
- package/src/svelte5.js +17 -28
- package/src/vitest.js +1 -2
- package/types/index.d.ts +8 -15
- package/src/__tests__/__snapshots__/render.test.js.snap +0 -48
- package/src/__tests__/fixtures/Comp2.svelte +0 -15
- package/src/__tests__/fixtures/Rerender.svelte +0 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testing-library/svelte",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.2",
|
|
4
4
|
"description": "Simple and complete Svelte testing utilities that encourage good testing practices.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"npm-run-all": "^4.1.5",
|
|
99
99
|
"prettier": "3.2.4",
|
|
100
100
|
"prettier-plugin-svelte": "3.1.2",
|
|
101
|
-
"svelte": "^4
|
|
101
|
+
"svelte": "^3 || ^4 || ^5",
|
|
102
102
|
"svelte-check": "^3.6.3",
|
|
103
103
|
"svelte-jester": "^3.0.0",
|
|
104
104
|
"typescript": "^5.3.3",
|
|
@@ -1,25 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { setTimeout } from 'node:timers/promises'
|
|
2
|
+
|
|
3
|
+
import { act, render } from '@testing-library/svelte'
|
|
4
|
+
import { describe, expect, test } from 'vitest'
|
|
2
5
|
|
|
3
|
-
import { act, fireEvent, render as stlRender } from '@testing-library/svelte'
|
|
4
6
|
import Comp from './fixtures/Comp.svelte'
|
|
5
7
|
|
|
6
8
|
describe('act', () => {
|
|
7
|
-
let props
|
|
8
|
-
|
|
9
|
-
const render = () => {
|
|
10
|
-
return stlRender(Comp, {
|
|
11
|
-
props
|
|
12
|
-
})
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
props = {
|
|
17
|
-
name: 'World'
|
|
18
|
-
}
|
|
19
|
-
})
|
|
20
|
-
|
|
21
9
|
test('state updates are flushed', async () => {
|
|
22
|
-
const { getByText } = render()
|
|
10
|
+
const { getByText } = render(Comp)
|
|
23
11
|
const button = getByText('Button')
|
|
24
12
|
|
|
25
13
|
expect(button).toHaveTextContent('Button')
|
|
@@ -31,24 +19,13 @@ describe('act', () => {
|
|
|
31
19
|
expect(button).toHaveTextContent('Button Clicked')
|
|
32
20
|
})
|
|
33
21
|
|
|
34
|
-
test('findByTestId returns the element', async () => {
|
|
35
|
-
const { findByTestId } = render()
|
|
36
|
-
|
|
37
|
-
expect(await findByTestId('test')).toHaveTextContent(`Hello ${props.name}!`)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
22
|
test('accepts async functions', async () => {
|
|
41
|
-
const
|
|
42
|
-
new Promise((resolve) => {
|
|
43
|
-
setTimeout(() => resolve(), ms)
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
const { getByText } = render()
|
|
23
|
+
const { getByText } = render(Comp)
|
|
47
24
|
const button = getByText('Button')
|
|
48
25
|
|
|
49
26
|
await act(async () => {
|
|
50
|
-
await
|
|
51
|
-
|
|
27
|
+
await setTimeout(100)
|
|
28
|
+
button.click()
|
|
52
29
|
})
|
|
53
30
|
|
|
54
31
|
expect(button).toHaveTextContent('Button Clicked')
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import { cleanup, render } from '@testing-library/svelte'
|
|
1
2
|
import { describe, expect, test, vi } from 'vitest'
|
|
2
|
-
import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
|
|
3
3
|
|
|
4
|
-
import { act, cleanup, render } from '@testing-library/svelte'
|
|
5
4
|
import Mounter from './fixtures/Mounter.svelte'
|
|
6
5
|
|
|
7
6
|
const onExecuted = vi.fn()
|
|
@@ -16,8 +15,8 @@ describe('cleanup', () => {
|
|
|
16
15
|
expect(document.body).toBeEmptyDOMElement()
|
|
17
16
|
})
|
|
18
17
|
|
|
19
|
-
test
|
|
20
|
-
|
|
18
|
+
test('cleanup unmounts component', () => {
|
|
19
|
+
renderSubject()
|
|
21
20
|
cleanup()
|
|
22
21
|
|
|
23
22
|
expect(onDestroyed).toHaveBeenCalledOnce()
|
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
import { prettyDOM } from '@testing-library/dom'
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
|
|
3
|
-
|
|
4
2
|
import { render } from '@testing-library/svelte'
|
|
3
|
+
import { describe, expect, test, vi } from 'vitest'
|
|
4
|
+
|
|
5
5
|
import Comp from './fixtures/Comp.svelte'
|
|
6
6
|
|
|
7
7
|
describe('debug', () => {
|
|
8
|
-
|
|
9
|
-
vi.
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
afterEach(() => {
|
|
13
|
-
console.log.mockRestore()
|
|
14
|
-
})
|
|
8
|
+
test('pretty prints the base element', () => {
|
|
9
|
+
vi.stubGlobal('console', { log: vi.fn(), warn: vi.fn(), error: vi.fn() })
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
const { container, debug } = render(Comp, { props: { name: 'world' } })
|
|
11
|
+
const { baseElement, debug } = render(Comp, { props: { name: 'world' } })
|
|
18
12
|
|
|
19
13
|
debug()
|
|
20
14
|
|
|
21
15
|
expect(console.log).toHaveBeenCalledTimes(1)
|
|
22
|
-
expect(console.log).toHaveBeenCalledWith(prettyDOM(
|
|
16
|
+
expect(console.log).toHaveBeenCalledWith(prettyDOM(baseElement))
|
|
23
17
|
})
|
|
24
18
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { fireEvent, render } from '@testing-library/svelte'
|
|
1
2
|
import { describe, expect, test } from 'vitest'
|
|
2
3
|
|
|
3
|
-
import { fireEvent, render } from '@testing-library/svelte'
|
|
4
4
|
import Comp from './fixtures/Comp.svelte'
|
|
5
5
|
|
|
6
6
|
describe('events', () => {
|
|
@@ -8,8 +8,9 @@ describe('events', () => {
|
|
|
8
8
|
const { getByText } = render(Comp, { props: { name: 'World' } })
|
|
9
9
|
const button = getByText('Button')
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
const result = fireEvent.click(button)
|
|
12
12
|
|
|
13
|
+
await expect(result).resolves.toBe(true)
|
|
13
14
|
expect(button).toHaveTextContent('Button Clicked')
|
|
14
15
|
})
|
|
15
16
|
|
|
@@ -17,14 +18,15 @@ describe('events', () => {
|
|
|
17
18
|
const { getByText } = render(Comp, { props: { name: 'World' } })
|
|
18
19
|
const button = getByText('Button')
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
const result = fireEvent(
|
|
21
22
|
button,
|
|
22
23
|
new MouseEvent('click', {
|
|
23
24
|
bubbles: true,
|
|
24
|
-
cancelable: true
|
|
25
|
+
cancelable: true,
|
|
25
26
|
})
|
|
26
27
|
)
|
|
27
28
|
|
|
29
|
+
await expect(result).resolves.toBe(true)
|
|
28
30
|
expect(button).toHaveTextContent('Button Clicked')
|
|
29
31
|
})
|
|
30
32
|
})
|
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
<svelte:options accessors />
|
|
2
2
|
|
|
3
3
|
<script>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export let name
|
|
4
|
+
export let name = 'World'
|
|
7
5
|
|
|
8
6
|
let buttonText = 'Button'
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
function handleClick () {
|
|
8
|
+
function handleClick() {
|
|
13
9
|
buttonText = 'Button Clicked'
|
|
14
10
|
}
|
|
15
11
|
</script>
|
|
16
12
|
|
|
17
13
|
<h1 data-testid="test">Hello {name}!</h1>
|
|
18
14
|
|
|
19
|
-
<div>we have {contextName}</div>
|
|
20
|
-
|
|
21
15
|
<button on:click={handleClick}>{buttonText}</button>
|
|
22
16
|
|
|
23
17
|
<style></style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { act, render, screen } from '@testing-library/svelte'
|
|
1
2
|
import { describe, expect, test, vi } from 'vitest'
|
|
2
3
|
|
|
3
|
-
import { act, render, screen } from '@testing-library/svelte'
|
|
4
4
|
import Mounter from './fixtures/Mounter.svelte'
|
|
5
5
|
import { IS_HAPPYDOM, IS_SVELTE_5 } from './utils.js'
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { render } from '@testing-library/svelte'
|
|
1
2
|
import { describe, expect, test } from 'vitest'
|
|
2
3
|
|
|
3
|
-
import { render } from '@testing-library/svelte'
|
|
4
4
|
import Comp from './fixtures/Comp.svelte'
|
|
5
5
|
|
|
6
6
|
describe('multi-base', () => {
|
|
@@ -13,11 +13,11 @@ describe('multi-base', () => {
|
|
|
13
13
|
{
|
|
14
14
|
target: treeA,
|
|
15
15
|
props: {
|
|
16
|
-
name: 'Tree A'
|
|
17
|
-
}
|
|
16
|
+
name: 'Tree A',
|
|
17
|
+
},
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
|
-
|
|
20
|
+
baseElement: treeA,
|
|
21
21
|
}
|
|
22
22
|
)
|
|
23
23
|
|
|
@@ -26,11 +26,11 @@ describe('multi-base', () => {
|
|
|
26
26
|
{
|
|
27
27
|
target: treeB,
|
|
28
28
|
props: {
|
|
29
|
-
name: 'Tree B'
|
|
30
|
-
}
|
|
29
|
+
name: 'Tree B',
|
|
30
|
+
},
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
|
|
33
|
+
baseElement: treeB,
|
|
34
34
|
}
|
|
35
35
|
)
|
|
36
36
|
|
|
@@ -1,123 +1,85 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { render } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, test } from 'vitest'
|
|
3
3
|
|
|
4
|
-
import { act, render as stlRender } from '@testing-library/svelte'
|
|
5
4
|
import Comp from './fixtures/Comp.svelte'
|
|
6
|
-
import
|
|
5
|
+
import { IS_SVELTE_5 } from './utils.js'
|
|
7
6
|
|
|
8
7
|
describe('render', () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const render = (additional = {}) => {
|
|
12
|
-
return stlRender(Comp, {
|
|
13
|
-
target: document.body,
|
|
14
|
-
props,
|
|
15
|
-
...additional,
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
props = {
|
|
21
|
-
name: 'World',
|
|
22
|
-
}
|
|
23
|
-
})
|
|
8
|
+
const props = { name: 'World' }
|
|
24
9
|
|
|
25
10
|
test('renders component into the document', () => {
|
|
26
|
-
const { getByText } = render()
|
|
11
|
+
const { getByText } = render(Comp, { props })
|
|
27
12
|
|
|
28
13
|
expect(getByText('Hello World!')).toBeInTheDocument()
|
|
29
14
|
})
|
|
30
15
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const { component, getByText } = render()
|
|
34
|
-
|
|
16
|
+
test('accepts props directly', () => {
|
|
17
|
+
const { getByText } = render(Comp, props)
|
|
35
18
|
expect(getByText('Hello World!')).toBeInTheDocument()
|
|
36
|
-
|
|
37
|
-
await act(() => {
|
|
38
|
-
component.$set({ name: 'Worlds' })
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
expect(getByText('Hello Worlds!')).toBeInTheDocument()
|
|
42
19
|
})
|
|
43
20
|
|
|
44
|
-
test('
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
expect(getByText('Hello World!')).toBeInTheDocument()
|
|
21
|
+
test('throws error when mixing svelte component options and props', () => {
|
|
22
|
+
expect(() => {
|
|
23
|
+
render(Comp, { props, name: 'World' })
|
|
24
|
+
}).toThrow(/Unknown options/)
|
|
25
|
+
})
|
|
50
26
|
|
|
51
|
-
|
|
27
|
+
test('throws error when mixing target option and props', () => {
|
|
28
|
+
expect(() => {
|
|
29
|
+
render(Comp, { target: document.createElement('div'), name: 'World' })
|
|
30
|
+
}).toThrow(/Unknown options/)
|
|
31
|
+
})
|
|
52
32
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
33
|
+
test('should return a container object wrapping the DOM of the rendered component', () => {
|
|
34
|
+
const { container, getByTestId } = render(Comp, props)
|
|
35
|
+
const firstElement = getByTestId('test')
|
|
56
36
|
|
|
57
|
-
expect(
|
|
37
|
+
expect(container.firstChild).toBe(firstElement)
|
|
58
38
|
})
|
|
59
39
|
|
|
60
|
-
test('should
|
|
61
|
-
const {
|
|
62
|
-
expect(getByText('Hello World!')).toBeInTheDocument()
|
|
63
|
-
})
|
|
40
|
+
test('should return a baseElement object, which holds the container', () => {
|
|
41
|
+
const { baseElement, container } = render(Comp, props)
|
|
64
42
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
() => {
|
|
68
|
-
const target = document.createElement('div')
|
|
69
|
-
const div = document.createElement('div')
|
|
70
|
-
document.body.appendChild(target)
|
|
71
|
-
target.appendChild(div)
|
|
72
|
-
const { container } = stlRender(Comp, {
|
|
73
|
-
target,
|
|
74
|
-
anchor: div,
|
|
75
|
-
props: { name: 'World' },
|
|
76
|
-
context: new Map([['name', 'context']]),
|
|
77
|
-
})
|
|
78
|
-
expect(container).toMatchSnapshot()
|
|
79
|
-
}
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
test.runIf(SVELTE_VERSION >= '5')(
|
|
83
|
-
'should accept svelte v5 component options',
|
|
84
|
-
() => {
|
|
85
|
-
const target = document.createElement('section')
|
|
86
|
-
document.body.appendChild(target)
|
|
87
|
-
|
|
88
|
-
const { container } = stlRender(Comp, {
|
|
89
|
-
target,
|
|
90
|
-
props: { name: 'World' },
|
|
91
|
-
context: new Map([['name', 'context']]),
|
|
92
|
-
})
|
|
93
|
-
expect(container).toMatchSnapshot()
|
|
94
|
-
}
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
test('should throw error when mixing svelte component options and props', () => {
|
|
98
|
-
expect(() => {
|
|
99
|
-
stlRender(Comp, { props: {}, name: 'World' })
|
|
100
|
-
}).toThrow(/Unknown options were found/)
|
|
43
|
+
expect(baseElement).toBe(document.body)
|
|
44
|
+
expect(baseElement.firstChild).toBe(container)
|
|
101
45
|
})
|
|
102
46
|
|
|
103
|
-
test('
|
|
104
|
-
const
|
|
47
|
+
test('if target is provided, use it as container and baseElement', () => {
|
|
48
|
+
const target = document.createElement('div')
|
|
49
|
+
const { baseElement, container } = render(Comp, { props, target })
|
|
105
50
|
|
|
106
|
-
expect(container
|
|
51
|
+
expect(container).toBe(target)
|
|
52
|
+
expect(baseElement).toBe(target)
|
|
107
53
|
})
|
|
108
54
|
|
|
109
|
-
test('
|
|
110
|
-
const
|
|
55
|
+
test('allow baseElement to be specified', () => {
|
|
56
|
+
const customBaseElement = document.createElement('div')
|
|
111
57
|
|
|
112
|
-
|
|
58
|
+
const { baseElement, container } = render(
|
|
59
|
+
Comp,
|
|
60
|
+
{ props },
|
|
61
|
+
{ baseElement: customBaseElement }
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
expect(baseElement).toBe(customBaseElement)
|
|
65
|
+
expect(baseElement.firstChild).toBe(container)
|
|
113
66
|
})
|
|
114
67
|
|
|
115
|
-
test(
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
68
|
+
test.skipIf(IS_SVELTE_5)('should accept anchor option in Svelte v4', () => {
|
|
69
|
+
const baseElement = document.body
|
|
70
|
+
const target = document.createElement('section')
|
|
71
|
+
const anchor = document.createElement('div')
|
|
72
|
+
baseElement.appendChild(target)
|
|
73
|
+
target.appendChild(anchor)
|
|
74
|
+
|
|
75
|
+
const { getByTestId } = render(
|
|
76
|
+
Comp,
|
|
77
|
+
{ props, target, anchor },
|
|
78
|
+
{ baseElement }
|
|
79
|
+
)
|
|
80
|
+
const firstElement = getByTestId('test')
|
|
120
81
|
|
|
121
|
-
expect(
|
|
82
|
+
expect(target.firstChild).toBe(firstElement)
|
|
83
|
+
expect(target.lastChild).toBe(anchor)
|
|
122
84
|
})
|
|
123
85
|
})
|
|
@@ -1,41 +1,50 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { expect, test, vi } from 'vitest'
|
|
1
|
+
import { act, render, screen } from '@testing-library/svelte'
|
|
2
|
+
import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
|
|
3
|
+
import { describe, expect, test, vi } from 'vitest'
|
|
5
4
|
|
|
6
|
-
import
|
|
5
|
+
import Comp from './fixtures/Comp.svelte'
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
describe('rerender', () => {
|
|
8
|
+
test('updates props', async () => {
|
|
9
|
+
const { rerender } = render(Comp, { name: 'World' })
|
|
10
|
+
const element = screen.getByText('Hello World!')
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
const onMounted = vi.fn()
|
|
12
|
-
const onDestroyed = vi.fn()
|
|
12
|
+
await rerender({ name: 'Dolly' })
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
props: { name: 'World 1', onMounted, onDestroyed },
|
|
14
|
+
expect(element).toHaveTextContent('Hello Dolly!')
|
|
16
15
|
})
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
expect(getByTestId('test')).toHaveTextContent(content)
|
|
21
|
-
expect(onMounted).toHaveBeenCalledOnce()
|
|
22
|
-
})
|
|
17
|
+
test('warns if incorrect arguments shape used', async () => {
|
|
18
|
+
vi.stubGlobal('console', { log: vi.fn(), warn: vi.fn(), error: vi.fn() })
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
const { rerender } = render(Comp, { name: 'World' })
|
|
21
|
+
const element = screen.getByText('Hello World!')
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
await rerender({ props: { name: 'Dolly' } })
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
expect(element).toHaveTextContent('Hello Dolly!')
|
|
26
|
+
expect(console.warn).toHaveBeenCalledOnce()
|
|
27
|
+
expect(console.warn).toHaveBeenCalledWith(
|
|
28
|
+
expect.stringMatching(/deprecated/iu)
|
|
29
|
+
)
|
|
30
|
+
})
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
test('change props with accessors', async () => {
|
|
33
|
+
const { component, getByText } = render(
|
|
34
|
+
Comp,
|
|
35
|
+
SVELTE_VERSION < '5'
|
|
36
|
+
? { accessors: true, props: { name: 'World' } }
|
|
37
|
+
: { name: 'World' }
|
|
38
|
+
)
|
|
39
|
+
const element = getByText('Hello World!')
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
rerender({ name: 'World 3' })
|
|
37
|
-
await expectToRender('Hello World 3!')
|
|
38
|
-
expect(onDestroyed).not.toHaveBeenCalled()
|
|
41
|
+
expect(element).toBeInTheDocument()
|
|
42
|
+
expect(component.name).toBe('World')
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
await act(() => {
|
|
45
|
+
component.name = 'Planet'
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
expect(element).toHaveTextContent('Hello Planet!')
|
|
49
|
+
})
|
|
41
50
|
})
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
+
import { render, screen, waitFor } from '@testing-library/svelte'
|
|
1
2
|
import { userEvent } from '@testing-library/user-event'
|
|
2
3
|
import { beforeEach, describe, expect, test, vi } from 'vitest'
|
|
3
4
|
|
|
4
|
-
import { IS_JSDOM, IS_SVELTE_5 } from './utils.js'
|
|
5
|
-
|
|
6
|
-
import { render, screen, waitFor } from '@testing-library/svelte'
|
|
7
5
|
import Transitioner from './fixtures/Transitioner.svelte'
|
|
6
|
+
import { IS_JSDOM, IS_SVELTE_5 } from './utils.js'
|
|
8
7
|
|
|
9
|
-
describe.
|
|
8
|
+
describe.skipIf(IS_SVELTE_5)('transitions', () => {
|
|
10
9
|
beforeEach(() => {
|
|
11
10
|
if (!IS_JSDOM) return
|
|
12
11
|
|
package/src/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable import/export */
|
|
1
2
|
import { act, cleanup } from './pure.js'
|
|
2
3
|
|
|
3
4
|
// If we're running in a test runner that supports afterEach
|
|
@@ -12,5 +13,9 @@ if (typeof afterEach === 'function' && !process.env.STL_SKIP_AUTO_CLEANUP) {
|
|
|
12
13
|
})
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
export
|
|
16
|
+
// export all base queries, screen, etc.
|
|
16
17
|
export * from '@testing-library/dom'
|
|
18
|
+
|
|
19
|
+
// export svelte-specific functions and custom `fireEvent`
|
|
20
|
+
// `fireEvent` must be a named export to take priority over wildcard export above
|
|
21
|
+
export { act, cleanup, fireEvent, render } from './pure.js'
|
package/src/pure.js
CHANGED
|
@@ -3,94 +3,76 @@ import {
|
|
|
3
3
|
getQueriesForElement,
|
|
4
4
|
prettyDOM,
|
|
5
5
|
} from '@testing-library/dom'
|
|
6
|
-
import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
|
|
7
6
|
import * as Svelte from 'svelte'
|
|
7
|
+
import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
|
|
8
8
|
|
|
9
9
|
const IS_SVELTE_5 = /^5\./.test(SVELTE_VERSION)
|
|
10
|
-
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
]
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (!isProps) {
|
|
29
|
-
const unrecognizedOptions = Object.keys(options).filter(
|
|
30
|
-
(option) => !svelteComponentOptions.includes(option)
|
|
10
|
+
|
|
11
|
+
export class SvelteTestingLibrary {
|
|
12
|
+
svelteComponentOptions = [
|
|
13
|
+
'target',
|
|
14
|
+
'accessors',
|
|
15
|
+
'anchor',
|
|
16
|
+
'props',
|
|
17
|
+
'hydrate',
|
|
18
|
+
'intro',
|
|
19
|
+
'context',
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
targetCache = new Set()
|
|
23
|
+
componentCache = new Set()
|
|
24
|
+
|
|
25
|
+
checkProps(options) {
|
|
26
|
+
const isProps = !Object.keys(options).some((option) =>
|
|
27
|
+
this.svelteComponentOptions.includes(option)
|
|
31
28
|
)
|
|
32
29
|
|
|
33
|
-
if
|
|
34
|
-
|
|
30
|
+
// Check if any props and Svelte options were accidentally mixed.
|
|
31
|
+
if (!isProps) {
|
|
32
|
+
const unrecognizedOptions = Object.keys(options).filter(
|
|
33
|
+
(option) => !this.svelteComponentOptions.includes(option)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
if (unrecognizedOptions.length > 0) {
|
|
37
|
+
throw Error(`
|
|
35
38
|
Unknown options were found [${unrecognizedOptions}]. This might happen if you've mixed
|
|
36
39
|
passing in props with Svelte options into the render function. Valid Svelte options
|
|
37
|
-
are [${svelteComponentOptions}]. You can either change the prop names, or pass in your
|
|
40
|
+
are [${this.svelteComponentOptions}]. You can either change the prop names, or pass in your
|
|
38
41
|
props for that component via the \`props\` option.\n\n
|
|
39
42
|
Eg: const { /** Results **/ } = render(MyComponent, { props: { /** props here **/ } })\n\n
|
|
40
43
|
`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return options
|
|
41
47
|
}
|
|
42
48
|
|
|
43
|
-
return options
|
|
49
|
+
return { props: options }
|
|
44
50
|
}
|
|
45
51
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const checkProps = buildCheckProps(svelteComponentOptions)
|
|
50
|
-
|
|
51
|
-
const buildRenderComponent =
|
|
52
|
-
({ target, ComponentConstructor }) =>
|
|
53
|
-
(options) => {
|
|
54
|
-
options = { target, ...checkProps(options) }
|
|
55
|
-
|
|
56
|
-
if (IS_SVELTE_5)
|
|
57
|
-
throw new Error('for Svelte 5, use `@testing-library/svelte/svelte5`')
|
|
52
|
+
render(Component, componentOptions = {}, renderOptions = {}) {
|
|
53
|
+
componentOptions = this.checkProps(componentOptions)
|
|
58
54
|
|
|
59
|
-
const
|
|
55
|
+
const baseElement =
|
|
56
|
+
renderOptions.baseElement ?? componentOptions.target ?? document.body
|
|
60
57
|
|
|
61
|
-
|
|
58
|
+
const target =
|
|
59
|
+
componentOptions.target ??
|
|
60
|
+
baseElement.appendChild(document.createElement('div'))
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
// It is unnecessary has no path to implementation in Svelte v5
|
|
65
|
-
if (!IS_SVELTE_5) {
|
|
66
|
-
component.$$.on_destroy.push(() => {
|
|
67
|
-
componentCache.delete(component)
|
|
68
|
-
})
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return component
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export const buildRender =
|
|
75
|
-
(buildRenderComponent) =>
|
|
76
|
-
(Component, { target, ...options } = {}, { container, queries } = {}) => {
|
|
77
|
-
container = container || document.body
|
|
78
|
-
target = target || container.appendChild(document.createElement('div'))
|
|
79
|
-
targetCache.add(target)
|
|
62
|
+
this.targetCache.add(target)
|
|
80
63
|
|
|
81
64
|
const ComponentConstructor = Component.default || Component
|
|
82
65
|
|
|
83
|
-
const
|
|
66
|
+
const component = this.renderComponent(ComponentConstructor, {
|
|
67
|
+
...componentOptions,
|
|
84
68
|
target,
|
|
85
|
-
ComponentConstructor,
|
|
86
69
|
})
|
|
87
70
|
|
|
88
|
-
let component = renderComponent(options)
|
|
89
|
-
|
|
90
71
|
return {
|
|
91
|
-
|
|
72
|
+
baseElement,
|
|
92
73
|
component,
|
|
93
|
-
|
|
74
|
+
container: target,
|
|
75
|
+
debug: (el = baseElement) => console.log(prettyDOM(el)),
|
|
94
76
|
rerender: async (props) => {
|
|
95
77
|
if (props.props) {
|
|
96
78
|
console.warn(
|
|
@@ -102,35 +84,57 @@ export const buildRender =
|
|
|
102
84
|
await Svelte.tick()
|
|
103
85
|
},
|
|
104
86
|
unmount: () => {
|
|
105
|
-
cleanupComponent(component)
|
|
87
|
+
this.cleanupComponent(component)
|
|
106
88
|
},
|
|
107
|
-
...getQueriesForElement(
|
|
89
|
+
...getQueriesForElement(baseElement, renderOptions.queries),
|
|
108
90
|
}
|
|
109
91
|
}
|
|
110
92
|
|
|
111
|
-
|
|
93
|
+
renderComponent(ComponentConstructor, componentOptions) {
|
|
94
|
+
if (IS_SVELTE_5) {
|
|
95
|
+
throw new Error('for Svelte 5, use `@testing-library/svelte/svelte5`')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const component = new ComponentConstructor(componentOptions)
|
|
99
|
+
|
|
100
|
+
this.componentCache.add(component)
|
|
112
101
|
|
|
113
|
-
|
|
114
|
-
|
|
102
|
+
// TODO(mcous, 2024-02-11): remove this behavior in the next major version
|
|
103
|
+
component.$$.on_destroy.push(() => {
|
|
104
|
+
this.componentCache.delete(component)
|
|
105
|
+
})
|
|
115
106
|
|
|
116
|
-
|
|
117
|
-
component.$destroy()
|
|
107
|
+
return component
|
|
118
108
|
}
|
|
119
|
-
}
|
|
120
109
|
|
|
121
|
-
|
|
122
|
-
|
|
110
|
+
cleanupComponent(component) {
|
|
111
|
+
const inCache = this.componentCache.delete(component)
|
|
123
112
|
|
|
124
|
-
|
|
125
|
-
|
|
113
|
+
if (inCache) {
|
|
114
|
+
component.$destroy()
|
|
115
|
+
}
|
|
126
116
|
}
|
|
127
|
-
}
|
|
128
117
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
cleanupTarget(target) {
|
|
119
|
+
const inCache = this.targetCache.delete(target)
|
|
120
|
+
|
|
121
|
+
if (inCache && target.parentNode === document.body) {
|
|
122
|
+
document.body.removeChild(target)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
cleanup() {
|
|
127
|
+
this.componentCache.forEach(this.cleanupComponent.bind(this))
|
|
128
|
+
this.targetCache.forEach(this.cleanupTarget.bind(this))
|
|
129
|
+
}
|
|
132
130
|
}
|
|
133
131
|
|
|
132
|
+
const instance = new SvelteTestingLibrary()
|
|
133
|
+
|
|
134
|
+
export const render = instance.render.bind(instance)
|
|
135
|
+
|
|
136
|
+
export const cleanup = instance.cleanup.bind(instance)
|
|
137
|
+
|
|
134
138
|
export const act = async (fn) => {
|
|
135
139
|
if (fn) {
|
|
136
140
|
await fn()
|
package/src/svelte5-index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable import/export */
|
|
1
2
|
import { act, cleanup } from './svelte5.js'
|
|
2
3
|
|
|
3
4
|
// If we're running in a test runner that supports afterEach
|
|
@@ -12,6 +13,10 @@ if (typeof afterEach === 'function' && !process.env.STL_SKIP_AUTO_CLEANUP) {
|
|
|
12
13
|
})
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
export
|
|
16
|
+
// export all base queries, screen, etc.
|
|
16
17
|
export * from '@testing-library/dom'
|
|
18
|
+
|
|
19
|
+
// export svelte-specific functions and custom `fireEvent`
|
|
20
|
+
// `fireEvent` must be a named export to take priority over wildcard export above
|
|
17
21
|
export { act, fireEvent } from './pure.js'
|
|
22
|
+
export { cleanup, render } from './svelte5.js'
|
package/src/svelte5.js
CHANGED
|
@@ -1,41 +1,30 @@
|
|
|
1
1
|
import { createClassComponent } from 'svelte/legacy'
|
|
2
|
-
import {
|
|
3
|
-
componentCache,
|
|
4
|
-
cleanup,
|
|
5
|
-
buildCheckProps,
|
|
6
|
-
buildRender,
|
|
7
|
-
} from './pure.js'
|
|
8
2
|
|
|
9
|
-
|
|
10
|
-
'target',
|
|
11
|
-
'props',
|
|
12
|
-
'events',
|
|
13
|
-
'context',
|
|
14
|
-
'intro',
|
|
15
|
-
'recover',
|
|
16
|
-
]
|
|
3
|
+
import { SvelteTestingLibrary } from './pure.js'
|
|
17
4
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
5
|
+
class Svelte5TestingLibrary extends SvelteTestingLibrary {
|
|
6
|
+
svelteComponentOptions = [
|
|
7
|
+
'target',
|
|
8
|
+
'props',
|
|
9
|
+
'events',
|
|
10
|
+
'context',
|
|
11
|
+
'intro',
|
|
12
|
+
'recover',
|
|
13
|
+
]
|
|
24
14
|
|
|
15
|
+
renderComponent(ComponentConstructor, componentOptions) {
|
|
25
16
|
const component = createClassComponent({
|
|
17
|
+
...componentOptions,
|
|
26
18
|
component: ComponentConstructor,
|
|
27
|
-
...options,
|
|
28
19
|
})
|
|
29
20
|
|
|
30
|
-
componentCache.add(component)
|
|
21
|
+
this.componentCache.add(component)
|
|
31
22
|
|
|
32
23
|
return component
|
|
33
24
|
}
|
|
25
|
+
}
|
|
34
26
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
/* eslint-disable import/export */
|
|
38
|
-
|
|
39
|
-
import { act, fireEvent } from './pure.js'
|
|
27
|
+
const instance = new Svelte5TestingLibrary()
|
|
40
28
|
|
|
41
|
-
export
|
|
29
|
+
export const render = instance.render.bind(instance)
|
|
30
|
+
export const cleanup = instance.cleanup.bind(instance)
|
package/src/vitest.js
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -18,12 +18,7 @@ export * from '@testing-library/dom'
|
|
|
18
18
|
|
|
19
19
|
type SvelteComponentOptions<C extends SvelteComponent> =
|
|
20
20
|
| ComponentProps<C>
|
|
21
|
-
|
|
|
22
|
-
ComponentConstructorOptions<ComponentProps<C>>,
|
|
23
|
-
'anchor' | 'props' | 'hydrate' | 'intro' | 'context'
|
|
24
|
-
>
|
|
25
|
-
|
|
26
|
-
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
|
|
21
|
+
| Partial<ComponentConstructorOptions<ComponentProps<C>>>
|
|
27
22
|
|
|
28
23
|
type Constructor<T> = new (...args: any[]) => T
|
|
29
24
|
|
|
@@ -35,24 +30,22 @@ export type RenderResult<
|
|
|
35
30
|
Q extends Queries = typeof queries,
|
|
36
31
|
> = {
|
|
37
32
|
container: HTMLElement
|
|
33
|
+
baseElement: HTMLElement
|
|
38
34
|
component: C
|
|
39
35
|
debug: (el?: HTMLElement | DocumentFragment) => void
|
|
40
|
-
rerender: (props: ComponentProps<C
|
|
36
|
+
rerender: (props: Partial<ComponentProps<C>>) => Promise<void>
|
|
41
37
|
unmount: () => void
|
|
42
38
|
} & { [P in keyof Q]: BoundFunction<Q[P]> }
|
|
43
39
|
|
|
44
40
|
export interface RenderOptions<Q extends Queries = typeof queries> {
|
|
45
|
-
|
|
41
|
+
baseElement?: HTMLElement
|
|
46
42
|
queries?: Q
|
|
47
43
|
}
|
|
48
44
|
|
|
49
|
-
export function render<
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
): RenderResult<C>
|
|
54
|
-
|
|
55
|
-
export function render<C extends SvelteComponent, Q extends Queries>(
|
|
45
|
+
export function render<
|
|
46
|
+
C extends SvelteComponent,
|
|
47
|
+
Q extends Queries = typeof queries,
|
|
48
|
+
>(
|
|
56
49
|
component: Constructor<C>,
|
|
57
50
|
componentOptions?: SvelteComponentOptions<C>,
|
|
58
51
|
renderOptions?: RenderOptions<Q>
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
-
|
|
3
|
-
exports[`render > should accept svelte v4 component options 1`] = `
|
|
4
|
-
<body>
|
|
5
|
-
<div>
|
|
6
|
-
<h1
|
|
7
|
-
data-testid="test"
|
|
8
|
-
>
|
|
9
|
-
Hello
|
|
10
|
-
World
|
|
11
|
-
!
|
|
12
|
-
</h1>
|
|
13
|
-
|
|
14
|
-
<div>
|
|
15
|
-
we have context
|
|
16
|
-
</div>
|
|
17
|
-
|
|
18
|
-
<button>
|
|
19
|
-
Button
|
|
20
|
-
</button>
|
|
21
|
-
<div />
|
|
22
|
-
</div>
|
|
23
|
-
</body>
|
|
24
|
-
`;
|
|
25
|
-
|
|
26
|
-
exports[`render > should accept svelte v5 component options 1`] = `
|
|
27
|
-
<body>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<section>
|
|
32
|
-
<h1
|
|
33
|
-
data-testid="test"
|
|
34
|
-
>
|
|
35
|
-
Hello World!
|
|
36
|
-
</h1>
|
|
37
|
-
|
|
38
|
-
<div>
|
|
39
|
-
we have context
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
<button>
|
|
43
|
-
Button
|
|
44
|
-
</button>
|
|
45
|
-
|
|
46
|
-
</section>
|
|
47
|
-
</body>
|
|
48
|
-
`;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import { onDestroy, onMount } from 'svelte'
|
|
3
|
-
|
|
4
|
-
export let onExecuted = undefined
|
|
5
|
-
export let onMounted = undefined
|
|
6
|
-
export let onDestroyed = undefined
|
|
7
|
-
|
|
8
|
-
export let name = ''
|
|
9
|
-
|
|
10
|
-
onExecuted?.()
|
|
11
|
-
|
|
12
|
-
onMount(() => onMounted?.())
|
|
13
|
-
|
|
14
|
-
onDestroy(() => onDestroyed?.())
|
|
15
|
-
</script>
|
|
16
|
-
|
|
17
|
-
<div data-testid="test">Hello {name}!</div>
|