首页 / Svelte 5 入门教程 / 测试

Svelte 5 入门教程

测试

本教程共 50 篇 · 第 39 篇 · 更新于 2026-08-05 · 约 5 分钟阅读

SvelteSvelte 5测试VitestPlaywright

本节目标:了解 Svelte 应用的三种测试方式,学会用 Vitest 测试响应式逻辑、用 mount 测试组件、用 Playwright 做端到端测试。

三种测试类型

Svelte 应用通常有三层测试,从细到粗:

类型测什么工具速度
单元测试纯函数、响应式逻辑Vitest
组件测试组件渲染和交互Vitest + jsdom
E2E 测试完整用户流程Playwright
Tip

不是所有逻辑都要放在组件里。数据转换、状态管理这些逻辑提取到 .svelte.js 文件中,更容易测试,覆盖率也更高。

Vitest 单元测试

Vitest 是 Vite 生态的测试框架,和 SvelteKit 无缝集成。安装:

npm install -D vitest

配置 vite.config.js

import { defineConfig } from 'vitest/config';

export default defineConfig({
	resolve: process.env.VITEST
		? { conditions: ['browser'] }
		: undefined
});

conditions: ['browser'] 让 Vitest 在 Node 中使用包的浏览器入口,这对 Svelte 组件很关键。

测试 .svelte.js 中的逻辑

把响应式逻辑放在 .svelte.js 文件中,然后直接测试:

// multiplier.svelte.ts
export function multiplier(initial: number, k: number) {
	let count = $state(initial);

	return {
		get value() {
			return count * k;
		},
		set: (c: number) => {
			count = c;
		}
	};
}
// multiplier.svelte.test.js
import { expect, test } from 'vitest';
import { multiplier } from './multiplier.svelte.js';

test('multiplier', () => {
	let double = multiplier(0, 2);

	expect(double.value).toEqual(0);

	double.set(5);
	expect(double.value).toEqual(10);
});

在测试文件中使用 Runes

如果测试文件名包含 .svelte(如 xxx.svelte.test.js),你可以在测试里直接使用 Runes:

// counter.svelte.test.js
import { flushSync } from 'svelte';
import { expect, test } from 'vitest';

test('reactive state', () => {
	let count = $state(0);
	let double = $derived(count * 2);

	expect(double).toEqual(0);

	count = 5;
	flushSync();
	expect(double).toEqual(10);
});

测试 $effect

测试包含 $effect 的代码时,需要用 $effect.root 包裹,并用 flushSync 强制执行副作用:

// logger.svelte.test.js
import { flushSync } from 'svelte';
import { expect, test } from 'vitest';
import { logger } from './logger.svelte.js';

test('effect logging', () => {
	const cleanup = $effect.root(() => {
		let count = $state(0);
		let log = logger(() => count);

		// flushSync 强制执行排队的 effect
		flushSync();
		expect(log).toEqual([0]);

		count = 1;
		flushSync();
		expect(log).toEqual([0, 1]);
	});

	cleanup();
});
Note

$effect 默认在微任务中执行。测试需要同步断言,所以用 flushSync() 把排队的副作用立即执行。

组件测试

组件测试需要 DOM 环境。先用 jsdom 模拟浏览器 API:

npm install -D jsdom

配置 Vitest 使用 jsdom:

// vite.config.js
import { defineConfig } from 'vitest/config';

export default defineConfig({
	test: {
		environment: 'jsdom'
	},
	resolve: process.env.VITEST
		? { conditions: ['browser'] }
		: undefined
});

用 mount/unmount 测试

Svelte 5 的 mountunmount API 可以直接在测试中挂载组件:

// component.test.js
import { flushSync, mount, unmount } from 'svelte';
import { expect, test } from 'vitest';
import Counter from './Counter.svelte';

test('Counter increments', () => {
	const component = mount(Counter, {
		target: document.body,
		props: { initial: 0 }
	});

	expect(document.body.innerHTML).toBe('<button>0</button>');

	// 模拟点击
	document.body.querySelector('button')?.click();
	flushSync();

	expect(document.body.innerHTML).toBe('<button>1</button>');

	// 清理
	unmount(component);
});

用 @testing-library/svelte

@testing-library/svelte 提供了更高层的 API,让测试更贴近用户视角:

npm install -D @testing-library/svelte @testing-library/user-event
// component.test.js
import { render, screen } from '@testing-library/svelte';
import userEvent from '@testing-library/user-event';
import { expect, test } from 'vitest';
import Counter from './Counter.svelte';

test('Counter increments', async () => {
	const user = userEvent.setup();
	render(Counter);

	const button = screen.getByRole('button');
	expect(button).toHaveTextContent('0');

	await user.click(button);
	expect(button).toHaveTextContent('1');
});
Tip

推荐用 @testing-library/svelte。它不关心组件内部实现,只测试用户看到的内容,测试更稳定。

E2E 测试

端到端测试模拟真实用户操作整个应用。用 Playwright 是当前主流方案:

npm init playwright

配置 Playwright 启动应用再测试:

// playwright.config.js
const config = {
	webServer: {
		command: 'npm run build && npm run preview',
		port: 4173
	},
	testDir: 'tests',
	testMatch: /(.+\.)?(test|spec)\.[jt]s/
};

export default config;

写测试时完全不需要知道 Svelte 的存在,只和浏览器交互:

// tests/home.spec.js
import { expect, test } from '@playwright/test';

test('首页显示标题', async ({ page }) => {
	await page.goto('/');
	await expect(page.locator('h1')).toBeVisible();
});

测试策略选择

场景推荐方式
测试纯函数逻辑单元测试,提取到 .svelte.js
测试组件渲染和交互@testing-library/svelte
测试响应式更新flushSync + 直接断言
测试包含 effect 的逻辑$effect.root + flushSync
测试完整用户流程Playwright E2E
Note

不要测试 Svelte 框架本身的功能(比如”$state 变了模板会不会更新”)。Svelte 有自己的测试套件。你应该测的是你的业务逻辑和组件行为。

本节回顾

  • 三种测试:单元测试(Vitest)、组件测试(Vitest + jsdom)、E2E 测试(Playwright)
  • .svelte.js 文件中的逻辑可以直接被 Vitest 测试
  • 测试文件名含 .svelte 时可在测试中使用 Runes
  • 测试 $effect 需要 $effect.root 包裹 + flushSync 强制执行
  • 组件测试可用 mount/unmount 底层 API 或 @testing-library/svelte 高层 API
  • E2E 测试用 Playwright,完全不知道 Svelte 的存在,只模拟用户操作