Some checks failed
Build and Deploy Frontend Learner / Build Frontend Learner Docker Image (push) Failing after 25s
Build and Deploy Frontend Learner / Deploy E-learning Frontend Learner to Dev Server (push) Has been skipped
Build and Deploy Frontend Learner / Notify Deployment Status (push) Failing after 1s
125 lines
6.4 KiB
TypeScript
125 lines
6.4 KiB
TypeScript
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 });
|
|
});
|
|
|
|
});
|