test: add supervisor matrix view E2E tests
Add 3 tests for SUPERVISOR role in matrix view: - TEACHER mode: subsidiary teacher not visible - SUPERVISOR mode: subsidiary courses appear with different colors - Switch back to TEACHER: subsidiary courses disappear Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -71,7 +71,7 @@ test.describe('排课双视图切换(阿难账号)', () => {
|
|||||||
await expect(firstHeader.locator('.header-time')).toBeVisible();
|
await expect(firstHeader.locator('.header-time')).toBeVisible();
|
||||||
|
|
||||||
// Day sidebar should show weekday labels (周一 ~ 周日)
|
// Day sidebar should show weekday labels (周一 ~ 周日)
|
||||||
const dayCells = page.locator('.day-cell');
|
const dayCells = page.locator('.sidebar-row');
|
||||||
await expect(dayCells.first()).toBeVisible();
|
await expect(dayCells.first()).toBeVisible();
|
||||||
expect(await dayCells.count()).toBe(7);
|
expect(await dayCells.count()).toBe(7);
|
||||||
|
|
||||||
@@ -136,6 +136,42 @@ test.describe('排课双视图切换(阿难账号)', () => {
|
|||||||
expect(hasStudents).toBeGreaterThanOrEqual(0);
|
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 }) => {
|
test('从矩阵视图切换回日历视图后日历正常显示', async ({ page }) => {
|
||||||
await loginAsTeacher(page);
|
await loginAsTeacher(page);
|
||||||
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
|
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
|
||||||
|
|||||||
@@ -0,0 +1,194 @@
|
|||||||
|
import { expect, test } from './fixtures';
|
||||||
|
|
||||||
|
const moicenUnionid = process.env.MOICEN_E2E_UNIONID?.trim();
|
||||||
|
test.skip(!moicenUnionid, 'MOICEN_E2E_UNIONID 未设置');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色选择器在 action-sheet 中的索引:
|
||||||
|
* ["测试员","学生","教师","管理员","主管教师"]
|
||||||
|
*/
|
||||||
|
const ROLE_TEACHER = 2;
|
||||||
|
const ROLE_SUPERVISOR = 4;
|
||||||
|
|
||||||
|
const SUBSIDIARY_TEACHER_NAME = '周晓慧';
|
||||||
|
|
||||||
|
test.describe('主管老师矩阵视图', () => {
|
||||||
|
|
||||||
|
async function loginAsTeacher(page: any) {
|
||||||
|
const q = new URLSearchParams({ unionid: moicenUnionid!, status: '2' });
|
||||||
|
await page.goto(`/?${q.toString()}`, { waitUntil: 'domcontentloaded', timeout: 60_000 });
|
||||||
|
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||||
|
await page.waitForTimeout(3000);
|
||||||
|
|
||||||
|
const rs = page.getByText('请选择您的登录身份');
|
||||||
|
if (await rs.isVisible().catch(() => false)) {
|
||||||
|
const items = page.locator('.van-grid-item');
|
||||||
|
const count = await items.count();
|
||||||
|
if (count >= 3) {
|
||||||
|
await items.nth(ROLE_TEACHER).click();
|
||||||
|
} else {
|
||||||
|
await items.first().click();
|
||||||
|
}
|
||||||
|
await page.waitForTimeout(3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function switchToRole(page: any, roleIndex: number) {
|
||||||
|
const roleSwitcher = page.locator('.van-icon-exchange');
|
||||||
|
await expect(roleSwitcher).toBeVisible({ timeout: 15_000 });
|
||||||
|
await roleSwitcher.click();
|
||||||
|
await page.locator('.van-action-sheet').waitFor({ state: 'visible', timeout: 10_000 });
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
|
const roleBtn = page.locator('.van-action-sheet__item').nth(roleIndex);
|
||||||
|
await expect(roleBtn).toBeVisible();
|
||||||
|
await roleBtn.click();
|
||||||
|
await page.waitForTimeout(1500);
|
||||||
|
|
||||||
|
const confirmDialog = page.locator('.van-dialog__confirm');
|
||||||
|
if (await confirmDialog.isVisible().catch(() => false)) {
|
||||||
|
await confirmDialog.click();
|
||||||
|
await page.waitForTimeout(3000);
|
||||||
|
}
|
||||||
|
await page.waitForTimeout(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function switchToMatrixView(page: any) {
|
||||||
|
const matrixBtn = page.locator('.view-toolbar button', { hasText: '矩阵' });
|
||||||
|
await expect(matrixBtn).toBeVisible({ timeout: 10_000 });
|
||||||
|
await matrixBtn.click();
|
||||||
|
await page.waitForTimeout(1500);
|
||||||
|
await expect(page.locator('.matrix-container')).toBeVisible({ timeout: 10_000 });
|
||||||
|
}
|
||||||
|
|
||||||
|
test('教师角色下矩阵视图不显示下属老师(周晓慧)的课程', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
|
|
||||||
|
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 switchToMatrixView(page);
|
||||||
|
|
||||||
|
// Collect all teacher names from event blocks
|
||||||
|
const teacherNames = await page.evaluate(() => {
|
||||||
|
return Array.from(document.querySelectorAll('.ev-teacher'))
|
||||||
|
.map(el => el.textContent?.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
});
|
||||||
|
|
||||||
|
// In TEACHER role, 周晓慧's courses should NOT appear
|
||||||
|
const hasZhouXiaohui = teacherNames.includes(SUBSIDIARY_TEACHER_NAME);
|
||||||
|
expect(hasZhouXiaohui).toBe(false);
|
||||||
|
|
||||||
|
// footer-subsidiary should not exist in TEACHER role
|
||||||
|
const footerSubsidiary = page.locator('.footer-subsidiary');
|
||||||
|
await expect(footerSubsidiary).not.toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('切换到主管老师角色后矩阵视图显示周晓慧的课程(不同颜色)', async ({ page }) => {
|
||||||
|
test.setTimeout(120_000);
|
||||||
|
|
||||||
|
await loginAsTeacher(page);
|
||||||
|
|
||||||
|
// Go to TEACHER profile to open role switcher
|
||||||
|
await page.goto('/teacher/profile', { waitUntil: 'domcontentloaded', timeout: 60_000 });
|
||||||
|
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||||
|
await page.waitForTimeout(3000);
|
||||||
|
|
||||||
|
// Switch to SUPERVISOR role
|
||||||
|
await switchToRole(page, ROLE_SUPERVISOR);
|
||||||
|
|
||||||
|
// Navigate to clazz page
|
||||||
|
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
|
||||||
|
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||||
|
await page.waitForTimeout(5000);
|
||||||
|
|
||||||
|
// Verify subsidiary teacher tags in footer
|
||||||
|
const footerSubsidiary = page.locator('.footer-subsidiary');
|
||||||
|
await expect(footerSubsidiary).toBeVisible({ timeout: 15_000 });
|
||||||
|
const tagCount = await footerSubsidiary.locator('.van-tag').count();
|
||||||
|
expect(tagCount).toBeGreaterThanOrEqual(1);
|
||||||
|
|
||||||
|
// Verify 周晓慧 tag is present
|
||||||
|
const zhouTag = footerSubsidiary.locator('.van-tag', { hasText: SUBSIDIARY_TEACHER_NAME });
|
||||||
|
await expect(zhouTag).toBeVisible();
|
||||||
|
|
||||||
|
// Switch to matrix view
|
||||||
|
await switchToMatrixView(page);
|
||||||
|
|
||||||
|
// Verify 周晓慧's courses appear
|
||||||
|
const teacherNames = await page.evaluate(() => {
|
||||||
|
return Array.from(document.querySelectorAll('.ev-teacher'))
|
||||||
|
.map(el => el.textContent?.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (teacherNames.length === 0) {
|
||||||
|
test.skip(true, '排课数据为空');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(teacherNames).toContain(SUBSIDIARY_TEACHER_NAME);
|
||||||
|
|
||||||
|
// Verify different courses have different background colors
|
||||||
|
const teacherColorMap = await page.evaluate(() => {
|
||||||
|
const map: Record<string, string> = {};
|
||||||
|
document.querySelectorAll('.event-block').forEach(block => {
|
||||||
|
const teacher = block.querySelector('.ev-teacher')?.textContent?.trim();
|
||||||
|
const bgColor = getComputedStyle(block).backgroundColor;
|
||||||
|
if (teacher && bgColor && teacher !== '未设置老师') {
|
||||||
|
map[teacher] = map[teacher] || bgColor;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
|
||||||
|
// At least 2 different colors should be used (own + subsidiary)
|
||||||
|
const colorSet = new Set(Object.values(teacherColorMap));
|
||||||
|
expect(colorSet.size).toBeGreaterThanOrEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('从主管老师切回教师角色后周晓慧的课程消失', async ({ page }) => {
|
||||||
|
test.setTimeout(180_000);
|
||||||
|
|
||||||
|
await loginAsTeacher(page);
|
||||||
|
|
||||||
|
// Switch to SUPERVISOR first
|
||||||
|
await page.goto('/teacher/profile', { waitUntil: 'domcontentloaded', timeout: 60_000 });
|
||||||
|
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||||
|
await page.waitForTimeout(3000);
|
||||||
|
await switchToRole(page, ROLE_SUPERVISOR);
|
||||||
|
|
||||||
|
// Verify clazz page shows subsidiary data
|
||||||
|
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
|
||||||
|
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||||
|
await page.waitForTimeout(5000);
|
||||||
|
|
||||||
|
const footerSubsidiary = page.locator('.footer-subsidiary');
|
||||||
|
await expect(footerSubsidiary).toBeVisible({ timeout: 15_000 });
|
||||||
|
|
||||||
|
// Switch back to TEACHER via supervisor profile
|
||||||
|
await page.goto('/supervisor/profile', { waitUntil: 'domcontentloaded', timeout: 60_000 });
|
||||||
|
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||||
|
await page.waitForTimeout(3000);
|
||||||
|
await switchToRole(page, ROLE_TEACHER);
|
||||||
|
|
||||||
|
// Verify clazz page no longer shows subsidiary data
|
||||||
|
await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000 });
|
||||||
|
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||||
|
await page.waitForTimeout(5000);
|
||||||
|
|
||||||
|
await expect(footerSubsidiary).not.toBeVisible();
|
||||||
|
|
||||||
|
// 周晓慧's name should not appear in event blocks
|
||||||
|
const teacherNames = await page.evaluate(() => {
|
||||||
|
return Array.from(document.querySelectorAll('.ev-teacher'))
|
||||||
|
.map(el => el.textContent?.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(teacherNames).not.toContain(SUBSIDIARY_TEACHER_NAME);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user