Skip to content

Commit 6bd7499

Browse files
authored
docs(examples): add typesafe createContext example (#475)
1 parent e2a8bb4 commit 6bd7499

File tree

6 files changed

+171
-11
lines changed

6 files changed

+171
-11
lines changed

examples/contexts/context.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { expect, test } from 'vitest'
33

44
import Subject from './context.svelte'
55

6-
test('notifications with messages from context', async () => {
6+
test('notifications with messages from context', () => {
77
const messages = {
88
get current() {
99
return [

examples/contexts/readme.md

Lines changed: 99 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,107 @@
11
# Context
22

3-
If your component requires access to contexts, you can pass those contexts in
4-
when you render the component. When using extra [component options][] like
3+
## Table of contents
4+
5+
- [Type-safe context](#type-safe-context)
6+
- [`typesafe-context.ts`](#typesafe-contextts)
7+
- [`typesafe-context.svelte`](#typesafe-contextsvelte)
8+
- [`typesafe-context.test.js`](#typesafe-contexttestjs)
9+
- [Context with key](#context-with-key)
10+
- [`context.svelte`](#contextsvelte)
11+
- [`context.test.js`](#contexttestjs)
12+
13+
## Type-safe context
14+
15+
If you use [createContext][], wrap your component in a wrapper function to
16+
create the context.
17+
18+
> \[!NOTE]
19+
>
20+
> Setting a context value in a wrapper function requires `svelte>=5.50.0`.
21+
22+
[createContext]: https://svelte.dev/docs/svelte/svelte#createContext
23+
24+
### `typesafe-context.ts`
25+
26+
```ts file=./typesafe-context.ts
27+
import { createContext } from 'svelte'
28+
29+
export interface Message {
30+
id: string
31+
text: string
32+
}
33+
34+
export interface MessagesContext {
35+
current: Message[]
36+
}
37+
38+
export const [getMessagesContext, setMessagesContext] =
39+
createContext<MessagesContext>()
40+
```
41+
42+
### `typesafe-context.svelte`
43+
44+
```svelte file=./typesafe-context.svelte
45+
<script lang="ts">
46+
import { getMessagesContext } from './typesafe-context.js'
47+
48+
let { label } = $props()
49+
50+
const messages = getMessagesContext()
51+
</script>
52+
53+
<div role="status" aria-label={label}>
54+
{#each messages.current as message (message.id)}
55+
<p>{message.text}</p>
56+
<hr />
57+
{/each}
58+
</div>
59+
```
60+
61+
### `typesafe-context.test.js`
62+
63+
```ts file=./typesafe-context.test.ts
64+
import { render, screen } from '@testing-library/svelte'
65+
import { expect, test } from 'vitest'
66+
67+
import { type MessagesContext, setMessagesContext } from './typesafe-context.js'
68+
import Subject from './typesafe-context.svelte'
69+
70+
test('notifications with messages from context', () => {
71+
const messages: MessagesContext = {
72+
get current() {
73+
return [
74+
{ id: 'abc', text: 'hello' },
75+
{ id: 'def', text: 'world' },
76+
]
77+
},
78+
}
79+
80+
const Wrapper: typeof Subject = (...args) => {
81+
setMessagesContext(messages)
82+
return Subject(...args)
83+
}
84+
85+
render(Wrapper, { label: 'Notifications' })
86+
87+
const status = screen.getByRole('status', { name: 'Notifications' })
88+
89+
expect(status).toHaveTextContent('hello world')
90+
})
91+
```
92+
93+
## Context with key
94+
95+
If you use [setContext][] and [getContext][], you can use the `context` option
96+
of `render` to pass a context in. When using extra [component options][] like
597
`context`, be sure to place props under the `props` key.
698

799
[component options]:
8100
https://testing-library.com/docs/svelte-testing-library/api#component-options
101+
[setcontext]: https://svelte.dev/docs/svelte/svelte#setContext
102+
[getcontext]: https://svelte.dev/docs/svelte/svelte#getContext
9103

10-
## Table of contents
11-
12-
- [`context.svelte`](#contextsvelte)
13-
- [`context.test.js`](#contexttestjs)
14-
15-
## `context.svelte`
104+
### `context.svelte`
16105

17106
```svelte file=./context.svelte
18107
<script>
@@ -31,15 +120,15 @@ when you render the component. When using extra [component options][] like
31120
</div>
32121
```
33122

34-
## `context.test.js`
123+
### `context.test.js`
35124

36125
```js file=./context.test.js
37126
import { render, screen } from '@testing-library/svelte'
38127
import { expect, test } from 'vitest'
39128

40129
import Subject from './context.svelte'
41130

42-
test('notifications with messages from context', async () => {
131+
test('notifications with messages from context', () => {
43132
const messages = {
44133
get current() {
45134
return [
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<script lang="ts">
2+
import { getMessagesContext } from './typesafe-context.js'
3+
4+
let { label } = $props()
5+
6+
const messages = getMessagesContext()
7+
</script>
8+
9+
<div role="status" aria-label={label}>
10+
{#each messages.current as message (message.id)}
11+
<p>{message.text}</p>
12+
<hr />
13+
{/each}
14+
</div>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { render, screen } from '@testing-library/svelte'
2+
import { expect, test } from 'vitest'
3+
4+
import { type MessagesContext, setMessagesContext } from './typesafe-context.js'
5+
import Subject from './typesafe-context.svelte'
6+
7+
test('notifications with messages from context', () => {
8+
const messages: MessagesContext = {
9+
get current() {
10+
return [
11+
{ id: 'abc', text: 'hello' },
12+
{ id: 'def', text: 'world' },
13+
]
14+
},
15+
}
16+
17+
const Wrapper: typeof Subject = (...args) => {
18+
setMessagesContext(messages)
19+
return Subject(...args)
20+
}
21+
22+
render(Wrapper, { label: 'Notifications' })
23+
24+
const status = screen.getByRole('status', { name: 'Notifications' })
25+
26+
expect(status).toHaveTextContent('hello world')
27+
})
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { createContext } from 'svelte'
2+
3+
export interface Message {
4+
id: string
5+
text: string
6+
}
7+
8+
export interface MessagesContext {
9+
current: Message[]
10+
}
11+
12+
export const [getMessagesContext, setMessagesContext] =
13+
createContext<MessagesContext>()

examples/tsconfig.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"compilerOptions": {
3+
"module": "node16",
4+
"allowJs": true,
5+
"skipLibCheck": true,
6+
"strict": true,
7+
"types": [
8+
"svelte",
9+
"vite/client",
10+
"vitest",
11+
"vitest/globals",
12+
"@testing-library/jest-dom"
13+
],
14+
"noEmit": true,
15+
"plugins": [{ "name": "typescript-svelte-plugin" }]
16+
}
17+
}

0 commit comments

Comments
 (0)