diff --git a/examples/contexts/context.test.js b/examples/contexts/context.test.js index 4a433d2..98a5a0c 100644 --- a/examples/contexts/context.test.js +++ b/examples/contexts/context.test.js @@ -3,7 +3,7 @@ import { expect, test } from 'vitest' import Subject from './context.svelte' -test('notifications with messages from context', async () => { +test('notifications with messages from context', () => { const messages = { get current() { return [ diff --git a/examples/contexts/readme.md b/examples/contexts/readme.md index 15284a9..0fb1134 100644 --- a/examples/contexts/readme.md +++ b/examples/contexts/readme.md @@ -1,18 +1,107 @@ # Context -If your component requires access to contexts, you can pass those contexts in -when you render the component. When using extra [component options][] like +## Table of contents + +- [Type-safe context](#type-safe-context) + - [`typesafe-context.ts`](#typesafe-contextts) + - [`typesafe-context.svelte`](#typesafe-contextsvelte) + - [`typesafe-context.test.js`](#typesafe-contexttestjs) +- [Context with key](#context-with-key) + - [`context.svelte`](#contextsvelte) + - [`context.test.js`](#contexttestjs) + +## Type-safe context + +If you use [createContext][], wrap your component in a wrapper function to +create the context. + +> \[!NOTE] +> +> Setting a context value in a wrapper function requires `svelte>=5.50.0`. + +[createContext]: https://svelte.dev/docs/svelte/svelte#createContext + +### `typesafe-context.ts` + +```ts file=./typesafe-context.ts +import { createContext } from 'svelte' + +export interface Message { + id: string + text: string +} + +export interface MessagesContext { + current: Message[] +} + +export const [getMessagesContext, setMessagesContext] = + createContext() +``` + +### `typesafe-context.svelte` + +```svelte file=./typesafe-context.svelte + + +
+ {#each messages.current as message (message.id)} +

{message.text}

+
+ {/each} +
+``` + +### `typesafe-context.test.js` + +```ts file=./typesafe-context.test.ts +import { render, screen } from '@testing-library/svelte' +import { expect, test } from 'vitest' + +import { type MessagesContext, setMessagesContext } from './typesafe-context.js' +import Subject from './typesafe-context.svelte' + +test('notifications with messages from context', () => { + const messages: MessagesContext = { + get current() { + return [ + { id: 'abc', text: 'hello' }, + { id: 'def', text: 'world' }, + ] + }, + } + + const Wrapper: typeof Subject = (...args) => { + setMessagesContext(messages) + return Subject(...args) + } + + render(Wrapper, { label: 'Notifications' }) + + const status = screen.getByRole('status', { name: 'Notifications' }) + + expect(status).toHaveTextContent('hello world') +}) +``` + +## Context with key + +If you use [setContext][] and [getContext][], you can use the `context` option +of `render` to pass a context in. When using extra [component options][] like `context`, be sure to place props under the `props` key. [component options]: https://testing-library.com/docs/svelte-testing-library/api#component-options +[setcontext]: https://svelte.dev/docs/svelte/svelte#setContext +[getcontext]: https://svelte.dev/docs/svelte/svelte#getContext -## Table of contents - -- [`context.svelte`](#contextsvelte) -- [`context.test.js`](#contexttestjs) - -## `context.svelte` +### `context.svelte` ```svelte file=./context.svelte + +
+ {#each messages.current as message (message.id)} +

{message.text}

+
+ {/each} +
diff --git a/examples/contexts/typesafe-context.test.ts b/examples/contexts/typesafe-context.test.ts new file mode 100644 index 0000000..ab69037 --- /dev/null +++ b/examples/contexts/typesafe-context.test.ts @@ -0,0 +1,27 @@ +import { render, screen } from '@testing-library/svelte' +import { expect, test } from 'vitest' + +import { type MessagesContext, setMessagesContext } from './typesafe-context.js' +import Subject from './typesafe-context.svelte' + +test('notifications with messages from context', () => { + const messages: MessagesContext = { + get current() { + return [ + { id: 'abc', text: 'hello' }, + { id: 'def', text: 'world' }, + ] + }, + } + + const Wrapper: typeof Subject = (...args) => { + setMessagesContext(messages) + return Subject(...args) + } + + render(Wrapper, { label: 'Notifications' }) + + const status = screen.getByRole('status', { name: 'Notifications' }) + + expect(status).toHaveTextContent('hello world') +}) diff --git a/examples/contexts/typesafe-context.ts b/examples/contexts/typesafe-context.ts new file mode 100644 index 0000000..60a3203 --- /dev/null +++ b/examples/contexts/typesafe-context.ts @@ -0,0 +1,13 @@ +import { createContext } from 'svelte' + +export interface Message { + id: string + text: string +} + +export interface MessagesContext { + current: Message[] +} + +export const [getMessagesContext, setMessagesContext] = + createContext() diff --git a/examples/tsconfig.json b/examples/tsconfig.json new file mode 100644 index 0000000..92ce4e8 --- /dev/null +++ b/examples/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "node16", + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "types": [ + "svelte", + "vite/client", + "vitest", + "vitest/globals", + "@testing-library/jest-dom" + ], + "noEmit": true, + "plugins": [{ "name": "typescript-svelte-plugin" }] + } +}