feat: add password recovery flow (#358)

This commit is contained in:
MasterChiefCN authored and GitHub committed 2026-08-31 09:58:36 +08:00
1 parent 8ebceecbb6
commit e124a9ea04
19 files changed
+875 -52

No files matched your search

+3 -3
View File
@@ -44,7 +44,7 @@ test("analytics keeps fixed range presets distinct and uses enabled channel mode
expect(source).toContain("onValuesChange={handlePricingValuesChange}");
expect(source).toContain("onChange={handlePricingModelChange}");
expect(source).toContain('hasOwnProperty.call(changedValues, "model")');
expect(source).toContain("if (matchingChannels.length) form.setFieldValue(\"channelId\", matchingChannels[0].id)");
expect(source).toContain('if (matchingChannels.length) form.setFieldValue("channelId", matchingChannels[0].id)');
expect(source).toContain("const sourceChannels = channels.filter((channel) => channel.enabled !== false)");
expect(source).toContain('inputMode="decimal"');
expect(source).toContain('className="admin-analytics-price-input"');
@@ -53,7 +53,7 @@ test("analytics keeps fixed range presets distinct and uses enabled channel mode
expect(source).toContain("zIndex={1200}");
expect(source).toContain("setPricingWorkspaceOpen(false)");
expect(source).toContain("validator: validatePriceInput");
expect(source).toContain('请输入非负价格,最多 6 位小数');
expect(source).toContain("请输入非负价格,最多 6 位小数");
expect(source).toContain("function formatPriceInput(micros: number)");
expect(source).toContain("function toMicros(value?: string | number)");
expect(source).not.toContain("<InputNumber");
@@ -123,7 +123,7 @@ test("task-first settings reveal dependent configuration only after the primary
expect(emailSource).toContain("{draftEnabled ? (");
expect(emailSource).toContain('id="admin-email-smtp"');
expect(emailSource).toContain('title="1. 是否发送注册邮箱验证码"');
expect(emailSource).toContain('title="1. 是否发送账户安全邮件"');
expect(emailSource).toContain('title="2. 配置 SMTP 连接与发件身份"');
expect(accessSource).toContain("{draftLinuxDOEnabled ? (");
+24
View File
@@ -0,0 +1,24 @@
import { expect, test } from "bun:test";
test("password recovery keeps the approved login placement and dedicated route", async () => {
const [loginSource, recoverySource, routerSource, sceneSource, authAPISource, emailSettingsSource] = await Promise.all([
Bun.file(new URL("../src/pages/auth/login.tsx", import.meta.url)).text(),
Bun.file(new URL("../src/pages/auth/forgot-password.tsx", import.meta.url)).text(),
Bun.file(new URL("../src/router.tsx", import.meta.url)).text(),
Bun.file(new URL("../src/pages/auth/auth-scene.tsx", import.meta.url)).text(),
Bun.file(new URL("../src/services/api/auth.ts", import.meta.url)).text(),
Bun.file(new URL("../src/pages/admin/components/email-settings-panel.tsx", import.meta.url)).text(),
]);
expect(loginSource).toContain('label="密码"');
expect(loginSource).toContain("忘记密码?");
expect(loginSource).toContain("forgotPasswordURL");
expect(routerSource).toContain('{ path: "/forgot-password"');
expect(sceneSource).toContain('eyebrow: "ACCOUNT RECOVERY"');
expect(recoverySource).toContain("如果该邮箱已绑定可找回的账号,验证码将发送到邮箱");
expect(recoverySource).toContain('autoComplete="one-time-code"');
expect(recoverySource).toContain('autoComplete="new-password"');
expect(authAPISource).toContain('api.post("/auth/password-reset-code"');
expect(authAPISource).toContain('api.post("/auth/password-reset"');
expect(emailSettingsSource).toContain("发送注册与密码找回验证码");
});