Testing
Streak.js projects use bun:test, the test runner built into Bun. No extra packages are required.
Setup
Bun discovers test files automatically. Place them alongside your source code or in a dedicated tests/ directory:
src/
handlers/
HomeDataHandler.ts
HomeDataHandler.test.ts ← test file
helpers/
colors.ts
colors.test.ts
Run all tests:
bun test Run a specific file:
bun test src/handlers/HomeDataHandler.test.ts Testing Data Handlers
Data handlers are async functions that return plain objects. Import the handler, call it, and assert the shape of the return value.
// src/handlers/HomeDataHandler.test.ts
import { describe, test, expect, beforeAll } from "bun:test";
import getHomeData from "./HomeDataHandler";
describe("HomeDataHandler", () => {
let data: Record<string, any>;
beforeAll(async () => {
data = await getHomeData();
});
test("returns status 200", () => {
expect(data.status).toBe(200);
});
test("HelloBanner has a heading", () => {
expect(data.HelloBanner).toBeDefined();
expect(typeof data.HelloBanner.heading).toBe("string");
expect(data.HelloBanner.heading.length).toBeGreaterThan(0);
});
test("PageHead has a non-empty title", () => {
expect(data.PageHead?.title).toBeTruthy();
});
}); Testing Patterns
Handler Shape
Verify every key the sitemap expects is present and has the correct type:
test("returns all required widget keys", () => {
const requiredKeys = ["PageHead", "HelloBanner", "HelloMessage"];
for (const key of requiredKeys) {
expect(data[key]).toBeDefined();
}
}); Non-Empty Strings
Guard against empty strings that would render blank content:
test("heading is a non-empty string", () => {
expect(typeof data.HelloBanner.heading).toBe("string");
expect(data.HelloBanner.heading.length).toBeGreaterThan(0);
}); Hex Color Values
If your handler returns color values, validate the format:
test("accentColor is a valid hex color", () => {
const hex = /^#[0-9a-fA-F]{6}$/;
expect(data.HelloBanner.accentColor).toMatch(hex);
}); ID Uniqueness
If the handler returns arrays with id fields, verify uniqueness:
test("article IDs are unique", () => {
const ids = data.ArticleList.items.map((item: any) => item.id);
expect(new Set(ids).size).toBe(ids.length);
}); Testing Widget Helpers
Widgets are stateless TSX components rendered at build time. You do not need DOM tests — Streak renders them to static HTML strings.
However, if a widget contains pure helper logic (formatting, calculation, data transformation), extract it into a separate file and test it independently:
// src/helpers/colors.ts
export const hexToRgb = (hex: string): [number, number, number] | null => {
const match = hex.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);
if (!match) return null;
return [parseInt(match[1], 16), parseInt(match[2], 16), parseInt(match[3], 16)];
}; // src/helpers/colors.test.ts
import { describe, test, expect } from "bun:test";
import { hexToRgb } from "./colors";
describe("hexToRgb", () => {
test("converts valid hex to RGB tuple", () => {
expect(hexToRgb("#ff8800")).toEqual([255, 136, 0]);
});
test("returns null for invalid input", () => {
expect(hexToRgb("not-a-color")).toBeNull();
});
}); What You Do Not Need to Test
- Widget JSX rendering — widgets produce static HTML at build time. The build itself is the test. If it builds, the HTML is correct.
- Script functions — these are serialized to strings and run in the browser. They cannot be unit-tested with
bun:test. Verify them manually in the browser. - Tailwind classes — class names are strings applied at build time. Tailwind compilation is tested by the CSS build step.
Focus your test effort on data handlers and extracted helper logic — these are the parts most likely to break when upstream data changes.