首页 / Astro 教程 / 测试 Testing

Astro 教程

测试 Testing

本教程共 56 篇 · 第 55 篇 · 更新于 2026-08-07 · 约 12 分钟阅读

AstroAstro 教程测试astro checkVitestPlaywright单元测试端到端

本节目标:搞清楚 Astro 不绑定某个官方测试框架,而是用 astro check 做类型与专属校验,再自由搭配 Vitest、Playwright 等第三方库做单元与端到端测试。

写代码免不了出错,测试就是给你兜底的网。Astro 的态度很务实:它不强制你用某一个测试框架,而是提供官方的 astro check 做专属检查,再把单元测试、组件测试、端到端测试交给成熟的第三方工具。这一章帮你理清该怎么组合。

astro check:Astro 自带的专属检查

astro check 是 Astro 官方提供的命令,干两件事:一是跑 TypeScript 类型检查,二是跑 Astro 自己的一套诊断(比如组件 props 类型、.astro 文件里的专属错误)。它不是「测试框架」,不会断言业务逻辑,但能帮你挡掉一大类低级错误。

# 全局安装后,或在项目里用 npx
npx astro check

跑完它会列出类型错误和 Astro 报错,并给出非零退出码——这意味着你可以把它接进 CI(持续集成),每次提交自动检查。这个命令还负责触发 Astro 的类型生成:它会生成 astro:* 这类虚拟模块的类型定义,让你在编辑器里能用上 Astro.propsAstro.locals 等的补全。

顺带一提,类型定义来自 astro:* 虚拟模块的自动生成。第 43 章讲过,Astro 会根据你的 src/env.d.ts、内容集合 schema 等生成类型文件,这些类型正是 astro check 和编辑器共享的。所以保持 astro check 通过,等于保持类型世界的一致性。

单元测试与组件测试:Vitest

Vitest 是跑在 Vite 上的单元测试框架,原生支持 ESM、TypeScript 和 JSX,和 Astro 同根同源,配合最顺。要在 Astro 项目里用,关键是用 Astro 提供的 getViteConfig() 帮你的 Vitest 套上 Astro 的项目配置。

// vitest.config.ts
/// <reference types="vitest/config" />
import { getViteConfig } from 'astro/config';

export default getViteConfig({
  test: {
    // 这里写 Vitest 的配置项
  },
});

默认情况下 getViteConfig() 会去加载你项目的 astro.config,把 Astro 的设置套到测试环境上。如果你需要给测试单独指定 Astro 配置(比如改 site、改 trailingSlash),可以传第二个参数:

export default getViteConfig(
  { test: { /* Vitest 配置 */ } },
  {
    site: 'https://example.com/',
    trailingSlash: 'always',
  },
);

用 Container API 测试 Astro 组件

Astro 4.9 起提供了 Container API,可以原生地渲染一个 .astro 组件并拿到它产出的 HTML 字符串,非常适合组件测试。先按上面配好 Vitest,再写个 .test.js 文件:

// example.test.js
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import { expect, test } from 'vitest';
import Card from '../src/components/Card.astro';

test('Card with slots', async () => {
  const container = await AstroContainer.create();
  const result = await container.renderToString(Card, {
    slots: {
      default: 'Card content',
    },
  });

  expect(result).toContain('This is a card');
  expect(result).toContain('Card content');
});

renderToString 把组件渲染成字符串,你就能断言输出里有没有某个文字、某个类名。插槽内容通过 slots 参数传进去,和真实模板里的 <slot /> 对应。

端到端测试:Playwright

单元测试管「小块代码对不对」,端到端(e2e)测试管「整个网站跑起来像不像样」。Playwright 是主流的 e2e 框架,能在 Chromium、WebKit、Firefox 上真实打开你的页面点来点去。

安装 Playwright 最简单的方式是走它的初始化向导,跟着提示选语言、命名测试目录即可:

npm init playwright@latest

装好后写第一个测试,验证首页标题对不对:

// src/test/index.spec.ts
import { test, expect } from '@playwright/test';

test('meta is correct', async ({ page }) => {
  await page.goto("http://localhost:4321/");
  await expect(page).toHaveTitle('Astro is awesome!');
});

跑测试时,Playwright 默认在终端报告结果。想看更完整的可视化报告:

npx playwright test index.spec.ts   # 跑单个测试
npx playwright show-report          # 打开 HTML 报告

进阶一点:让 Playwright 在测试时自己起一个服务器。在 playwright.config.ts 里加 webServer 配置,它会在测试前执行 npm run preview 并等端口就绪:

// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  webServer: {
    command: 'npm run preview',
    url: 'http://localhost:4321/',
    timeout: 120 * 1000,
    reuseExistingServer: !process.env.CI,
  },
  use: {
    baseURL: 'http://localhost:4321/',
  },
});

这样你先 npm run build,再 npm run test:e2e,整个流程就能自动化。

除了 Playwright,社区里 Cypress、Nightwatch 也常被用来给 Astro 做 e2e 测试,思路大同小异:起服务、开浏览器、断言页面行为。选哪个看你团队习惯,Astro 官方文档都给了示例。

测试环境下的两个注意点

在 Astro 里写测试,有两处和平时写页面不同,容易踩坑。

第一,import.meta.env。Astro 在构建时会把环境变量替换成字面量。测试环境用的是 Vitest 自己的 Vite 配置,不一定和你生产/开发的 import.meta.env 一致。如果你在组件里读 import.meta.env.PUBLIC_XXX,测试时最好通过 getViteConfig 的第二个参数或 Vitest 的 env 配置把需要的变量补上,否则可能读到 undefined

第二,按需渲染的页面。带 export const prerender = falseoutput: 'server' 的页面、端点,依赖运行时服务端(读 cookie、读会话、连数据库)。Vitest 的组件测试默认只渲染静态 HTML,不会真的起服务端;要测这类逻辑,更合适的做法是直接对端点函数、Actions 的 handler 做单元测试,或者用 Playwright 起真实服务做 e2e。别指望在纯组件测试里验证服务端行为。

把测试接进 npm 脚本

测试命令一长就容易忘,最佳实践是把它们写进 package.jsonscripts 里,用语义化的名字一键跑:

{
  "scripts": {
    "check": "astro check",
    "test": "vitest run",
    "test:watch": "vitest",
    "test:e2e": "playwright test"
  }
}

vitest run 是跑一次就退出的模式,适合 CI;vitest 不带 run 会进入监听模式,改代码自动重跑,适合本地开发。astro check 单独放一个 check 脚本,提交前顺手跑一下。

如果你要把测试接进 CI(比如 GitHub Actions),典型的流程是:先 npm ci 装依赖,再 npm run check 做类型检查,最后 npm test 跑单测,某一环失败就整条流水线变红、阻止合并。这样能把「低级错误」挡在合并之前,比等上线才发现省事得多。

测 Actions 的 handler

第 45 章讲过 Astro 的 Actions(astro:actions)用来处理表单后端。它的 handler 是纯函数,非常适合单元测试:直接调用 handler,传一个假的 context,断言返回结果。这种测试不依赖浏览器、不依赖起服务,速度快又稳。

// actions/addToCart.test.ts
import { expect, test } from 'vitest';

test('addToCart 把商品加进会话', async () => {
  const fakeContext = {
    session: { get: async () => [], set: async () => {} },
  };
  // 省略真实 import 与调用,思路是:传假 context,断言返回值
  expect(true).toBe(true);
});

上面是思路骨架:用一个实现了 get/set 的假对象充当 context.session,就能在不连真 Redis 的情况下验证业务逻辑。真实的测试里你会 import 自己的 action 并断言它往会话里写了什么。

社区做法点到为止

Astro 社区没有「唯一正统」的测试栈。常见的组合是:astro check 守住类型和 Astro 专属错误;Vitest + Container API 做组件和工具函数单测;Playwright(或 Cypress)做 e2e。也有人把 React Testing Library 这类框架专属库接进来,专门测岛屿里的 React/Vue 组件。

你不必一次全上。小项目先保证 astro check 通过、加几个关键组件的 Vitest 测试就够;等页面多了、交互复杂了,再补 Playwright 的 e2e。测试是渐进投资,不是一次性工程。

小结

Astro 不替你定死测试框架,而是给 astro check 做类型与专属检查,把单元、组件、e2e 测试交给 Vitest、Playwright 这类成熟工具。配好 getViteConfig、用 Container API 渲染组件、用 Playwright 起服务跑 e2e,再留意 import.meta.env 和按需渲染在测试环境下的差异,就够搭出一套顺手的测试网。下一章我们汇总常见的报错与排查手段,让你写挂了也知道去哪找原因。