Now that AI is generating a big portion of our frontend code, speed is no longer the main bottleneck.
Confidence is.
We’ve seen this before: when teams wanted to move fast, the real enabler wasn’t “more code” — it was having a solid testing strategy that allowed safe refactoring and iteration.
That hasn’t changed. If anything, it’s more important now.
In previous posts, I talked about the TWD philosophy, but one idea is key here:
Test what you own. Mock what you don’t.
With this mindset, TWD (Test While Developing) lets you create deterministic UI tests, where you fully control the environment, simulate any scenario, and avoid flaky behavior.
The Problem: Allow AI Know Your Project
AI can write tests… but not your tests.
It doesn’t know:
- how your project is structured
- what should be mocked
- how your auth works
- what “good tests” look like in your codebase
So even if it generates tests, they often:
- don’t follow your patterns
- mock the wrong things
- miss important flows
The Solution: TWD + Skills
To solve this, we introduced TWD skills inside a Claude Code plugin.
These skills give the AI:
- context about your project
- rules to follow
- patterns to reuse
So instead of generic tests, you get tests that actually fit your codebase.
/twd:setup — The Most Important First Step
Everything starts here:
/twd:setup
This is an interactive setup that analyzes your project and creates:
.claude/twd-patterns.md
This file becomes the source of truth for how tests should be written.
What /twd:setup Does
- Detects your framework, Vite config, entry points, CSS setup
- Asks about:
- auth & permissions
- API structure
- third-party dependencies
- state management
- Generates a project-specific testing config
- Optionally installs and configures TWD for you
How It Looks in Practice
You just run:
/twd:setup
And the agent starts understanding your project:
👁 prompt using twd:setup skill
It will ask the right questions to understand how your app works and detect your frontend configuration:
- What should be mocked?
- How does auth behave?
- Where are your services?
Once completed, it generates your config file:
.claude/twd-patterns.md
This is critical — every future test uses this as context.
If something is outdated, it will even suggest improvements:
👁 Asking to improve current configuration
And when it's done, it guides you to the next step:
👁 Message recomendating the next step using the twd-tester skill
Why This Matters
Without this step, AI-generated tests are:
- generic
- inconsistent
- sometimes useless
With /twd:setup, tests become aligned with your architecture.
The plugin also includes skills for:
- automatic test generation
- CI setup
- test quality analysis
- test gap detection
- flow visualisation
We’ll cover those in future posts.
Final Thought
AI can make you faster.
But tests are what let you keep that speed without breaking everything.
If you care about frontend quality in the AI era, don’t just generate code:
Generate confidence.
Agent conversation:
<command-message>twd:setup</command-message>
<command-name>/twd:setup</command-name>
Base directory for this skill: [REDACTED]/.claude/plugins/cache/twd-ai/twd/1.1.0/skills/setup
TWD Project Setup
You are configuring TWD (Test While Developing) for this project. Your job is to detect project settings, ask questions for what can't be auto-detected, and generate a .claude/twd-patterns.md configuration file.
Step 1: Auto-Detect Project Settings
Read these files to pre-fill answers (read all in parallel):
-
package.json— detect framework from dependencies:-
react/react-dom→ React -
vue→ Vue -
@angular/core→ Angular -
solid-js→ Solid - Also detect CSS/component libraries:
@mui/material,@chakra-ui/react,antd,@mantine/core,vuetify,primevue,element-plus,@angular/material
-
-
vite.config.ts(or.js,.mjs) — detect:-
basefield (Vite base path, default/) -
server.port(dev server port, default5173)
-
index.html— detect entry point from<script>src attributeGlob for
src/services/,src/api/,src/lib/api— detect API/services folderCheck if
public/directory exists — confirm public folder name-
Detect state management from
package.jsondependencies:-
zustand→ Zustand -
@reduxjs/toolkitorredux→ Redux -
jotai→ Jotai -
pinia→ Pinia
-
Check if
.claude/twd-patterns.mdalready exists — offer to update vs overwrite
Step 2: Ask Questions
IMPORTANT: Use the AskUserQuestion tool for ALL questions. This provides an interactive UI experience. Never dump questions as a plain numbered list in text output.
Present auto-detected values as a summary first, then ask questions in two batches:
Batch 1: Project basics (confirm auto-detected values)
Do NOT ask individual questions for values you already detected. Show a single summary of all detected values and ask "Does anything look wrong?" using AskUserQuestion. The user only needs to respond if something is incorrect. Example:
Here's what I detected:
- Framework: React
- Vite base path:/
- Dev server port:5173
- Entry point:src/main.tsx
- Public folder:public/
- API services:src/services/
- CSS library: MUI
- State management: ZustandDoes anything look wrong, or should I continue?
Batch 2: Testing concerns (need user input)
After confirming batch 1, use AskUserQuestion for each of these that requires user input:
- CSS library docs (only if a CSS library was detected): Where are the docs? (URL, local path, or "skip")
- Auth middleware: Does your project have route-based auth/permissions? If yes, briefly describe the pattern.
-
Third-party modules: Does your project use external services that need mocking in tests? (e.g., Auth0, Stripe, analytics)
- If yes: Which modules and how are they imported?
- The agent needs this to know what to Sinon-stub in tests — "test what you own, mock what you don't"
-
State reset (only if state management was detected): How do you reset the store? (e.g.,
useStore.setState(initialState),store.$reset())- TWD runs without page reloads — store state persists between tests and must be reset in beforeEach
Step 3: Generate .claude/twd-patterns.md
Create the .claude/ directory if it doesn't exist, then write .claude/twd-patterns.md with the following sections. Only include sections that are relevant — omit sections that don't apply.
# TWD Project Patterns
## Project Configuration
- **Framework**: FRAMEWORK
- **Vite base path**: BASE_PATH
- **Dev server port**: PORT
- **Entry point**: ENTRY_FILE
- **Public folder**: PUBLIC_DIR
### Relay Commands
```bash
# Run all tests (default — use this if base path is / and port is 5173)
npx twd-relay run
# Run all tests (custom config)
npx twd-relay run --port PORT --path "BASE_PATH__twd/ws"
Standard Imports
import { twd, userEvent, screenDom, expect } from "twd-js";
import { describe, it, beforeEach, afterEach } from "twd-js/runner";
// Project-specific imports go here (added by user)
Visit Paths
All twd.visit() calls must include the base path prefix:
await twd.visit("BASE_PATH");
await twd.visit("BASE_PATHsome-page");
Standard beforeEach / afterEach
beforeEach(() => {
twd.clearRequestMockRules();
twd.clearComponentMocks();
Sinon.restore();
// STORE_RESET (if applicable — e.g., useStore.setState(initialState), store.$reset())
// AUTH_SETUP (if applicable)
// THIRD_PARTY_STUBS (if applicable — e.g., Sinon.stub(authModule, 'useAuth').returns(...))
});
afterEach(() => {
twd.clearRequestMockRules();
});
API Service Types
Service/API types are located in: API_FOLDER
Read files in this folder to understand endpoint URLs and response shapes when writing mock data.
CSS / Component Library
- Library: CSS_LIB
- Docs: CSS_DOCS_LOCATION
When writing tests, refer to library docs for correct ARIA roles and component structure.
Auth Middleware
AUTH_DESCRIPTION
Route → Permission Mapping
| Route | Required Permissions |
|---|---|
| (to be filled by developer) |
Third-Party Modules
"Test what you own, mock what you don't." These external modules should be stubbed in tests:
| Module | Import Pattern | Stub Strategy |
|---|---|---|
| MODULE_NAME | import { hook } from 'package' |
Sinon.stub(moduleObj, 'hook').returns(...) |
| (to be filled by developer) |
See the test-writing reference for the default-export object pattern required for ESM stubbing.
Portals and Dialogs
Use screenDomGlobal instead of screenDom for elements rendered in portals (modals, dropdowns, tooltips):
import { screenDomGlobal } from "twd-js";
const modal = screenDomGlobal.getByRole("dialog");
### Template rules:
- If base path is `/`, simplify visit paths to just `await twd.visit("/page")`
- If port is `5173` and base path is `/`, use `npx twd-relay run` (no flags)
- Omit the "Auth Middleware" section entirely if no auth
- Omit the "Third-Party Modules" section entirely if no external modules
- Omit the "CSS / Component Library" section if none detected
- Omit the "API Service Types" section if no services folder found
- Omit the `STORE_RESET` comment in beforeEach if no state management library
- Omit the `AUTH_SETUP` comment in beforeEach if no auth middleware
- Omit the `THIRD_PARTY_STUBS` comment in beforeEach if no third-party modules
## Step 4: Optionally Run Setup
After generating the config file, check if TWD is already installed. If not, ask the user if they want to run setup now:
1. `npm install twd-js`
2. `npm install --save-dev twd-relay`
3. `npx twd-js init PUBLIC_DIR --save`
4. Configure entry point — **insert this DEV block BEFORE the existing app mount code** (before `createRoot`, `createApp`, etc.). The import is **`twd-js/bundled`**, NOT `twd-js`:
```typescript
if (import.meta.env.DEV) {
const { initTWD } = await import('twd-js/bundled');
const tests = import.meta.glob("./**/*.twd.test.ts");
initTWD(tests, {
open: true,
position: 'left',
serviceWorker: true,
serviceWorkerUrl: '/mock-sw.js',
});
// Connect twd-relay browser client
const { createBrowserClient } = await import('twd-relay/browser');
const client = createBrowserClient({ url: `${window.location.origin}/__twd/ws` });
client.connect();
}
Adjustments: If Vite
baseis not/, updateserviceWorkerUrlto'/BASE/mock-sw.js'and relay URL to`${window.location.origin}/BASE/__twd/ws`.
- Add Vite plugins:
import { twdHmr } from 'twd-js/vite-plugin';
import { twdRemote } from 'twd-relay/vite';
import type { PluginOption } from 'vite';
// Add to plugins array:
plugins: [
// ... other plugins
twdHmr(),
twdRemote() as PluginOption,
]
- Write a first test file
Only run steps the user approves. Show what each step does before executing.
Output
When done, summarize:
- Where the config file was written
- What values were detected vs asked
- What setup steps were completed (if any)
- Next steps for the user (e.g., "Run npm run dev to see the TWD sidebar")
Setting up TWD for your project. Let me detect your project settings first.
Here's what I detected from your project:
- Framework: React 19 + TypeScript
-
Vite base path:
/(default) -
Dev server port:
5173(default) -
Entry point:
src/main.tsx -
Public folder:
public/ -
API services:
src/api/(foundtodos.ts) - CSS: Tailwind CSS v4 + Radix UI + shadcn/ui pattern (CVA, clsx, tailwind-merge)
- State management: Zustand
No auth middleware or third-party modules detected. Let me confirm this with you.
Now let me ask about the remaining items that need your input.
Got it. Let me generate the configuration file.
Config file written. Now let me check if TWD is already installed.
TWD is not installed yet. Let me ask if you'd like to run the setup.
Let's start with installing the packages and initializing TWD.
Good. Now let me configure the entry point and Vite plugins.
Now add the Vite plugins.
Now let me read the API file to write a meaningful first test.
Now let me create a first test file for the Helloworld page.
TWD setup is complete. Here's a summary:
Config file: .claude/twd-patterns.md
Auto-detected values: React 19, Vite defaults (/, 5173), src/main.tsx, public/, src/api/, Tailwind + Radix UI, Zustand
Setup steps completed:
1. Installed twd-js and twd-relay
2. Initialized service worker in public/mock-sw.js
3. Added TWD dev block to src/main.tsx (before app mount)
4. Added twdHmr() and twdRemote() Vite plugins to vite.config.ts
5. Created first test: src/pages/Helloworld/Helloworld.twd.test.ts
Next steps:
- Run npm run dev to start the dev server — you'll see the TWD sidebar on the left
- Run npx twd-relay run in a separate terminal to execute tests from CLI
For further actions, you may consider blocking this person and/or reporting abuse
