95 lines
5.3 KiB
TypeScript
95 lines
5.3 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);
|
|
}
|
|
|
|
test.describe('ระบบห้องเรียนออนไลน์ (Classroom & Learning)', () => {
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
await setupLogin(page);
|
|
});
|
|
|
|
test('6.1 เข้าห้องเรียนหลัก (Classroom Basic Layout)', async ({ page }) => {
|
|
// สมมติว่ามี Course ID: 1 ทดสอบแบบเปิดหน้าตรงๆ
|
|
await page.goto(`${BASE_URL}/classroom/learning?course_id=1`);
|
|
|
|
// 1. โครงร่างของหน้า (Top Bar) ควรมีปุ่มกลับ กับไอคอนแผงด้านข้าง
|
|
const backBtn = page.getByRole('button').filter({ has: page.locator('i.q-icon', { hasText: 'arrow_back' }) }).first();
|
|
await expect(backBtn).toBeVisible({ timeout: 15_000 });
|
|
|
|
const menuCurriculumBtn = page.getByRole('button').filter({ has: page.locator('i.q-icon', { hasText: 'menu_open' }) }).first();
|
|
await expect(menuCurriculumBtn).toBeVisible({ timeout: 15_000 });
|
|
|
|
// 2. เช็คว่ามีพื้นที่ Sidebar หลักสูตร (CurriculumSidebar Component) โผล่ขึ้นมาหรือมีอยู่ใน DOM
|
|
const sidebar = page.locator('.q-drawer').first();
|
|
if (!await sidebar.isVisible()) {
|
|
await menuCurriculumBtn.click();
|
|
}
|
|
await expect(sidebar).toBeVisible();
|
|
});
|
|
|
|
test('6.2 เช็คสถานะการเข้าถึงเนื้อหา (Access Control)', async ({ page }) => {
|
|
// ลองสุ่ม Course ID สูงๆ ที่อาจจะไม่อนุญาตให้เรียน (ไม่มีสิทธิ์) ควรรองรับกล่องแจ้งเตือนด้วย Alert ของระบบ
|
|
// ใน learning.vue จะมีการสั่ง `alert(msg)` แต่อาจจะต้องพึ่งกลไก Intercepter
|
|
|
|
page.on('dialog', async dialog => {
|
|
// หน้าต่าง Alert ถ้ามีสิทธิ์ไม่อนุญาตมันจะเด้งอันนี้
|
|
expect(dialog.message()).toBeTruthy();
|
|
await dialog.accept();
|
|
});
|
|
|
|
await page.goto(`${BASE_URL}/classroom/learning?course_id=99999`);
|
|
|
|
// รอดู Loading หายไป
|
|
const loadingMask = page.locator('.animate-pulse, .q-spinner');
|
|
await loadingMask.first().waitFor({ state: 'hidden', timeout: 20_000 }).catch(() => {});
|
|
});
|
|
|
|
test('6.3 การแสดงผลช่องวิดีโอ (Video Player) หรือ พื้นที่ทำข้อสอบ (Quiz)', async ({ page }) => {
|
|
// เข้าหน้าห้องเรียน Course id: 1
|
|
await page.goto(`${BASE_URL}/classroom/learning?course_id=1`);
|
|
|
|
// กรณีที่ 1: อาจแสดง Video ถ้าเป็นบทเรียนวิดีโอ
|
|
const videoLocator = page.locator('video').first();
|
|
|
|
// กรณีที่ 2: ถ้าบทแรกเป็น Quiz จะแสดงไอคอนแบบทดสอบ
|
|
const quizLocator = page.getByText(/เริ่มทำแบบทดสอบ|แบบทดสอบ/i).first();
|
|
|
|
// กรณีที่ 3: ไม่มีบทเรียนเนื้อหาใดๆ เลยให้แสดง
|
|
const errorLocator = page.getByText(/ไม่สามารถเข้าถึง/i).first();
|
|
|
|
try {
|
|
await Promise.race([
|
|
videoLocator.waitFor({ state: 'visible', timeout: 20_000 }),
|
|
quizLocator.waitFor({ state: 'visible', timeout: 20_000 }),
|
|
errorLocator.waitFor({ state: 'visible', timeout: 20_000 })
|
|
]);
|
|
|
|
const isOkay = (await videoLocator.isVisible()) || (await quizLocator.isVisible()) || (await errorLocator.isVisible());
|
|
expect(isOkay).toBeTruthy();
|
|
} catch {
|
|
// ถ้าไม่มีเลยใน 20 วิ ถือว่าหน้าอาจจะล้มเหลว หรือเป็น Content เปล่า
|
|
// ให้ลอง Capture เพื่อเก็บข้อมูลไปใช้งาน
|
|
await page.screenshot({ path: 'tests/e2e/screenshots/classroom-blank-state.png', fullPage: true });
|
|
}
|
|
});
|
|
|
|
});
|