Watch
0
0
Fork
You've already forked hyperhive
0

swarm-ui: test the review try-out form's pure logic

The try-out page's checks and request body get tests under the
package's node runner: the repo check, a row's checks in their order,
a shared name, and the open-a-PR gate (repo, then each row in order,
then a shared name, with no PR number). Also the row a request sends,
and the row a loaded rule becomes.

Refs #5259
This commit is contained in:
atlas 2026-10-14 17:31:49 +02:00 • committed by mara
commit 36c3f38717

View file

@ -0,0 +1,132 @@
// The review try-out form's pure logic: the repo and row checks, the gate on
// opening a PR from the rows, and the request body each row becomes. Run by
// `npm test`, which Node runs with its built-in test runner and type
// stripping, so the `.ts` module is imported as it is.
import assert from "node:assert/strict";
import { test } from "node:test";
import {
draftFromRule,
draftProblem,
duplicateName,
hasTypedText,
prNumber,
repoProblem,
rowsProblem,
thresholdValue,
toBody,
} from "../src/pages/review-tryout/TryOutTypes.ts";
// A row ready to send, with `over` replacing any of its fields.
function row(over = {}) {
return {
key: 0,
name: "no-ads",
description: "No ads.",
polarity: "negative",
threshold: "80",
...over,
};
}
test("a repo is owner/name with forge-safe characters in each part", () => {
assert.equal(repoProblem("hyperhive/hyperhive"), null);
assert.equal(repoProblem(" o/r.name_x-1 "), null);
for (const bad of ["", "o", "o/", "/r", "o/r/x", "o/..", "./r", "o/r s"]) {
assert.match(repoProblem(bad), /owner\/name/, bad);
}
});
test("a row needs a name, then a description, then a whole 0-100 threshold", () => {
assert.equal(draftProblem(row()), null);
assert.match(draftProblem(row({ name: " " })), /a name/);
assert.match(
draftProblem(row({ name: " ", description: "" })),
/a name/,
"the name is checked first",
);
assert.match(
draftProblem(row({ description: " " })),
/no-ads needs a description/,
);
assert.match(
draftProblem(row({ description: "", threshold: "x" })),
/description/,
"the description is checked before the threshold",
);
for (const bad of ["", "101", "-1", "1.5", "x"]) {
assert.match(draftProblem(row({ threshold: bad })), /threshold/, bad);
}
assert.equal(draftProblem(row({ threshold: " 100 " })), null);
assert.equal(draftProblem(row({ threshold: "0" })), null);
});
test("two rows with one trimmed name are refused", () => {
assert.equal(duplicateName([row(), row({ name: "other" })]), null);
assert.match(
duplicateName([row(), row({ name: " no-ads " })]),
/two classifications are named no-ads/,
);
});
test("opening a PR is gated by the repo, then each row, then a shared name", () => {
const good = [row(), row({ name: "other" })];
assert.equal(rowsProblem("o/r", good), null);
// Each check on its own.
assert.match(rowsProblem("", good), /owner\/name/);
assert.match(rowsProblem("o/r", [row(), row({ name: "" })]), /a name/);
assert.match(rowsProblem("o/r", [row(), row()]), /two classifications/);
// The order: a bad repo wins over a bad row, and a bad row over a shared
// name.
assert.match(rowsProblem("o", [row({ name: "" })]), /owner\/name/);
assert.match(
rowsProblem("o/r", [row(), row({ threshold: "x" }), row()]),
/threshold/,
);
// Rows are checked in their order.
assert.match(
rowsProblem("o/r", [row({ description: "" }), row({ name: "" })]),
/no-ads needs a description/,
);
});
test("opening a PR needs no PR number, which a run does", () => {
assert.equal(prNumber(""), null);
assert.equal(rowsProblem("o/r", [row()]), null);
assert.equal(prNumber(" 7 "), 7);
assert.equal(prNumber("0"), null);
assert.equal(prNumber("7a"), null);
});
test("a row becomes the request's classification", () => {
assert.deepEqual(
toBody(
row({ name: " no-ads ", description: " No ads. ", threshold: " 60 " }),
),
{
name: "no-ads",
description: " No ads. ",
polarity: "negative",
threshold: 60,
},
);
assert.equal(thresholdValue("101"), null);
});
test("a loaded rule becomes a row that sends back the same rule", () => {
const rule = {
name: "no-ads",
description: "No ads.",
polarity: "negative",
threshold: 80,
};
const d = draftFromRule(rule, 3);
assert.deepEqual(d, { key: 3, ...rule, threshold: "80" });
assert.deepEqual(toBody(d), rule);
});
test("only a typed name or description counts as the user's work", () => {
assert.equal(hasTypedText([row({ name: " ", description: "" })]), false);
assert.equal(hasTypedText([row({ name: "", description: "x" })]), true);
});