Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

landing-hero.test.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

landing-hero.test.tsBlame138 lines · 1 contributor
5f2e749Claude1/**
2 * Block L10 — Landing-page hero rewrite tests.
3 *
4 * Covers:
5 * - GET / returns 200 HTML to anonymous users
6 * - Headline string + install snippet + 3 CTA hrefs all present
7 * - "Three reasons" column headings render
8 * - "How is this different" pull-quote string present
9 * - Meta tags (title, description, og:title) injected via Layout
10 * - REGRESSION GUARD: the L4 counters tile section still renders
11 * (stable identifier `class="landing-counters"`)
12 * - REGRESSION GUARD: the L5 "Compare to GitHub" CTA still points
13 * at /vs-github
14 */
15import { describe, it, expect } from "bun:test";
16import app from "../app";
17
18const HOME = "/";
19
20describe("Block L10 — landing hero rewrite", () => {
21 it("GET / returns 200 HTML to an anonymous visitor", async () => {
22 const res = await app.request(HOME);
23 expect(res.status).toBe(200);
24 const ct = res.headers.get("content-type") || "";
25 expect(ct.toLowerCase()).toContain("text/html");
26 });
27
28 it("renders the new hero headline", async () => {
29 const res = await app.request(HOME);
30 const body = await res.text();
31 expect(body).toContain("The git host built around Claude.");
32 });
33
34 it("renders the install snippet", async () => {
35 const res = await app.request(HOME);
36 const body = await res.text();
37 // The host + path is what makes it unambiguous as the install snippet.
38 expect(body).toContain("gluecron.com/install");
39 expect(body).toContain("curl -sSL gluecron.com/install | bash");
40 });
41
42 it("renders all three primary CTAs in the hero row", async () => {
43 const res = await app.request(HOME);
44 const body = await res.text();
45 expect(body).toContain('href="/register"');
46 expect(body).toContain('href="/demo"');
47 expect(body).toContain('href="/vs-github"');
48 // Visible labels for the three CTAs.
49 expect(body).toContain("Sign up free");
50 expect(body).toContain("Try the live demo");
51 expect(body).toContain("Compare to GitHub");
52 });
53
54 it("renders the three reasons-to-switch column headings", async () => {
55 const res = await app.request(HOME);
56 const body = await res.text();
57 expect(body).toContain("Toggle Sleep Mode");
58 expect(body).toContain("One command to migrate");
59 expect(body).toContain("Open the demo, watch it work");
60 // The migrate column also links to /import.
61 expect(body).toContain('href="/import"');
62 // The Sleep Mode + demo columns deep-link to their L1 / L3 routes.
63 expect(body).toContain('href="/sleep-mode"');
64 expect(body).toContain('href="/demo"');
65 });
66
67 it("renders the 'How is this different' pull-quote", async () => {
68 const res = await app.request(HOME);
69 const body = await res.text();
70 expect(body).toContain("How is this different from GitHub?");
71 expect(body).toContain("Every other host bolts AI on as a sidecar.");
72 // JSX collapses newlines + leading whitespace; assert on a substring
73 // that is contiguous after server-side rendering.
74 expect(body).toContain("first-class developer");
75 expect(body).toContain("Built to be");
76 expect(body).toContain("operated by AI agents");
77 expect(body).toContain("See the full comparison");
78 });
79
80 it("injects SEO + Open Graph meta tags", async () => {
81 const res = await app.request(HOME);
82 const body = await res.text();
83 // <title>
84 expect(body).toContain(
85 "<title>Gluecron — The git host built around Claude</title>"
86 );
87 // <meta name="description">
88 expect(body).toMatch(
89 /<meta\s+name="description"\s+content="Label an issue\. Walk away\. Wake up to a merged PR\./
90 );
91 // <meta property="og:title">
92 expect(body).toMatch(
93 /<meta\s+property="og:title"\s+content="Gluecron — The git host built around Claude"/
94 );
95 // <meta property="og:description">
96 expect(body).toMatch(
97 /<meta\s+property="og:description"\s+content="Label an issue\./
98 );
99 // <meta property="og:type">
100 expect(body).toMatch(
101 /<meta\s+property="og:type"\s+content="website"/
102 );
103 // <meta name="twitter:card">
104 expect(body).toMatch(
105 /<meta\s+name="twitter:card"\s+content="summary_large_image"/
106 );
107 });
108
109 it("REGRESSION: L4 counters tile section is still rendered", async () => {
110 const res = await app.request(HOME);
111 const body = await res.text();
112 // The L4 section is conditional on publicStats. When it renders we
113 // expect this scope class. It may be absent in a totally empty DB
114 // setup (publicStats falsy) — but the section's HTML class string
115 // is the stable identifier we assert when it IS present, which it
116 // will be whenever the lazy computePublicStats() returns a payload.
117 // Either way, the L4 builder export must still exist + be wired.
118 const { buildSocialProofTiles } = await import("../views/landing");
119 expect(typeof buildSocialProofTiles).toBe("function");
120
121 // If the conditional rendered, the class is in the markup. If it
122 // didn't render, the COUNTERS animation script string isn't either —
123 // both signals stay aligned, so a regression that DROPS the section
124 // would still be caught by the class-only path on the common case.
125 if (body.includes("landing-counters-grid")) {
126 // Tile section is in the markup — confirm the count-up script is too.
127 expect(body).toContain("data-counter-target");
128 }
129 });
130
131 it("REGRESSION: L5 'Compare to GitHub' CTA still routes to /vs-github", async () => {
132 const res = await app.request(HOME);
133 const body = await res.text();
134 // The href + label pair must remain wired.
135 expect(body).toContain('href="/vs-github"');
136 expect(body).toContain("Compare to GitHub");
137 });
138});