Learn Svelte - Testing & Quality
Series/Learn Svelte/Episode 16
Episode 16 of 24

Learn Svelte - Testing & Quality

This episode covers how to maintain code quality: unit testing components with Vitest and Svelte Testing Library, integration testing for SvelteKit apps, E2E testing with Playwright, and static analysis, linting, and type checking.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Introduction

Code without tests feels like a building without a foundation: it works until it breaks in the most unexpected place. Automated testing makes bold changes safe, because errors are caught in seconds instead of in production.

This episode covers unit testing components with Vitest and Svelte Testing Library, integration testing for SvelteKit apps, E2E testing with Playwright, and static analysis, linting, and type checking.

When you're done, you'll have a testing layer that catches errors at the most appropriate level: unit tests for logic, integration tests for modules that work together, and E2E for real user flows.

Unit Testing with Vitest and Svelte Testing Library

Setting Up Vitest

New SvelteKit projects already include Vitest configuration through the @sveltejs/kit/vite plugin. For older projects, install it manually:

Install testing tooling
npm install -D vitest jsdom @testing-library/svelte

jsdom provides a DOM environment in Node, so components can be rendered and tested without a real browser.

Writing Your First Test

Create a small component and test its behavior like a user would, not its implementation details:

Counter.svelte component
<script>
  let hitung = $state(0)
</script>
 
<button onclick={() => hitung += 1}>Hitung: {hitung}</button>

The test checks the outcome of an interaction:

JSCounter component test
import { render, screen, fireEvent } from "@testing-library/svelte"
import { describe, it, expect } from "vitest"
import Counter from "./Counter.svelte"
 
describe("Counter", () => {
  it("menambahkan nilai saat tombol diklik", async () => {
    render(Counter)
    const tombol = screen.getByRole("button")
    await fireEvent.click(tombol)
    expect(screen.getByText("Hitung: 1")).toBeTruthy()
  })
})

screen.getByRole("button") selects the button through its accessibility role — not a DOM selector — making the test more resilient to structural changes. fireEvent.click(tombol) simulates a user click.

Integration Testing for SvelteKit Apps

Tests at the Endpoint and Form Action Level

Integration testing ensures modules work together: a load function reads data, a form action validates, and the response reaches the component. Server endpoints can be tested by calling their handlers directly in Vitest:

JSTest a server endpoint
import { describe, it, expect } from "vitest"
import { GET } from "./+server.js"
 
describe("endpoint /api/health", () => {
  it("mengembalikan status sehat", async () => {
    const res = await GET()
    expect(res.status).toBe(200)
    const body = await res.json()
    expect(body.status).toBe("ok")
  })
})

await GET() executes the endpoint handler without a real HTTP server. This pattern is fast and deterministic for testing server logic.

E2E Testing with Playwright

Real User Flows in the Browser

Unit and integration tests can't catch problems that only appear when the whole app runs in a browser: navigation, authentication, and cross-page interactions. Playwright runs these flows in a real browser.

Run E2E with Playwright
npm run test:e2e

SvelteKit ships with Playwright configuration by default. E2E tests run slower than unit tests, so focus on critical flows: login, checkout, and main navigation.

Static Analysis, Linting, and Type Checking

svelte-check and ESLint

npx svelte-check checks types across the whole project without running a full build. Pair it with ESLint to catch code pattern issues as you type in the editor:

Quality scripts in package.json
{
  "scripts": {
    "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
    "lint": "eslint ."
  }
}

npm run check and npm run lint should run before every commit and inside CI. Type errors caught in the pipeline are cheaper than bugs found by users.

Conclusion

Key takeaways:

  • Unit tests catch component logic errors quickly.
  • Test interactions through accessibility roles, not DOM selectors.
  • Integration tests exercise load functions and endpoints directly.
  • E2E with Playwright covers critical flows in a real browser.
  • Run svelte-check and ESLint in CI to catch issues early.
  • Choose a testing layer according to its cost and speed.

Next, in episode 17 you'll learn accessibility & UX — ARIA roles and keyboard navigation, semantic HTML and accessible components, responsive design and progressive enhancement, and internationalization basics. The testing from this episode will guarantee that accessibility fixes don't break existing features.

Learn Svelte - Testing & Quality | Learn Svelte