Testing & Tooling
test สามชั้น
หัวข้อที่มีชื่อว่า “test สามชั้น”เว็บ Astro ส่วนใหญ่เป็น HTML ที่ render บน server พร้อม island ไม่กี่ตัว ซึ่งกำหนดว่าคุณจะ test ยังไง สามชั้นครอบคลุมทั้งหมด:
| ชั้น | Tool | ตรวจอะไร |
|---|---|---|
| Unit | Vitest | logic ล้วน — helper, data transform, schema parsing |
| Component | Astro Container API (+ Vitest) | component render HTML ที่คาดหวังจาก props/slots ที่ให้ |
| End-to-end | Playwright | หน้าจริงใน browser จริง รวมถึง island interactivity |
หลักการคร่าว ๆ: ดัน logic เข้า function ล้วนแล้ว unit-test ตรงนั้น, render-test component ที่ output สำคัญ และใช้ end-to-end test ไม่กี่ตัวสำหรับ flow ที่เกี่ยวกับ hydration และ navigation จริง
unit test ด้วย Vitest
หัวข้อที่มีชื่อว่า “unit test ด้วย Vitest”เพราะ 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');});component test ด้วย Container API
หัวข้อที่มีชื่อว่า “component test ด้วย Container API”เพื่อ 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 ของตัวเอง
end-to-end ด้วย Playwright
หัวข้อที่มีชื่อว่า “end-to-end ด้วย Playwright”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"]
Dev Toolbar
หัวข้อที่มีชื่อว่า “Dev Toolbar”ระหว่าง development Astro แสดง Dev Toolbar ที่ด้านล่างของหน้า — toolbar เตือนปัญหา accessibility, แสดงว่า component ไหนเป็น island (และ hydration directive ของตัวเอง) และมี plugin สำหรับ audit และ debug เป็นวิธีที่เร็วที่สุดในการเห็นว่า อะไรกลายเป็น island จริง ๆ และจับปัญหา a11y ระหว่างสร้าง Dev Toolbar รันแค่ตอน dev และไม่ส่งขึ้น production