Skip to content
Draft
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
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,14 @@
"svelte": "^3 || ^4 || ^5 || ^5.0.0-next.0",
"vitest": "^4.0.0"
},
"dependencies": {
"@testing-library/svelte-core": "^1.0.0-next.2"
},
"devDependencies": {
"@antfu/eslint-config": "^2.24.1",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@vitest/browser-playwright": "^4.0.0-beta.15",
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"@types/node": "^24.10.1",
"@vitest/browser-playwright": "^4.0.9",
"bumpp": "^9.4.2",
"changelogithub": "^0.13.9",
"eslint": "^9.8.0",
Expand All @@ -63,7 +67,7 @@
"tsx": "^4.17.0",
"typescript": "^5.5.4",
"vite": "^7.1.9",
"vitest": "^4.0.0-beta.15",
"vitest": "^4.0.9",
"zx": "^8.1.4"
}
}
355 changes: 178 additions & 177 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

19 changes: 0 additions & 19 deletions src/core/index.js

This file was deleted.

46 changes: 0 additions & 46 deletions src/core/legacy.js

This file was deleted.

51 changes: 0 additions & 51 deletions src/core/modern.svelte.js

This file was deleted.

41 changes: 0 additions & 41 deletions src/core/validate-options.js

This file was deleted.

111 changes: 13 additions & 98 deletions src/pure.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,21 @@
// @ts-check

import * as Svelte from 'svelte'

import { page, utils } from 'vitest/browser'
import { mount, unmount, updateProps, validateOptions } from './core/index.js'
import { cleanup, render as coreRender } from '@testing-library/svelte-core'

const { debug, getElementLocatorSelectors } = utils

/**
* @type {Set<Element>}
*/
const targetCache = new Set()
/**
* @type {Set<import('svelte').SvelteComponent>}
*/
const componentCache = new Set()

/**
* Customize how Svelte renders the component.
*
* @template {import('svelte').SvelteComponent} C
* @typedef {import('svelte').ComponentProps<C> | Partial<import('svelte').ComponentConstructorOptions<import('svelte').ComponentProps<C>>>} SvelteComponentOptions
*/

/**
* Customize how Testing Library sets up the document and binds queries.
*
* @typedef {{
* baseElement?: HTMLElement
* }} RenderOptions
*/

/**
* The rendered component and bound testing functions.
*
* @template {import('svelte').SvelteComponent} C
* @template {import('@testing-library/svelte-core/types').Component} C
*
* @typedef {{
* container: HTMLElement
* baseElement: HTMLElement
* component: C
* component: import('@testing-library/svelte-core/types').Exports<C>
* debug: (el?: HTMLElement) => void
* rerender: (props: Partial<import('svelte').ComponentProps<C>>) => Promise<void>
* rerender: import('@testing-library/svelte-core/types').Rerender<C>
* unmount: () => void
* locator: import('vitest/browser').Locator
* } & import('vitest/browser').LocatorSelectors} RenderResult
Expand All @@ -50,88 +24,29 @@ const componentCache = new Set()
/**
* Render a component into the document.
*
* @template {import('svelte').SvelteComponent} C
* @template {import('@testing-library/svelte-core/types').Component} C
*
* @param {import('../types/pure.js').ComponentType<C>} Component - The component to render.
* @param {SvelteComponentOptions<C>} options - Customize how Svelte renders the component.
* @param {RenderOptions} renderOptions - Customize how Testing Library sets up the document and binds queries.
* @param {import('@testing-library/svelte-core/types').ComponentImport<C>} Component - The component to render.
* @param {import('@testing-library/svelte-core/types').ComponentOptions<C>} options - Customize how Svelte renders the component.
* @param {import('@testing-library/svelte-core/types').SetupOptions} renderOptions - Customize how the document and queries are set up..
* @returns {RenderResult<C>} The rendered component and bound testing functions.
*/
function render(Component, options = {}, renderOptions = {}) {
options = validateOptions(options)

const baseElement
= renderOptions.baseElement ?? options.target ?? document.body

const { baseElement, container, component, rerender, unmount } = coreRender(Component, options, renderOptions)
const queries = getElementLocatorSelectors(baseElement)

const target
= options.target ?? baseElement.appendChild(document.createElement('div'))

targetCache.add(target)

const component = mount(
'default' in Component ? Component.default : Component,
{ ...options, target },
cleanupComponent,
)

componentCache.add(component)

return {
baseElement,
component,
container: target,
locator: page.elementLocator(target),
container,
locator: page.elementLocator(container),
debug: (el = baseElement) => {
debug(el)
},
rerender: async (props) => {
if (props.props) {
console.warn(
'rerender({ props: {...} }) deprecated, use rerender({...}) instead',
)
props = props.props
}

updateProps(component, props)
await Svelte.tick()
},
unmount: () => {
cleanupComponent(component)
},
rerender,
unmount,
...queries,
}
}

/**
* Remove a component from the component cache.
* @param {import('svelte').SvelteComponent} component
*/
function cleanupComponent(component) {
const inCache = componentCache.delete(component)

if (inCache) {
unmount(component)
}
}

/**
* Remove a target element from the target cache
* @param {Element} target
*/
function cleanupTarget(target) {
const inCache = targetCache.delete(target)

if (inCache) {
document.body.removeChild(target)
}
}

/** Unmount all components and remove elements added to `<body>`. */
function cleanup() {
componentCache.forEach(cleanupComponent)
targetCache.forEach(cleanupTarget)
}

export { cleanup, render }
Loading