- Unit and functional tests live next to the file they test, named after it (e.g.
permissions.test.tsalongsidepermissions.ts). - Functional tests live under
apps/host/tests/functional/(resolution, loading, performance specs driven in-process against the preview server). - E2E tests live under
apps/host/tests/e2e/(truapi.spec.tsexercises the full truapi surface against a realhost-playground.dotbuild). - Tests are user stories. Name each test as a user story:
As a <role>, I <action> and <outcome>for behaviour, orAs a <role>, <observable property>for invariants. - Structure with Given / When / Then. Every multi-step test body uses
// Given,// When,// Thencomments to separate setup, action, and assertions.
test("As a user using per-product smoldot, the host must only spawn one instance of the light client", async ({
page,
}) => {
// Given
await setBackend(page, "smoldot-direct");
await mockProtocolIframe(page, successfulResolveResponse("bafyfake..."));
const workerUrls: string[] = [];
page.on("worker", (w) => {
workerUrls.push(w.url());
});
// When
await page.goto(HOST_URL, { waitUntil: "domcontentloaded" });
await page.waitForTimeout(5_000);
// Then
const hostShellOrigin = `http://${DOMAIN}.localhost:${PORT}`;
const hostShellSmoldotWorkers = workerUrls.filter(
(url) => url.startsWith(hostShellOrigin) && url.includes("smoldot_worker"),
);
expect(hostShellSmoldotWorkers).toEqual([]);
});Good documentation starts with a single, clear sentence. Everything else comes after a newline.
- Lead with one sentence. The first line of any doc comment should explain what the thing does, not how. Additional context goes after a blank line.
- Don't restate the code. If the function signature already tells the story, don't repeat it in prose. Document why, not what.
- Use examples. A short usage example is worth more than a paragraph of explanation.
- Link to related items. Help readers navigate. Reference related functions, types, or modules directly rather than describing them.
- Think about context. If you're explaining too many foreign concepts to document one function, the API design may need work.
- No code section separators. Don't use
// -----------or similar decorative dividers to split sections within a file. Let the code structure speak for itself. - No em-dashes, semicolons, prose-conjunction
+, or Unicode arrows (→,←,↔). Rewrite the sentence. Two short sentences read better than one long one with a dash, and arrows belong in diagrams (where->is fine if it's a real arrow, not a stand-in for "becomes" or "then"). - No external spec citations in code comments. Don't write "per RFC 0001" or "see EIP-137" inside a comment. Explain the rule itself. If a reader needs the spec, the commit message and the PR description are the right place. Code comments stand alone.
- No "on-chain" in prose. Say "network" or "remote" instead. The host already knows the data sits on a chain. Calling it "the network value" reads naturally; "the on-chain value" reads as crypto jargon.
/** Resolve a `.dot` label to its IPFS CID via the dotNS contract. */
export async function resolveLabel(label: string): Promise<Cid | null> {- Start with a single-sentence JSDoc comment.
- Add parameter/return descriptions only when the types aren't self-explanatory.
- For modules, put a block comment at the top of the file explaining the purpose and key design decisions.
/**
* Two-build, per-product subdomain bridge.
*
* The host shell at name.dot.li resolves the label, then iframes
* name.app.dot.li with the resolved CID threaded through the URL contract. Each product gets a distinct origin so SW, storage, and auth stay isolated across products.
*/- Start with a single, clear sentence. Follow up after a newline if needed.
- Don't repeat what the code already says.
- Use examples and links generously.
- If documenting something requires explaining too many unrelated concepts, reconsider the API design.