feat: Establish Playwright testing infrastructure with initial tests for authentication, admin, and instructor modules, and fix instructor video and quiz lesson management pages.
All checks were successful
Build and Deploy Frontend Management to Dev Server / Build Frontend Management Docker Image (push) Successful in 1m17s
Build and Deploy Frontend Management to Dev Server / Deploy E-learning Frontend Management to Dev Server (push) Successful in 8s
Build and Deploy Frontend Management to Dev Server / Notify Deployment Status (push) Successful in 2s
All checks were successful
Build and Deploy Frontend Management to Dev Server / Build Frontend Management Docker Image (push) Successful in 1m17s
Build and Deploy Frontend Management to Dev Server / Deploy E-learning Frontend Management to Dev Server (push) Successful in 8s
Build and Deploy Frontend Management to Dev Server / Notify Deployment Status (push) Successful in 2s
This commit is contained in:
parent
734d922393
commit
9bc24fbe8a
18 changed files with 1344 additions and 7 deletions
133
frontend_management/tests/instructor/courses-list.spec.ts
Normal file
133
frontend_management/tests/instructor/courses-list.spec.ts
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { TEST_URLS } from '../fixtures/test-data';
|
||||
|
||||
/**
|
||||
* Instructor Courses List Page Tests
|
||||
* ใช้ cookies จาก instructor-setup project (ไม่ต้อง login ซ้ำ)
|
||||
*/
|
||||
test.describe('Instructor Courses List', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto(TEST_URLS.instructorCourses);
|
||||
await page.waitForLoadState('networkidle');
|
||||
});
|
||||
|
||||
test('should display page header', async ({ page }) => {
|
||||
await expect(page.getByText('หลักสูตรของฉัน')).toBeVisible();
|
||||
await expect(page.getByText('จัดการหลักสูตรที่คุณสร้าง')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should have create course button', async ({ page }) => {
|
||||
const createBtn = page.getByRole('button', { name: /สร้างหลักสูตรใหม่/ });
|
||||
await expect(createBtn).toBeVisible();
|
||||
});
|
||||
|
||||
test('should navigate to create course page', async ({ page }) => {
|
||||
await page.getByRole('button', { name: /สร้างหลักสูตรใหม่/ }).click();
|
||||
await page.waitForURL('**/instructor/courses/create**');
|
||||
await expect(page).toHaveURL(/\/instructor\/courses\/create/);
|
||||
});
|
||||
|
||||
test('should display stats cards', async ({ page }) => {
|
||||
await expect(page.getByText('หลักสูตรทั้งหมด')).toBeVisible();
|
||||
await expect(page.getByText('เผยแพร่แล้ว')).toBeVisible();
|
||||
await expect(page.getByText('รอตรวจสอบ')).toBeVisible();
|
||||
await expect(page.getByText('แบบร่าง')).toBeVisible();
|
||||
await expect(page.getByText('ถูกปฏิเสธ')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should have search input', async ({ page }) => {
|
||||
const searchInput = page.locator('input[placeholder*="ค้นหา"]');
|
||||
await expect(searchInput).toBeVisible();
|
||||
});
|
||||
|
||||
test('should have status filter dropdown', async ({ page }) => {
|
||||
// Click the status select to open dropdown
|
||||
const statusSelect = page.locator('.q-select').first();
|
||||
await expect(statusSelect).toBeVisible();
|
||||
});
|
||||
|
||||
test('should filter by status', async ({ page }) => {
|
||||
// Open status dropdown
|
||||
await page.locator('.q-select').first().click();
|
||||
|
||||
// Select "เผยแพร่แล้ว" (APPROVED)
|
||||
await page.getByText('เผยแพร่แล้ว').click();
|
||||
|
||||
// Wait for API re-fetch
|
||||
await page.waitForLoadState('networkidle');
|
||||
});
|
||||
|
||||
test('should toggle between card and table view', async ({ page }) => {
|
||||
// Switch to table view
|
||||
await page.locator('.q-btn-toggle button').last().click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
// Table should appear
|
||||
await expect(page.locator('.q-table')).toBeVisible();
|
||||
|
||||
// Table should have expected columns
|
||||
await expect(page.getByText('หลักสูตร')).toBeVisible();
|
||||
await expect(page.getByText('สถานะ')).toBeVisible();
|
||||
await expect(page.getByText('ราคา')).toBeVisible();
|
||||
|
||||
// Switch back to card view
|
||||
await page.locator('.q-btn-toggle button').first().click();
|
||||
await page.waitForTimeout(300);
|
||||
});
|
||||
|
||||
test('should show course cards with status badges', async ({ page }) => {
|
||||
// Wait for courses to load (either card or empty state)
|
||||
const hasCards = await page.locator('.q-badge').first().isVisible().catch(() => false);
|
||||
const isEmpty = await page.getByText('ยังไม่มีหลักสูตร').isVisible().catch(() => false);
|
||||
|
||||
// Either courses exist with badges or empty state shows
|
||||
expect(hasCards || isEmpty).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should show course action menu', async ({ page }) => {
|
||||
const moreBtn = page.locator('button:has(.q-icon[class*="more_vert"])').first();
|
||||
const hasCourses = await moreBtn.isVisible().catch(() => false);
|
||||
|
||||
if (hasCourses) {
|
||||
await moreBtn.click();
|
||||
|
||||
// Menu should show duplicate and delete options
|
||||
await expect(page.getByText('ทำสำเนา')).toBeVisible();
|
||||
await expect(page.getByText('ลบ')).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('should open clone dialog from menu', async ({ page }) => {
|
||||
const moreBtn = page.locator('button:has(.q-icon[class*="more_vert"])').first();
|
||||
const hasCourses = await moreBtn.isVisible().catch(() => false);
|
||||
|
||||
if (hasCourses) {
|
||||
await moreBtn.click();
|
||||
await page.getByText('ทำสำเนา').click();
|
||||
|
||||
// Clone dialog should appear
|
||||
await expect(page.getByText('ทำสำเนาหลักสูตร')).toBeVisible();
|
||||
await expect(page.locator('.q-dialog input').first()).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('should handle rejected course view details', async ({ page }) => {
|
||||
// Filter by rejected status
|
||||
await page.locator('.q-select').first().click();
|
||||
await page.getByText('ถูกปฏิเสธ').click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// If there are rejected courses, clicking view should show rejection dialog
|
||||
const viewBtn = page.locator('button:has(.q-icon[class*="visibility"])').first();
|
||||
const hasRejected = await viewBtn.isVisible().catch(() => false);
|
||||
|
||||
if (hasRejected) {
|
||||
await viewBtn.click();
|
||||
|
||||
// Rejection dialog should appear
|
||||
await expect(page.getByText('หลักสูตรถูกปฏิเสธ')).toBeVisible();
|
||||
await expect(page.getByText('เหตุผลการปฏิเสธ')).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /คืนสถานะเป็นแบบร่าง/ })).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
67
frontend_management/tests/instructor/dashboard.spec.ts
Normal file
67
frontend_management/tests/instructor/dashboard.spec.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { TEST_URLS } from '../fixtures/test-data';
|
||||
|
||||
/**
|
||||
* Instructor Dashboard Tests
|
||||
* ใช้ cookies จาก instructor-setup project (ไม่ต้อง login ซ้ำ)
|
||||
*/
|
||||
test.describe('Instructor Dashboard', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto(TEST_URLS.instructorDashboard);
|
||||
await page.waitForLoadState('networkidle');
|
||||
});
|
||||
|
||||
test('should display welcome message', async ({ page }) => {
|
||||
await expect(page.locator('h1')).toContainText('สวัสดี');
|
||||
});
|
||||
|
||||
test('should display stats cards', async ({ page }) => {
|
||||
await expect(page.getByText('หลักสูตรทั้งหมด')).toBeVisible();
|
||||
await expect(page.getByText('ผู้เรียนทั้งหมด')).toBeVisible();
|
||||
await expect(page.getByText('เรียนจบแล้ว')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should display course status breakdown', async ({ page }) => {
|
||||
await expect(page.getByText('สถานะหลักสูตร')).toBeVisible();
|
||||
await expect(page.getByText('เผยแพร่แล้ว')).toBeVisible();
|
||||
await expect(page.getByText('รอตรวจสอบ')).toBeVisible();
|
||||
await expect(page.getByText('แบบร่าง')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should display recent courses section', async ({ page }) => {
|
||||
await expect(page.getByText('หลักสูตร')).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'ดูทั้งหมด' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('should navigate to courses list', async ({ page }) => {
|
||||
await page.getByRole('button', { name: 'ดูทั้งหมด' }).click();
|
||||
await page.waitForURL('**/instructor/courses**');
|
||||
await expect(page).toHaveURL(/\/instructor\/courses/);
|
||||
});
|
||||
|
||||
test('should show user menu on avatar click', async ({ page }) => {
|
||||
await page.locator('.w-12.h-12.rounded-full').click();
|
||||
|
||||
await expect(page.getByText('โปรไฟล์')).toBeVisible();
|
||||
await expect(page.getByText('ออกจากระบบ')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should navigate to profile', async ({ page }) => {
|
||||
await page.locator('.w-12.h-12.rounded-full').click();
|
||||
await page.getByText('โปรไฟล์').click();
|
||||
|
||||
await page.waitForURL('**/instructor/profile**');
|
||||
await expect(page).toHaveURL(/\/instructor\/profile/);
|
||||
});
|
||||
|
||||
test('should logout and redirect to login', async ({ page }) => {
|
||||
await page.locator('.w-12.h-12.rounded-full').click();
|
||||
await page.getByText('ออกจากระบบ').click();
|
||||
|
||||
// Confirm logout dialog
|
||||
await page.locator('.q-dialog').getByText('ออกจากระบบ').click();
|
||||
|
||||
await page.waitForURL('**/login**', { timeout: 10_000 });
|
||||
await expect(page).toHaveURL(/\/login/);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue