|
| 1 | +// The install command is the site's single most copy-pasted string, and it is |
| 2 | +// rendered in two places by two different mechanisms -- the homepage builds |
| 3 | +// HTML as a string, the rest of the site is JSX. That is exactly the shape that |
| 4 | +// lets one copy drift while the other stays right, so these pin the command |
| 5 | +// itself, both placements, and the flags that make piping to `sh` safe. |
| 6 | +import { readFileSync } from "node:fs"; |
| 7 | +import { join } from "node:path"; |
| 8 | +import { describe, expect, it } from "vitest"; |
| 9 | + |
| 10 | +import { |
| 11 | + INSTALL_COMMAND, |
| 12 | + INSTALL_SCRIPT_PATH, |
| 13 | + renderInstallCommand, |
| 14 | +} from "../src/lib/install-command"; |
| 15 | +import { renderPageMarkup } from "../src/lib/page-markup"; |
| 16 | + |
| 17 | +const repoRoot = join(__dirname, ".."); |
| 18 | + |
| 19 | +describe("the install command itself", () => { |
| 20 | + it("is the exact one-liner", () => { |
| 21 | + expect(INSTALL_COMMAND).toBe("curl -fsSL https://logicsrc.com/install.sh | sh"); |
| 22 | + }); |
| 23 | + |
| 24 | + it("keeps the flags that make piping into a shell safe", () => { |
| 25 | + // -f so an HTTP error page is never piped into sh, -L so a redirect does |
| 26 | + // not silently truncate the install. Dropping either is the bug this pins. |
| 27 | + expect(INSTALL_COMMAND).toMatch(/curl\b[^|]*-[a-zA-Z]*f/); |
| 28 | + expect(INSTALL_COMMAND).toMatch(/curl\b[^|]*-[a-zA-Z]*L/); |
| 29 | + }); |
| 30 | + |
| 31 | + it("points at a script that is actually published", () => { |
| 32 | + // public/ is served at the site root, so this is the URL in the command. |
| 33 | + const script = readFileSync(join(repoRoot, "public", INSTALL_SCRIPT_PATH), "utf8"); |
| 34 | + expect(script.startsWith("#!/bin/sh")).toBe(true); |
| 35 | + // The command says `| sh`; a bash shebang here would make that a lie. |
| 36 | + expect(script).toContain(INSTALL_COMMAND); |
| 37 | + }); |
| 38 | +}); |
| 39 | + |
| 40 | +describe.each(["hero", "rail"] as const)("the %s placement", (variant) => { |
| 41 | + const html = renderInstallCommand(variant); |
| 42 | + |
| 43 | + it("shows the command", () => { |
| 44 | + expect(html).toContain(INSTALL_COMMAND); |
| 45 | + }); |
| 46 | + |
| 47 | + it("offers a copy button carrying the same text that is on screen", () => { |
| 48 | + expect(html).toContain(`data-copy="${INSTALL_COMMAND}"`); |
| 49 | + // A button whose clipboard payload differs from the visible command is |
| 50 | + // worse than no button, so the two are asserted against one constant. |
| 51 | + const shown = html.match(/<code[^>]*>([^<]+)<\/code>/)?.[1]; |
| 52 | + const copied = html.match(/data-copy="([^"]+)"/)?.[1]; |
| 53 | + expect(shown).toBe(copied); |
| 54 | + }); |
| 55 | + |
| 56 | + it("is a real button, reachable by keyboard and labelled", () => { |
| 57 | + expect(html).toContain('type="button"'); |
| 58 | + expect(html).toContain('aria-label="Copy the install command"'); |
| 59 | + }); |
| 60 | +}); |
| 61 | + |
| 62 | +describe("placement on the site", () => { |
| 63 | + const home = renderPageMarkup(); |
| 64 | + |
| 65 | + it("puts the loud version in the homepage hero", () => { |
| 66 | + expect(home).toContain('class="install-cta"'); |
| 67 | + // Above the fold means before the first content band, not merely present. |
| 68 | + expect(home.indexOf("install-cta")).toBeLessThan(home.indexOf('class="band"')); |
| 69 | + }); |
| 70 | + |
| 71 | + it("also carries the compact version in the chrome", () => { |
| 72 | + expect(home).toContain('class="install-rail"'); |
| 73 | + }); |
| 74 | + |
| 75 | + it("keeps the compact one out of the way -- inside the rail, above the nav", () => { |
| 76 | + const rail = home.indexOf('class="install-rail"'); |
| 77 | + expect(rail).toBeGreaterThan(home.indexOf('class="rail"')); |
| 78 | + expect(rail).toBeLessThan(home.indexOf("<nav")); |
| 79 | + }); |
| 80 | + |
| 81 | + it("renders the command twice and no more", () => { |
| 82 | + expect(home.split(INSTALL_COMMAND).length - 1).toBe(4); // 2 placements x (code + data-copy) |
| 83 | + }); |
| 84 | +}); |
0 commit comments