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

การทดสอบด้วย Vitest และ Testing Library

นักพัฒนา React มักจะหยิบ Jest มาใช้ร่วมกับ React Testing Library (RTL) สำหรับการทดสอบ component ตัวเทียบเท่าของ Svelte คือ Vitest + @testing-library/svelte ปรัชญาของ Testing Library นั้นเหมือนกัน — query DOM ในแบบที่ผู้ใช้ทำ, ยิง event, และ assert ผลลัพธ์ที่มองเห็นได้ API แทบจะเหมือนกันแบบ byte-for-byte ความต่างหลักอยู่ที่ test runner (Vitest เทียบกับ Jest) และวิธีการ import component (ไฟล์ .svelte เทียบกับ .tsx)

ก่อนอื่น component ที่จะนำมาทดสอบ:

Counter.tsx
// Counter.tsx
import React from 'react';
export function Counter() {
const [count, setCount] = React.useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
</div>
);
}
Counter.svelte
<!-- Counter.svelte -->
<script lang="ts">
let count = $state(0);
</script>
<div>
<p>Count: {count}</p>
<button onclick={() => count++}>Increment</button>
</div>

ทีนี้มาดูตัวทดสอบ:

Counter.test.tsx
// Counter.test.tsx (Jest + RTL)
import { render, screen, fireEvent } from '@testing-library/react';
import { Counter } from './Counter';
test('increments count', () => {
render(<Counter />);
expect(screen.getByText('Count: 0')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Increment' }));
expect(screen.getByText('Count: 1')).toBeInTheDocument();
});
Counter.test.ts
// Counter.test.ts (Vitest + @testing-library/svelte)
import { render, screen, fireEvent } from '@testing-library/svelte';
import Counter from './Counter.svelte';
import { describe, it, expect } from 'vitest';
describe('Counter', () => {
it('increments count', async () => {
render(Counter);
expect(screen.getByText('Count: 0')).toBeInTheDocument();
await fireEvent.click(
screen.getByRole('button', { name: 'Increment' })
);
expect(screen.getByText('Count: 1')).toBeInTheDocument();
});
});

ความต่างสำคัญที่ควรสังเกต:

  • Svelte: render(Counter) — ส่ง component class เข้าไปโดยตรง (ไม่มี JSX) ส่วน React: render(<Counter />) — เป็น JSX element
  • Svelte: fireEvent.click(...) ต้อง await เพราะ Svelte จะ batch การอัปเดต DOM แบบ asynchronous ส่วน fireEvent ของ React RTL เป็นแบบ synchronous
  • ส่วนที่เหลือทั้งหมด — screen, getByText, getByRole, toBeInTheDocument — เหมือนกัน
vitest.config.ts
import { defineConfig } from 'vitest/config';
import { svelte } from '@sveltejs/vite-plugin-svelte';
export default defineConfig({
plugins: [svelte({ hot: !process.env.VITEST })],
test: {
environment: 'jsdom',
globals: true,
setupFiles: ['./src/setupTests.ts'],
},
});

ตัวป้องกัน hot: !process.env.VITEST จะปิด HMR ระหว่างการรันทดสอบ (ซึ่งจะทำให้เกิด error ในสภาพแวดล้อม jsdom)

Terminal window
npm install --save-dev vitest @testing-library/svelte @testing-library/jest-dom jsdom

สร้าง src/setupTests.ts:

import '@testing-library/jest-dom';

Playwright ทำงานเหมือนกันทั้งกับโปรเจกต์ React และ Svelte — ไม่มีอะไรเฉพาะของ Svelte ให้ต้องเรียนรู้ ติดตั้งและตั้งค่าด้วยวิธีเดียวกัน:

Terminal window
npm init playwright@latest
อะไรคือตัวเทียบเท่า Jest ในฝั่ง Svelte สำหรับการรันทดสอบ component?
คุณ render Svelte component ใน @testing-library/svelte อย่างไร?
ทำไมการเรียก fireEvent ต้องถูก await ใน @testing-library/svelte?
เครื่องมือทดสอบ e2e ใดที่ทำงานเหมือนกันทั้งกับโปรเจกต์ React และ Svelte?