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(); } }); });