8.3 KiB
🧪 Introduction to Test-Driven-UI Development
Here’s an introduction to the TestDrive-UI development philosophy.
It explains how to develop UI components the TestDrive-UI way, why each tool is part of the stack, and links directly to their official projects.
“Design the test first — let the interface emerge”
🎯 What is TestDrive-UI?
TestDrive-UI is a lightweight, browser-first development scaffold for building interactive web components using a Test-Driven Development (TDD) workflow.
It provides a reproducible structure that’s simple enough for hobby projects, but robust enough for AI-assisted, agent-driven development loops.
Core idea: Every UI feature begins as a behavioral test — not a design or mockup. The implementation grows only to satisfy that test. The UI emerges naturally from verified expectations.
🧱 The Toolchain Overview
| Tool | Purpose | Why it’s used | Website |
|---|---|---|---|
| 🧩 Lit | Define Web Components with declarative rendering | Fast, framework-agnostic, minimal build overhead; lets you create reusable, encapsulated components | https://lit.dev |
| 🧪 Mocha | Test runner for JavaScript | Mature, flexible, CLI-friendly — ideal for writing descriptive, behavior-oriented tests (describe / it) |
https://mochajs.org |
| 💬 Chai | Assertion library | Clean, readable syntax for expectations (expect(value).to.equal(...)) |
https://www.chaijs.com |
| 🧠 JSDOM | Simulated DOM for Node | Lets you run DOM-based UI tests without a browser; deterministic and CI-friendly | https://github.com/jsdom/jsdom |
| ⚡ Vite | Development server & bundler | Instant hot-reloads and minimal config for web-component projects | https://vitejs.dev |
| 🧱 Storybook (optional) | Visual component sandbox | Lets you document, preview, and visually test each component in isolation | https://storybook.js.org |
| 🔬 Playwright (optional) | End-to-end browser testing | Adds full browser automation for real UI validation | https://playwright.dev |
Together, these tools form the TestDrive-UI loop:
Requirement → Test (Mocha+Chai) → Implementation (Lit) → Run (Vite) → Refine → Repeat
🧩 How the Development Flow Works
1. Define the Behavior
Write a short requirement statement or JSON spec describing what the component should do — not how it looks.
Example:
“When the user types in the input field, the greeting updates immediately.”
This requirement drives both test and implementation.
2. Write the Test First
Create a Mocha test file in src/components/<component-name>/<component>.test.js:
import "./hello-world.js";
describe("<hello-world>", () => {
it("updates the greeting when user types", async () => {
const el = document.createElement("hello-world");
document.body.appendChild(el);
const input = el.shadowRoot.querySelector("input");
input.value = "Agent";
input.dispatchEvent(new Event("input"));
await el.updateComplete;
const greeting = el.shadowRoot.querySelector(".greeting");
expect(greeting.textContent.trim()).to.equal("Hello, Agent!");
});
});
When you run npm test, this test will fail until you implement the behavior.
3. Implement Just Enough Code to Pass
Write the smallest possible component in Lit to satisfy the test:
import { LitElement, html, css } from "lit";
export class HelloWorld extends LitElement {
static properties = { name: { type: String } };
constructor() { super(); this.name = "World"; }
render() {
return html`
<div class="greeting">Hello, ${this.name}!</div>
<input type="text" .value=${this.name} @input=${this._onInput} />
`;
}
_onInput(e) { this.name = e.target.value; }
}
customElements.define("hello-world", HelloWorld);
Run tests again — they should now pass.
4. Refine, Extend, and Visualize
When a component works, visualize it:
npm run dev
Vite opens the browser instantly so you can adjust styling and layout.
Optionally, use Storybook to display multiple variants:
export default { title: "UI/Hello World" };
export const Default = () => `<hello-world></hello-world>`;
export const Named = () => `<hello-world name="Coulomb"></hello-world>`;
5. Iterate
Each new behavior (feature, bugfix, style rule, accessibility improvement) starts with a new test. The system evolves incrementally, each step verifiable by automation.
🧠 Why This Matters
| Principle | Benefit |
|---|---|
| TDD-first | Prevents UI drift and regression early. |
| Declarative UI (Lit) | Clean separation of state and template. |
| Deterministic Testing (JSDOM + Mocha) | Reproducible results without browser complexity. |
| Fast Iteration (Vite) | Keeps flow tight and interactive. |
| Optional Visual Layer (Storybook) | Communication and design documentation built in. |
🧩 Advanced Extensions
Once the base workflow feels solid, TestDrive-UI scales elegantly to more advanced cases:
- Shared reactive stores — implement central state management (see Tutorial 6).
- Persistence — save data using localStorage or IndexedDB (see Tutorial 7).
- Agent automation — use AI coding agents to generate and maintain tests automatically (see Tutorial 8).
- End-to-end testing — run full browser simulations via Playwright.
🔗 Official Tool Links
| Tool | Website |
|---|---|
| Lit | https://lit.dev |
| Mocha | https://mochajs.org |
| Chai | https://www.chaijs.com |
| JSDOM | https://github.com/jsdom/jsdom |
| Vite | https://vitejs.dev |
| Storybook | https://storybook.js.org |
| Playwright | https://playwright.dev |
🚀 Quick Start Recap
# Clone or unzip scaffold
npm install
# Run tests
npm test
# Start live preview
npm run dev
- Tests define behavior.
- Components evolve from tests.
- UIs emerge naturally from verified code.
TestDrive-UI isn’t a framework — it’s a method. It’s how you and your coding agents learn to reason about interfaces through evidence.
Start with our tutorials to get going.
xxx