mirror of
https://github.com/github/awesome-copilot.git
synced 2026-10-13 15:24:25 +00:00
96 lines
4.4 KiB
JavaScript
96 lines
4.4 KiB
JavaScript
// Tests for the element model: cleaning up loose input and picking readable text colors.
|
|
// Run `node --test` in the extension folder.
|
|
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import { COLORS, DARK_PALETTE, LIGHT_PALETTE, MAX_PEN_POINTS, diffOps, luminance, mergeOps, normalizeElement, normalizeElements, sameJson, staticPaint } from "./model.mjs";
|
|
|
|
const contrast = (a, b) => {
|
|
const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
|
|
return (hi + 0.05) / (lo + 0.05);
|
|
};
|
|
|
|
test("text on every solid color is readable in both themes", () => {
|
|
for (const [theme, palette] of [["light", LIGHT_PALETTE], ["dark", DARK_PALETTE]]) {
|
|
const paint = staticPaint(palette);
|
|
for (const color of COLORS) {
|
|
const ratio = contrast(paint(color, "onSolid"), paint(color, "solid"));
|
|
assert.ok(ratio >= 4.5, `${theme} ${color} is only ${ratio.toFixed(2)}:1`);
|
|
}
|
|
}
|
|
});
|
|
|
|
test("loose input is cleaned up, and arrows to missing shapes are dropped", () => {
|
|
const out = normalizeElements([
|
|
{ id: "a", type: "rect" },
|
|
{ id: "a", type: "circle", x: 200 },
|
|
{ type: "arrow", from: "a", to: "missing" },
|
|
{ type: "spaceship" },
|
|
null,
|
|
"rect",
|
|
]);
|
|
assert.deepEqual(out.map((e) => e.type), ["rect", "ellipse"]);
|
|
assert.equal(out[0].id, "a");
|
|
assert.notEqual(out[1].id, "a");
|
|
});
|
|
|
|
test("the ops from diffOps turn one list into the other", () => {
|
|
// A small random generator (MINSTD), so a failure can be run again.
|
|
let seed = 7;
|
|
const rand = (n) => {
|
|
seed = (seed * 48271) % 2147483647;
|
|
return seed % n;
|
|
};
|
|
const shape = (id) => normalizeElement({ id, type: "rect", x: rand(5) * 10, text: rand(2) ? "a" : "" });
|
|
for (let round = 0; round < 500; round++) {
|
|
const before = Array.from({ length: rand(8) }, (_, i) => shape(`e${i}`));
|
|
let after = before.filter(() => rand(4)).map((e) => (rand(3) ? e : shape(e.id)));
|
|
after.push(...Array.from({ length: rand(3) }, (_, i) => shape(`n${i}`)));
|
|
if (rand(2)) after = after.sort(() => rand(3) - 1);
|
|
const ops = diffOps(new Map(before.map((e) => [e.id, e])), after);
|
|
if (!ops) {
|
|
assert.deepEqual(after, before);
|
|
continue;
|
|
}
|
|
assert.deepEqual(mergeOps(before, ops), after);
|
|
// Only elements that changed are sent.
|
|
for (const el of ops.upserts) assert.ok(!sameJson(el, before.find((e) => e.id === el.id)));
|
|
}
|
|
});
|
|
|
|
test("sameJson compares data, not key order", () => {
|
|
assert.ok(sameJson({ a: 1, b: [1, { c: 2 }] }, { b: [1, { c: 2 }], a: 1 }));
|
|
assert.ok(!sameJson({ a: 1 }, { a: 1, b: 2 }));
|
|
assert.ok(!sameJson({ a: 1, c: 2 }, { a: 1, b: 2 }));
|
|
assert.ok(!sameJson([1, 2], { 0: 1, 1: 2 }));
|
|
assert.ok(!sameJson([[1, 2]], [[1, 3]]));
|
|
assert.ok(!sameJson(null, {}));
|
|
});
|
|
|
|
test("a stroke with too many points keeps both its ends", () => {
|
|
const points = Array.from({ length: 3 * MAX_PEN_POINTS }, (_, i) => [i, i % 7]);
|
|
const pen = normalizeElement({ type: "pen", points });
|
|
assert.equal(pen.points.length, MAX_PEN_POINTS);
|
|
assert.deepEqual(pen.points[0], points[0]);
|
|
assert.deepEqual(pen.points.at(-1), points.at(-1));
|
|
// Spread evenly, and in order.
|
|
assert.ok(pen.points.every((p, i) => i === 0 || p[0] > pen.points[i - 1][0]));
|
|
assert.equal(normalizeElement({ type: "pen", points: points.slice(0, 10) }).points.length, 10);
|
|
});
|
|
|
|
test("any one element, however big, fits in what a page can send as it closes", () => {
|
|
// Browsers only deliver keepalive requests after the page is gone, and refuse them past 64 KiB
|
|
// in all (see flushBeacon in public/sync.js).
|
|
const far = -999999.94;
|
|
const pen = normalizeElement({ id: "p".repeat(64), type: "pen", color: "#123456", points: Array.from({ length: 3 * MAX_PEN_POINTS }, () => [far, far]) });
|
|
assert.equal(pen.points.length, MAX_PEN_POINTS);
|
|
assert.deepEqual(pen.points[0], [-999999.9, -999999.9]);
|
|
// A lone surrogate is written as a 6 byte escape, the most any one character of a label takes.
|
|
const text = "\ud800".repeat(10000);
|
|
const labelled = ["rect", "ellipse", "diamond", "cylinder", "text", "arrow"].map((type) =>
|
|
normalizeElement({ id: type[0].repeat(64), type, text, from: "f".repeat(64), to: "g".repeat(64) }));
|
|
for (const el of [pen, ...labelled]) {
|
|
const body = JSON.stringify({ clientId: "c".repeat(64), drawingId: "d".repeat(64), seq: Number.MAX_SAFE_INTEGER, ops: { upserts: [el], deletes: [] } });
|
|
assert.ok(Buffer.byteLength(body) <= 64 * 1024, `${el.type}: ${Buffer.byteLength(body)} bytes`);
|
|
}
|
|
});
|