Skip to content

Commit d874c2c

Browse files
committed
docs(svelte-testing-library): simplify examples with link to STL repository
1 parent 1b9e396 commit d874c2c

File tree

1 file changed

+28
-226
lines changed

1 file changed

+28
-226
lines changed

docs/svelte-testing-library/example.mdx

Lines changed: 28 additions & 226 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,51 @@ title: Example
44
sidebar_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

1614
This 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"
4144
import {render, screen} from '@testing-library/svelte'
42-
import userEvent from '@testing-library/user-event'
45+
import {userEvent} from '@testing-library/user-event'
4346
import {expect, test} from 'vitest'
4447

45-
import Greeter from './greeter.svelte'
48+
import Subject from './basic.svelte'
4649

4750
test('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

5760
test('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

Comments
 (0)