Skip to content

test(ci): build a real application, and read back the page it serves - #275

Open
evens-stone wants to merge 2 commits into
mainfrom
test/lab-app-smoke
Open

test(ci): build a real application, and read back the page it serves#275
evens-stone wants to merge 2 commits into
mainfrom
test/lab-app-smoke

Conversation

@evens-stone

Copy link
Copy Markdown
Contributor

Closes #101.

Ce que le dépôt ne testait pas

Toutes les barrières s'arrêtaient à la frontière du paquet. build:ci exclut explicitement @stone-js/lab-*, test:lab ne lance que les tests unitaires des applications du lab, et la suite de chaque paquet teste ses propres modules. Donc rien n'exécutait jamais stone build sur une application, et rien ne demandait jamais une page à une application construite.

Le prix a été payé : une page rendue côté serveur a livré le marqueur littéral <!--env-js--> à la place du script d'environnement public, sur le chemin SSR et sur le chemin SSG, aussi longtemps que le marqueur a existé. Tous les tests unitaires passaient pendant ce temps : le défaut vivait dans la seule étape qu'aucun n'atteignait, une application construite qui répond à une requête.

Ce que fait cette barrière

scripts/smoke-lab.mjs parcourt cette étape. Il construit quatre applications du lab avec les paquets en cours de test, puis relit ce que chacune sert :

Application Ce qui est lu Ce qui est vérifié
lab-spa (CSR) dist/index.html aucun marqueur de build ne survit, le script d'environnement est lié
lab-ssg les deux pages générées idem, plus le balisage déjà présent dans le document
lab-ssr la réponse HTTP du serveur démarré idem, sur ce qu'un navigateur reçoit vraiment
lab-rest-api GET /tasks 200 et le JSON attendu

Une vingtaine de secondes. Le même script tourne en local par pnpm run smoke:ci, et il est dans pnpm run verify, donc les deux ne peuvent pas diverger.

Les applications sont celles du lab parce qu'elles sont membres de l'espace de travail et résolues par workspace:*. Un starter s'installe depuis le registre : en construire un testerait ce qui est déjà publié, pas le changement en cours.

Vérifié contre le défaut qu'elle garde

Le correctif retiré, six vérifications échouent : les deux pages SSG et la réponse SSR (no build marker survives, links the public environment script). Le correctif en place, tout passe.

Notes

🤖 Generated with Claude Code

evens-stone and others added 2 commits September 5, 2026 02:02
… script

An SSR document served `<!--env-js-->` verbatim to every visitor while the built
`index.html` next to it carried `<script src="/env/environments.js">`. So
`window.process.env` was empty on a page rendered by the server and populated on
the same page rendered by the client, and nothing said so.

The pipeline says why without needing a build. The server file middleware (6) reads
`dist/.stone/tmp/index.html` and freezes it into the server bundle; the bundler (7)
seals it; the cleaner (8) moves that same file to `dist/index.html`; and the public
env middleware (9) replaces the marker there, on a file the server never reads
again. The client got the script, the server kept the comment.

The injection happens where the template is captured now, before it is frozen into
the bundle, and it is one function used by the three places that do it, because
three hand-written copies of one replacement is how one of them stayed wrong
through a release.

The end-to-end run on a real SSR application with a `.env.public` is the one check
I could not perform; the pipeline order and a unit test are what this rests on.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Closes #101.

Every gate in this repository stopped at the package boundary. `build:ci` excludes
`@stone-js/lab-*`, `test:lab` runs only their unit tests, and each package's suite tests
its own modules. So nothing ever ran `stone build` on an application, and nothing ever
asked a built application for a page.

The gap had a price. A server-rendered page shipped the literal `<!--env-js-->` marker in
place of the public environment script, on the SSR path and on the SSG path, for as long
as the marker existed. Every unit test passed the whole time: the defect lived in the one
step none of them reached, a built application answering a request.

`scripts/smoke-lab.mjs` walks that step. It builds four lab applications with the packages
under test, then reads back what each one serves: a CSR page and two generated SSG pages
off disk, an SSR response fetched over HTTP from the booted server, and a JSON route from
the API application. It asserts what a browser would receive, not what a mock returned:
no build marker survives, the public environment script is linked, the markup is already
in the document where it should be. Roughly twenty seconds.

The applications are the lab ones because they are workspace members resolved through
`workspace:*`. A starter installs from the registry, so building one would test what is
already published rather than the change at hand.

Checked against the defect it guards: with the fix reverted, six checks fail, the two SSG
pages and the SSR response. With it in place, every check passes.

The three frontend lab applications gain a committed `.env.public`, without which the
environment script has nothing to generate and the assertion would pass vacuously. The
values are public by construction, compiled into the browser bundle, so a fixture is the
honest place for them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@evens-stone evens-stone added type: chore Housekeeping, no user-facing change area: frontend type: dx labels Sep 5, 2026
@sonarqubecloud

sonarqubecloud Bot commented Sep 5, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: frontend type: chore Housekeeping, no user-facing change type: dx

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci: add a scaffold smoke test (npm create @stone-js)

1 participant