ข้ามไปยังเนื้อหา

Testing & Tooling

เว็บ Astro ส่วนใหญ่เป็น HTML ที่ render บน server พร้อม island ไม่กี่ตัว ซึ่งกำหนดว่าคุณจะ test ยังไง สามชั้นครอบคลุมทั้งหมด:

ชั้นToolตรวจอะไร
UnitVitestlogic ล้วน — helper, data transform, schema parsing
ComponentAstro Container API (+ Vitest)component render HTML ที่คาดหวังจาก props/slots ที่ให้
End-to-endPlaywrightหน้าจริงใน browser จริง รวมถึง island interactivity

หลักการคร่าว ๆ: ดัน logic เข้า function ล้วนแล้ว unit-test ตรงนั้น, render-test component ที่ output สำคัญ และใช้ end-to-end test ไม่กี่ตัวสำหรับ flow ที่เกี่ยวกับ hydration และ navigation จริง

เพราะ Astro รันบน Vite Vitest จึงเป็น unit-test runner ที่เป็นธรรมชาติ — config เดียวกัน, เริ่มทันที อะไรที่เป็น TypeScript ล้วน (date formatter, filter, Zod schema) ก็ test แบบปกติ:

import { expect, test } from 'vitest';
import { formatDate } from '../src/lib/format';
test('formatDate renders a friendly date', () => {
expect(formatDate(new Date('2026-01-15'))).toBe('Jan 15, 2026');
});

เพื่อ test ว่า component .astro render HTML ถูกต้อง ใช้ Astro Container API — API นี้ render component เป็น string แบบแยกเดี่ยว ไม่ต้องมี browser ตอนนี้เปิดให้ใช้ในชื่อ experimental_AstroContainer:

import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import { expect, test } from 'vitest';
import Card from '../src/components/Card.astro';
test('Card renders its title and slotted content', async () => {
const container = await AstroContainer.create();
const result = await container.renderToString(Card, {
props: { title: 'Hello' },
slots: { default: 'Body content' },
});
expect(result).toContain('Hello');
expect(result).toContain('Body content');
});

คุณได้ HTML ที่ render เป็น string แล้ว assert กับ string นั้นได้เลย — เร็ว และ exercise component จริงรวมถึง props และ slot ของตัวเอง

Container test render HTML แต่ไม่รัน island สำหรับพฤติกรรมที่ขึ้นกับ hydration — คลิก island ที่ interactive, client-side navigation ด้วย <ClientRouter />, การ submit form — ใช้ Playwright (หรือ Cypress) ขับ browser จริงกับเว็บที่ build แล้ว:

import { test, expect } from '@playwright/test';
test('counter island increments on click', async ({ page }) => {
await page.goto('/');
await page.getByRole('button', { name: 'Increment' }).click();
await expect(page.getByText('Count: 1')).toBeVisible();
});
flowchart LR
  logic["plain logic"] --> vitest["Vitest unit test"]
  comp["component HTML output"] --> container["Container API test"]
  flow["hydrated flows and navigation"] --> pw["Playwright e2e"]
test ที่ชั้นซึ่งตรงกับความเสี่ยง

ระหว่าง development Astro แสดง Dev Toolbar ที่ด้านล่างของหน้า — toolbar เตือนปัญหา accessibility, แสดงว่า component ไหนเป็น island (และ hydration directive ของตัวเอง) และมี plugin สำหรับ audit และ debug เป็นวิธีที่เร็วที่สุดในการเห็นว่า อะไรกลายเป็น island จริง ๆ และจับปัญหา a11y ระหว่างสร้าง Dev Toolbar รันแค่ตอน dev และไม่ส่งขึ้น production

tool ไหน render component .astro เป็น HTML string แบบแยกเดี่ยวเพื่อ test?
ทำไมต้องมี Playwright เพิ่มจาก Container API test?
unit-test runner ที่เป็นธรรมชาติของโปรเจกต์ Astro คืออะไร และทำไม?
Astro Dev Toolbar ช่วยเรื่องอะไร?