Testing
Prerequisites
Section titled “Prerequisites”Minimal testing prerequisites
Dependencies.
# Test Suitespnpm i -D @playwright/test vitest @vitest/ui vitest-tsconfig-paths# Playwright Browser Dependenciespnpm dlx playwright install # npx playwrigth install# Testing Librarypnpm i -D jsom @testing-library/svelte @testling-library/user-event @testing-library/jest-domUni Testing - Vitest and Testing Library Svelte
import { sveltekit } from "@sveltejs/kit/vite";import { defineConfig } from "vite";import { configDefaults } from "vitest/config";import tsconfigPaths from "vitest-tsconfig-paths";
export default defineConfig({ plugins: [sveltekit(), tsconfigPaths()], test: { plugins: [tsconfigPaths()], globals: true, reporters: "verbose", environment: "jsdom", restoreMocks: true, includeSource: ["src/**/*.{test,spec}.{js,ts}"], setupFiles: ["./src/test.config.ts"], coverage: { exclude: ["./src/test.config.ts"], }, exclude: [...configDefaults.exclude, "tests"], },});import { expect, afterEach } from "vitest";import { cleanup } from "@testing-library/svelte";import "@testing-library/jest-dom";import * as matchers from "@testing-library/jest-dom/matchers";expect.extend(matchers); // extend jest matchersafterEach(cleanup); // cleanup DOM after each testEnabling Global imports for unit tests
{ "compilerOptions": { "types": ["vitest/globals"] }}or use unplugin-auto-import install pnpm install -D unplugin-auto-import/vite
import { sveltekit } from "@sveltejs/kit/vite";import { defineConfig } from "vite";import { configDefaults } from "vitest/config";import AutoImport from "unplugin-auto-import/vite";
export default defineConfig({ plugins: [ sveltekit(), AutoImport({ imports: ["vitest"], dts: true, // generate TypeScript declaration }), ], test: { // ... rest of the options },});Integration Testing - Playwright
import type { PlaywrightTestConfig } from "@playwright/test";const config: PlaywrightTestConfig = { webServer: { command: "pnpm run build && pnpm run preview", port: 4173, }, fullyParallel: true, reporter: "html", testDir: "tests", testMatch: /(.+\.)?(test|spec)\.[jt]s/,};export default config;Additional ignored files
.DS_Storenode_modules/build/.svelte-kit/package.env.env.*!.env.examplevite.config.js.timestamp-*vite.config.ts.timestamp-*test-resultsplaywright-reportExternal Links to read more about configuration Vitest Config Playwright Config
Testing in Action
Section titled “Testing in Action”TODO! Create a Simple Svelte App
Hooking into Svelte
Section titled “Hooking into Svelte”/* eslint-disable @typescript-eslint/no-empty-function */import matchers from "@testing-library/jest-dom/matchers";import { expect, vi } from "vitest";expect.extend(matchers);vi.mock("$app/environment", () => ({ browser: true }));import { configDefaults, defineConfig } from "vitest/config";import { svelte } from "@sveltejs/vite-plugin-svelte";
export default defineConfig({ plugins: [svelte({ hot: !process.env.VITEST })], define: { "import.meta.vitest": "undefined", }, test: { globals: true, environment: "jsdom", includeSource: ["src/**/*.{test,spec}.{js,ts,svelte}"], setupFiles: ["./src/test.config.ts"], coverage: { exclude: ["./src/test.config.ts"], }, exclude: [...configDefaults.exclude, "tests"], },});Hooking into SvelteKit
Section titled “Hooking into SvelteKit”import matchers from "@testing-library/jest-dom/matchers";import { expect, vi } from "vitest";import { readable } from "svelte/store";import type * as environments from "$app/environment";import type * as navigation from "$app/navigation";import type * as stores from "$app/stores";import type { Navigation, Page } from "@sveltejs/kit";expect.extend(matchers);
vi.mock("$app/environment", (): typeof environments => ({ browser: true, dev: true, building: false, version: "any",}));
// Mock SvelteKit runtime module $app/navigationvi.mock("$app/navigation", (): typeof navigation => ({ afterNavigate: () => {}, beforeNavigate: () => {}, disableScrollHandling: () => {}, goto: () => Promise.resolve(), invalidate: () => Promise.resolve(), invalidateAll: () => Promise.resolve(), preloadData: () => Promise.resolve(), preloadCode: () => Promise.resolve(),}));
// Mock SvelteKit runtime module $app/storesvi.mock("$app/stores", (): typeof stores => { const getStores: typeof stores.getStores = () => { const navigating = readable<Navigation | null>(null); const page = readable<Page>({ url: new URL("http://localhost"), params: {}, route: { id: null, }, status: 200, error: null, data: {}, form: undefined, }); const updated = { subscribe: readable(false).subscribe, check: async () => false, };
return { navigating, page, updated }; };
const page: typeof stores.page = { subscribe(fn) { return getStores().page.subscribe(fn); }, }; const navigating: typeof stores.navigating = { subscribe(fn) { return getStores().navigating.subscribe(fn); }, }; const updated: typeof stores.updated = { subscribe(fn) { return getStores().updated.subscribe(fn); }, check: async () => false, };
return { getStores, navigating, page, updated, };});import { expect, afterEach, vi } from "vitest";import { cleanup, configure } from "@testing-library/svelte";import "@testing-library/jest-dom";import * as matchers from "@testing-library/jest-dom/matchers";import type { Navigation, Page } from "@sveltejs/kit";import { readable } from "svelte/store";import type * as environment from "$app/environment";import type * as stores from "$app/stores";import type * as navigation from "$app/navigation";
expect.extend(matchers);afterEach(cleanup);
configure({ asyncUtilTimeout: 1500,});
// Mock SvelteKit runtime module $app/environmentvi.mock("$app/environment", (): typeof environment => ({ browser: false, dev: true, building: false, version: "any",}));
// Mock SvelteKit runtime module $app/navigationvi.mock("$app/navigation", (): typeof navigation => ({ afterNavigate: () => {}, onNavigate: () => {}, beforeNavigate: () => {}, disableScrollHandling: () => {}, goto: () => Promise.resolve(), invalidate: () => Promise.resolve(), invalidateAll: () => Promise.resolve(), preloadData: () => Promise.resolve(), preloadCode: () => Promise.resolve(),}));
// Mock SvelteKit runtime module $app/storesvi.mock("$app/stores", (): typeof stores => { const getStores: typeof stores.getStores = () => { const navigating = readable<Navigation | null>(null); const page = readable<Page>({ url: new URL("http://localhost"), params: {}, route: { id: null, }, status: 200, error: null, data: {}, form: undefined, }); const updated = { subscribe: readable(false).subscribe, check: async () => false, };
return { navigating, page, updated }; };
const page: typeof stores.page = { subscribe(fn) { return getStores().page.subscribe(fn); }, }; const navigating: typeof stores.navigating = { subscribe(fn) { return getStores().navigating.subscribe(fn); }, }; const updated: typeof stores.updated = { subscribe(fn) { return getStores().updated.subscribe(fn); }, check: async () => false, };
return { getStores, navigating, page, updated, };});