前言
Svelte,一个语法简洁、入门容易,面向未来的前端框架。从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1:
Svelte 以其独特的编译时优化机制著称,具有轻量级、高性能、易上手等特性,非常适合构建轻量级 Web 项目,也是我做个人项目的首选技术栈。
目前 Svelte 基于 Svelte 5 发布了最新的官方文档,但却缺少对应的中文文档。为了帮助大家学习 Svelte,为爱发电翻译了官方文档。
我同时搭建了 Svelte 最新的中文文档站点:https://svelte.yayujs.com ,如果需要辅助学习,也可以入手我的小册《Svelte 开发指南》,语法篇、实战篇、原理篇三大篇章带你系统掌握 Svelte!
虽说是翻译,但个人并不喜欢严格遵守原文,为了保证中文阅读流畅,会删减部分语句,对难懂的部分也会另做补充解释,希望能给大家带来一个好的中文学习体验。
欢迎围观我的“网页版朋友圈”、加入“冴羽·成长陪伴社群”,踏上“前端大佬成长之路”。
测试
测试可以帮助您编写和维护代码,防止出现回归问题。测试框架可以帮助您完成这一目标,通过让您能够描述对代码行为的断言或期望。
Svelte 对于您使用哪种测试框架并不持有特定立场 — 您可以使用 Vitest、Jasmine、Cypress 和 Playwright 等解决方案来编写单元测试、集成测试和端到端测试。
使用 Vitest 进行单元和集成测试
单元测试允许您测试代码中的小型独立部分。集成测试允许您测试应用程序的各个部分,以查看它们是否协同工作。如果您使用 Vite(包括通过 SvelteKit),我们推荐使用 Vitest。
首先安装 Vitest:
npm install -D vitest
然后调整您的 vite.config.js
:
/// file: vite.config.js
import { defineConfig } from +++'vitest/config'+++;export default defineConfig({// ...// 告诉 Vitest 使用 `package.json` 文件中的 `browser` 入口点,即使它在 Node 中运行resolve: process.env.VITEST? {conditions: ['browser']}: undefined
});
[!NOTE] 如果加载所有包的浏览器版本不适合您的需求,例如您还需要测试后端库,您可能需要使用别名配置
现在您可以为 .js/.ts
文件中的代码编写单元测试:
/// file: multiplier.svelte.test.js
import { flushSync } from 'svelte';
import { expect, test } from 'vitest';
import { multiplier } from './multiplier.js';test('Multiplier', () => {let double = multiplier(0, 2);expect(double.value).toEqual(0);double.set(5);expect(double.value).toEqual(10);
});
在测试文件中使用符文(runes)
您可以在测试文件中使用符文。首先确保您的打包工具知道在运行测试之前要通过 Svelte 编译器处理文件,方法是在文件名中添加 .svelte
(例如 multiplier.svelte.test.js
)。之后,您就可以在测试中使用符文了。
/// file: multiplier.svelte.test.js
import { flushSync } from 'svelte';
import { expect, test } from 'vitest';
import { multiplier } from './multiplier.svelte.js';test('Multiplier', () => {let count = $state(0);let double = multiplier(() => count, 2);expect(double.value).toEqual(0);count = 5;expect(double.value).toEqual(10);
});
如果被测试的代码使用了 effects,您需要将测试包装在 $effect.root
中:
/// file: logger.svelte.test.js
import { flushSync } from 'svelte';
import { expect, test } from 'vitest';
import { logger } from './logger.svelte.js';test('Effect', () => {const cleanup = $effect.root(() => {let count = $state(0);// logger 使用 $effect 来记录其输入的更新let log = logger(() => count);// 效果通常在微任务后运行,// 使用 flushSync 同步执行所有待处理的效果flushSync();expect(log.value).toEqual([0]);count = 1;flushSync();expect(log.value).toEqual([0, 1]);});cleanup();
});
组件测试
您可以使用 Vitest 在隔离环境下测试您的组件。
[!NOTE] 在编写组件测试之前,请考虑是否真的需要测试组件本身,还是更多地关注组件内部的逻辑。如果是后者,考虑将逻辑提取出来单独测试,避免组件测试的开销
首先安装 jsdom(一个提供 DOM API 模拟的库):
npm install -D jsdom
然后调整您的 vite.config.js
:
/// file: vite.config.js
import { defineConfig } from 'vitest/config';export default defineConfig({plugins: [/* ... */],test: {// 如果您在客户端测试组件,您需要设置 DOM 环境。// 如果不是所有文件都需要这个环境,您可以在测试文件顶部使用// `// @vitest-environment jsdom` 注释来代替。environment: 'jsdom'},// 告诉 Vitest 使用 `package.json` 文件中的 `browser` 入口点,即使它在 Node 中运行resolve: process.env.VITEST? {conditions: ['browser']}: undefined
});
之后,您可以创建一个测试文件,在其中导入要测试的组件,以编程方式与之交互并编写关于结果的预期:
/// file: component.test.js
import { flushSync, mount, unmount } from 'svelte';
import { expect, test } from 'vitest';
import Component from './Component.svelte';test('Component', () => {// 使用 Svelte 的 `mount` API 实例化组件const component = mount(Component, {target: document.body, // 由于 jsdom 的存在,`document` 是可用的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>');// 从 DOM 中移除组件unmount(component);
});
虽然这个过程非常简单明了,但它也比较底层且有些脆弱,因为组件的精确结构可能会频繁变化。像 @testing-library/svelte 这样的工具可以帮助简化测试。上面的测试可以重写为:
/// file: component.test.js
import { render, screen } from '@testing-library/svelte';
import userEvent from '@testing-library/user-event';
import { expect, test } from 'vitest';
import Component from './Component.svelte';test('Component', async () => {const user = userEvent.setup();render(Component);const button = screen.getByRole('button');expect(button).toHaveTextContent(0);await user.click(button);expect(button).toHaveTextContent(1);
});
当编写涉及双向绑定、上下文或代码片段属性的组件测试时,最好为您的特定测试创建一个包装组件并与之交互。@testing-library/svelte
包含一些示例。
使用 Playwright 进行端到端测试
E2E(端到端的简称)测试允许您从用户的视角测试整个应用程序。本节以 Playwright 为例,但您也可以使用其他解决方案,如 Cypress 或 NightwatchJS。
要开始使用 Playwright,可以通过 VS Code 扩展 安装,或者使用 npm init playwright
从命令行安装。它也是运行 npx sv create
时设置 CLI 的一部分。
完成后,您应该有一个 tests
文件夹和一个 Playwright 配置。您可能需要调整该配置,告诉 Playwright 在运行测试之前要做什么 - 主要是在某个端口启动您的应用程序:
/// file: 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 作为一个框架的存在,所以您主要是和 DOM 交互并编写断言。
// @errors: 2307 7031
/// file: tests/hello-world.spec.js
import { expect, test } from '@playwright/test';test('主页包含预期的 h1', async ({ page }) => {await page.goto('/');await expect(page.locator('h1')).toBeVisible();
});
Svelte 中文文档
本篇已收录在专栏 《Svelte 中文文档》,该系列预计 40 篇。
系统学习 Svelte,欢迎入手小册《Svelte 开发指南》。语法篇、实战篇、原理篇三大篇章带你系统掌握 Svelte!
此外我还写过 JavaScript 系列、TypeScript 系列、React 系列、Next.js 系列、冴羽答读者问等 14 个系列文章, 全系列文章目录:https://github.com/mqyqingfeng/Blog
欢迎围观我的“网页版朋友圈”、加入“冴羽·成长陪伴社群”,踏上“前端大佬成长之路”。