Skip to main content
Svelte Fundamentals
CHAPTER 24 Beginner

Testing in Svelte

Updated: May 18, 2026
5 min read

# CHAPTER 24

Testing in Svelte

1. Chapter Introduction

Testing ensures your components behave correctly today and continue to work when code changes tomorrow. The modern Svelte testing stack uses Vitest (a blazing-fast Vite-native test runner) and @testing-library/svelte (for component rendering tests that simulate real user interactions).

2. Learning Objectives

  • Set up Vitest and Svelte Testing Library.
  • Write unit tests for pure JavaScript functions and stores.
  • Write component tests that simulate user interaction.
  • Follow testing best practices.

3. Setup

bash
1
npm install -D vitest @testing-library/svelte @testing-library/jest-dom jsdom
vite.config.js
123456789101112
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';

export default defineConfig({
  plugins: [svelte({ hot: !process.env.VITEST })],
  test: {
    include: ['src/**/*.test.{js,ts}'],
    environment: 'jsdom',
    globals: true,
    setupFiles: ['./src/test-setup.js']
  }
});
javascript
12
// src/test-setup.js
import '@testing-library/jest-dom';
bash
123
# Run tests
npm run test       # watch mode
npm run test -- --run  # single run

4. Testing Pure Functions

javascript
12345678
// src/lib/utils/math.js
export function calculateTotal(price, quantity) {
  return price * quantity;
}

export function formatCurrency(amount, currency = 'USD') {
  return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount);
}
javascript
1234567891011121314151617181920212223
// src/lib/utils/math.test.js
import { describe, it, expect } from 'vitest';
import { calculateTotal, formatCurrency } from './math.js';

describe('calculateTotal', () => {
  it('multiplies price by quantity', () => {
    expect(calculateTotal(10, 5)).toBe(50);
  });

  it('returns 0 when quantity is 0', () => {
    expect(calculateTotal(99.99, 0)).toBe(0);
  });

  it('handles decimal prices', () => {
    expect(calculateTotal(9.99, 3)).toBeCloseTo(29.97);
  });
});

describe('formatCurrency', () => {
  it('formats USD by default', () => {
    expect(formatCurrency(1234.5)).toBe('$1,234.50');
  });
});

5. Testing Svelte Stores

javascript
12345678910111213141516171819202122232425262728293031323334
// src/lib/stores/counter.test.js
import { describe, it, expect, beforeEach } from 'vitest';
import { get } from 'svelte/store';
import { createCounter } from './counterStore.js';

describe('createCounter store', () => {
  let counter;

  beforeEach(() => {
    counter = createCounter(0, 1);
  });

  it('has the initial value', () => {
    expect(get(counter)).toBe(0);
  });

  it('increments', () => {
    counter.increment();
    expect(get(counter)).toBe(1);
  });

  it('decrements', () => {
    counter.increment();
    counter.decrement();
    expect(get(counter)).toBe(0);
  });

  it('resets to initial value', () => {
    counter.increment();
    counter.increment();
    counter.reset();
    expect(get(counter)).toBe(0);
  });
});

6. Testing Svelte Components

svelte
12345678
<!-- src/lib/Counter.svelte -->
<script>
  let count = 0;
</script>

<h2 data-testid="count">{count}</h2>
<button on:click={() => count++}>Increment</button>
<button on:click={() => count = 0}>Reset</button>
javascript
1234567891011121314151617181920212223242526272829
// src/lib/Counter.test.js
import { describe, it, expect } from &#039;vitest&#039;;
import { render, fireEvent } from &#039;@testing-library/svelte&#039;;
import Counter from &#039;./Counter.svelte&#039;;

describe(&#039;Counter component&#039;, () => {
  it(&#039;renders with initial count of 0&#039;, () => {
    const { getByTestId } = render(Counter);
    expect(getByTestId(&#039;count&#039;).textContent).toBe(&#039;0&#039;);
  });

  it(&#039;increments when button is clicked&#039;, async () => {
    const { getByText, getByTestId } = render(Counter);
    const button = getByText(&#039;Increment&#039;);

    await fireEvent.click(button);
    expect(getByTestId(&#039;count&#039;).textContent).toBe(&#039;1&#039;);

    await fireEvent.click(button);
    expect(getByTestId(&#039;count&#039;).textContent).toBe(&#039;2&#039;);
  });

  it(&#039;resets to 0 when Reset is clicked&#039;, async () => {
    const { getByText, getByTestId } = render(Counter);
    await fireEvent.click(getByText(&#039;Increment&#039;));
    await fireEvent.click(getByText(&#039;Reset&#039;));
    expect(getByTestId(&#039;count&#039;).textContent).toBe(&#039;0&#039;);
  });
});

7. Testing with Props

javascript
123456789101112
// Testing a component with props
import { render } from &#039;@testing-library/svelte&#039;;
import UserCard from &#039;./UserCard.svelte&#039;;

it(&#039;displays user name and role&#039;, () => {
  const { getByText } = render(UserCard, {
    props: { name: &#039;Alice Johnson&#039;, role: &#039;Admin&#039; }
  });

  expect(getByText(&#039;Alice Johnson&#039;)).toBeInTheDocument();
  expect(getByText(&#039;Admin&#039;)).toBeInTheDocument();
});

8. Common Mistakes

  • Testing implementation details: Don't test internal variables. Test what the user sees (getByText, getByRole).
  • Not using await with fireEvent: Svelte DOM updates are async. Always await events and then check DOM state.

9. MCQs

Question 1

What is the Vite-native test runner for Svelte?

Question 2

What library provides component rendering utilities like render and fireEvent?

Question 3

How do you read a store's value synchronously in a test?

Question 4

Why should you await fireEvent.click(button) in tests?

Question 5

What data- attribute makes elements easy to target in tests?

Question 6

What jest-dom matcher checks if an element is in the document?

Question 7

How do you pass props in @testing-library/svelte render?

Question 8

What beforeEach does in a test suite?

Question 9

What is the testing philosophy of @testing-library?

Question 10

What getByText does?

10. Interview Questions

  • Q: What is the difference between unit testing and component testing in Svelte?
  • Q: Why is testing "behavior not implementation" important?

11. Summary

Vitest + @testing-library/svelte provides a modern, fast, and intuitive testing stack. Unit tests for pure functions and stores verify logic. Component tests verify user-visible behavior by simulating clicks and form inputs. This approach builds a confidence safety net for fearless refactoring.

12. Next Chapter Recommendation

In Chapter 25: Building Reusable UI Components, we create a production-quality component library — buttons, inputs, modals, and cards — following design system principles.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·