refactor: restructure repo for cleaner GitHub landing page
Reduce visible top-level items from 21 to 14: - Untrack test-results/, tmp/, public symlink (added to .gitignore) - Move agent-teams/ → docs/agent-teams/ - Move mobile-test/ → test/mobile/ - Move tools/remotion/ → scripts/remotion/ - Move eslint.config.js, vitest.config.ts → config/ All path references updated across CLAUDE.md, package.json, .prettierignore, vitest configs, and capture scripts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@@ -48,7 +48,12 @@ Thumbs.db
|
|||||||
# Generated output
|
# Generated output
|
||||||
out/
|
out/
|
||||||
screenshots-echo-diag/
|
screenshots-echo-diag/
|
||||||
tools/remotion/out/
|
scripts/remotion/out/
|
||||||
|
|
||||||
|
# Artifacts that should not be tracked
|
||||||
|
test-results/
|
||||||
|
tmp/
|
||||||
|
public
|
||||||
|
|
||||||
# Claude Code plan tracking
|
# Claude Code plan tracking
|
||||||
plan.json
|
plan.json
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ src/web/public/app.js
|
|||||||
src/web/public/styles.css
|
src/web/public/styles.css
|
||||||
src/web/public/mobile.css
|
src/web/public/mobile.css
|
||||||
src/web/public/index.html
|
src/web/public/index.html
|
||||||
tools/
|
scripts/remotion/
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ Codeman is a Claude Code session manager with web interface and autonomous Ralph
|
|||||||
|
|
||||||
**CI**: `.github/workflows/ci.yml` runs `typecheck`, `lint`, `format:check` on push to master/main and on PRs (Node 22). Tests excluded (they spawn tmux).
|
**CI**: `.github/workflows/ci.yml` runs `typecheck`, `lint`, `format:check` on push to master/main and on PRs (Node 22). Tests excluded (they spawn tmux).
|
||||||
|
|
||||||
**Code style**: Prettier (`singleQuote: true`, `printWidth: 120`, `trailingComma: "es5"`). ESLint flat config (`eslint.config.js`) allows `no-console`, warns on `@typescript-eslint/no-explicit-any`. Ignores: `app.js`, `scripts/**/*.mjs`, `src/web/public/vendor/**`, `tools/**`, `remotion/**`.
|
**Code style**: Prettier (`singleQuote: true`, `printWidth: 120`, `trailingComma: "es5"`). ESLint flat config (`config/eslint.config.js`) allows `no-console`, warns on `@typescript-eslint/no-explicit-any`. Ignores: `app.js`, `scripts/**/*.mjs`, `src/web/public/vendor/**`, `scripts/remotion/**`.
|
||||||
|
|
||||||
## Common Gotchas
|
## Common Gotchas
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ Codeman is a Claude Code session manager with web interface and autonomous Ralph
|
|||||||
|
|
||||||
**Hook events**: Claude Code hooks trigger via `/api/hook-event`. Key events: `permission_prompt`, `elicitation_dialog`, `idle_prompt`, `stop`, `teammate_idle`, `task_completed`. See `src/hooks-config.ts`.
|
**Hook events**: Claude Code hooks trigger via `/api/hook-event`. Key events: `permission_prompt`, `elicitation_dialog`, `idle_prompt`, `stop`, `teammate_idle`, `task_completed`. See `src/hooks-config.ts`.
|
||||||
|
|
||||||
**Agent Teams**: `TeamWatcher` polls `~/.claude/teams/`, matches to sessions via `leadSessionId`. Teammates are in-process threads appearing as subagents. Enable: `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`. See `agent-teams/`.
|
**Agent Teams**: `TeamWatcher` polls `~/.claude/teams/`, matches to sessions via `leadSessionId`. Teammates are in-process threads appearing as subagents. Enable: `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`. See `docs/agent-teams/`.
|
||||||
|
|
||||||
**Circuit breaker**: Prevents respawn thrashing. States: `CLOSED` → `HALF_OPEN` → `OPEN`. Reset: `/api/sessions/:id/ralph-circuit-breaker/reset`.
|
**Circuit breaker**: Prevents respawn thrashing. States: `CLOSED` → `HALF_OPEN` → `OPEN`. Reset: `/api/sessions/:id/ralph-circuit-breaker/reset`.
|
||||||
|
|
||||||
@@ -204,7 +204,7 @@ npx vitest run -t "pattern" # By name (SAFE)
|
|||||||
|
|
||||||
**Ports**: Pick unique ports manually. Search `const PORT =` before adding new tests.
|
**Ports**: Pick unique ports manually. Search `const PORT =` before adding new tests.
|
||||||
|
|
||||||
**Respawn tests**: Use `MockSession` from `test/respawn-test-utils.ts`. **Route tests**: `app.inject()` in `test/routes/`. **Mobile tests**: Playwright suite in `mobile-test/` (135 device profiles).
|
**Respawn tests**: Use `MockSession` from `test/respawn-test-utils.ts`. **Route tests**: `app.inject()` in `test/routes/`. **Mobile tests**: Playwright suite in `test/mobile/` (135 device profiles).
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
@@ -226,7 +226,7 @@ Target: 20 sessions, 50 agent windows at 60fps. Limits in `src/config/`: termina
|
|||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
Deep-dive docs in `docs/`: `respawn-state-machine.md`, `ralph-wiggum-guide.md`, `claude-code-hooks-reference.md`, `terminal-anti-flicker.md`, `opencode-integration.md`, `qr-auth-plan.md`, `orchestrator-loop-architecture.md`, `browser-testing-guide.md`. Agent Teams: `agent-teams/README.md`. SSE events: `src/web/sse-events.ts` + `constants.js`.
|
Deep-dive docs in `docs/`: `respawn-state-machine.md`, `ralph-wiggum-guide.md`, `claude-code-hooks-reference.md`, `terminal-anti-flicker.md`, `opencode-integration.md`, `qr-auth-plan.md`, `orchestrator-loop-architecture.md`, `browser-testing-guide.md`. Agent Teams: `docs/agent-teams/README.md`. SSE events: `src/web/sse-events.ts` + `constants.js`.
|
||||||
|
|
||||||
## Scripts
|
## Scripts
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ export default tseslint.config(
|
|||||||
'src/web/public/vendor/**',
|
'src/web/public/vendor/**',
|
||||||
'src/web/public/app.js',
|
'src/web/public/app.js',
|
||||||
'scripts/**/*.mjs',
|
'scripts/**/*.mjs',
|
||||||
'tools/**',
|
'scripts/remotion/**',
|
||||||
'remotion/**',
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
|
import { resolve } from 'node:path';
|
||||||
import { defineConfig } from 'vitest/config';
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
|
const root = resolve(import.meta.dirname, '..');
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
test: {
|
test: {
|
||||||
|
root,
|
||||||
globals: true,
|
globals: true,
|
||||||
environment: 'node',
|
environment: 'node',
|
||||||
include: ['test/**/*.test.ts'],
|
include: ['test/**/*.test.ts'],
|
||||||
@@ -15,12 +15,12 @@
|
|||||||
"dev": "tsx src/index.ts web",
|
"dev": "tsx src/index.ts web",
|
||||||
"web": "node dist/index.js web",
|
"web": "node dist/index.js web",
|
||||||
"clean": "rm -rf dist",
|
"clean": "rm -rf dist",
|
||||||
"test": "vitest run",
|
"test": "vitest run --config config/vitest.config.ts",
|
||||||
"test:watch": "vitest",
|
"test:watch": "vitest --config config/vitest.config.ts",
|
||||||
"test:coverage": "vitest run --coverage",
|
"test:coverage": "vitest run --config config/vitest.config.ts --coverage",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"lint": "eslint 'src/**/*.ts'",
|
"lint": "eslint --config config/eslint.config.js 'src/**/*.ts'",
|
||||||
"lint:fix": "eslint 'src/**/*.ts' --fix",
|
"lint:fix": "eslint --config config/eslint.config.js 'src/**/*.ts' --fix",
|
||||||
"format": "prettier --write 'src/**/*.ts'",
|
"format": "prettier --write 'src/**/*.ts'",
|
||||||
"format:check": "prettier --check 'src/**/*.ts'",
|
"format:check": "prettier --check 'src/**/*.ts'",
|
||||||
"capture:subagents": "node scripts/capture-subagent-screenshots.mjs",
|
"capture:subagents": "node scripts/capture-subagent-screenshots.mjs",
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ const SUBAGENT_ACTIVITY = {
|
|||||||
'agent-002': [
|
'agent-002': [
|
||||||
{ type: 'tool', tool: 'Glob', input: { pattern: 'test/**/*.test.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-002' },
|
{ type: 'tool', tool: 'Glob', input: { pattern: 'test/**/*.test.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-002' },
|
||||||
{ type: 'tool', tool: 'Read', input: { file_path: '/home/arkon/codeman/test/respawn-test-utils.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-002' },
|
{ type: 'tool', tool: 'Read', input: { file_path: '/home/arkon/codeman/test/respawn-test-utils.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-002' },
|
||||||
{ type: 'tool', tool: 'Read', input: { file_path: '/home/arkon/codeman/vitest.config.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-002' },
|
{ type: 'tool', tool: 'Read', input: { file_path: '/home/arkon/codeman/config/vitest.config.ts' }, timestamp: new Date().toISOString(), agentId: 'agent-002' },
|
||||||
{ type: 'message', role: 'assistant', text: 'Analyzing test patterns: MockSession, unique ports, fileParallelism: false...', timestamp: new Date().toISOString(), agentId: 'agent-002' },
|
{ type: 'message', role: 'assistant', text: 'Analyzing test patterns: MockSession, unique ports, fileParallelism: false...', timestamp: new Date().toISOString(), agentId: 'agent-002' },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* Usage: node scripts/capture-video-screenshots.mjs
|
* Usage: node scripts/capture-video-screenshots.mjs
|
||||||
* Port: 3198 (static file server)
|
* Port: 3198 (static file server)
|
||||||
* Output: remotion/public/ (6 PNGs)
|
* Output: scripts/scripts/remotion/public/ (6 PNGs)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { chromium } from 'playwright';
|
import { chromium } from 'playwright';
|
||||||
@@ -21,7 +21,7 @@ import { fileURLToPath } from 'url';
|
|||||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||||
const PROJECT_ROOT = join(__dirname, '..');
|
const PROJECT_ROOT = join(__dirname, '..');
|
||||||
const PUBLIC_DIR = join(PROJECT_ROOT, 'src', 'web', 'public');
|
const PUBLIC_DIR = join(PROJECT_ROOT, 'src', 'web', 'public');
|
||||||
const OUTPUT_DIR = join(PROJECT_ROOT, 'remotion', 'public');
|
const OUTPUT_DIR = join(PROJECT_ROOT, 'scripts', 'remotion', 'public');
|
||||||
const PORT = 3198;
|
const PORT = 3198;
|
||||||
|
|
||||||
const DESKTOP_VIEWPORT = { width: 1920, height: 1080 };
|
const DESKTOP_VIEWPORT = { width: 1920, height: 1080 };
|
||||||
@@ -516,7 +516,7 @@ async function captureDesktopWelcome(browser) {
|
|||||||
path: join(OUTPUT_DIR, 'desktop-welcome.png'),
|
path: join(OUTPUT_DIR, 'desktop-welcome.png'),
|
||||||
fullPage: false,
|
fullPage: false,
|
||||||
});
|
});
|
||||||
console.log(' Saved: remotion/public/desktop-welcome.png');
|
console.log(' Saved: scripts/remotion/public/desktop-welcome.png');
|
||||||
} finally {
|
} finally {
|
||||||
await context.close();
|
await context.close();
|
||||||
}
|
}
|
||||||
@@ -545,7 +545,7 @@ async function captureDesktopClaude(browser) {
|
|||||||
path: join(OUTPUT_DIR, 'desktop-claude.png'),
|
path: join(OUTPUT_DIR, 'desktop-claude.png'),
|
||||||
fullPage: false,
|
fullPage: false,
|
||||||
});
|
});
|
||||||
console.log(' Saved: remotion/public/desktop-claude.png');
|
console.log(' Saved: scripts/remotion/public/desktop-claude.png');
|
||||||
} finally {
|
} finally {
|
||||||
await context.close();
|
await context.close();
|
||||||
}
|
}
|
||||||
@@ -575,7 +575,7 @@ async function captureDesktopBothClaude(browser) {
|
|||||||
path: join(OUTPUT_DIR, 'desktop-both-claude.png'),
|
path: join(OUTPUT_DIR, 'desktop-both-claude.png'),
|
||||||
fullPage: false,
|
fullPage: false,
|
||||||
});
|
});
|
||||||
console.log(' Saved: remotion/public/desktop-both-claude.png');
|
console.log(' Saved: scripts/remotion/public/desktop-both-claude.png');
|
||||||
} finally {
|
} finally {
|
||||||
await context.close();
|
await context.close();
|
||||||
}
|
}
|
||||||
@@ -605,7 +605,7 @@ async function captureDesktopBothOpencode(browser) {
|
|||||||
path: join(OUTPUT_DIR, 'desktop-both-opencode.png'),
|
path: join(OUTPUT_DIR, 'desktop-both-opencode.png'),
|
||||||
fullPage: false,
|
fullPage: false,
|
||||||
});
|
});
|
||||||
console.log(' Saved: remotion/public/desktop-both-opencode.png');
|
console.log(' Saved: scripts/remotion/public/desktop-both-opencode.png');
|
||||||
} finally {
|
} finally {
|
||||||
await context.close();
|
await context.close();
|
||||||
}
|
}
|
||||||
@@ -634,7 +634,7 @@ async function captureMobileClaude(browser) {
|
|||||||
path: join(OUTPUT_DIR, 'mobile-claude.png'),
|
path: join(OUTPUT_DIR, 'mobile-claude.png'),
|
||||||
fullPage: false,
|
fullPage: false,
|
||||||
});
|
});
|
||||||
console.log(' Saved: remotion/public/mobile-claude.png');
|
console.log(' Saved: scripts/remotion/public/mobile-claude.png');
|
||||||
} finally {
|
} finally {
|
||||||
await context.close();
|
await context.close();
|
||||||
}
|
}
|
||||||
@@ -663,7 +663,7 @@ async function captureMobileOpencode(browser) {
|
|||||||
path: join(OUTPUT_DIR, 'mobile-opencode.png'),
|
path: join(OUTPUT_DIR, 'mobile-opencode.png'),
|
||||||
fullPage: false,
|
fullPage: false,
|
||||||
});
|
});
|
||||||
console.log(' Saved: remotion/public/mobile-opencode.png');
|
console.log(' Saved: scripts/remotion/public/mobile-opencode.png');
|
||||||
} finally {
|
} finally {
|
||||||
await context.close();
|
await context.close();
|
||||||
}
|
}
|
||||||
@@ -706,12 +706,12 @@ async function main() {
|
|||||||
console.log('All 6 screenshots captured!');
|
console.log('All 6 screenshots captured!');
|
||||||
console.log('='.repeat(60));
|
console.log('='.repeat(60));
|
||||||
console.log('\nOutput files:');
|
console.log('\nOutput files:');
|
||||||
console.log(' remotion/public/desktop-welcome.png');
|
console.log(' scripts/remotion/public/desktop-welcome.png');
|
||||||
console.log(' remotion/public/desktop-claude.png');
|
console.log(' scripts/remotion/public/desktop-claude.png');
|
||||||
console.log(' remotion/public/desktop-both-claude.png');
|
console.log(' scripts/remotion/public/desktop-both-claude.png');
|
||||||
console.log(' remotion/public/desktop-both-opencode.png');
|
console.log(' scripts/remotion/public/desktop-both-opencode.png');
|
||||||
console.log(' remotion/public/mobile-claude.png');
|
console.log(' scripts/remotion/public/mobile-claude.png');
|
||||||
console.log(' remotion/public/mobile-opencode.png');
|
console.log(' scripts/remotion/public/mobile-opencode.png');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('\nFatal error:', err.message);
|
console.error('\nFatal error:', err.message);
|
||||||
console.error(err.stack);
|
console.error(err.stack);
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 390 KiB After Width: | Height: | Size: 390 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"status": "failed",
|
|
||||||
"failedTests": []
|
|
||||||
}
|
|
||||||
@@ -18,20 +18,20 @@ Validates Codeman's mobile UI across 135 devices, covering:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run all mobile tests
|
# Run all mobile tests
|
||||||
npx vitest run --config mobile-test/vitest.config.ts
|
npx vitest run --config test/mobile/vitest.config.ts
|
||||||
|
|
||||||
# Run a single test file
|
# Run a single test file
|
||||||
npx vitest run --config mobile-test/vitest.config.ts mobile-test/keyboard.test.ts
|
npx vitest run --config test/mobile/vitest.config.ts test/mobile/keyboard.test.ts
|
||||||
|
|
||||||
# Quick mode — 6 representative devices, skip full matrix
|
# Quick mode — 6 representative devices, skip full matrix
|
||||||
CI_QUICK=1 npx vitest run --config mobile-test/vitest.config.ts
|
CI_QUICK=1 npx vitest run --config test/mobile/vitest.config.ts
|
||||||
|
|
||||||
# Full device matrix only (135 devices)
|
# Full device matrix only (135 devices)
|
||||||
npx vitest run --config mobile-test/vitest.config.ts mobile-test/device-matrix.test.ts
|
npx vitest run --config test/mobile/vitest.config.ts test/mobile/device-matrix.test.ts
|
||||||
|
|
||||||
# Update visual baselines (delete old baselines, re-run)
|
# Update visual baselines (delete old baselines, re-run)
|
||||||
rm -rf mobile-test/snapshots/*.png
|
rm -rf test/mobile/snapshots/*.png
|
||||||
npx vitest run --config mobile-test/vitest.config.ts mobile-test/visual-regression.test.ts
|
npx vitest run --config test/mobile/vitest.config.ts test/mobile/visual-regression.test.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
## Test Files
|
## Test Files
|
||||||
@@ -126,7 +126,7 @@ Swipe simulation includes intermediate move points and timing to satisfy `SwipeH
|
|||||||
|
|
||||||
Uses `pixelmatch` + `pngjs` (both in devDeps) for pixel-level comparison:
|
Uses `pixelmatch` + `pngjs` (both in devDeps) for pixel-level comparison:
|
||||||
|
|
||||||
- **Baselines** stored in `mobile-test/snapshots/` (git-tracked)
|
- **Baselines** stored in `test/mobile/snapshots/` (git-tracked)
|
||||||
- **Tolerance**: 0.5% pixel diff (handles anti-aliasing)
|
- **Tolerance**: 0.5% pixel diff (handles anti-aliasing)
|
||||||
- **On failure**: `.actual.png` and `.diff.png` generated (gitignored)
|
- **On failure**: `.actual.png` and `.diff.png` generated (gitignored)
|
||||||
- **Update**: Delete baseline PNGs and re-run — new baselines auto-created
|
- **Update**: Delete baseline PNGs and re-run — new baselines auto-created
|
||||||
@@ -96,7 +96,7 @@ export const SUBAGENT = {
|
|||||||
export const VISUAL = {
|
export const VISUAL = {
|
||||||
DEFAULT_THRESHOLD: 0.1,
|
DEFAULT_THRESHOLD: 0.1,
|
||||||
MAX_DIFF_PERCENT: 0.5,
|
MAX_DIFF_PERCENT: 0.5,
|
||||||
SNAPSHOT_DIR: 'mobile-test/snapshots',
|
SNAPSHOT_DIR: 'test/mobile/snapshots',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// Visual regression breakpoints (width values for screenshot comparison)
|
// Visual regression breakpoints (width values for screenshot comparison)
|
||||||
|
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
@@ -166,19 +166,19 @@ describe('Visual Regression', () => {
|
|||||||
* To update visual baselines:
|
* To update visual baselines:
|
||||||
*
|
*
|
||||||
* 1. Delete the specific snapshot:
|
* 1. Delete the specific snapshot:
|
||||||
* rm mobile-test/snapshots/<name>.png
|
* rm test/mobile/snapshots/<name>.png
|
||||||
*
|
*
|
||||||
* 2. Re-run the test:
|
* 2. Re-run the test:
|
||||||
* npx vitest run mobile-test/visual-regression.test.ts
|
* npx vitest run test/mobile/visual-regression.test.ts
|
||||||
*
|
*
|
||||||
* 3. Review the new baseline:
|
* 3. Review the new baseline:
|
||||||
* The test will create a fresh .png and pass (isNewBaseline = true).
|
* The test will create a fresh .png and pass (isNewBaseline = true).
|
||||||
*
|
*
|
||||||
* To update ALL baselines:
|
* To update ALL baselines:
|
||||||
* rm -rf mobile-test/snapshots/ && npx vitest run mobile-test/visual-regression.test.ts
|
* rm -rf test/mobile/snapshots/ && npx vitest run test/mobile/visual-regression.test.ts
|
||||||
*
|
*
|
||||||
* Diff images for failed comparisons are saved as <name>.diff.png
|
* Diff images for failed comparisons are saved as <name>.diff.png
|
||||||
* alongside the baseline in mobile-test/snapshots/.
|
* alongside the baseline in test/mobile/snapshots/.
|
||||||
*/
|
*/
|
||||||
it('placeholder — see comments above for baseline update instructions', () => {
|
it('placeholder — see comments above for baseline update instructions', () => {
|
||||||
expect(true).toBe(true);
|
expect(true).toBe(true);
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
|
import { resolve } from 'node:path';
|
||||||
import { defineConfig } from 'vitest/config';
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
|
const root = resolve(import.meta.dirname, '../..');
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
test: {
|
test: {
|
||||||
|
root,
|
||||||
globals: true,
|
globals: true,
|
||||||
environment: 'node',
|
environment: 'node',
|
||||||
include: ['mobile-test/**/*.test.ts'],
|
include: ['test/mobile/**/*.test.ts'],
|
||||||
setupFiles: ['./test/setup.ts'],
|
setupFiles: ['./test/setup.ts'],
|
||||||
fileParallelism: false,
|
fileParallelism: false,
|
||||||
testTimeout: 60_000,
|
testTimeout: 60_000,
|
||||||
|
Before Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 20 KiB |