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-dom
Uni 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 test
Enabling Global imports for unit tests
{ "compilerOptions": { "types": ["vitest/globals"] }}
or use unplugin-auto-import install pnpm install -D unplugin-auto-import/vite
unplugin-auto-import
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-report
External Links to read more about configuration Vitest Config Playwright Config
TODO! Create a Simple Svelte App
/* 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'] }})
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 }})