92 lines
5.1 KiB
TypeScript
92 lines
5.1 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);
|
|
}
|
|
|
|
// ฟังก์ชันจำลองล็อกอิน (เพื่อที่จะเข้า Dashboard ได้)
|
|
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('ระบบหน้าแดชบอร์ดนักเรียน (Dashboard & My Courses)', () => {
|
|
|
|
// บังคับให้ Test ทุกข้อในกลุ่มนี้ ล็อกอินก่อนเสมอ
|
|
test.beforeEach(async ({ page }) => {
|
|
await setupLogin(page);
|
|
});
|
|
|
|
test('5.1 หน้าแรกของ Dashboard โหลดได้ปกติ', async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/dashboard`);
|
|
await page.waitForTimeout(1000);
|
|
|
|
// ตรวจสอบว่ามี UI เบื้องต้น เช่น คำต้อนรับ หรือสรุปสถิติ (ถ้ามี)
|
|
const welcomeText = page.getByText(/ยินดีต้อนรับกลับ/i, { exact: false });
|
|
const profileSummary = page.locator('.q-avatar, img[alt*="Profile"], img[src*="avatar"]').first();
|
|
|
|
await expect(welcomeText.first().or(profileSummary)).toBeVisible({ timeout: 10_000 });
|
|
});
|
|
|
|
test('5.2 โหลดหน้า คอร์สของฉัน (My Courses)', async ({ page }) => {
|
|
// ลองกดเมนูด้านซ้ายเพื่อนำทาง
|
|
const myCoursesMenu = page.getByRole('link', { name: /คอร์สของฉัน|My Courses/i }).first()
|
|
.or(page.locator('a[href="/dashboard/my-courses"]').first());
|
|
|
|
await myCoursesMenu.click();
|
|
await page.waitForURL('**/dashboard/my-courses', { timeout: 10_000 });
|
|
|
|
// ตรวจสอบโครงสร้างว่าโหลดเรียบร้อย
|
|
const heading = page.locator('h2').filter({ hasText: /คอร์สของฉัน|My Courses/i }).first();
|
|
await expect(heading).toBeVisible();
|
|
|
|
// เช็คว่ามีช่องค้นหาคอร์ส
|
|
const searchInput = page.locator('input[placeholder*="ค้นหา"]').first();
|
|
await expect(searchInput).toBeVisible();
|
|
|
|
// เช็คปุ่มเปลี่ยนมุมมอง Grid/List (ดูจากไอคอน)
|
|
await expect(page.locator('i.q-icon').filter({ hasText: 'grid_view' }).first()).toBeVisible();
|
|
await expect(page.locator('i.q-icon').filter({ hasText: 'view_list' }).first()).toBeVisible();
|
|
});
|
|
|
|
test('5.3 กรองคอร์สด้วยเมนูหมวดหมู่ (Category Filter) ใน My Courses', async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/dashboard/my-courses`);
|
|
await page.waitForTimeout(1500); // รอ API หรือ UI Mount นิดนึง
|
|
|
|
// มองหาปุ่มตัวกรองทั้งหมด
|
|
const filterAllBtn = page.getByRole('button').filter({ hasText: /ทั้งหมด|All/i }).first();
|
|
|
|
if (await filterAllBtn.isVisible()) {
|
|
await filterAllBtn.click();
|
|
// เช็คว่าข้อมูลโหลด (หาองค์ประกอบ Loading spinner หรือรอ Layout นิ่ง)
|
|
await page.locator('.q-spinner').waitFor({ state: 'hidden', timeout: 5000 }).catch(() => {});
|
|
}
|
|
});
|
|
|
|
test('5.4 ลองค้นหาคอร์ส (Search Input) ไม่พบข้อมูล', async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/dashboard/my-courses`);
|
|
|
|
const searchInput = page.locator('input[placeholder*="ค้นหา"]').first();
|
|
await expect(searchInput).toBeVisible();
|
|
|
|
// ลองพิมพ์ชื่อมั่วๆ
|
|
await searchInput.fill('คอร์สที่ไม่มีอยู่จริงแน่นอน1234');
|
|
|
|
// ตรวจสอบว่ามีกล่อง Empty State ขึ้นบอกอธิบาย
|
|
const emptyState = page.locator('h3').filter({ hasText: /ไม่พบ|ไม่เจอ|No result/i }).first()
|
|
.or(page.locator('i.q-icon').filter({ hasText: 'search_off' }));
|
|
|
|
await expect(emptyState.first()).toBeVisible({ timeout: 10_000 });
|
|
});
|
|
});
|