feat: Implement E2E tests for authentication, student account, discovery, and classroom features, alongside new browse pages and a useAuth composable.
All checks were successful
Build and Deploy Frontend Learner / Build Frontend Learner Docker Image (push) Successful in 48s
Build and Deploy Frontend Learner / Deploy E-learning Frontend Learner to Dev Server (push) Successful in 4s
Build and Deploy Frontend Learner / Notify Deployment Status (push) Successful in 1s
All checks were successful
Build and Deploy Frontend Learner / Build Frontend Learner Docker Image (push) Successful in 48s
Build and Deploy Frontend Learner / Deploy E-learning Frontend Learner to Dev Server (push) Successful in 4s
Build and Deploy Frontend Learner / Notify Deployment Status (push) Successful in 1s
This commit is contained in:
parent
0205aab461
commit
b0b665f588
35 changed files with 546 additions and 862 deletions
129
Frontend-Learner/tests/e2e/helpers.ts
Normal file
129
Frontend-Learner/tests/e2e/helpers.ts
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* @file helpers.ts
|
||||
* @description Shared E2E test helpers — ฟังก์ชันที่ใช้ร่วมกันในทุกไฟล์ test
|
||||
* รวม: waitAppSettled, login helpers, common locators, constants
|
||||
*/
|
||||
import { type Page, type Locator, expect } from '@playwright/test';
|
||||
|
||||
// ==========================================
|
||||
// Constants
|
||||
// ==========================================
|
||||
export const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:3000';
|
||||
export const TEST_EMAIL = 'studentedtest@example.com';
|
||||
export const TEST_PASSWORD = 'admin123';
|
||||
|
||||
/** Timeout configs — ปรับค่าได้ที่เดียว */
|
||||
export const TIMEOUT: Record<string, number> = {
|
||||
/** รอหน้าโหลด */
|
||||
PAGE_LOAD: 15_000,
|
||||
/** รอ login + redirect */
|
||||
LOGIN: 25_000,
|
||||
/** รอ element แสดงผล */
|
||||
ELEMENT: 12_000,
|
||||
/** รอ network settle */
|
||||
SETTLE: 300,
|
||||
};
|
||||
|
||||
// ==========================================
|
||||
// Wait Helpers
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* รอให้แอปโหลดเสร็จสมบูรณ์ (DOM + Network + hydration)
|
||||
*/
|
||||
export async function waitAppSettled(page: Page, ms = TIMEOUT.SETTLE) {
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
await page.waitForLoadState('networkidle').catch(() => {});
|
||||
await page.waitForTimeout(ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* รอจนกว่า locator ใดก็ได้ใน array จะ visible
|
||||
* @throws เมื่อไม่มี locator ไหน visible ภายใน timeout
|
||||
*/
|
||||
export async function expectAnyVisible(
|
||||
page: Page,
|
||||
locators: Locator[],
|
||||
timeout = TIMEOUT.PAGE_LOAD
|
||||
) {
|
||||
const start = Date.now();
|
||||
while (Date.now() - start < timeout) {
|
||||
for (const loc of locators) {
|
||||
try {
|
||||
if (await loc.isVisible()) return;
|
||||
} catch { /* locator detached / stale — ลองใหม่ */ }
|
||||
}
|
||||
await page.waitForTimeout(200);
|
||||
}
|
||||
throw new Error(
|
||||
`None of the expected locators became visible within ${timeout}ms`
|
||||
);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Login Locators
|
||||
// ==========================================
|
||||
|
||||
export function emailLocator(page: Page): Locator {
|
||||
return page
|
||||
.locator('input[type="email"]')
|
||||
.or(page.getByRole('textbox', { name: /อีเมล|email/i }))
|
||||
.first();
|
||||
}
|
||||
|
||||
export function passwordLocator(page: Page): Locator {
|
||||
return page
|
||||
.locator('input[type="password"]')
|
||||
.or(page.getByRole('textbox', { name: /รหัสผ่าน|password/i }))
|
||||
.first();
|
||||
}
|
||||
|
||||
export function loginButtonLocator(page: Page): Locator {
|
||||
return page
|
||||
.getByRole('button', { name: /เข้าสู่ระบบ|login/i })
|
||||
.or(page.locator('button[type="submit"]'))
|
||||
.first();
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Login Flow
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* ล็อกอินด้วย test account — ใช้ใน beforeEach ของ tests ที่ต้อง authenticate
|
||||
*
|
||||
* @param page — Playwright Page
|
||||
* @param opts — ตัวเลือกเสริม
|
||||
* @param opts.assertDashboard — (default: true) ถ้า true จะ assert ว่าเข้า dashboard สำเร็จ
|
||||
*
|
||||
* @throws หาก login ล้มเหลวหรือไม่ถึง dashboard
|
||||
*/
|
||||
export async function setupLogin(
|
||||
page: Page,
|
||||
opts: { assertDashboard?: boolean } = {}
|
||||
) {
|
||||
const { assertDashboard = true } = opts;
|
||||
|
||||
await page.goto(`${BASE_URL}/auth/login`, { waitUntil: 'domcontentloaded' });
|
||||
await waitAppSettled(page);
|
||||
|
||||
// กรอกข้อมูล
|
||||
await emailLocator(page).fill(TEST_EMAIL);
|
||||
await passwordLocator(page).fill(TEST_PASSWORD);
|
||||
await loginButtonLocator(page).click();
|
||||
|
||||
// รอ redirect ไป dashboard
|
||||
await page.waitForURL('**/dashboard', { timeout: TIMEOUT.LOGIN });
|
||||
await waitAppSettled(page);
|
||||
|
||||
if (assertDashboard) {
|
||||
// ยืนยันว่าเข้า dashboard ได้จริง
|
||||
const evidence = [
|
||||
page.locator('.q-page-container').first(),
|
||||
page.locator('.q-drawer').first(),
|
||||
page.locator('img[src*="avataaars"]').first(),
|
||||
page.locator('img[alt],[alt="User Avatar"]').first(),
|
||||
];
|
||||
await expectAnyVisible(page, evidence, TIMEOUT.PAGE_LOAD);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue