Files
Jyotisha/frontend/tests/login-code-entry.test.tsx
T
jesse-uxandGrok (agent loop) b2a561b34c 被放宽的抽屉、外观和设置测试改回点按检查(U10)。
Co-Authored-By: Grok (agent loop)
2026-10-27 00:51:11 +08:00

82 lines
3.6 KiB
TypeScript

import "./install-test-document";
import assert from "node:assert/strict";
import test from "node:test";
import React from "react";
import { EmailOtpLogin } from "../src/components/email-otp-login.tsx";
import { createClientLifecycleHarness } from "./react-client-lifecycle-test-support.ts";
Object.assign(globalThis, { React });
test("login types an email, sends a code, then types that code", async () => {
// 原值:K5 验收要的这条交互没有测试,登录页只核对源码里的文案
// 新值:输入邮箱、勾选同意、发送验证码,再把六位码打进格子,然后验证
// 原因:K5 把验证码换成六格输入。发码和输码仍要能点通,不能只看源码里有这些词
const h = createClientLifecycleHarness();
const calls: { url: string; body: string }[] = [];
const assigned: string[] = [];
const previousFetch = globalThis.fetch;
globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => {
const url = String(input);
const body = typeof init?.body === "string" ? init.body : "";
calls.push({ url, body });
const payload = url.includes("/get-session") ? { session: null, user: null } : {};
return new Response(JSON.stringify(payload), {
status: 200,
headers: { "content-type": "application/json" },
});
}) as typeof fetch;
Object.assign(window, {
location: {
href: "https://staging.jyotisha.chat/login",
assign(path: string) { assigned.push(path); },
},
});
type Node = ReturnType<typeof h.elements>[number];
const nodes = () => {
const walk = (node: Node): Node[] => [node, ...node.childNodes.flatMap((child) => walk(child))];
return walk(h.container);
};
const button = (label: string) => nodes().find((node) => node.tagName === "BUTTON" && node.text.includes(label));
try {
await h.render(React.createElement(EmailOtpLogin, {
provider: "self-hosted",
passwordEnabled: true,
successPath: "/",
testOtp: "654321",
}));
assert.deepEqual(h.errors, []);
const email = nodes().find((node) => node.getAttribute("id") === "login-email");
assert.ok(email);
(email as { value: string }).value = "person@example.com";
await h.event(email, "onChange", { target: email, currentTarget: email });
assert.equal(typeof email.props.onChange, "function");
const consent = nodes().find((node) => node.getAttribute("role") === "checkbox");
assert.ok(consent);
await h.event(consent);
const form = nodes().find((node) => node.tagName === "FORM");
assert.ok(form);
await h.event(form, "onSubmit");
await h.idle();
assert.ok(button("验证并登录"));
assert.ok(calls.some((call) => call.body.includes("person@example.com")));
const slots = nodes().filter((node) => node.getAttribute("data-slot") === "input-otp-slot");
assert.equal(slots.length, 6);
const otp = nodes().find((node) => node.tagName === "INPUT" && node.getAttribute("autocomplete") === "one-time-code")
?? nodes().find((node) => node.tagName === "INPUT");
assert.ok(otp);
(otp as { value?: string }).value = "654321";
await h.event(otp, "onChange", { target: otp, currentTarget: otp });
await h.idle();
const filled = nodes().filter((node) => node.getAttribute("data-slot") === "input-otp-slot").map((node) => node.text).join("");
assert.equal(filled, "654321");
await h.event(nodes().find((node) => node.tagName === "FORM")!, "onSubmit");
await h.idle();
assert.deepEqual(assigned, ["/"]);
assert.deepEqual(h.errors, []);
} finally {
globalThis.fetch = previousFetch;
await h.close();
}
});