Build Vite + React frontend components and/or vitest tests for a task. Iterates until all tests pass 100%.
Steps
- •Check prerequisites:
test -d frontend && echo "OK" || echo "ERROR: No frontend/ directory" test -f frontend/package.json && echo "OK" || echo "ERROR: No package.json"
If missing, stop and tell the user: "No frontend scaffolded. Re-run npx wao create with frontend option."
Check Playwright if task is frontend-integration:
cd frontend && npx playwright --version 2>/dev/null || echo "Playwright not installed — run: cd frontend && npx playwright install"
- •
Read
tasks.jsonand find the task matching$ARGUMENTS(task id). Update its status to"in_progress". - •
Read
plan.mdfor UI specifications:- •Components to build
- •User interactions
- •AO process connections
- •State management
- •
Read
docs/wao-sdk.md(browser section) forwao/webpatterns. - •
If the task type is
frontend— write React components:Write components in
frontend/src/:jsximport { AO, AR } from "wao/web" // browser only — NOT wao/test // ArConnect wallet integration async function connectWallet() { await window.arweaveWallet.connect(["ACCESS_ADDRESS", "SIGN_TRANSACTION"]) const addr = await window.arweaveWallet.getActiveAddress() return addr } // AO process interaction async function sendMessage(processId, action, tags) { const ao = new AO() const { p } = ao.p(processId) const result = await p.msg(action, tags) return result }Key patterns:
- •Import from
wao/web(NOTwao/test— that's Node.js only) - •ArConnect wallet via
window.arweaveWallet - •Process interaction via
ao.p(processId).msg() - •Use React hooks for state management
- •Handle loading, error, and success states
- •Import from
- •
If the task type is
frontend-test— write vitest tests:Write tests in
frontend/test/:jsximport { describe, it, expect, vi } from "vitest" import { render, screen, fireEvent, waitFor } from "@testing-library/react" import { MyComponent } from "../src/MyComponent" // Mock wao/web vi.mock("wao/web", () => ({ AO: vi.fn(() => ({ p: vi.fn(() => ({ msg: vi.fn().mockResolvedValue({ res: { Output: { data: "ok" } } }) })) })), })) // Mock ArConnect Object.defineProperty(window, "arweaveWallet", { value: { connect: vi.fn(), getActiveAddress: vi.fn().mockResolvedValue("test-addr"), }, }) describe("MyComponent", () => { it("renders correctly", () => { render(<MyComponent />) expect(screen.getByText("expected")).toBeTruthy() }) it("handles wallet connection", async () => { render(<MyComponent />) fireEvent.click(screen.getByRole("button", { name: /connect/i })) await waitFor(() => { expect(window.arweaveWallet.connect).toHaveBeenCalled() }) }) // Test: render, interaction, state updates, error states, loading states }) - •
Run tests:
bashcd frontend && npm run test:unit
- •
If tests fail, keep debugging. Do not stop. On each iteration:
- •Read the full error output — stack traces, assertion messages, log lines
- •Identify the FIRST failing test (fix failures in order)
- •Classify: is the bug in component code or test code?
- •Fix ONE issue per iteration (don't change multiple things at once)
- •Re-run the failing test file specifically (faster feedback than full suite)
- •If the same error persists after 3 different fix attempts, step back:
- •Re-read the relevant docs (
wao/webpatterns, React testing library, vitest mocking) - •Check if the plan itself has a wrong assumption
- •Try a completely different approach
- •Re-read the relevant docs (
- •Continue iterating until all tests pass — there is no retry limit
Only escalate to the user if:
- •The failure is environmental (missing dependency, port conflict, permissions)
- •The test requires user input (wallet, external service URL)
- •You've tried 10+ iterations with no progress on the same error
- •
Update the task status to
"done"intasks.json.IMPORTANT: Only mark done if all tests pass 100%.