@@ -4,48 +4,51 @@ title: Example
44sidebar_label : Example
55---
66
7- For additional resources, patterns, and best practices about testing Svelte
8- components and other Svelte features, take a look at the [ Svelte Society testing
9- recipes] [ testing-recipes ] .
7+ :::tip
108
11- [ testing-recipes ] :
12- https://sveltesociety.dev/recipes/ testing- and-debugging/unit-testing-svelte-component
9+ See the [ svelte- testing-library repository ] [ repository-examples ] for detailed
10+ examples, including examples for testing older Svelte 3 and 4 components.
1311
14- ## Basic
12+ :::
1513
1614This basic example demonstrates how to:
1715
18- - Pass props to your Svelte component using ` render `
19- - Query the structure of your component's DOM elements using ` screen `
16+ - Pass props to your Svelte component using [ ` render() ` ] [ render ]
17+ - [ Query] [ ] the structure of your component's DOM elements using
18+ [ ` screen ` ] [ screen ]
2019- Interact with your component using [ ` @testing-library/user-event ` ] [ user-event ]
2120- Make assertions using ` expect ` , using matchers from
2221 [ ` @testing-library/jest-dom ` ] [ jest-dom ]
2322
24- ``` html title="greeter.svelte"
23+ For additional resources, patterns, and best practices about testing Svelte
24+ components and other Svelte features, take a look at the [ Svelte Society testing
25+ recipes] [ testing-recipes ] .
26+
27+ ``` html title="basic.svelte"
2528<script >
26- export let name
29+ let { name} = $props ()
2730
28- let showGreeting = false
31+ let showGreeting = $state ( false )
2932
30- const handleClick = () => (showGreeting = true )
33+ const onclick = () => (showGreeting = true )
3134 </script >
3235
33- <button on:click = " {handleClick} " >Greet</button >
36+ <button {onclick} >Greet</button >
3437
3538{#if showGreeting}
3639<p >Hello {name}</p >
3740{/if}
3841```
3942
40- ``` js title="greeter .test.js"
43+ ``` js title="basic .test.js"
4144import {render , screen } from ' @testing-library/svelte'
42- import userEvent from ' @testing-library/user-event'
45+ import { userEvent } from ' @testing-library/user-event'
4346import {expect , test } from ' vitest'
4447
45- import Greeter from ' ./greeter .svelte'
48+ import Subject from ' ./basic .svelte'
4649
4750test (' no initial greeting' , () => {
48- render (Greeter , {name: ' World' })
51+ render (Subject , {name: ' World' })
4952
5053 const button = screen .getByRole (' button' , {name: ' Greet' })
5154 const greeting = screen .queryByText (/ hello/ iu )
@@ -56,7 +59,7 @@ test('no initial greeting', () => {
5659
5760test (' greeting appears on click' , async () => {
5861 const user = userEvent .setup ()
59- render (Greeter , {name: ' World' })
62+ render (Subject , {name: ' World' })
6063
6164 const button = screen .getByRole (' button' )
6265 await user .click (button)
@@ -66,213 +69,12 @@ test('greeting appears on click', async () => {
6669})
6770```
6871
72+ [ repository-examples] :
73+ https://github.com/testing-library/svelte-testing-library/tree/main/examples
74+ [ testing-recipes] :
75+ https://sveltesociety.dev/recipes/testing-and-debugging/unit-testing-svelte-component
76+ [ query ] : ../queries/about.mdx
77+ [ screen ] : ../queries/about.mdx#screen
78+ [ render ] : ./api.mdx#render
6979[ user-event ] : ../user-event/intro.mdx
7080[ jest-dom ] : https://github.com/testing-library/jest-dom
71-
72- ## Events
73-
74- Events can be tested using spy functions. If you're using Vitest you can use
75- [ ` vi.fn() ` ] [ vi-fn ] to create a spy.
76-
77- :::info
78-
79- Consider using function props to make testing events easier.
80-
81- :::
82-
83- ``` html title="button-with-event.svelte"
84- <button on:click >click me</button >
85- ```
86-
87- ``` html title="button-with-prop.svelte"
88- <script >
89- export let onClick
90- </script >
91-
92- <button on:click =" {onClick}" >click me</button >
93- ```
94-
95- ``` js title="button.test.ts"
96- import {render , screen } from ' @testing-library/svelte'
97- import userEvent from ' @testing-library/user-event'
98- import {expect , test , vi } from ' vitest'
99-
100- import ButtonWithEvent from ' ./button-with-event.svelte'
101- import ButtonWithProp from ' ./button-with-prop.svelte'
102-
103- test (' button with event' , async () => {
104- const user = userEvent .setup ()
105- const onClick = vi .fn ()
106-
107- const {component } = render (ButtonWithEvent)
108- component .$on (' click' , onClick)
109-
110- const button = screen .getByRole (' button' )
111- await user .click (button)
112-
113- expect (onClick).toHaveBeenCalledOnce ()
114- })
115-
116- test (' button with function prop' , async () => {
117- const user = userEvent .setup ()
118- const onClick = vi .fn ()
119-
120- render (ButtonWithProp, {onClick})
121-
122- const button = screen .getByRole (' button' )
123- await user .click (button)
124-
125- expect (onClick).toHaveBeenCalledOnce ()
126- })
127- ```
128-
129- [ vi-fn ] : https://vitest.dev/api/vi.html#vi-fn
130-
131- ## Slots
132-
133- Slots cannot be tested directly. It's usually easier to structure your code so
134- that you can test the user-facing results, leaving any slots as an
135- implementation detail.
136-
137- However, if slots are an important developer-facing API of your component, you
138- can use a wrapper component and "dummy" children to test them. Test IDs can be
139- helpful when testing slots in this manner.
140-
141- ``` html title="heading.svelte"
142- <h1 >
143- <slot />
144- </h1 >
145- ```
146-
147- ``` html title="heading.test.svelte"
148- <script >
149- import Heading from ' ./heading.svelte'
150- </script >
151-
152- <Heading >
153- <span data-testid =" child" />
154- </Heading >
155- ```
156-
157- ``` js title="heading.test.js"
158- import {render , screen , within } from ' @testing-library/svelte'
159- import {expect , test } from ' vitest'
160-
161- import HeadingTest from ' ./heading.test.svelte'
162-
163- test (' heading with slot' , () => {
164- render (HeadingTest)
165-
166- const heading = screen .getByRole (' heading' )
167- const child = within (heading).getByTestId (' child' )
168-
169- expect (child).toBeInTheDocument ()
170- })
171- ```
172-
173- ## Two-way data binding
174-
175- Two-way data binding cannot be tested directly. It's usually easier to structure
176- your code so that you can test the user-facing results, leaving the binding as
177- an implementation detail.
178-
179- However, if two-way binding is an important developer-facing API of your
180- component, you can use a wrapper component and writable store to test the
181- binding itself.
182-
183- ``` html title="text-input.svelte"
184- <script >
185- export let value = ' '
186- </script >
187-
188- <input type =" text" bind:value =" {value}" />
189- ```
190-
191- ``` html title="text-input.test.svelte"
192- <script >
193- import TextInput from ' ./text-input.svelte'
194-
195- export let valueStore
196- </script >
197-
198- <TextInput bind:value =" {$valueStore}" />
199- ```
200-
201- ``` js title="text-input.test.js"
202- import {render , screen } from ' @testing-library/svelte'
203- import userEvent from ' @testing-library/user-event'
204- import {get , writable } from ' svelte/store'
205- import {expect , test } from ' vitest'
206-
207- import TextInputTest from ' ./text-input.test.svelte'
208-
209- test (' text input with value binding' , async () => {
210- const user = userEvent .setup ()
211- const valueStore = writable (' ' )
212-
213- render (TextInputTest, {valueStore})
214-
215- const input = screen .getByRole (' textbox' )
216- await user .type (input, ' hello world' )
217-
218- expect (get (valueStore)).toBe (' hello world' )
219- })
220- ```
221-
222- ## Contexts
223-
224- If your component requires access to contexts, you can pass those contexts in
225- when you [ ` render ` ] [ component-options ] the component. When you use options like
226- ` context ` , be sure to place props under the ` props ` key.
227-
228- [ component-options ] : ./api.mdx#component-options
229-
230- ``` html title="notifications-provider.svelte"
231- <script >
232- import {setContext } from ' svelte'
233- import {writable } from ' svelte/stores'
234-
235- setContext (' messages' , writable ([]))
236- </script >
237- ```
238-
239- ``` html title="notifications.svelte"
240- <script >
241- import {getContext } from ' svelte'
242-
243- export let label
244-
245- const messages = getContext (' messages' )
246- </script >
247-
248- <div role =" status" aria-label =" {label}" >
249- {#each $messages as message (message.id)}
250- <p >{message.text}</p >
251- <hr />
252- {/each}
253- </div >
254- ```
255-
256- ``` js title="notifications.test.js"
257- import {render , screen } from ' @testing-library/svelte'
258- import {readable } from ' svelte/store'
259- import {expect , test } from ' vitest'
260-
261- import Notifications from ' ./notifications.svelte'
262-
263- test (' notifications with messages from context' , async () => {
264- const messages = readable ([
265- {id: ' abc' , text: ' hello' },
266- {id: ' def' , text: ' world' },
267- ])
268-
269- render (Notifications, {
270- context: new Map ([[' messages' , messages]]),
271- props: {label: ' Notifications' },
272- })
273-
274- const status = screen .getByRole (' status' , {name: ' Notifications' })
275-
276- expect (status).toHaveTextContent (' hello world' )
277- })
278- ```
0 commit comments