Skip to content

Testing

Minimal testing prerequisites

Dependencies.

Installing dependencies
# Test Suites
pnpm i -D @playwright/test vitest @vitest/ui vitest-tsconfig-paths
# Playwright Browser Dependencies
pnpm dlx playwright install # npx playwrigth install
# Testing Library
pnpm i -D jsom @testing-library/svelte @testling-library/user-event @testing-library/jest-dom

Uni Testing - Vitest and Testing Library Svelte

vite.config.ts
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"],
},
});
src/test.config.ts
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 matchers
afterEach(cleanup); // cleanup DOM after each test

Enabling Global imports for unit tests

tsconfig.json
{
"compilerOptions": {
"types": ["vitest/globals"]
}
}

or use unplugin-auto-import install pnpm install -D unplugin-auto-import/vite

vite.config.ts
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

playwright.config.ts
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

.gitignore
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
test-results
playwright-report

External Links to read more about configuration Vitest Config Playwright Config

TODO! Create a Simple Svelte App

src/test.config.ts
/* 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 }));
vite.config.ts
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"],
},
});
src/test.config.ts
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/navigation
vi.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/stores
vi.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,
};
});
src/test.config.ts
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/environment
vi.mock("$app/environment", (): typeof environment => ({
browser: false,
dev: true,
building: false,
version: "any",
}));
// Mock SvelteKit runtime module $app/navigation
vi.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/stores
vi.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,
};
});