# 🔄 เปรียบเทียบ Jest กับ Playwright

## สารบัญ

1. [ภาพรวมและวัตถุประสงค์](#1-ภาพรวมและวัตถุประสงค์)
2. [ความแตกต่างหลัก](#2-ความแตกต่างหลัก)
3. [เปรียบเทียบรายละเอียด](#3-เปรียบเทียบรายละเอียด)
4. [การติดตั้งและตั้งค่า](#4-การติดตั้งและตั้งค่า)
5. [ตัวอย่างการใช้งาน](#5-ตัวอย่างการใช้งาน)
6. [ข้อดีข้อเสีย](#6-ข้อดีข้อเสีย)
7. [เมื่อไหร่ควรใช้อะไร](#7-เมื่อไหร่ควรใช้อะไร)
8. [การใช้งานร่วมกัน](#8-การใช้งานร่วมกัน)
9. [สรุป](#9-สรุป)

---

## 1. ภาพรวมและวัตถุประสงค์

### 1.1 Jest คืออะไร?

**Jest** เป็น JavaScript Testing Framework ที่พัฒนาโดย Facebook (Meta)

**วัตถุประสงค์หลัก:**

- ทดสอบ **Logic และ Function** ของโค้ด (Unit Testing)
- ทดสอบการทำงานร่วมกันของส่วนต่างๆ (Integration Testing)
- ทดสอบโดยไม่ต้องเปิด Browser
- เน้นความเร็วและความง่ายในการใช้งาน

**ตำแหน่งใน Testing Pyramid:**

```
        /\
       /  \      E2E Tests (Playwright) ← 5-10%
      /----\
     /      \    Integration Tests ← 15-20%
    /--------\
   /          \  Unit Tests (Jest) ← 70-75%
  /____________\
```

### 1.2 Playwright คืออะไร?

**Playwright** เป็น End-to-End (E2E) Testing Framework ที่พัฒนาโดย Microsoft

**วัตถุประสงค์หลัก:**

- ทดสอบ **User Journey** ทั้งหมด (E2E Testing)
- ทดสอบการทำงานของ Web Application จริง
- ทดสอบบน Browser จริง (Chromium, Firefox, WebKit)
- เน้นการทดสอบจากมุมมองของผู้ใช้งาน

**ตำแหน่งใน Testing Pyramid:**

```
        /\
       /  \      E2E Tests (Playwright) ← อยู่ตรงนี้!
      /----\     ทดสอบทั้งระบบ
     /      \
    /--------\
   /          \
  /____________\
```

---

## 2. ความแตกต่างหลัก

### 2.1 ตารางเปรียบเทียบแบบย่อ

| หัวข้อ        | Jest                        | Playwright               |
| ------------- | --------------------------- | ------------------------ |
| **ประเภท**    | Unit/Integration Testing    | E2E Testing              |
| **ทดสอบอะไร** | Function, Logic, Components | User Flows, UI, ทั้งระบบ |
| **Browser**   | ไม่ต้องใช้ (jsdom)          | ใช้ Browser จริง         |
| **ความเร็ว**  | เร็วมาก (ms)                | ช้ากว่า (seconds)        |
| **ต้นทุน**    | ต่ำ                         | สูงกว่า                  |
| **ใช้เมื่อ**  | Development ทุกวัน          | CI/CD, Release           |
| **สร้างโดย**  | Facebook (Meta)             | Microsoft                |

### 2.2 ความแตกต่างแบบละเอียด

#### 🎯 วัตถุประสงค์การใช้งาน

**Jest:**

```javascript
// ทดสอบ FUNCTION ทำงานถูกต้องไหม
function calculateTotal(price, quantity) {
  return price * quantity;
}

test("คำนวณยอดรวมถูกต้อง", () => {
  expect(calculateTotal(100, 2)).toBe(200);
});
```

**Playwright:**

```javascript
// ทดสอบ USER สามารถเพิ่มสินค้าในตะกร้าได้ไหม
test("เพิ่มสินค้าลงตะกร้า", async ({ page }) => {
  await page.goto("https://example.com");
  await page.click("#add-to-cart");
  await expect(page.locator(".cart-count")).toHaveText("1");
});
```

#### 🌐 สภาพแวดล้อมการทดสอบ

**Jest:**

- รันใน **Node.js Environment**
- ใช้ **jsdom** จำลอง DOM (ไม่ใช่ Browser จริง)
- ไม่มี Window, Document จริง
- เร็วมาก แต่ไม่สมจริง 100%

**Playwright:**

- รันบน **Browser จริง** (Chromium, Firefox, WebKit)
- มี Window, Document, CSS, JavaScript ครบถ้วน
- ทดสอบได้เหมือนผู้ใช้งานจริง
- ช้ากว่า แต่สมจริง 100%

---

## 3. เปรียบเทียบรายละเอียด

### 3.1 การติดตั้ง

#### Jest

```bash
# ขนาดเล็กกว่า, ติดตั้งเร็ว
npm install --save-dev jest

# ถ้าใช้กับ React
npm install --save-dev @testing-library/react @testing-library/jest-dom
```

#### Playwright

```bash
# ขนาดใหญ่กว่า (ต้องดาวน์โหลด Browser)
npm init playwright@latest

# Browser จะถูกดาวน์โหลด ~300MB
```

### 3.2 การตั้งค่าเบื้องต้น

#### Jest - jest.config.js

```javascript
module.exports = {
  testEnvironment: "jsdom", // จำลอง Browser
  coverageDirectory: "coverage", // Code coverage
  testMatch: ["**/*.test.js"], // Pattern ของ test files
  collectCoverageFrom: ["src/**/*.js"],
};
```

#### Playwright - playwright.config.js

```javascript
module.exports = {
  testDir: "./tests",
  use: {
    baseURL: "http://localhost:3000",
    screenshot: "only-on-failure",
    video: "retain-on-failure",
  },
  projects: [
    { name: "chromium", use: { ...devices["Desktop Chrome"] } },
    { name: "firefox", use: { ...devices["Desktop Firefox"] } },
    { name: "webkit", use: { ...devices["Desktop Safari"] } },
  ],
};
```

### 3.3 โครงสร้างพื้นฐาน

#### Jest

```javascript
// calculator.test.js
describe("Calculator", () => {
  test("บวกเลข", () => {
    expect(add(1, 2)).toBe(3);
  });

  test("ลบเลข", () => {
    expect(subtract(5, 3)).toBe(2);
  });
});
```

#### Playwright

```javascript
// login.spec.js
import { test, expect } from "@playwright/test";

test.describe("Login Flow", () => {
  test("เข้าสู่ระบบสำเร็จ", async ({ page }) => {
    await page.goto("/login");
    await page.fill("#username", "admin");
    await page.fill("#password", "password");
    await page.click("#login-button");
    await expect(page).toHaveURL("/dashboard");
  });
});
```

### 3.4 Assertions (การตรวจสอบ)

#### Jest - ตรวจสอบค่า

```javascript
expect(value).toBe(expected); // เท่ากับ
expect(value).toEqual(expected); // Object เท่ากัน
expect(array).toContain(item); // มีสมาชิก
expect(fn).toThrow(); // โยน Error
expect(value).toBeTruthy(); // เป็นจริง
expect(value).toBeGreaterThan(3); // มากกว่า
```

#### Playwright - ตรวจสอบ UI

```javascript
await expect(page).toHaveTitle("Home"); // Title ของหน้า
await expect(locator).toBeVisible(); // มองเห็น Element
await expect(locator).toHaveText("OK"); // ข้อความ
await expect(locator).toHaveValue("5"); // ค่าใน Input
await expect(locator).toBeDisabled(); // ปิดการใช้งาน
await expect(locator).toHaveCSS("color", "rgb(255, 0, 0)"); // CSS
```

### 3.5 Mocking (การจำลอง)

#### Jest - Mock Functions/Modules

```javascript
// Mock function
const mockFn = jest.fn();
mockFn.mockReturnValue(42);

// Mock module
jest.mock("./api", () => ({
  fetchData: jest.fn().mockResolvedValue({ id: 1, name: "Test" }),
}));

// Spy on function
const spy = jest.spyOn(obj, "method");
expect(spy).toHaveBeenCalledWith("argument");
```

#### Playwright - Mock API/Network

```javascript
// Mock API Response
await page.route("**/api/users", (route) => {
  route.fulfill({
    status: 200,
    contentType: "application/json",
    body: JSON.stringify([{ id: 1, name: "Mock User" }]),
  });
});

// Intercept Network
await page.route("**/api/**", (route) => route.abort());
```

### 3.6 Asynchronous Testing

#### Jest

```javascript
// Using async/await
test("ดึงข้อมูล API", async () => {
  const data = await fetchData();
  expect(data.name).toBe("John");
});

// Using promises
test("ดึงข้อมูล API", () => {
  return fetchData().then((data) => {
    expect(data.name).toBe("John");
  });
});
```

#### Playwright

```javascript
// ทุกอย่างเป็น async/await
test("รอให้ Element ปรากฏ", async ({ page }) => {
  await page.goto("/");

  // Auto-wait: รอจนกว่า Element จะปรากฏ
  await page.click("button");

  // รอ Navigation
  await page.waitForNavigation();

  // รอ Element
  await page.waitForSelector(".loading", { state: "hidden" });
});
```

---

## 4. การติดตั้งและตั้งค่า

### 4.1 Jest - Quick Start

```bash
# 1. ติดตั้ง
npm install --save-dev jest

# 2. เพิ่มใน package.json
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  }
}

# 3. สร้างไฟล์ทดสอบ
# sum.js
function sum(a, b) {
  return a + b;
}
module.exports = sum;

# sum.test.js
const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

# 4. รัน tests
npm test
```

### 4.2 Playwright - Quick Start

```bash
# 1. ติดตั้ง
npm init playwright@latest

# 2. ระบบจะถาม:
# - TypeScript or JavaScript? → JavaScript
# - Test folder? → tests
# - GitHub Actions? → false
# - Install browsers? → true

# 3. สร้างไฟล์ทดสอบ
# tests/example.spec.js
import { test, expect } from '@playwright/test';

test('homepage has title', async ({ page }) => {
  await page.goto('https://playwright.dev/');
  await expect(page).toHaveTitle(/Playwright/);
});

# 4. รัน tests
npx playwright test

# 5. ดู Report
npx playwright show-report
```

---

## 5. ตัวอย่างการใช้งาน

### 5.1 ตัวอย่าง: ทดสอบ Shopping Cart

#### Jest - ทดสอบ Logic

```javascript
// cart.js - Business Logic
class ShoppingCart {
  constructor() {
    this.items = [];
  }

  addItem(item) {
    this.items.push(item);
  }

  getTotal() {
    return this.items.reduce((sum, item) => sum + item.price, 0);
  }

  getItemCount() {
    return this.items.length;
  }

  removeItem(itemId) {
    this.items = this.items.filter((item) => item.id !== itemId);
  }
}

module.exports = ShoppingCart;
```

```javascript
// cart.test.js - Unit Tests
const ShoppingCart = require("./cart");

describe("ShoppingCart", () => {
  let cart;

  beforeEach(() => {
    cart = new ShoppingCart();
  });

  test("เริ่มต้นตะกร้าว่าง", () => {
    expect(cart.getItemCount()).toBe(0);
    expect(cart.getTotal()).toBe(0);
  });

  test("เพิ่มสินค้าได้", () => {
    cart.addItem({ id: 1, name: "Book", price: 100 });
    expect(cart.getItemCount()).toBe(1);
  });

  test("คำนวณยอดรวมถูกต้อง", () => {
    cart.addItem({ id: 1, name: "Book", price: 100 });
    cart.addItem({ id: 2, name: "Pen", price: 20 });
    expect(cart.getTotal()).toBe(120);
  });

  test("ลบสินค้าได้", () => {
    cart.addItem({ id: 1, name: "Book", price: 100 });
    cart.addItem({ id: 2, name: "Pen", price: 20 });
    cart.removeItem(1);
    expect(cart.getItemCount()).toBe(1);
    expect(cart.getTotal()).toBe(20);
  });
});
```

**ผลลัพธ์:**

```
PASS  cart.test.js
  ShoppingCart
    ✓ เริ่มต้นตะกร้าว่าง (2 ms)
    ✓ เพิ่มสินค้าได้ (1 ms)
    ✓ คำนวณยอดรวมถูกต้อง (1 ms)
    ✓ ลบสินค้าได้ (1 ms)

Tests:       4 passed, 4 total
Time:        0.5s
```

#### Playwright - ทดสอบ User Flow

```javascript
// tests/shopping-cart.spec.js - E2E Tests
import { test, expect } from "@playwright/test";

test.describe("Shopping Cart E2E", () => {
  test("ผู้ใช้สามารถเพิ่มสินค้าลงตะกร้าได้", async ({ page }) => {
    // 1. เปิดหน้าสินค้า
    await page.goto("https://shop.example.com/products");

    // 2. ตรวจสอบว่าตะกร้าว่าง
    await expect(page.locator(".cart-count")).toHaveText("0");

    // 3. คลิกเพิ่มสินค้า
    await page.click('button:has-text("Add to Cart"):first');

    // 4. รอให้ระบบอัพเดท
    await page.waitForTimeout(500);

    // 5. ตรวจสอบจำนวนในตะกร้า
    await expect(page.locator(".cart-count")).toHaveText("1");
  });

  test("ผู้ใช้สามารถดูสินค้าในตะกร้าได้", async ({ page }) => {
    // Setup: เพิ่มสินค้า
    await page.goto("https://shop.example.com/products");
    await page.click('button:has-text("Add to Cart"):first');

    // 1. เปิดตะกร้า
    await page.click(".cart-icon");

    // 2. ตรวจสอบว่ามีสินค้า
    await expect(page.locator(".cart-item")).toHaveCount(1);

    // 3. ตรวจสอบยอดรวม
    await expect(page.locator(".total-price")).toContainText("฿");
  });

  test("ผู้ใช้สามารถลบสินค้าออกจากตะกร้าได้", async ({ page }) => {
    // Setup
    await page.goto("https://shop.example.com/products");
    await page.click('button:has-text("Add to Cart"):first');
    await page.click(".cart-icon");

    // 1. คลิกลบสินค้า
    await page.click(".remove-item-btn");

    // 2. ยืนยันการลบ
    await page.click('button:has-text("Confirm")');

    // 3. ตรวจสอบว่าตะกร้าว่าง
    await expect(page.locator(".cart-empty-message")).toBeVisible();
    await expect(page.locator(".cart-count")).toHaveText("0");
  });

  test("Complete checkout flow", async ({ page }) => {
    // 1. เพิ่มสินค้า
    await page.goto("https://shop.example.com/products");
    await page.click('button:has-text("Add to Cart"):first');

    // 2. ไปหน้า Checkout
    await page.click(".cart-icon");
    await page.click('button:has-text("Checkout")');

    // 3. กรอกข้อมูล
    await page.fill("#name", "John Doe");
    await page.fill("#email", "john@example.com");
    await page.fill("#address", "123 Main St");

    // 4. ยืนยันคำสั่งซื้อ
    await page.click('button:has-text("Place Order")');

    // 5. ตรวจสอบหน้า Success
    await expect(page).toHaveURL(/.*\/order-success/);
    await expect(page.locator(".success-message")).toBeVisible();
  });
});
```

**ผลลัพธ์:**

```
Running 4 tests using 4 workers

  ✓ Shopping Cart E2E > ผู้ใช้สามารถเพิ่มสินค้าลงตะกร้าได้ (chromium) (2.5s)
  ✓ Shopping Cart E2E > ผู้ใช้สามารถดูสินค้าในตะกร้าได้ (chromium) (3.1s)
  ✓ Shopping Cart E2E > ผู้ใช้สามารถลบสินค้าออกจากตะกร้าได้ (chromium) (3.8s)
  ✓ Shopping Cart E2E > Complete checkout flow (chromium) (5.2s)

  4 passed (14.6s)
```

### 5.2 สังเกตความแตกต่าง

| ประเด็น          | Jest                    | Playwright              |
| ---------------- | ----------------------- | ----------------------- |
| **สิ่งที่ทดสอบ** | Logic ของ class         | การใช้งานจริงบน website |
| **ความเร็ว**     | 0.5 วินาที (4 tests)    | 14.6 วินาที (4 tests)   |
| **Environment**  | Node.js (ไม่มี Browser) | Browser จริง            |
| **Assertions**   | ค่าตัวแปร, การคำนวณ     | UI Elements, Navigation |
| **เมื่อไร**      | ทุกครั้งที่เขียนโค้ด    | ก่อน Deploy             |

---

## 6. ข้อดีข้อเสีย

### 6.1 Jest

#### ✅ ข้อดี

1. **เร็วมาก**
   - รันหลักร้อย tests ภายในไม่กี่วินาที
   - ไม่ต้องรอ Browser load

2. **ใช้งานง่าย**
   - Zero configuration
   - มี Matchers มากมาย
   - Watch mode สะดวก

3. **ต้นทุนต่ำ**
   - ไม่ใช้ทรัพยากรมาก
   - รันได้บน CI/CD เร็ว

4. **Debug ง่าย**
   - Error message ชัดเจน
   - ระบุบรรทัดที่ผิดแม่นยำ

5. **เหมาะกับ TDD**
   - เขียน Test ก่อน Code ได้
   - รัน Tests ซ้ำๆ เร็ว

#### ❌ ข้อเสีย

1. **ไม่ทดสอบ Browser จริง**
   - jsdom ไม่สมบูรณ์
   - CSS, Layout อาจไม่ทำงาน

2. **ไม่เห็น UI**
   - ไม่รู้ว่าหน้าตาเป็นยังไง
   - ไม่สามารถทดสอบ Visual

3. **จำกัดในการทดสอบ Integration**
   - ต้อง Mock หลายอย่าง
   - ไม่ได้ทดสอบทั้งระบบ

### 6.2 Playwright

#### ✅ ข้อดี

1. **ทดสอบสมจริง**
   - ใช้ Browser จริง
   - เห็น UI จริง
   - ทดสอบได้เหมือนผู้ใช้

2. **Cross-Browser**
   - ทดสอบได้หลาย Browser
   - Chromium, Firefox, WebKit

3. **ทดสอบทั้งระบบ**
   - Frontend + Backend + Database
   - User Journey สมบูรณ์

4. **Auto-wait**
   - รอ Element อัตโนมัติ
   - ลด flaky tests

5. **Screenshot & Video**
   - บันทึกหลักฐาน
   - Debug ง่าย

#### ❌ ข้อเสีย

1. **ช้า**
   - รัน test ใช้เวลานาน
   - ไม่เหมาะรันบ่อยๆ

2. **ซับซ้อนกว่า**
   - ต้องเข้าใจ Async/Await
   - Selector หายาก

3. **ต้นทุนสูง**
   - ใช้ CPU/RAM มาก
   - CI/CD ช้า แพงกว่า

4. **Flaky Tests**
   - Network ล่ม
   - Timing issues

5. **Maintenance**
   - UI เปลี่ยน tests พัง
   - ต้องอัพเดทบ่อย

---

## 7. เมื่อไหร่ควรใช้อะไร

### 7.1 ใช้ Jest เมื่อ:

#### ✅ ใช้ Jest สำหรับ:

1. **Unit Testing**

   ```javascript
   // ทดสอบ pure functions
   test("formatDate formats correctly", () => {
     expect(formatDate("2024-01-01")).toBe("1 มกราคม 2567");
   });
   ```

2. **Business Logic**

   ```javascript
   // คำนวณส่วนลด, ภาษี, shipping
   test("คำนวณส่วนลด 10%", () => {
     expect(calculateDiscount(1000, 0.1)).toBe(100);
   });
   ```

3. **Data Transformation**

   ```javascript
   // แปลงข้อมูล, format
   test("แปลง array เป็น object", () => {
     const result = arrayToObject([{ id: 1, name: "A" }]);
     expect(result).toEqual({ 1: { id: 1, name: "A" } });
   });
   ```

4. **React Components (Unit)**

   ```javascript
   // ทดสอบ component แยกส่วน
   test("Button renders correctly", () => {
     render(<Button label="Click me" />);
     expect(screen.getByText("Click me")).toBeInTheDocument();
   });
   ```

5. **API Utils**
   ```javascript
   // ทดสอบ API helper functions
   test("buildQueryString", () => {
     expect(buildQueryString({ page: 1, limit: 10 })).toBe("?page=1&limit=10");
   });
   ```

### 7.2 ใช้ Playwright เมื่อ:

#### ✅ ใช้ Playwright สำหรับ:

1. **User Flows**

   ```javascript
   // ทดสอบการใช้งานจริง
   test("ผู้ใช้สามารถสมัครสมาชิกได้", async ({ page }) => {
     await page.goto("/register");
     await page.fill("#email", "user@example.com");
     await page.click("#submit");
     await expect(page).toHaveURL("/welcome");
   });
   ```

2. **Integration Testing**

   ```javascript
   // ทดสอบหลายส่วนทำงานร่วมกัน
   test("เพิ่มสินค้า → ชำระเงิน → ดูประวัติ", async ({ page }) => {
     // ทดสอบทั้ง flow
   });
   ```

3. **Cross-Browser**

   ```javascript
   // ทดสอบความเข้ากันได้
   test("ทำงานบน Safari", async ({ page }) => {
     // จะรันบน webkit
   });
   ```

4. **Visual Testing**

   ```javascript
   // ทดสอบหน้าตา
   test("หน้า Homepage ถูกต้อง", async ({ page }) => {
     await page.goto("/");
     await expect(page).toHaveScreenshot("homepage.png");
   });
   ```

5. **Authentication Flows**
   ```javascript
   // Login, Logout, Session
   test("เข้าสู่ระบบ", async ({ page }) => {
     await login(page, "admin", "password");
     await expect(page.locator(".user-name")).toBeVisible();
   });
   ```

### 7.3 Decision Tree

```
┌─────────────────────────────────────────────┐
│ ต้องการทดสอบอะไร?                            │
└─────────────────┬───────────────────────────┘
                  │
        ┌─────────┴──────────┐
        │                    │
    Function/           User Flow/
     Logic?              UI/E2E?
        │                    │
        ▼                    ▼
    ┌───────┐          ┌──────────┐
    │ JEST  │          │Playwright│
    └───────┘          └──────────┘
        │                    │
        ▼                    ▼
   - เร็ว (ms)          - ช้า (seconds)
   - รันบ่อย          - รันก่อน deploy
   - ในขณะ dev        - ทดสอบ browser จริง
   - ไม่ต้อง browser  - เห็น UI จริง
```

### 7.4 ตัวอย่างการตัดสินใจ

#### Scenario 1: ทดสอบ Validation Function

```javascript
// ใช้ JEST ✅
function validateEmail(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

test("email ถูกต้อง", () => {
  expect(validateEmail("test@example.com")).toBe(true);
  expect(validateEmail("invalid")).toBe(false);
});
```

**เหตุผล:** เป็น pure function, เร็ว, ไม่ต้องการ UI

#### Scenario 2: ทดสอบ Form Submission

```javascript
// ใช้ PLAYWRIGHT ✅
test("ส่ง Contact Form สำเร็จ", async ({ page }) => {
  await page.goto("/contact");
  await page.fill("#name", "John");
  await page.fill("#email", "john@example.com");
  await page.fill("#message", "Hello");
  await page.click("#submit");
  await expect(page.locator(".success")).toBeVisible();
});
```

**เหตุผล:** ต้องทดสอบทั้ง form, validation, API, response

---

## 8. การใช้งานร่วมกัน

### 8.1 Strategy: 70-20-10 Rule

```
┌────────────────────────────────────────────┐
│          Testing Strategy                   │
├────────────────────────────────────────────┤
│  70% - Jest (Unit Tests)                   │
│    - Fast feedback                         │
│    - ทดสอบ logic ทุก function              │
│    - รันทุกครั้งที่ commit                  │
│                                            │
│  20% - Jest (Integration Tests)            │
│    - ทดสอบส่วนทำงานร่วมกัน                 │
│    - Mock API ระดับ integration            │
│                                            │
│  10% - Playwright (E2E Tests)              │
│    - ทดสอบ critical user flows             │
│    - รันก่อน deploy                        │
│    - รันบน CI/CD                           │
└────────────────────────────────────────────┘
```

### 8.2 ตัวอย่าง Project Structure

```
my-project/
├── src/
│   ├── utils/
│   │   ├── calculator.js
│   │   └── validator.js
│   ├── components/
│   │   ├── Button.js
│   │   └── Form.js
│   └── services/
│       └── api.js
│
├── tests/
│   ├── unit/              ← Jest Unit Tests (70%)
│   │   ├── calculator.test.js
│   │   ├── validator.test.js
│   │   └── Button.test.js
│   │
│   ├── integration/       ← Jest Integration (20%)
│   │   ├── api.test.js
│   │   └── Form.test.js
│   │
│   └── e2e/              ← Playwright E2E (10%)
│       ├── login.spec.js
│       ├── checkout.spec.js
│       └── registration.spec.js
│
├── jest.config.js
├── playwright.config.js
└── package.json
```

### 8.3 package.json Scripts

```json
{
  "scripts": {
    "test": "npm run test:unit && npm run test:integration",
    "test:unit": "jest tests/unit",
    "test:integration": "jest tests/integration",
    "test:e2e": "playwright test",
    "test:all": "npm test && npm run test:e2e",

    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",

    "test:e2e:ui": "playwright test --ui",
    "test:e2e:debug": "playwright test --debug",
    "test:e2e:report": "playwright show-report"
  }
}
```

### 8.4 CI/CD Workflow

```yaml
# .github/workflows/test.yml
name: Tests

on: [push, pull_request]

jobs:
  unit-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm install
      - run: npm run test:unit # เร็ว, รันทุก commit

  integration-tests:
    runs-on: ubuntu-latest
    needs: unit-tests
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm install
      - run: npm run test:integration

  e2e-tests:
    runs-on: ubuntu-latest
    needs: integration-tests
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm install
      - run: npx playwright install --with-deps
      - run: npm run test:e2e # ช้า, รันก่อน merge
      - uses: actions/upload-artifact@v3
        if: failure()
        with:
          name: playwright-report
          path: playwright-report/
```

### 8.5 Development Workflow

```
1. เขียน Code ใหม่
   │
   ▼
2. เขียน Jest Unit Tests (ทันที)
   - npm run test:watch
   - ทดสอบ logic
   │
   ▼
3. Integration Tests (ถ้าจำเป็น)
   - npm run test:integration
   │
   ▼
4. Git Commit
   - Pre-commit hook: รัน jest tests
   │
   ▼
5. Push to GitHub
   - CI รัน all jest tests
   │
   ▼
6. ก่อน Merge PR
   - CI รัน playwright e2e tests
   │
   ▼
7. ก่อน Deploy Production
   - รัน full test suite
   - npm run test:all
```

---

## 9. สรุป

### 9.1 สรุปความแตกต่างหลัก

| หัวข้อ            | Jest               | Playwright       |
| ----------------- | ------------------ | ---------------- |
| **ระดับการทดสอบ** | Unit + Integration | E2E              |
| **ทดสอบอะไร**     | Logic, Functions   | User Flows, UI   |
| **สภาพแวดล้อม**   | Node.js (jsdom)    | Browser จริง     |
| **ความเร็ว**      | ⚡ เร็วมาก (ms)    | 🐢 ช้ากว่า (sec) |
| **ใช้เมื่อไร**    | ทุกวัน, ขณะพัฒนา   | ก่อน Deploy      |
| **ต้นทุน**        | 💰 ต่ำ             | 💰💰💰 สูง       |
| **ความซับซ้อน**   | 😊 ง่าย            | 😰 ซับซ้อนกว่า   |
| **Debug**         | ✅ ง่าย            | ⚠️ ยากกว่า       |
| **CI/CD**         | เร็ว, ถูก          | ช้า, แพง         |

### 9.2 Golden Rules

#### ✅ DOs

1. **ใช้ Jest สำหรับ:**
   - Unit tests (70% ของ tests ทั้งหมด)
   - Development feedback loop
   - TDD approach

2. **ใช้ Playwright สำหรับ:**
   - Critical user journeys
   - Pre-deployment verification
   - Cross-browser testing

3. **ใช้ทั้งคู่:**
   - Jest: Fast feedback
   - Playwright: Confidence

#### ❌ DON'Ts

1. **อย่าใช้ Playwright สำหรับ:**
   - Unit testing (ช้าเกินไป)
   - ทดสอบ pure functions
   - Development loop

2. **อย่าใช้ Jest สำหรับ:**
   - E2E flows (ไม่สมจริง)
   - Visual testing
   - Cross-browser

3. **อย่าพึ่งแค่อย่างเดียว:**
   - Jest alone = ไม่รู้ว่าระบบทำงานจริง
   - Playwright alone = ช้า, แพง, ไม่ครอบคลุม

### 9.3 Testing Pyramid - Remember!

```
        ▲
       ╱ ╲
      ╱E2E╲      ← 10% Playwright
     ╱─────╲      (Slow, Expensive)
    ╱       ╲
   ╱  Integ  ╲   ← 20% Jest
  ╱───────────╲   (Medium Speed)
 ╱             ╲
╱  Unit Tests  ╲ ← 70% Jest
═════════════════  (Fast, Cheap)
```

### 9.4 เมื่อไหร่ควรรัน Tests

```javascript
// ระหว่างพัฒนา (ทุกวัน)
npm run test:watch           // Jest - Auto-rerun on save

// ก่อน Commit
npm test                     // Jest - All unit tests

// ก่อน Push
npm run test:integration     // Jest - Integration tests

// ก่อน Merge PR
npm run test:e2e             // Playwright - Critical flows

// ก่อน Deploy Production
npm run test:all             // ทุกอย่าง!
```

### 9.5 คำแนะนำสุดท้าย

1. **เริ่มจาก Jest**
   - ง่าย, เร็ว, ได้ feedback ทันที
   - สร้างนิสัยเขียน test

2. **ค่อยเพิ่ม Playwright**
   - เมื่อ project ใหญ่ขึ้น
   - เมื่อมี critical flows

3. **Maintain Balance**
   - 70-20-10 rule
   - อย่าทดสอบน้อยหรือมากเกินไป

4. **ปรับตาม Context**
   - Project เล็ก: Jest เพียงพอ
   - Project ใหญ่: ใช้ทั้งคู่
   - E-commerce, Banking: Playwright สำคัญมาก

---

## ภาคผนวก

### A. Quick Reference

#### Jest Cheat Sheet

```javascript
// Basic
test("description", () => {
  expect(value).toBe(expected);
});

// Common Matchers
expect(value).toBe(5);
expect(value).toEqual({ a: 1 });
expect(array).toContain(item);
expect(fn).toThrow();

// Async
test("async", async () => {
  const data = await fetchData();
  expect(data).toBeDefined();
});

// Mock
const mock = jest.fn();
mock.mockReturnValue(42);
expect(mock).toHaveBeenCalled();
```

#### Playwright Cheat Sheet

```javascript
// Basic
test("description", async ({ page }) => {
  await page.goto("/");
  await expect(page).toHaveTitle("Title");
});

// Actions
await page.click("button");
await page.fill("#input", "text");
await page.selectOption("#select", "value");

// Assertions
await expect(page.locator(".class")).toBeVisible();
await expect(page.locator("#id")).toHaveText("text");

// Wait
await page.waitForSelector(".loading", { state: "hidden" });
await page.waitForNavigation();
```

### B. ลิงก์ทรัพยากร

#### Jest

- [Jest Official Docs](https://jestjs.io/)
- [Testing Library](https://testing-library.com/)

#### Playwright

- [Playwright Official Docs](https://playwright.dev/)
- [Playwright Best Practices](https://playwright.dev/docs/best-practices)

---

**สร้างโดย:** คู่มือการสอน Software Testing and Evaluation  
**อัพเดทล่าสุด:** February 2026  
**เวอร์ชัน:** 1.0
