home / client / test / catalog.test.mjs
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// loadCatalog's observable behaviour over 35 documents, catText across the
// three languages, and the card markup social's presence badges select against.
import test from "node:test";
import assert from "node:assert/strict";
import { boot, h, serialize, vectors } from "./harness.mjs";

const { lib } = await boot();
const v = vectors("catalog");
const ct = vectors("cat-text");
const cards = vectors("cards");

test("loadCatalog replays every recorded document", async () => {
  const warns = [];
  const realWarn = console.warn;
  const results = [];
  for (const c of v.script) {
    globalThis.fetch = async () => {
      if (c.throws) throw new Error("offline");
      if (c.status) return { ok: false, status: c.status };
      if (c.badJson) return { ok: true, status: 200, json: async () => { throw new Error("bad json"); } };
      return { ok: true, status: 200, json: async () => c.doc };
    };
    const seen = [];
    console.warn = (...a) => seen.push(a[0]);
    let got;
    try {
      got = { ok: JSON.parse(JSON.stringify(await lib.loadCatalog())) };
    } catch (e) {
      got = { threw: String(e.message ?? e) };
    }
    console.warn = realWarn;
    results.push(got);
    warns.push(seen);
  }
  console.warn = realWarn;

  v.script.forEach((c, i) => {
    // the recorded `fellBackToSnapshot` flag is derived, not an input
    const want = { ...v.out[i] };
    delete want.fellBackToSnapshot;
    assert.deepEqual(results[i], want, `case ${i}: ${c.label}`);
    assert.deepEqual(warns[i], v.warnings[i], `case ${i} warnings: ${c.label}`);
  });
});

test("an entry with no i18n keeps NO i18n key at all in the copy", () => {
  // {...a, i18n: undefined} left no key behind in JSON.stringify; the port
  // builds the copy with Object.assign + one unchecked-set of js/undefined, so
  // the same must hold — a `null` here would change the serialized catalog.
  const i = v.script.findIndex((s) => s.label === "missing-optional-lb");
  assert.ok(!("i18n" in v.out[i].ok.apps[0]));
  const entry = lib.validate(v.script[i].doc).apps[0];
  assert.equal(JSON.stringify(entry), JSON.stringify(v.out[i].ok.apps[0]));
});

test("the entry copy keeps its 11-12 keys in source order (the #js-at-nine trap)", () => {
  // catalog entries are wider than eight fields, so a #js/js-obj literal would
  // have emitted them in hash order. Compare the serialized key sequence.
  const doc = {
    v: 1,
    apps: [{
      id: "a", name: "N", host: "h.example", kind: "game", tagline: "t", description: "d",
      tags: ["x"], accent: "rose", glyph: "chat", status: "new",
      lb: { g: "g", maxScore: 9 }, glyphSvg: "<svg/>",
      i18n: { ro: { tagline: "r" } },
    }],
  };
  const got = lib.validate(doc).apps[0];
  assert.deepEqual(Object.keys(got), Object.keys(doc.apps[0]));
  assert.equal(Object.keys(got).length, 13);
});

test("catText across en/ro/hu", () => {
  for (const lang of ct.script.langs) {
    lib.setLang(lang);
    const got = ct.script.entries.map((e) => [lib.catText(e, "tagline"), lib.catText(e, "description")]);
    assert.deepEqual(got, ct.out[lang], `lang ${lang}`);
  }
  lib.setLang("en");
});

test("renderCatalog emits the historical card markup, per language", () => {
  for (const lang of ["en", "ro", "hu"]) {
    lib.setLang(lang);
    const root = h("div", { class: "apps" });
    lib.renderCatalog(root, cards.script);
    assert.equal(serialize(root), cards.out[lang], `cards in ${lang}`);
  }
  lib.setLang("en");
});

static mirror of HEAD · about · clone: git clone https://git.ardegazu.ro/home.git