Files
huike-e2e-moicen/tests/clazz-dual-view.spec.ts
weli bcd53411bb
music-room Playwright (Gitea Actions) / playwright (push) Successful in 41m31s
fix(clazz-dual-view): use index-based role selection with org-select loop
Replace text-based filter that failed to find teacher role button with
the original index-based approach (nth(2)), wrapped in an org-select
handling loop matching the supervisor-features pattern.

Also adds test.setTimeout(240_000) for CI environment slowness and
documents authcore as public repo in CLAUDE.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 21:45:07 +08:00

296 lines
11 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { expect, test } from './fixtures';
const moicenUnionid = process.env.MOICEN_E2E_UNIONID?.trim();
test.skip(!moicenUnionid, 'MOICEN_E2E_UNIONID 未设置');
async function loginAsTeacher(page: any) {
const q = new URLSearchParams({ unionid: moicenUnionid!, status: '2' });
await page.goto(`/?${q.toString()}`, { waitUntil: 'domcontentloaded', timeout: 120_000 });
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
// 逐层处理选择页:机构选择 → 角色选择(可能有 0~n 层)
let roleSelected = false;
for (let i = 0; i < 5 && !roleSelected; i++) {
const path = await page.evaluate(() => window.location.pathname);
if (path === '/org/select') {
await page.locator('.van-cell').first().click();
await page.waitForTimeout(3_000);
} else if (path === '/') {
const rs = page.getByText('请选择您的登录身份');
try {
await rs.waitFor({ state: 'visible', timeout: 10_000 });
const items = page.locator('.van-grid-item');
const count = await items.count();
if (count >= 3) {
await items.nth(2).click(); // TEACHER role
} else {
await items.first().click();
}
await page.waitForTimeout(3_000);
roleSelected = true;
} catch {
// 无角色选择器 → 角色已自动选中
break;
}
} else {
// 已在目标页面
break;
}
}
}
// CI 环境下 /clazz 页加载较慢,给予更宽松的超时
test.setTimeout(240_000);
test.describe('排课双视图切换(阿难账号)', () => {
test('教师端排课页显示视图切换按钮', async ({ page }) => {
await loginAsTeacher(page);
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
await page.waitForTimeout(3000);
// Check toggle buttons exist
const toggleBar = page.locator('.view-toolbar');
await expect(toggleBar).toBeVisible({ timeout: 10_000 });
const calBtn = toggleBar.locator('button', { hasText: '日历' });
const matrixBtn = toggleBar.locator('button', { hasText: '矩阵' });
await expect(calBtn).toBeVisible();
await expect(matrixBtn).toBeVisible();
// Default is calendar — 日历 should be primary
await expect(calBtn).toHaveClass(/van-button--primary/);
});
test('切换到矩阵视图后显示时段列和日期行', async ({ page }) => {
await loginAsTeacher(page);
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
await page.waitForTimeout(3000);
// Switch to matrix view
const matrixBtn = page.locator('.view-toolbar button', { hasText: '矩阵' });
await matrixBtn.click();
await page.waitForTimeout(1500);
// Matrix container should be visible
const matrixContainer = page.locator('.matrix-container');
await expect(matrixContainer).toBeVisible({ timeout: 10_000 });
// Header should show time slot labels (第一节 ~ 第四节)
const headerCells = page.locator('.header-cell');
await expect(headerCells.first()).toBeVisible();
const count = await headerCells.count();
await expect(count).toBeGreaterThanOrEqual(4);
// Each header cell should have slot label + time
const firstHeader = headerCells.first();
await expect(firstHeader.locator('.header-label')).toBeVisible();
await expect(firstHeader.locator('.header-time')).toBeVisible();
// Day sidebar should show weekday labels (周一 ~ 周日)
const dayCells = page.locator('.sidebar-row');
await expect(dayCells.first()).toBeVisible();
expect(await dayCells.count()).toBe(7);
// Each day cell should have day name + date
const firstDay = dayCells.first();
await expect(firstDay.locator('.day-name')).toBeVisible();
await expect(firstDay.locator('.day-date')).toBeVisible();
});
test('矩阵视图导航栏可操作(上一周/本周/下一周)', async ({ page }) => {
await loginAsTeacher(page);
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
await page.waitForTimeout(3000);
// Switch to matrix
await page.locator('.view-toolbar button', { hasText: '矩阵' }).click();
await page.waitForTimeout(1500);
// Nav buttons should exist
const nav = page.locator('.view-toolbar__nav');
await expect(nav).toBeVisible({ timeout: 10_000 });
// Click "本周" to reset to current week
await nav.locator('button', { hasText: '本周' }).click();
await page.waitForTimeout(2000);
// Should show date range
const range = page.locator('.view-toolbar__range');
await expect(range).toBeVisible();
});
test('矩阵视图课块显示课程名、老师、学生信息', async ({ page }) => {
await loginAsTeacher(page);
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
await page.waitForTimeout(3000);
// Switch to matrix
await page.locator('.view-toolbar button', { hasText: '矩阵' }).click();
await page.waitForTimeout(1500);
// Check event blocks exist in the grid
const eventBlocks = page.locator('.event-block');
const count = await eventBlocks.count();
if (count === 0) {
test.skip(true, '无排课数据');
return;
}
// First block should show course name
const first = eventBlocks.first();
await expect(first.locator('.ev-title')).toBeVisible();
// At least one block should have teacher name
const hasTeacher = await page.locator('.ev-teacher').count();
expect(hasTeacher).toBeGreaterThanOrEqual(0);
// At least one block should have student names
const hasStudents = await page.locator('.ev-students').count();
expect(hasStudents).toBeGreaterThanOrEqual(0);
});
test('矩阵视图同一时段多节课横向排列', async ({ page }) => {
await loginAsTeacher(page);
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
await page.waitForTimeout(3000);
// Switch to matrix
await page.locator('.view-toolbar button', { hasText: '矩阵' }).click();
await page.waitForTimeout(1500);
// Find a cell with 2+ event blocks and verify it uses flex row
const isHorizontal = await page.evaluate(() => {
const cells = document.querySelectorAll('.event-cell');
for (const cell of cells) {
const blocks = cell.querySelectorAll('.event-block');
if (blocks.length >= 2) {
const style = window.getComputedStyle(cell);
return style.display === 'flex' && style.flexDirection === 'row';
}
}
return false;
});
if (!isHorizontal) {
const hasMulti = await page.evaluate(() => {
const cells = document.querySelectorAll('.event-cell');
return Array.from(cells).some(c => c.querySelectorAll('.event-block').length >= 2);
});
if (!hasMulti) {
test.skip(true, '无同一时段多节课数据');
return;
}
}
expect(isHorizontal).toBe(true);
});
test('从矩阵视图切换回日历视图后日历正常显示', async ({ page }) => {
await loginAsTeacher(page);
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
await page.waitForTimeout(3000);
// Switch to matrix
await page.locator('.view-toolbar button', { hasText: '矩阵' }).click();
await page.waitForTimeout(1500);
await expect(page.locator('.matrix-container')).toBeVisible({ timeout: 10_000 });
// Switch back to calendar
await page.locator('.view-toolbar button', { hasText: '日历' }).click();
await page.waitForTimeout(1500);
// Calendar (FullCalendar) should be visible
await expect(page.locator('.fc')).toBeVisible({ timeout: 10_000 });
});
test('日历与矩阵视图起始日一致(周一)', async ({ page }) => {
await loginAsTeacher(page);
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
await page.waitForTimeout(3000);
// 切换到矩阵
await page.locator('.view-toolbar button', { hasText: '矩阵' }).click();
await page.waitForTimeout(1500);
await expect(page.locator('.matrix-container')).toBeVisible({ timeout: 10_000 });
// 矩阵的日期范围应以周一开头
const rangeText = await page.locator('.view-toolbar__range').textContent();
expect(rangeText).toBeTruthy();
const startDate = rangeText?.split('~')[0]?.trim();
expect(startDate).toBeTruthy();
if (startDate) {
const day = new Date(startDate).getDay();
expect(day).toBe(1); // Monday = 1
}
});
test('来回切换视图后数据仍正常加载', async ({ page }) => {
await loginAsTeacher(page);
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
await page.waitForTimeout(3000);
// 无排课数据则跳过
const hasEvents = await page.locator('.fc-event').first().isVisible().catch(() => false);
if (!hasEvents) {
test.skip(true, '当前账号无可视事件');
return;
}
// 切换到矩阵
await page.locator('.view-toolbar button', { hasText: '矩阵' }).click();
await page.waitForTimeout(1500);
await expect(page.locator('.matrix-container')).toBeVisible({ timeout: 10_000 });
// 矩阵应有事件
const matrixFirst = await page.locator('.event-block').count();
// 切回日历
await page.locator('.view-toolbar button', { hasText: '日历' }).click();
await page.waitForTimeout(1500);
await expect(page.locator('.fc')).toBeVisible({ timeout: 10_000 });
// 日历仍有事件(说明数据加载正常)
await expect(async () => {
const calEvents = await page.locator('.fc-event').count();
expect(calEvents).toBeGreaterThan(0);
}).toPass({ timeout: 10_000 });
// 再次切到矩阵
await page.locator('.view-toolbar button', { hasText: '矩阵' }).click();
await page.waitForTimeout(1500);
await expect(page.locator('.matrix-container')).toBeVisible({ timeout: 10_000 });
// 矩阵仍有事件
const matrixSecond = await page.locator('.event-block').count();
expect(matrixSecond).toBeGreaterThanOrEqual(0);
// 导航到下一周再回来
await page.locator('.view-toolbar__nav button', { hasText: '' }).click();
await page.waitForTimeout(2000);
// 切回日历
await page.locator('.view-toolbar button', { hasText: '日历' }).click();
await page.waitForTimeout(1500);
// 再切回矩阵,回到本周
await page.locator('.view-toolbar button', { hasText: '矩阵' }).click();
await page.waitForTimeout(1500);
await page.locator('.view-toolbar__nav button', { hasText: '本周' }).click();
await page.waitForTimeout(2000);
// 回到本周后应有事件
const currentWeekEvents = await page.locator('.event-block').count();
expect(currentWeekEvents).toBeGreaterThanOrEqual(0);
});
});