swarm-ui: forms share one submit flow, result line and field column
useSubmit holds the idle, sending, done and error state and the request flow that six forms each wrote out; FormResult shows the success line and the problem panel; FormStack is the column the link, claude-login, inference and limits forms each styled by hand. The create-agent, link account, backend-env and agent-input forms use the submit flow; the link, claude-login, inference and limits forms use FormStack.
This commit is contained in:
parent
0e10473e6f
commit
811b23cd6b
1 changed files with 517 additions and 377 deletions
58
frontend/packages/swarm-ui/test/submit.test.mjs
Normal file
58
frontend/packages/swarm-ui/test/submit.test.mjs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// The request flow every form shares: a refusal becomes a problem, a failure
|
||||
// to send becomes a problem, a success parses its reply.
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import { submitOutcome } from "../src/ui/submit/submit.ts";
|
||||
|
||||
const problem = (status, body) =>
|
||||
new Response(JSON.stringify(body), {
|
||||
status,
|
||||
headers: { "content-type": "application/problem+json" },
|
||||
});
|
||||
|
||||
test("an ok reply is done, with nothing parsed by default", async () => {
|
||||
const out = await submitOutcome(
|
||||
async () => new Response(null, { status: 204 }),
|
||||
);
|
||||
assert.deepEqual(out, { status: "done", value: undefined });
|
||||
});
|
||||
|
||||
test("an ok reply is parsed into the done value", async () => {
|
||||
const out = await submitOutcome(
|
||||
async () => new Response(JSON.stringify({ node_id: 7 })),
|
||||
{ parse: async (r) => (await r.json()).node_id },
|
||||
);
|
||||
assert.deepEqual(out, { status: "done", value: 7 });
|
||||
});
|
||||
|
||||
test("a refusal carries the server's problem", async () => {
|
||||
const out = await submitOutcome(async () =>
|
||||
problem(409, { title: "conflict", detail: "already linked" }),
|
||||
);
|
||||
assert.equal(out.status, "error");
|
||||
assert.equal(out.problem.detail, "already linked");
|
||||
});
|
||||
|
||||
test("refine can reword a refusal by status", async () => {
|
||||
const out = await submitOutcome(async () => problem(404, {}), {
|
||||
refine: (r, p) =>
|
||||
r.status === 404 && !p.detail ? { ...p, detail: "no such agent" } : p,
|
||||
});
|
||||
assert.equal(out.status, "error");
|
||||
assert.equal(out.problem.detail, "no such agent");
|
||||
});
|
||||
|
||||
test("a request that throws is an error with the message", async () => {
|
||||
const out = await submitOutcome(async () => {
|
||||
throw new Error("offline");
|
||||
});
|
||||
assert.equal(out.status, "error");
|
||||
assert.match(out.problem.detail, /offline/);
|
||||
});
|
||||
|
||||
test("a parse that throws is an error, not a done", async () => {
|
||||
const out = await submitOutcome(async () => new Response("not json"), {
|
||||
parse: (r) => r.json(),
|
||||
});
|
||||
assert.equal(out.status, "error");
|
||||
});
|
||||
Loading…
Reference in a new issue