diff --git a/.project-docs/30-worklog/tasks/20260821-remember-below-login-4a7c91d2.md b/.project-docs/30-worklog/tasks/20260821-remember-below-login-4a7c91d2.md new file mode 100644 index 0000000..f74908f --- /dev/null +++ b/.project-docs/30-worklog/tasks/20260821-remember-below-login-4a7c91d2.md @@ -0,0 +1,47 @@ +# Task: Move remember password below login button + +## Identity + +- Task ID: 20260821-remember-below-login-4a7c91d2 +- Mode: Feature +- Branch: codex/20260821-remember-below-login-4a7c91d2-remember-below-login +- Worktree: D:\w\makelore-remember-below-login-4a7c91d2 +- Base commit: eedd20d0618f64b525c53a3362a74eddeebd4421 +- Owner: codex +- Status: Ready for Integration + +## Scope + +- Move the password-login “记住密码” control directly below the login button and above the shared agreement control. +- Preserve the existing remembered-password state, availability, submission, and secure-storage behavior. +- Add focused unit and Electron smoke coverage for the new control order. + +## Intent And Constraints + +- Treat the supplied login screenshot as the visual reference: password field → login button → remember-password control → agreement. +- Keep this as a Renderer layout-only change; do not alter Main-owned credential persistence, Works Square authentication, form validation, or spacing tokens. +- Work only in the isolated feature worktree because local `main` remains owned by the existing remember-password integration task. + +## Outcome + +- Reordered the existing login button and remember-password label in the password form. +- Added a DOM-order assertion to the login-page unit test. +- Extended the shared Electron login smoke with a rendered-bounds assertion proving that the remember-password checkbox appears below the login button. +- No authentication, persistence, API, or styling behavior changed. + +## Verification + +- `pnpm exec vitest run tests/unit/login-page.test.tsx` — 1 file / 13 tests passed. +- `pnpm exec eslint src/pages/Login/index.tsx tests/unit/login-page.test.tsx tests/e2e/app-smoke.spec.ts` — passed. +- `pnpm run typecheck` — passed. +- `pnpm run build:vite` — Renderer, Electron Main, preload, and utility worker builds passed; existing dynamic-import and large-chunk advisory warnings remain. +- `pnpm exec playwright test tests/e2e/app-smoke.spec.ts --grep 'can skip setup and open the native login surface'` — 1 Electron smoke passed. +- `git diff --check` — passed with repository line-ending conversion notices only. + +## Follow-ups + +- Integrate the isolated feature branch into local `main` when its current integration ownership and documentation-drift blocker are resolved or explicitly taken over. + +## Promotion Candidates + +- None. This is a local presentation-order correction and does not change the canonical remember-password boundary or product behavior. diff --git a/src/pages/Login/index.tsx b/src/pages/Login/index.tsx index 75965fb..4df35e0 100644 --- a/src/pages/Login/index.tsx +++ b/src/pages/Login/index.tsx @@ -392,6 +392,10 @@ export function Login() { setPassword(event.target.value)} /> + - ) : (
diff --git a/tests/e2e/app-smoke.spec.ts b/tests/e2e/app-smoke.spec.ts index ebb8c34..02fa0c8 100644 --- a/tests/e2e/app-smoke.spec.ts +++ b/tests/e2e/app-smoke.spec.ts @@ -35,6 +35,17 @@ test.describe('Makelore Electron smoke flows', () => { .toHaveAttribute('aria-selected', 'true'); await expect(page.getByLabel('用户名', { exact: true })).toBeVisible(); await expect(page.getByLabel('密码', { exact: true })).toBeVisible(); + const loginButton = page.getByRole('button', { name: '登录', exact: true }); + const rememberPasswordCheckbox = page.getByRole('checkbox', { name: '记住密码', exact: true }); + await expect(rememberPasswordCheckbox).toBeVisible(); + const [loginButtonBox, rememberPasswordBox] = await Promise.all([ + loginButton.boundingBox(), + rememberPasswordCheckbox.boundingBox(), + ]); + if (!loginButtonBox || !rememberPasswordBox) { + throw new Error('Login controls did not produce visible bounds'); + } + expect(rememberPasswordBox.y).toBeGreaterThan(loginButtonBox.y + loginButtonBox.height); await expect(page.getByRole('button', { name: '在浏览器中继续', exact: true })).toHaveCount(0); }); diff --git a/tests/unit/login-page.test.tsx b/tests/unit/login-page.test.tsx index 271da5f..83a3ba2 100644 --- a/tests/unit/login-page.test.tsx +++ b/tests/unit/login-page.test.tsx @@ -108,7 +108,13 @@ describe('Login page', () => { expect(screen.getByRole('tab', { name: '验证码登录' })).toHaveAttribute('aria-selected', 'false'); expect(screen.getByLabelText('用户名')).toHaveAttribute('autocomplete', 'username'); expect(screen.getByLabelText('密码')).toHaveAttribute('autocomplete', 'current-password'); - expect(await screen.findByRole('checkbox', { name: '记住密码' })).toBeEnabled(); + const rememberPasswordCheckbox = await screen.findByRole('checkbox', { name: '记住密码' }); + const loginButton = screen.getByRole('button', { name: '登录' }); + expect(rememberPasswordCheckbox).toBeEnabled(); + expect( + loginButton.compareDocumentPosition(rememberPasswordCheckbox) + & Node.DOCUMENT_POSITION_FOLLOWING, + ).toBe(Node.DOCUMENT_POSITION_FOLLOWING); expect(screen.queryByText(/浏览器|微信|注册/)).not.toBeInTheDocument(); });