-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathpure.js
155 lines (126 loc) · 3.95 KB
/
pure.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
146
147
148
149
150
151
152
153
154
155
import {
fireEvent as dtlFireEvent,
getQueriesForElement,
prettyDOM,
} from '@testing-library/dom'
import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
import * as Svelte from 'svelte'
const IS_SVELTE_5 = /^5\./.test(SVELTE_VERSION)
export class SvelteTestingLibrary {
svelteComponentOptions = [
'accessors',
'anchor',
'props',
'hydrate',
'intro',
'context',
]
targetCache = new Set()
componentCache = new Set()
checkProps(options) {
const isProps = !Object.keys(options).some((option) =>
this.svelteComponentOptions.includes(option)
)
// Check if any props and Svelte options were accidentally mixed.
if (!isProps) {
const unrecognizedOptions = Object.keys(options).filter(
(option) => !this.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 [${this.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 }
}
render(Component, { target, ...options } = {}, { container, queries } = {}) {
container = container || document.body
target = target || container.appendChild(document.createElement('div'))
this.targetCache.add(target)
const ComponentConstructor = Component.default || Component
const component = this.renderComponent(
{
target,
ComponentConstructor,
},
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: () => {
this.cleanupComponent(component)
},
...getQueriesForElement(container, queries),
}
}
renderComponent({ target, ComponentConstructor }, options) {
options = { target, ...this.checkProps(options) }
if (IS_SVELTE_5)
throw new Error('for Svelte 5, use `@testing-library/svelte/svelte5`')
const component = new ComponentConstructor(options)
this.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(() => {
this.componentCache.delete(component)
})
}
return component
}
cleanupComponent(component) {
const inCache = this.componentCache.delete(component)
if (inCache) {
component.$destroy()
}
}
cleanupTarget(target) {
const inCache = this.targetCache.delete(target)
if (inCache && target.parentNode === document.body) {
document.body.removeChild(target)
}
}
cleanup() {
this.componentCache.forEach(this.cleanupComponent.bind(this))
this.targetCache.forEach(this.cleanupTarget.bind(this))
}
}
const instance = new SvelteTestingLibrary()
export const render = instance.render.bind(instance)
export const cleanup = instance.cleanup.bind(instance)
export const act = async (fn) => {
if (fn) {
await fn()
}
return Svelte.tick()
}
export 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
}
})