Skip to content
Back to skills

Svelte Testing Patterns

ASecurity

> Test Svelte 5 components with Vitest and @testing-library/svelte — render, user events, store mocking, and async tick flushing

  • 20 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 11, 2026
testingtypescriptbashreacttestingapi

Works with

  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned September 11, 2026

npx -y skills add Intense-Visions/harness-engineering --skill svelte-testing-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Svelte Testing Patterns?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Svelte Testing Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/intense-visions-svelte-testing-patterns/badge)](https://www.skillsdirectory.com/skills/intense-visions-svelte-testing-patterns)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# Svelte Testing Patterns

> Test Svelte 5 components with Vitest and @testing-library/svelte — render, user events, store mocking, and async tick flushing

## When to Use

- You are writing unit tests for Svelte components
- You need to test reactive behavior triggered by user interactions (clicks, input, form submission)
- You need to mock Svelte stores or module imports in tests
- You are testing async behavior and need to flush the update queue with `tick()`

## Instructions

**Setup:**

1. Install dependencies and configure Vitest with the Svelte plugin:

```bash
npm install -D vitest @testing-library/svelte @testing-library/jest-dom jsdom
```

```typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config';
import { svelte } from '@sveltejs/vite-plugin-svelte';

export default defineConfig({
  plugins: [svelte({ hot: !process.env.VITEST })],
  test: {
    environment: 'jsdom',
    setupFiles: ['./src/tests/setup.ts'],
    globals: true,
  },
});
```

```typescript
// src/tests/setup.ts
import '@testing-library/jest-dom';
```

**Rendering components:**

2. Use `render` from `@testing-library/svelte` to mount components. Query the DOM with Testing Library queries:

```typescript
import { render, screen } from '@testing-library/svelte';
import MyButton from '$lib/components/MyButton.svelte';

test('renders with label', () => {
  render(MyButton, { props: { label: 'Click me' } });
  expect(screen.getByRole('button', { name: 'Click me' })).toBeInTheDocument();
});
```

3. Pass props using the `props` option:

```typescript
render(UserCard, {
  props: {
    user: { id: 1, name: 'Alice', email: 'alice@example.com' },
  },
});
```

**Firing events:**

4. Use `fireEvent` or the `userEvent` library for simulating interactions:

```typescript
import { render, screen, fireEvent } from '@testing-library/svelte';
import Counter from '$lib/components/Counter.svelte';

test('increments on click', async () => {
  render(Counter);
  const button = screen.getByRole('button', { name: '+' });

  await fireEvent.click(button);
  await fireEvent.click(button);

  expect(screen.getByText('2')).toBeInTheDocument();
});
```

5. Use `@testing-library/user-event` for more realistic interactions (typing, tabbing):

```typescript
import userEvent from '@testing-library/user-event';

test('types in search input', async () => {
  const user = userEvent.setup();
  render(SearchBar);

  await user.type(screen.getByRole('searchbox'), 'svelte');
  expect(screen.getByDisplayValue('svelte')).toBeInTheDocument();
});
```

**Async updates with tick:**

6. After triggering reactive updates, await `tick()` from `svelte` to flush Svelte's update queue:

```typescript
import { tick } from 'svelte';

test('shows error after failed submit', async () => {
  render(LoginForm);

  await fireEvent.submit(screen.getByRole('form'));
  await tick();

  expect(screen.getByText('Email is required')).toBeInTheDocument();
});
```

**Testing stores:**

7. Mock writable stores by importing and setting them directly:

```typescript
import { count } from '$lib/stores/counter';
import CounterDisplay from '$lib/components/CounterDisplay.svelte';

test('displays current count', () => {
  count.set(42);
  render(CounterDisplay);
  expect(screen.getByText('42')).toBeInTheDocument();
});
```

**Mocking modules:**

8. Use `vi.mock` to mock module imports in tests:

```typescript
vi.mock('$lib/services/api', () => ({
  fetchUsers: vi.fn().mockResolvedValue([
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' },
  ]),
}));

test('renders fetched users', async () => {
  render(UserList);
  await tick();

  expect(screen.getByText('Alice')).toBeInTheDocument();
  expect(screen.getByText('Bob')).toBeInTheDocument();
});
```

**Testing with context:**

9. Wrap components in a context provider using a wrapper component, or use the `context` option:

```typescript
render(MyComponent, {
  context: new Map([['theme', { primary: '#3b82f6' }]]),
});
```

## Details

**Svelte 5 vs. Svelte 4 testing differences:**

Svelte 5 with `@testing-library/svelte` v5+ uses the new component API internally. The test API (render, screen, fireEvent) is unchanged from the user's perspective. Ensure `@testing-library/svelte` v5 or later for Svelte 5 components.

**The Testing Library philosophy:**

Prefer queries that reflect how users perceive the UI:

1. `getByRole` — most semantic (button, heading, checkbox, etc.)
2. `getByLabelText` — for form fields
3. `getByPlaceholderText` — fallback for inputs
4. `getByText` — visible text content
5. `getByTestId` — last resort (add `data-testid` to elements)

Avoid testing implementation details (component state, store values) — test observable behavior.

**`act` in Svelte:**

Unlike React Testing Library, Svelte Testing Library uses `tick()` for flushing updates rather than `act()`. Most interactions already resolve automatically with `await`; `tick()` is needed when updates are triggered by direct reactive changes rather than DOM events.

**Testing SvelteKit load functions:**

Load functions are plain async functions — test them directly without mounting a component:

```typescript
import { load } from './+page.server';

test('returns user data', async () => {
  const result = await load({
    params: { id: '1' },
    locals: { user: mockUser },
    fetch: global.fetch,
  } as any);

  expect(result.user.id).toBe(1);
});
```

**Snapshot testing:**

```typescript
test('matches snapshot', () => {
  const { container } = render(MyComponent);
  expect(container).toMatchSnapshot();
});
```

Use sparingly — prefer behavior assertions over structural snapshots.

## Source

https://kit.svelte.dev/docs/testing

## Process

1. Read the instructions and examples in this document.
2. Apply the patterns to your implementation, adapting to your specific context.
3. Verify your implementation against the details and edge cases listed above.

## Harness Integration

- **Type:** knowledge — this skill is a reference document, not a procedural workflow.
- **No tools or state** — consumed as context by other skills and agents.

## Success Criteria

- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.

Files in this skill

  • SKILL.md6.1 KB
  • skill.yaml839 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…