82 lines
3.6 KiB
TypeScript
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();
|
|
}
|
|
});
|