testRolesAndHostProtocols

tcmts.cli.test.e2e.react.testRolesAndHostProtocols · #hbgumtxz · term

A package's manifest gives its definitions roles, known by their hashes: a component with the stylesheet role is linked to as <Stylesheet> is (the browser is sent the file, not its text). And it says the version of tcm's host protocol its code speaks: a tcm that doesn't serve that version won't build an app using it.

import { okIn, tcmIn, tempDir } from "#codebase/tcmts/cli/test/e2e/harness";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";

export const testRolesAndHostProtocols = () => {
  const dir = tempDir("roles");
  const tcm = (...args: string[]) => okIn(dir, ...args);
  const write = (file: string, text: string) => fs.writeFileSync(path.join(dir, file), text);
  tcm("init");
  fs.rmSync(path.join(dir, "scratch.ts"));
  write("styles.css", ".app { color: rebeccapurple; }\n");
  tcm("add", "styles.css", "--into", "site");
  const ui = (host: number) =>
    `// tcm: namespace ui\nexport const manifest = { name: "ui", npm: false, host: ${host}, roles: { Sheet: "stylesheet" } };\n/** Its look, as text or as the file it's linked to. */\nexport const Sheet = ({ css }: { css: string }) => <style>{css}</style>;\n`;
  write("ui.tsx", ui(2));
  tcm("add", "ui.tsx");
  write(
    "site.tsx",
    `// tcm: namespace site\nimport { useState } from "react";\nimport { styles } from "#codebase/site";\nimport { Sheet } from "#codebase/ui";\nexport const App = () => {\n  const [n, setN] = useState(0);\n  return <div className="app"><Sheet css={styles} /><button onClick={() => setN(n + 1)}>{n}</button></div>;\n};\n`,
  );
  tcm("add", "site.tsx");

  // a host protocol this tcm doesn't serve: not built
  const refused = tcmIn(dir, "build", "site.App", "--static", "out");
  assert.notEqual(refused.status, 0);
  assert.match(
    refused.out,
    /ui \(ui\) speaks version 2 of tcm's host protocol, and this tcm serves 1: use a tcm that serves it/,
  );

  // one it serves: built, the stylesheet given to the role's component sent as a file the browser links to
  write("ui.tsx", ui(1));
  tcm("update", "ui.tsx");
  tcm("build", "site.App", "--static", "out");
  const assets = path.join(dir, "out", "_app", "assets");
  const files = fs.readdirSync(assets);
  const js = files
    .filter((f) => f.endsWith(".js"))
    .map((f) => fs.readFileSync(path.join(assets, f), "utf8"));
  assert.ok(
    js.some(
      (t) =>
        /styles-[a-z2-7]{8}\.css, linked to \*\//.test(t) || /styles\.css, linked to \*\//.test(t),
    ),
    files.join(", "),
  );
  assert.ok(
    !js.some((t) => t.includes("rebeccapurple")),
    "the browser's code holds no stylesheet text",
  );
  const css = files.find((f) => /^styles-[a-z2-7]{8}\.css$/.test(f));
  assert.ok(css, files.join(", "));
  assert.match(fs.readFileSync(path.join(assets, css!), "utf8"), /rebeccapurple/);
}

uses