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
133 lines
5.9 KiB
TypeScript
133 lines
5.9 KiB
TypeScript
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();
|
|
}
|
|
});
|
|
});
|