import { test, expect } from '@playwright/test'; const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000'; async function waitAppSettled(page: any) { await page.waitForLoadState('domcontentloaded'); await page.waitForLoadState('networkidle').catch(() => {}); await page.waitForTimeout(200); } // ฟังก์ชันจำลองล็อกอิน (เพราะทำข้อสอบต้องล็อกอินเสมอ) async function setupLogin(page: any) { await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' }); await waitAppSettled(page); await page.locator('input[type="email"]').or(page.getByRole('textbox', { name: /อีเมล|email/i })).first().fill('studentedtest@example.com'); await page.locator('input[type="password"]').or(page.getByRole('textbox', { name: /รหัสผ่าน|password/i })).first().fill('admin123'); await page.getByRole('button', { name: /เข้าสู่ระบบ|login/i }).or(page.locator('button[type="submit"]')).first().click(); await page.waitForURL('**/dashboard', { timeout: 15_000 }).catch(() => {}); await waitAppSettled(page); } // ฟังก์ชัน Mock ข้อมูลข้อสอบให้ Playwright ไม่ต้องไปดึงจากฐานข้อมูลจริงๆ (เพื่อป้องกันปัญหาคอร์ส/บทเรียนไม่มีอยู่จริง) async function mockQuizData(page: any) { await page.route('**/lessons/*', async (route: any) => { // สมมติข้อมูลข้อสอบจำลองให้มี 15 ข้อเพื่อเทส Pagination ได้ const mockQuestions = Array.from({ length: 15 }, (_, i) => ({ id: i + 1, question: { th: `คำถามข้อที่ ${i + 1}?`, en: `Question ${i + 1}?` }, text: { th: `คำถามข้อที่ ${i + 1}?`, en: `Question ${i + 1}?` }, choices: [ { id: i * 10 + 1, text: { th: 'ก', en: 'A' } }, { id: i * 10 + 2, text: { th: 'ข', en: 'B' } }, { id: i * 10 + 3, text: { th: 'ค', en: 'C' } } ] })); await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ success: true, data: { id: 17, type: 'QUIZ', quiz: { id: 99, title: { th: 'แบบทดสอบปลายภาค (Mock)', en: 'Final Exam (Mock)' }, time_limit: 30, questions: mockQuestions } }, progress: {} }) }); }); } test.describe('ระบบทำแบบทดสอบ (Quiz System)', () => { test.beforeEach(async ({ page }) => { // ต้อง Login ก่อนเรียน! await setupLogin(page); }); test('โหลดหน้า Quiz และคลิกระบบเริ่มทำข้อสอบได้ (Start Screen)', async ({ page }) => { await mockQuizData(page); // สมมติเอาที่ quiz ใน course 2 lesson 17 (ซึ่ง API เสาะหาจะถูกดักจับและ Mock ไว้ด้านบนแล้ว) await page.goto(`${BASE_URL}/classroom/quiz?course_id=2&lesson_id=17`); // หน้าจอ Start Screen ต้องขึ้นมา const startBtn = page.getByRole('button', { name: /เริ่มทำแบบทดสอบ|Start/i }).first(); await expect(startBtn).toBeVisible({ timeout: 15_000 }); // ลองกดเริ่มทำ await startBtn.click(); // เช็คว่าหน้า Taking (พื้นที่ทำข้อสอบข้อที่ 1) โผล่มา const questionText = page.locator('h3').first(); // ชื่อคำถาม await expect(questionText).toBeVisible({ timeout: 10_000 }); }); test('ทดสอบระบบแถบข้อสอบ แบ่งหน้า (Pagination - เลื่อนซ้าย/ขวา)', async ({ page }) => { await mockQuizData(page); await page.goto(`${BASE_URL}/classroom/quiz?course_id=2&lesson_id=17`); // เข้าเมนูแบบทดสอบ const startBtn = page.getByRole('button', { name: /เริ่มทำแบบทดสอบ|Start/i }).first(); await expect(startBtn).toBeVisible({ timeout: 15_000 }); await startBtn.click(); // เช็คว่ามีลูกศรเลื่อนหน้าข้อสอบ (Paginations) สำหรับแบบทดสอบเกิน 10 ข้อที่สร้างมาใหม่ const nextPaginationPageBtn = page.locator('button').filter({ has: page.locator('i.q-icon:has-text("chevron_right")') }).first(); if (await nextPaginationPageBtn.isVisible()) { // หากปุ่มแสดง (บอกว่ามีข้อสอบหลายหน้า) ลองกดข้าม await expect(nextPaginationPageBtn).toBeEnabled(); await nextPaginationPageBtn.click(); // เช็คว่ากดแล้ว ข้อที่ 11 โผล่มา const question11Btn = page.locator('button').filter({ hasText: /^11$/ }).first(); await expect(question11Btn).toBeVisible(); } }); test('การแสดงผลปุ่มถัดไป/ส่งคำตอบ (Submit & Navigation UI)', async ({ page }) => { await mockQuizData(page); await page.goto(`${BASE_URL}/classroom/quiz?course_id=2&lesson_id=17`); const startBtn = page.getByRole('button', { name: /เริ่มทำแบบทดสอบ|Start/i }).first(); await expect(startBtn).toBeVisible({ timeout: 15_000 }); await startBtn.click(); // รอให้หน้าโหลดคำถามเสร็จก่อน ค่อยหาปุ่ม await expect(page.locator('h3').first()).toBeVisible({ timeout: 10_000 }); const submitBtn = page.locator('button').filter({ hasText: /(ส่งคำตอบ|Submit)/i }).first(); const nextBtn = page.locator('button').filter({ hasText: /(ถัดไป|Next)/i }).first(); // แบบทดสอบข้อแรก ต้องมีปุ่ม ถัดไป(Next) หรือปุ่มส่ง ถ้ามีแค่ 1 ข้อ await expect(submitBtn.or(nextBtn)).toBeVisible({ timeout: 10_000 }); }); });