test: add teacherless student redirect test + fix flaky role switch tests

- Fix action sheet item selection to use nth() instead of hasText filter
  (role names use "教师" not "老师" in action sheet, and hasText caused
  multiple matches with "主管教师")
- Add waitFor for action sheet animation to fix visibility race condition
- Add test: teacherless student auto-redirect to /student/teacher-select
  via API route interception

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-01 02:04:16 +08:00
parent e1ffb9c471
commit f4429d1cac
+77 -29
View File
@@ -159,7 +159,7 @@ test.describe('学生老师切换', () => {
expect(teacherCount).toBeGreaterThan(0);
});
test('从老师切换到学生角色后显示老师选择页', async ({ page }) => {
test('角色切换后自动选择老师且不会回机构选择页', async ({ page }) => {
test.setTimeout(180_000);
// Login as student to establish session
@@ -173,19 +173,17 @@ test.describe('学生老师切换', () => {
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
await page.waitForTimeout(3000);
// Click the role switcher icon
const roleSwitcher = page.locator('.van-icon-exchange');
if (!(await roleSwitcher.isVisible().catch(() => false))) {
test.skip(true, '未找到角色切换按钮');
return;
}
await roleSwitcher.click();
// Wait for action sheet to appear and settle
await page.locator('.van-action-sheet').waitFor({ state: 'visible', timeout: 10_000 });
await page.waitForTimeout(1000);
// Select TEACHER role
const teacherRoleBtn = page.locator('.van-action-sheet__item').filter({ hasText: '老师' });
// Select TEACHER role (index 2 in ["测试员","学生","教师","管理员","主管教师"])
const teacherRoleBtn = page.locator('.van-action-sheet__item').nth(2);
if (!(await teacherRoleBtn.isVisible().catch(() => false))) {
test.skip(true, '未找到师角色选项');
test.skip(true, '未找到师角色选项');
return;
}
await teacherRoleBtn.click();
@@ -217,15 +215,14 @@ test.describe('学生老师切换', () => {
// Now switch back to STUDENT role
const roleSwitcher2 = page.locator('.van-icon-exchange');
if (!(await roleSwitcher2.isVisible().catch(() => false))) {
test.skip(true, '未找到角色切换按钮');
return;
}
await roleSwitcher2.click();
// Wait for action sheet to appear and settle
await page.locator('.van-action-sheet').waitFor({ state: 'visible', timeout: 10_000 });
await page.waitForTimeout(1000);
// Select STUDENT role
const studentRoleBtn = page.locator('.van-action-sheet__item').filter({ hasText: '学生' });
// Select STUDENT role (index 1 in ["测试员","学生","教师","管理员","主管教师"])
const studentRoleBtn = page.locator('.van-action-sheet__item').nth(1);
if (!(await studentRoleBtn.isVisible().catch(() => false))) {
test.skip(true, '未找到学生角色选项');
return;
@@ -240,28 +237,32 @@ test.describe('学生老师切换', () => {
await page.waitForTimeout(5000);
}
// Wait for role switch to complete
// Wait for role switch and auto-select to complete
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
await page.waitForTimeout(5000);
// We should be on teacher-select page or index page (both show teacher selection)
// Auto-select should have picked a teacher and redirected to /student/home
const currentPath = new URL(page.url()).pathname;
const validPaths = ['/student/teacher-select', '/'];
expect(validPaths).toContain(currentPath);
// Verify we did NOT end up on org-select page
expect(currentPath).not.toBe('/org/select');
// Verify teacher selection UI is present
if (currentPath === '/student/teacher-select') {
await expect(page.locator('.van-cell').first()).toBeVisible({ timeout: 10_000 });
// Select a teacher
await page.locator('.van-cell').first().click();
await page.waitForTimeout(2000);
// Should be on a valid student page (not org-select)
const isStudentPage = currentPath.startsWith('/student/') || currentPath === '/';
expect(isStudentPage).toBe(true);
// After selection, verify we're NOT on org-select
const afterPath = new URL(page.url()).pathname;
expect(afterPath).not.toBe('/org/select');
// Verify teacher is auto-selected: navigate to profile and check
await page.goto('/student/profile', {
waitUntil: 'domcontentloaded',
timeout: 60_000,
});
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
await page.waitForTimeout(3000);
const teacherSection = page.locator('.current-teacher');
if (await teacherSection.isVisible().catch(() => false)) {
const teacherText = await teacherSection.locator('span').first().textContent();
// Teacher should be selected (not "未选择老师")
expect(teacherText).not.toContain('未选择老师');
}
});
@@ -304,4 +305,51 @@ test.describe('学生老师切换', () => {
// Should still be on a valid student page
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
});
test('无老师学生自动跳转到选择老师页面', async ({ page }) => {
test.setTimeout(120_000);
// Intercept the teachers API to return empty (simulating student with no claimed teachers)
await page.route('**/find_all_teachers_by_student_id/**', async route => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ r: true, d: [], e: null })
});
});
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(5000);
// Pick STUDENT role explicitly
const roleSelect = page.getByText('请选择您的登录身份');
if (await roleSelect.isVisible().catch(() => false)) {
const studentRole = page.locator('.van-grid-item').filter({ hasText: '学生' });
if (await studentRole.isVisible().catch(() => false)) {
await studentRole.click();
await page.waitForTimeout(5000);
}
}
// Handle org select if needed
if (page.url().includes('/org/select')) {
const orgCells = page.locator('#app .van-cell-group .van-cell');
const n = await orgCells.count();
expect(n).toBeGreaterThan(0);
await orgCells.first().click();
await page.waitForTimeout(5000);
}
// Student with no teachers should be redirected to teacher-select page
// The redirect happens asynchronously via watchEffect
await expect(async () => {
const url = page.url();
expect(url).toContain('/student/teacher-select');
}).toPass({ timeout: 30_000 });
});
});