@magic/test

Svelte Testing

@magic/test includes built-in support for testing Svelte 5 components. It compiles Svelte components, mounts them in a DOM environment, and provides utilities for interacting with and asserting on component behavior.

Internally uses js-dom to create the DOM and HTML elements.

mount

import { mount, html, tryCatch } from '@magic/test'const component = './path/to/MyComponent.svelte'export default [  {    component,    props: { message: 'Hello' },    fn: ({ target }) => html(target).includes('Hello'),    expect: true,    info: 'renders the message prop',  },]

Exported Functions

  • mount(filePath, options) - Mounts a Svelte component and returns { target, component, unmount }
  • html(target) - Returns innerHTML of a mounted component's target element
  • text(target) - Returns textContent of a target element
  • component(instance) - Returns the component instance for accessing exported values
  • props(target) - Returns an object of attribute name/value pairs from the target element

Interaction Functions

  • click(target, selector?) - Clicks an element (optionally filtered by CSS selector)
  • dblClick(target) - Double clicks
  • contextMenu(target) - Right click
  • mouseDown(target) - Mouse down
  • mouseUp(target) - Mouse up
  • mouseMove(target) - Mouse move
  • mouseEnter(target) - Mouse enter
  • mouseLeave(target) - Mouse leave
  • mouseOver(target) - Mouse over
  • mouseOut(target) - Mouse out
  • keyDown(target, key) - Key down
  • keyPress(target, key) - Key press
  • keyUp(target, key) - Key up
  • type(target, text) - Type text into input
  • input(target, value) - Input value
  • change(target, value) - Change event
  • blur(target) - Blur event
  • focus(target) - Focus event
  • submit(target) - Submit form
  • pointerDown(target) - Pointer down
  • pointerUp(target) - Pointer up
  • pointerMove(target) - Pointer move
  • touchStart(target) - Touch start
  • touchMove(target) - Touch move
  • touchEnd(target) - Touch end
  • copy(target) - Copy event
  • cut(target) - Cut event
  • paste(target) - Paste event
  • dragStart(target) - Drag start
  • drag(target) - Drag
  • dragEnd(target) - Drag end
  • dragEnter(target) - Drag enter
  • dragLeave(target) - Drag leave
  • dragOver(target) - Drag over
  • drop(target) - Drop
  • resize(target, w, h) - Resize
  • scroll(target, x, y) - Scroll
  • animationStart(target) - Animation start
  • animationEnd(target) - Animation end
  • transitionEnd(target) - Transition end
  • play(target) - Play media
  • pause(target) - Pause media
  • trigger(target, eventType, options?) - Custom event
  • checked(target) - Checkbox state

Test Properties

  • component - Path to the .svelte file
  • props - Props to pass to the component
  • fn - Test function receiving { target, component, unmount }

Accessing Component State

import { mount, html } from '@magic/test'const component = './src/lib/svelte/components/Counter.svelte'export default [  {    component,    fn: async ({ target, component: instance }) => {      return instance.count    },    expect: 0,    info: 'initial count is 0',  },]

Automatic Test Exports

When testing Svelte 5 components, @magic/test automatically exports $state and $derived variables, making them accessible in tests without requiring manual exports.

**Note:** This automatic export feature is specific to **Svelte 5** only. Svelte 4 components do not have this capability.

<!-- Component.svelte --><script>  let count = $state(0)  let doubled = $derived(count * 2)  <!-- No export needed! --></script><button class="inc">+</button><span>{doubled}</span>

Test - works automatically!

import { mount } from '@magic/test'export default [  {    component: './Component.svelte',    fn: async ({ component }) => component.count,  // 0    expect: 0,    info: 'access $state without manual export',  },  {    component: './Component.svelte',    fn: async ({ component }) => component.doubled,  // 0 (derived)    expect: 0,    info: 'access $derived without manual export',  },]

This works automatically for all $state and $derived runes. No configuration needed!

Testing Error Handling

import { mount, tryCatch } from '@magic/test'const component = './src/lib/svelte/components/MyComponent.svelte'export default [  {    fn: tryCatch(mount, component, { props: null }),    expect: t => t.message === 'Props must be an object, got object',    info: 'throws when props is null',  },]

SvelteKit Mocks

Mocks SvelteKit $app modules:

import { browser, dev, prod, createStaticPage } from '@magic/test'export default [  {    fn: () => browser, // true if in browser environment    expect: false,    info: 'not in browser by default',  },  {    fn: () => dev, // true if in dev mode    expect: process.env.NODE_ENV === 'development',    info: 'dev reflects NODE_ENV',  },  {    fn: () => prod, // true if in production mode    expect: false,    info: 'not in prod by default',  },]

createStaticPage

Creates a static page mock for SvelteKit testing:

import { createStaticPage } from '@magic/test'export default [  {    fn: createStaticPage,    expect: t => typeof t.html === 'string' && typeof t.render === 'function',    info: 'createStaticPage returns html string and render function',  },]

compileSvelte

Compile Svelte component source to a module for testing:

import { compileSvelte } from '@magic/test'export default [  {    fn: async () => {      const source = `<button>Click</button>`      const { js, css } = compileSvelte(source, 'button.svelte')      return js.code.includes('button') && css.code === ''    },    expect: true,    info: 'compiles Svelte source to module',  },]

Available functions:

  • compileSvelte(source, filename) - Compiles Svelte source to JS/CSS modules
  • ensureSvelte() - Lazy-loads the Svelte package, throws if not installed

ensureSvelte

Lazy-loads the Svelte package. Throws if Svelte is not installed:

import { ensureSvelte } from '@magic/test'export default [  {    fn: async () => {      const svelte = await ensureSvelte()      return svelte.version.startsWith('5')    },    expect: true,    info: 'loads svelte package',  },]