清理旧 Portal 导航兼容(07-16-legacy-portal-navigation-compat-cleanup)

这个提交包含在:
2026-07-16 16:46:44 +08:00
父节点 10e155e5fb
当前提交 9a8b7477b6
共修改 2 个文件,包含 27 行新增和 24 行删除
+27 -22
查看文件
@@ -90,8 +90,8 @@ SYNC_ENV=0 bash deploy/trialrun/deploy.sh
### 1. Scope / Trigger ### 1. Scope / Trigger
- Trigger: frontend shell, navigation labels, sidebar grouping, Portal/workbench - Trigger: frontend shell, navigation labels, sidebar grouping, workbench copy,
copy, or live smoke assertions change. or live smoke assertions change.
- Purpose: prevent public deployment from being marked failed only because - Purpose: prevent public deployment from being marked failed only because
smoke tests look for stale navigation copy while the page itself is healthy. smoke tests look for stale navigation copy while the page itself is healthy.
@@ -102,45 +102,48 @@ SYNC_ENV=0 bash deploy/trialrun/deploy.sh
- Shared assertions: `client/tests/e2e/helpers/smokeAssertions.ts` - Shared assertions: `client/tests/e2e/helpers/smokeAssertions.ts`
- Workbench route: `/portal` - Workbench route: `/portal`
- Current primary workbench nav label: `工作台` - Current primary workbench nav label: `工作台`
- Historical nav label still allowed in mocks or older fixtures: `Portal` - Stale user-facing label that must not be accepted by current mocks or smoke:
`Portal`
### 3. Contracts ### 3. Contracts
- `assertPortalLoaded(page)` must assert route and page content first: - `assertPortalLoaded(page)` must assert route and page content first:
`/portal` URL and the `今日待处理` heading. `/portal` URL and the `今日待处理` heading.
- Navigation-label assertions for the workbench link must accept both `工作台` - Navigation-label assertions for the workbench link must require the exact
and `Portal` while older mocks still use English labels. current label `工作台`; mocks and fixtures must use the same contract.
- Navigation assertions must be role-aware. Admin/manager smoke may assert - Navigation assertions must be role-aware. Admin/manager smoke may assert
team/admin entries such as `团队`, but ordinary employee smoke must not team/admin entries such as `团队`, but ordinary employee smoke must not
require links that `NavLinks` intentionally hides for that role. require links that `NavLinks` intentionally hides for that role.
- Smoke tests must not require a copy string that is not a product contract for - Smoke tests must not require a copy string that is not a product contract for
public availability. public availability.
- If the product intentionally renames the primary workbench label again, update - If the product intentionally renames the primary workbench label again,
the shared smoke helper rather than duplicating route-specific assertions in update the product contract, fixtures and shared smoke helper together rather
each live smoke test. than adding an ad hoc fallback in one live smoke test.
### 4. Validation & Error Matrix ### 4. Validation & Error Matrix
- Page reaches `/portal`, `今日待处理` is visible, but nav label is `工作台` -> - Page reaches `/portal`, `今日待处理` is visible, but nav label is `工作台` ->
smoke should pass. smoke should pass.
- Page reaches `/portal` and renders `Portal` as the user-facing nav label ->
smoke should fail as a stale-copy regression.
- Employee reaches `/portal`, role-aware navigation hides `团队`, and employee - Employee reaches `/portal`, role-aware navigation hides `团队`, and employee
pages such as `项目` remain reachable -> smoke should pass. pages such as `项目` remain reachable -> smoke should pass.
- Page reaches `/portal`, but `今日待处理` is missing -> smoke should fail. - Page reaches `/portal`, but `今日待处理` is missing -> smoke should fail.
- Page stays on login, `/403`, error fallback or another route -> smoke should - Page stays on login, `/403`, error fallback or another route -> smoke should
fail. fail.
- New shell label appears only in one live smoke test -> move the compatibility - New shell label appears only in one live smoke test -> stop and align the
logic into `smokeAssertions.ts`. product contract, fixtures and shared helper before changing smoke.
### 5. Good/Base/Bad Cases ### 5. Good/Base/Bad Cases
- Good: `assertPortalLoaded` checks `/portal`, `今日待处理`, and a workbench link - Good: `assertPortalLoaded` checks `/portal`, `今日待处理`, and an exact
matching either `工作台` or `Portal`. `工作台` workbench link.
- Good: `assertMainNavVisible(page, { expectTeam: false })` is used for - Good: `assertMainNavVisible(page, { expectTeam: false })` is used for
ordinary employee live smoke. ordinary employee live smoke.
- Base: mocked E2E fixtures may still emit `Portal`; live public navigation may - Base: the internal route and helper name may retain `portal`, while all
emit `工作台`. user-facing navigation fixtures and assertions use `工作台`.
- Bad: live smoke hard-codes only `Portal` and blocks deployment after a valid - Bad: a mock emits `Portal` and smoke accepts it as a valid current label,
Chinese navigation rollout. masking a user-facing English-copy regression.
- Bad: employee live smoke requires the `团队` sidebar link after role-aware - Bad: employee live smoke requires the `团队` sidebar link after role-aware
navigation intentionally hides it. navigation intentionally hides it.
@@ -148,6 +151,8 @@ SYNC_ENV=0 bash deploy/trialrun/deploy.sh
- After changing live smoke assertions, run: - After changing live smoke assertions, run:
`cd client && npm run typecheck` `cd client && npm run typecheck`
- Load the focused visual and shell specs with Playwright `--list` when changing
fixture/report contracts.
- For public deploy verification, run live smoke or the readiness wrapper: - For public deploy verification, run live smoke or the readiness wrapper:
`LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-live-smoke-readiness.sh` `LIVE_SMOKE_BASE_URL=https://oa.hyinda.com bash scripts/qa/run-live-smoke-readiness.sh`
- When changing the shell or Portal page, include a focused Playwright check - When changing the shell or Portal page, include a focused Playwright check
@@ -157,12 +162,6 @@ SYNC_ENV=0 bash deploy/trialrun/deploy.sh
#### Wrong #### Wrong
```ts
await expect(page.getByRole("link", { name: "Portal" }).first()).toBeVisible();
```
#### Correct
```ts ```ts
await expect( await expect(
page.getByRole("link", { name: "工作台", exact: true }) page.getByRole("link", { name: "工作台", exact: true })
@@ -171,6 +170,12 @@ await expect(
).toBeVisible(); ).toBeVisible();
``` ```
#### Correct
```ts
await expect(page.getByRole("link", { name: "工作台", exact: true }).first()).toBeVisible();
```
## Scenario: Trial Run Runtime Navigation Baseline ## Scenario: Trial Run Runtime Navigation Baseline
### 1. Scope / Trigger ### 1. Scope / Trigger
@@ -250,7 +250,6 @@ async function readMetrics(page: Page) {
clippedControls, clippedControls,
forbiddenLike: forbiddenPage, forbiddenLike: forbiddenPage,
appErrorLike: text.includes("页面加载失败") || text.includes("加载失败") || text.includes("出错了"), appErrorLike: text.includes("页面加载失败") || text.includes("加载失败") || text.includes("出错了"),
navPortalCopy: text.includes("Portal"),
}; };
}, ENGLISH_PRIMARY_TERMS); }, ENGLISH_PRIMARY_TERMS);
} }
@@ -413,7 +412,6 @@ async function auditRoute(page: Page, plan: RoutePlan) {
clippedCount: metrics.clippedControls.length, clippedCount: metrics.clippedControls.length,
forbiddenLike: metrics.forbiddenLike, forbiddenLike: metrics.forbiddenLike,
appErrorLike: metrics.appErrorLike, appErrorLike: metrics.appErrorLike,
navPortalCopy: metrics.navPortalCopy,
}, },
}); });
} }