Most "demos" don't survive their first real user. The button breaks on Safari. The text overflows on the small screen. The API call times out and the page just sits there. Real engineering is the gap between "it worked once on my computer" and "it works for someone else, all week, even when things go wrong."
This project is that gap. Three disciplines: tests, states, accessibility. A week of silence after you ship.
You ship the URL to the named user. Then you stay quiet for a week. No live chat. No fixes-while-they-watch. They use it as if you weren't there. After the week, you ask: what worked? What didn't? What annoyed you?
Step by step
-
Set up Vitest properly.
Vitest is fast, easy, and uses the same syntax as Jest.
npm install -D vitest @vitest/ui jsdom. Thennpx vitest --uiopens a beautiful local dashboard. Real engineers run their tests on every save with--watch. You will too by the end of this project. -
Write at least 12 tests across 3 categories.
4 happy-path, 4 edge cases, 4 error states. Naming convention:
describe('functionName'), thenit('does the specific thing under specific condition'). The complete file is in the worked example below. -
Cover the 5 real edge cases your user will hit.
Edge cases aren't theoretical. They're: the user has no internet for 8 seconds. The API returns a 429. The user's input has weird characters. The user clicks the button 4 times in a row. The user's clock is wrong. List five real ones for your tool. Add tests for each.
-
Add the 4 real states: loading / done / empty / error.
For every state your tool can be in, ask: does the user know what's happening? Three states most kids forget: loading (something is happening), empty (nothing to show), error (something broke and here's what to do).
-
Make it accessible enough that a grandparent could use it.
Accessibility isn't a checklist for grown-ups. It's the cost of knowing your real users are not all 16-year-olds with perfect eyesight on the latest iPhone. Ten things that move the needle are in the worked example. Test with the keyboard alone. Test with VoiceOver / NVDA. Run Lighthouse — aim for 95+.
-
Add a privacy-respecting analytics layer.
You want to know: did anyone use it? Which buttons are clicked most? Did anyone hit an error? Without trackers, cookies, or anything your user would object to.
localStorage-only, owned by the user, viewable on demand. -
The week of silence.
Send the URL. Don't watch over their shoulder. Don't message them halfway through. Wait a week. After the week, ask three questions. Don't ask "did you like it?" — they'll lie. Ask: "What's the last thing you used it for? Was there a moment it didn't do what you wanted? When did you stop using it, if you stopped?" Pick three things and fix them. That's v1.1.
A complete worked example, every file
The Owen book picker, hardened. Vitest tests, four real states, accessibility upgrades, privacy analytics, debug overlay.
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { pickBook, formatSuggestion, sanitizeVibe, BookStore } from './picker.js';
describe('pickBook', () => {
it('returns a book from the requested vibe', () => {
const result = pickBook('weird-scifi', BookStore);
expect(result).toHaveProperty('title');
expect(result).toHaveProperty('author');
expect(BookStore['weird-scifi']).toContainEqual(result);
});
it('returns null for an unknown vibe (no crash)', () => {
expect(pickBook('cookbook', BookStore)).toBeNull();
});
it('returns null for an empty vibe pool', () => {
expect(pickBook('weird-scifi', { 'weird-scifi': [] })).toBeNull();
});
it('handles "surprise" by sampling all vibes', () => {
const all = Object.values(BookStore).flat();
for (let i = 0; i < 10; i++) {
const r = pickBook('surprise', BookStore);
expect(all).toContainEqual(r);
}
});
});
describe('formatSuggestion', () => {
it('shows title and author', () => {
const out = formatSuggestion({ title: 'Piranesi', author: 'Clarke', why: 'go.' });
expect(out).toContain('Piranesi');
expect(out).toContain('Clarke');
});
it('handles missing fields gracefully', () => {
const out = formatSuggestion({});
expect(out).not.toContain('undefined');
expect(out).not.toContain('null');
});
it('escapes HTML to prevent XSS', () => {
const out = formatSuggestion({ title: '', author: 'X', why: 'y' });
expect(out).not.toContain('