-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathsvelte5.js
145 lines (118 loc) · 3.79 KB
/
svelte5.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import {
fireEvent as dtlFireEvent,
getQueriesForElement,
prettyDOM,
} from '@testing-library/dom'
import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
import { createClassComponent as createComponentSvelte5 } from 'svelte/legacy'
import * as Svelte from 'svelte'
const IS_SVELTE_5 = /^5\./.test(SVELTE_VERSION)
const targetCache = new Set()
const componentCache = new Set()
const svelteComponentOptions = IS_SVELTE_5
? ['target', 'props', 'events', 'context', 'intro', 'recover']
: ['accessors', 'anchor', 'props', 'hydrate', 'intro', 'context']
const render = (
Component,
{ target, ...options } = {},
{ container, queries } = {}
) => {
container = container || document.body
target = target || container.appendChild(document.createElement('div'))
targetCache.add(target)
const ComponentConstructor = Component.default || Component
const checkProps = (options) => {
const isProps = !Object.keys(options).some((option) =>
svelteComponentOptions.includes(option)
)
// Check if any props and Svelte options were accidentally mixed.
if (!isProps) {
const unrecognizedOptions = Object.keys(options).filter(
(option) => !svelteComponentOptions.includes(option)
)
if (unrecognizedOptions.length > 0) {
throw Error(`
Unknown options were found [${unrecognizedOptions}]. This might happen if you've mixed
passing in props with Svelte options into the render function. Valid Svelte options
are [${svelteComponentOptions}]. You can either change the prop names, or pass in your
props for that component via the \`props\` option.\n\n
Eg: const { /** Results **/ } = render(MyComponent, { props: { /** props here **/ } })\n\n
`)
}
return options
}
return { props: options }
}
const renderComponent = (options) => {
options = { target, ...checkProps(options) }
const component = IS_SVELTE_5
? createComponentSvelte5({ component: ComponentConstructor, ...options })
: new ComponentConstructor(options)
componentCache.add(component)
// TODO(mcous, 2024-02-11): remove this behavior in the next major version
// It is unnecessary has no path to implementation in Svelte v5
if (!IS_SVELTE_5) {
component.$$.on_destroy.push(() => {
componentCache.delete(component)
})
}
return component
}
let component = renderComponent(options)
return {
container,
component,
debug: (el = container) => console.log(prettyDOM(el)),
rerender: async (props) => {
if (props.props) {
console.warn(
'rerender({ props: {...} }) deprecated, use rerender({...}) instead'
)
props = props.props
}
component.$set(props)
await Svelte.tick()
},
unmount: () => {
cleanupComponent(component)
},
...getQueriesForElement(container, queries),
}
}
const cleanupComponent = (component) => {
const inCache = componentCache.delete(component)
if (inCache) {
component.$destroy()
}
}
const cleanupTarget = (target) => {
const inCache = targetCache.delete(target)
if (inCache && target.parentNode === document.body) {
document.body.removeChild(target)
}
}
const cleanup = () => {
componentCache.forEach(cleanupComponent)
targetCache.forEach(cleanupTarget)
}
const act = async (fn) => {
if (fn) {
await fn()
}
return Svelte.tick()
}
const fireEvent = async (...args) => {
const event = dtlFireEvent(...args)
await Svelte.tick()
return event
}
Object.keys(dtlFireEvent).forEach((key) => {
fireEvent[key] = async (...args) => {
const event = dtlFireEvent[key](...args)
await Svelte.tick()
return event
}
})
/* eslint-disable import/export */
export * from '@testing-library/dom'
export { render, cleanup, fireEvent, act }