Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ To do your own cleanup, or if you're using another framework, call the `setup` a
import { cleanup, render, setup } from '@testing-library/svelte'

// before
setup()
await setup()

// test
render(/* ... */)
Expand All @@ -159,7 +159,7 @@ render(/* ... */)
cleanup()
```

To disable auto-cleanup in Vitest, set the `autoCleanup` option of the plugin to false:
To disable auto-setup and cleanup in Vitest, set the `autoCleanup` option of the plugin to false:

```js
svelteTesting({ autoCleanup: false })
Expand Down
23 changes: 22 additions & 1 deletion packages/svelte-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ afterwards.
- [API](#api)
- [`render`](#render)
- [`setup`](#setup)
- [`wrapperSetup`](#wrappersetup)
- [`mount`](#mount)
- [`cleanup`](#cleanup)
- [`addCleanupTask`](#addcleanuptask)
Expand All @@ -30,7 +31,9 @@ import type {

import { bindQueries, type Queries } from './bring-your-own-queries.js'

beforeEach(() => {
beforeEach(async () => {
// Required to use the `wrapper` render option
await SvelteCore.wrapperSetup()
SvelteCore.cleanup()
})

Expand Down Expand Up @@ -125,12 +128,30 @@ const { baseElement, container, mountOptions } = setup(
| `wrapper` | [Svelte component][svelte-component-docs] | A component to wrap the component under test, e.g. a context provider | `undefined` |
| `wrapperProps` | `Props` | Props to pass to the `wrapper` component | `undefined` |

> \[!IMPORTANT]
> Using the `wrapper` option requires awaiting [`wrapperSetup`](#wrappersetup)
> beforehand, e.g. in a `beforeEach` hook.

| Result | Type | Description | Default |
| -------------- | ------------------------------------ | ---------------------------------------- | ----------------------------------- |
| `baseElement` | `HTMLElement` | The base element | `document.body` |
| `container` | `HTMLElement` | The component's immediate parent element | `<div>` appended to `document.body` |
| `mountOptions` | [`mount` options][svelte-mount-docs] | Validated options to pass to `mount` | `{ target, props: {} }` |

### `wrapperSetup`

Load the wrapper scaffold for the installed version of Svelte. Await this before
rendering with the [`wrapper`](#setup) option, e.g. in a `beforeEach` hook.
Rendering with a `wrapper` before `wrapperSetup` resolves throws a
`WrapperNotSetupError`.

```ts
await wrapperSetup()
```

The scaffold is loaded once and cached, so calling `wrapperSetup` repeatedly is
cheap.

### `mount`

Mount a Svelte component into the document.
Expand Down
1 change: 1 addition & 0 deletions packages/svelte-core/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export * from './cleanup.js'
export * from './mount.js'
export * from './render.js'
export * from './setup.js'
export { wrapperSetup } from './wrapper.js'
4 changes: 2 additions & 2 deletions packages/svelte-core/src/mount.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as Svelte from 'svelte'
import { addCleanupTask, removeCleanupTask } from './cleanup.js'
import { createProps } from './props.svelte.js'
import { IS_MODERN_SVELTE } from './svelte-version.js'
import WrapperScaffold from './wrapper-scaffold.svelte'
import { getWrapperScaffold } from './wrapper.js'

/**
* Mount a modern Svelte 5 component into the DOM.
Expand Down Expand Up @@ -108,7 +108,7 @@ const setupComponent = (Component, mountOptions, setupOptions = {}) => {
if (wrapper) {
return {
isWrapper: true,
componentToMount: WrapperScaffold,
componentToMount: getWrapperScaffold(),
mountOptions: {
...mountOptions,
props: {
Expand Down
21 changes: 21 additions & 0 deletions packages/svelte-core/src/wrapper-scaffold-legacy.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script>
export let wrapper
export let wrapperProps
export let component
export let componentProps

let wrapperInstance
let componentInstance

export const getWrapper = () => wrapperInstance
export const getComponent = () => componentInstance
export const getComponentProps = () => componentProps
</script>

<svelte:component this={wrapper} bind:this={wrapperInstance} {...wrapperProps}>
<svelte:component
this={component}
bind:this={componentInstance}
{...componentProps}
/>
</svelte:component>
24 changes: 11 additions & 13 deletions packages/svelte-core/src/wrapper-scaffold.svelte
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
<script>
export let wrapper
export let wrapperProps
export let component
export let componentProps
let {
wrapper: Wrapper,
wrapperProps,
component: Component,
componentProps,
} = $props()

let wrapperInstance
let componentInstance
let wrapperInstance = $state()
let componentInstance = $state()

export const getWrapper = () => wrapperInstance
export const getComponent = () => componentInstance
export const getComponentProps = () => componentProps
</script>

<svelte:component this={wrapper} bind:this={wrapperInstance} {...wrapperProps}>
<svelte:component
this={component}
bind:this={componentInstance}
{...componentProps}
/>
</svelte:component>
<Wrapper bind:this={wrapperInstance} {...wrapperProps}>
<Component bind:this={componentInstance} {...componentProps} />
</Wrapper>
50 changes: 50 additions & 0 deletions packages/svelte-core/src/wrapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { IS_MODERN_SVELTE } from './svelte-version.js'

/** @type {import('../types.js').Component | undefined} */
let WrapperScaffold

/** @type {Promise<unknown> | undefined} */
let scaffoldInitialization

class WrapperNotSetupError extends Error {
constructor() {
super(
'Ensure `setup()` runs (e.g. in `beforeEach`) before using `wrapper` option.'
)
this.name = 'WrapperNotSetupError'
}
}

/**
* Import the proper wrapper scaffolding for the current version of Svelte.
*
* Supports the `wrapper` option of `render` / `mount`.
*/
const wrapperSetup = async () => {
if (!scaffoldInitialization) {
scaffoldInitialization = initializeScaffold()
}

await scaffoldInitialization
}

/** Import the scaffold component and set up module singletons. */
const initializeScaffold = async () => {
const scaffoldImport = IS_MODERN_SVELTE
? import('./wrapper-scaffold.svelte')
: import('./wrapper-scaffold-legacy.svelte')

const { default: Scaffold } = await scaffoldImport
WrapperScaffold = Scaffold
}

/** Get the wrapper scaffolding component. */
const getWrapperScaffold = () => {
if (!WrapperScaffold) {
throw new WrapperNotSetupError()
}

return WrapperScaffold
}

export { getWrapperScaffold, wrapperSetup }
4 changes: 2 additions & 2 deletions packages/svelte/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { act, cleanup, setup } from './pure.js'
// if you don't like this then set the STL_SKIP_AUTO_CLEANUP env variable.
if (typeof process !== 'undefined' && !process.env.STL_SKIP_AUTO_CLEANUP) {
if (typeof beforeEach === 'function') {
beforeEach(() => {
setup()
beforeEach(async () => {
await setup()
})
}

Expand Down
8 changes: 6 additions & 2 deletions packages/svelte/src/pure.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,15 @@ const render = (Component, options = {}, renderOptions = {}) => {
}

/**
* Configure `@testing-library/dom` for usage with Svelte.
* Set up the test environment
*
* Ensures events fired from `@testing-library/dom`
* and `@testing-library/user-event` wait for Svelte
* to flush changes to the DOM before proceeding.
*
* Sets up the rendering core for the `wrapper` option.
*/
const setup = () => {
const setup = async () => {
const originalConfig = DomTestingLibrary.getConfig()

DomTestingLibrary.configure({
Expand All @@ -88,6 +90,8 @@ const setup = () => {
Core.addCleanupTask(() => {
DomTestingLibrary.configure(originalConfig)
})

return Core.wrapperSetup()
}

/** Unmount components, remove elements added to `<body>`, and reset `@testing-library/dom`. */
Expand Down
4 changes: 2 additions & 2 deletions packages/svelte/src/vitest.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const afterEach = async () => {
cleanup()
}

beforeEach(() => {
setup()
beforeEach(async () => {
await setup()
return afterEach
})
1 change: 1 addition & 0 deletions tests/envs/svelte3/node16/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/user-event": "^14.6.1",
"@vitest/coverage-v8": "0.x.x",
"browserslist": "4.28.2",
"expect-type": "^1.2.1",
"happy-dom": "14.x.x",
"jest": "^29.7.0",
Expand Down
1 change: 1 addition & 0 deletions tests/envs/svelte4/node16/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/user-event": "^14.6.1",
"@vitest/coverage-v8": "0.x.x",
"browserslist": "4.28.2",
"expect-type": "^1.2.1",
"happy-dom": "14.x.x",
"jest": "^29.7.0",
Expand Down