Skip to content

Commit 926c269

Browse files
committed
Merge branch 'as-class' into align-render-options
2 parents 9172cdf + 1df1c7c commit 926c269

File tree

2 files changed

+104
-119
lines changed

2 files changed

+104
-119
lines changed

src/pure.js

Lines changed: 87 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -7,92 +7,61 @@ import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
77
import * as Svelte from 'svelte'
88

99
const IS_SVELTE_5 = /^5\./.test(SVELTE_VERSION)
10-
export const targetCache = new Set()
11-
export const componentCache = new Set()
12-
13-
const svelteComponentOptions = [
14-
'accessors',
15-
'anchor',
16-
'props',
17-
'hydrate',
18-
'intro',
19-
'context',
20-
]
21-
22-
export const buildCheckProps = (svelteComponentOptions) => (options) => {
23-
const isOptions = Object.keys(options).some((option) =>
24-
svelteComponentOptions.includes(option)
25-
)
26-
27-
// Check if any props and Svelte options were accidentally mixed.
28-
if (isOptions) {
29-
const unrecognizedOptions = Object.keys(options).filter(
30-
(option) => !svelteComponentOptions.includes(option)
31-
)
32-
33-
if (unrecognizedOptions.length > 0) {
34-
throw Error(`
35-
Unknown component options: [${unrecognizedOptions.join(', ')}]
36-
Valid Svelte component options: [${svelteComponentOptions.join(', ')}]
37-
38-
This error occurs if props are mixed with Svelte component options,
39-
or any props use the same name as a Svelte component option.
40-
Either rename the props, or place props under the \`props\` option.
41-
42-
Eg: const { /** results **/ } = render(MyComponent, { props: { /** props here **/ } })
43-
`)
44-
}
45-
46-
return options
47-
}
48-
49-
return { props: options }
50-
}
51-
52-
const checkProps = buildCheckProps(svelteComponentOptions)
53-
54-
const buildRenderComponent =
55-
({ target, ComponentConstructor }) =>
56-
(options) => {
57-
options = checkProps(options)
58-
59-
if (IS_SVELTE_5)
60-
throw new Error('for Svelte 5, use `@testing-library/svelte/svelte5`')
61-
62-
const component = new ComponentConstructor(options)
6310

64-
componentCache.add(component)
11+
export class SvelteTestingLibrary {
12+
svelteComponentOptions = [
13+
'accessors',
14+
'anchor',
15+
'props',
16+
'hydrate',
17+
'intro',
18+
'context',
19+
]
20+
21+
targetCache = new Set()
22+
componentCache = new Set()
23+
24+
checkProps(options) {
25+
const isProps = !Object.keys(options).some((option) =>
26+
this.svelteComponentOptions.includes(option)
27+
)
6528

66-
// TODO(mcous, 2024-02-11): remove this behavior in the next major version
67-
// It is unnecessary has no path to implementation in Svelte v5
68-
if (!IS_SVELTE_5) {
69-
component.$$.on_destroy.push(() => {
70-
componentCache.delete(component)
71-
})
29+
// Check if any props and Svelte options were accidentally mixed.
30+
if (!isProps) {
31+
const unrecognizedOptions = Object.keys(options).filter(
32+
(option) => !this.svelteComponentOptions.includes(option)
33+
)
34+
35+
if (unrecognizedOptions.length > 0) {
36+
throw Error(`
37+
Unknown options were found [${unrecognizedOptions}]. This might happen if you've mixed
38+
passing in props with Svelte options into the render function. Valid Svelte options
39+
are [${this.svelteComponentOptions}]. You can either change the prop names, or pass in your
40+
props for that component via the \`props\` option.\n\n
41+
Eg: const { /** Results **/ } = render(MyComponent, { props: { /** props here **/ } })\n\n
42+
`)
43+
}
44+
45+
return options
7246
}
7347

74-
return component
48+
return { props: options }
7549
}
7650

77-
export const buildRender =
78-
(buildRenderComponent) =>
79-
(Component, options = {}, renderOptions = {}) => {
80-
const baseElement =
81-
renderOptions.baseElement ?? options.target ?? document.body
82-
83-
const target =
84-
options.target ?? baseElement.appendChild(document.createElement('div'))
85-
86-
targetCache.add(target)
51+
render(Component, { target, ...options } = {}, { container, queries } = {}) {
52+
container = container || document.body
53+
target = target || container.appendChild(document.createElement('div'))
54+
this.targetCache.add(target)
8755

8856
const ComponentConstructor = Component.default || Component
8957

90-
const renderComponent = buildRenderComponent({
91-
target,
92-
ComponentConstructor,
93-
})
94-
95-
let component = renderComponent({ target, ...options })
58+
const component = this.renderComponent(
59+
{
60+
target,
61+
ComponentConstructor,
62+
},
63+
options
64+
)
9665

9766
return {
9867
container,
@@ -109,35 +78,61 @@ export const buildRender =
10978
await Svelte.tick()
11079
},
11180
unmount: () => {
112-
cleanupComponent(component)
81+
this.cleanupComponent(component)
11382
},
11483
...getQueriesForElement(container, queries),
11584
}
11685
}
11786

118-
export const render = buildRender(buildRenderComponent)
87+
renderComponent({ target, ComponentConstructor }, options) {
88+
options = { target, ...this.checkProps(options) }
89+
90+
if (IS_SVELTE_5)
91+
throw new Error('for Svelte 5, use `@testing-library/svelte/svelte5`')
92+
93+
const component = new ComponentConstructor(options)
94+
95+
this.componentCache.add(component)
96+
97+
// TODO(mcous, 2024-02-11): remove this behavior in the next major version
98+
// It is unnecessary has no path to implementation in Svelte v5
99+
if (!IS_SVELTE_5) {
100+
component.$$.on_destroy.push(() => {
101+
this.componentCache.delete(component)
102+
})
103+
}
104+
105+
return component
106+
}
119107

120-
export const cleanupComponent = (component) => {
121-
const inCache = componentCache.delete(component)
108+
cleanupComponent(component) {
109+
const inCache = this.componentCache.delete(component)
122110

123-
if (inCache) {
124-
component.$destroy()
111+
if (inCache) {
112+
component.$destroy()
113+
}
125114
}
126-
}
127115

128-
const cleanupTarget = (target) => {
129-
const inCache = targetCache.delete(target)
116+
cleanupTarget(target) {
117+
const inCache = this.targetCache.delete(target)
130118

131-
if (inCache && target.parentNode === document.body) {
132-
document.body.removeChild(target)
119+
if (inCache && target.parentNode === document.body) {
120+
document.body.removeChild(target)
121+
}
133122
}
134-
}
135123

136-
export const cleanup = () => {
137-
componentCache.forEach(cleanupComponent)
138-
targetCache.forEach(cleanupTarget)
124+
cleanup() {
125+
this.componentCache.forEach(this.cleanupComponent.bind(this))
126+
this.targetCache.forEach(this.cleanupTarget.bind(this))
127+
}
139128
}
140129

130+
const instance = new SvelteTestingLibrary()
131+
132+
export const render = instance.render.bind(instance)
133+
134+
export const cleanup = instance.cleanup.bind(instance)
135+
141136
export const act = async (fn) => {
142137
if (fn) {
143138
await fn()

src/svelte5.js

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,31 @@
11
import { createClassComponent } from 'svelte/legacy'
2-
import {
3-
componentCache,
4-
cleanup,
5-
buildCheckProps,
6-
buildRender,
7-
} from './pure.js'
2+
import { SvelteTestingLibrary } from './pure.js'
83

9-
const svelteComponentOptions = [
10-
'target',
11-
'props',
12-
'events',
13-
'context',
14-
'intro',
15-
'recover',
16-
]
4+
class Svelte5TestingLibrary extends SvelteTestingLibrary {
5+
svelteComponentOptions = [
6+
'target',
7+
'props',
8+
'events',
9+
'context',
10+
'intro',
11+
'recover',
12+
]
1713

18-
const checkProps = buildCheckProps(svelteComponentOptions)
19-
20-
const buildRenderComponent =
21-
({ target, ComponentConstructor }) =>
22-
(options) => {
23-
options = checkProps(options)
14+
renderComponent({ target, ComponentConstructor }, options) {
15+
options = { target, ...this.checkProps(options) }
2416

2517
const component = createClassComponent({
2618
component: ComponentConstructor,
2719
...options,
2820
})
2921

30-
componentCache.add(component)
22+
this.componentCache.add(component)
3123

3224
return component
3325
}
26+
}
3427

35-
const render = buildRender(buildRenderComponent)
36-
37-
/* eslint-disable import/export */
38-
39-
import { act, fireEvent } from './pure.js'
28+
const instance = new Svelte5TestingLibrary()
4029

41-
export { render, cleanup, fireEvent, act }
30+
export const render = instance.render.bind(instance)
31+
export const cleanup = instance.cleanup.bind(instance)

0 commit comments

Comments
 (0)