import { expect, test } from "@playwright/test"; function envelope(data: unknown) { return { requestId: "mock-request", data, }; } test("E2E 企微首次绑定:未绑定回退到密码登录后可继续进入目标页", async ({ page }) => { await page.addInitScript(() => { Object.defineProperty(window.navigator, "userAgent", { configurable: true, value: "Mozilla/5.0 wxwork/4.1.20 MicroMessenger/7.0.1", }); }); await page.route("**/api/auth/sso/providers", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify(envelope([])), }); }); await page.route("**/api/auth/wecom/config", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify( envelope({ enabled: true, entryEnabled: true, oauthEnabled: true, corpId: "wx-test-corp", agentId: "1000001", loginUrl: "/api/auth/wecom/login?returnTo=%2Fmobile", bindEnabled: true, defaultReturnTo: "/mobile", status: "ready", statusReasons: [], }), ), }); }); await page.route("**/api/auth/login", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", headers: { "set-cookie": "has_session=1; Path=/; SameSite=Lax" }, body: JSON.stringify( envelope({ accessToken: "wecom-fallback-token", expiresIn: 900, mustChangePassword: false, wecomBindingStatus: "bound", }), ), }); }); await page.route("**/api/auth/refresh", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", headers: { "set-cookie": "has_session=1; Path=/; SameSite=Lax" }, body: JSON.stringify( envelope({ accessToken: "wecom-fallback-token", expiresIn: 900, mustChangePassword: false, }), ), }); }); await page.route("**/api/me", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify( envelope({ id: "employee-1", employeeNo: "HYD000123", name: "张三", phone: "13800000001", email: "zhangsan@example.com", departmentId: "dept-1", directManagerId: null, status: "active", notificationPushEnabled: true, roleCodes: ["employee"], permissions: [], profileCompleteness: { hasEmergencyContact: true, hasBankAccount: false, hasAvatar: false, hasIdNumber: false, score: 25, }, wecomBinding: { externalUserId: "wecom-user-1", createdAt: "2026-05-04T12:00:00.000Z", }, }), ), }); }); await page.route("**/api/system/navigation", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify( envelope({ workspace: { id: "workspace-1", persisted: true, profile: "small_team_internal", orgMode: "single_company", primaryEntryMode: "wecom", notificationStrategy: "in_app", devicePriority: "mobile", moduleVisibility: {}, createdAt: null, updatedAt: null, updatedBy: null, }, sections: { main: [{ key: "portal", href: "/portal", label: "Portal", icon: "home_app_logo", placement: "main", permissionCodes: [], featureFlagKey: null }], admin: [], backup: [], }, recommendedRolePresets: [], }), ), }); }); await page.route((url) => url.pathname === "/api/notifications", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify( envelope({ page: 1, pageSize: 10, total: 0, unreadOnly: true, unreadCount: 0, items: [], }), ), }); }); await page.route("**/api/portal/home", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify( envelope({ workspace: { id: "workspace-1", persisted: true, profile: "small_team_internal" }, greeting: { name: "张三" }, cards: [], pendingTasks: { count: 0, href: "/workflow/tasks" }, myApplications: [], riskSummary: null, announcements: [], quickLinks: [], todayPresence: null, teamPresence: null, weeklyReport: null, weeklySummary: null, todoSummary: { openCount: 0, highPriorityCount: 0, href: "/todos" }, projectSummary: { myCount: 0, overdueMilestonesCount: 0, highPriorityTaskCount: 0, openRiskCount: 0, followUpDueTodayCount: 0, closurePendingProjectCount: 0, href: "/projects" }, peopleLifecycle: null, adoptionSummary: null, recentActivities: [], teamStatusBoard: [], }), ), }); }); await page.goto("/login?redirect=%2Fmobile&wecom=unbound"); await expect(page.getByTestId("login-wecom-notice")).toContainText("当前企业微信账号尚未绑定"); if (await page.getByTestId("login-identifier").count() === 0) { await page.getByRole("button", { name: "使用账号密码登录" }).click(); } await page.getByTestId("login-identifier").fill("zhangsan@example.com"); await page.getByTestId("login-password").fill("ResetA1abc123def456"); await page.getByTestId("login-submit").click(); await expect(page).toHaveURL(/\/mobile/); });