Skip to content

Commit 5c8375b

Browse files
committed
Add desktop Playwright e2e harness
1 parent 998d839 commit 5c8375b

22 files changed

Lines changed: 1283 additions & 24 deletions

.github/workflows/ci.yml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,100 @@ jobs:
7474
wget
7575
- name: Install desktop dependencies
7676
run: just desktop-install-ci
77+
- name: Install Playwright Chromium
78+
run: cd desktop && pnpm exec playwright install --with-deps chromium
7779
- name: Desktop lint and format
7880
run: just desktop-check
7981
- name: Desktop build
8082
run: just desktop-build
83+
- name: Desktop smoke e2e
84+
run: cd desktop && pnpm exec playwright test --project=smoke
8185
- name: Desktop Tauri check
8286
run: just desktop-tauri-check
87+
- name: Upload desktop e2e artifacts
88+
if: failure()
89+
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4
90+
with:
91+
name: desktop-e2e-artifacts
92+
path: |
93+
desktop/playwright-report
94+
desktop/test-results
95+
if-no-files-found: ignore
96+
97+
desktop-e2e-integration:
98+
name: Desktop E2E Integration
99+
runs-on: ubuntu-latest
100+
timeout-minutes: 45
101+
permissions:
102+
contents: read
103+
steps:
104+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
105+
- uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1
106+
- uses: Swatinem/rust-cache@ad397744b0d591a723ab90405b7247fac0e6b8db # v2
107+
with:
108+
workspaces: desktop/src-tauri
109+
- name: Install desktop dependencies
110+
run: just desktop-install-ci
111+
- name: Install Playwright Chromium
112+
run: cd desktop && pnpm exec playwright install --with-deps chromium
113+
- name: Desktop build
114+
run: just desktop-build
115+
- name: Start integration services
116+
run: docker compose up -d
117+
- name: Wait for integration services
118+
run: |
119+
wait_healthy() {
120+
local service="$1"
121+
local container="$2"
122+
for attempt in $(seq 1 60); do
123+
status=$(docker inspect --format='{{.State.Health.Status}}' "${container}" 2>/dev/null || echo "not_found")
124+
if [ "${status}" = "healthy" ]; then
125+
echo "${service} is healthy"
126+
return 0
127+
fi
128+
sleep 2
129+
done
130+
docker logs "${container}" || true
131+
return 1
132+
}
133+
wait_healthy "MySQL" "sprout-mysql"
134+
wait_healthy "Redis" "sprout-redis"
135+
wait_healthy "Typesense" "sprout-typesense"
136+
- name: Start relay
137+
run: |
138+
nohup env \
139+
DATABASE_URL=mysql://sprout:sprout_dev@localhost:3306/sprout \
140+
REDIS_URL=redis://localhost:6379 \
141+
TYPESENSE_URL=http://localhost:8108 \
142+
TYPESENSE_API_KEY=sprout_dev_key \
143+
RELAY_URL=ws://localhost:3000 \
144+
SPROUT_BIND_ADDR=0.0.0.0:3000 \
145+
SPROUT_REQUIRE_AUTH_TOKEN=false \
146+
cargo run -p sprout-relay > /tmp/sprout-relay.log 2>&1 &
147+
echo $! > /tmp/sprout-relay.pid
148+
for attempt in $(seq 1 60); do
149+
status_code=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/api/channels || true)
150+
if [ "${status_code}" != "000" ]; then
151+
exit 0
152+
fi
153+
sleep 1
154+
done
155+
cat /tmp/sprout-relay.log
156+
exit 1
157+
- name: Seed desktop e2e data
158+
run: bash scripts/setup-desktop-test-data.sh
159+
- name: Desktop relay-backed e2e
160+
run: cd desktop && pnpm exec playwright test --project=integration
161+
- name: Upload desktop integration artifacts
162+
if: failure()
163+
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4
164+
with:
165+
name: desktop-e2e-integration-artifacts
166+
path: |
167+
desktop/playwright-report
168+
desktop/test-results
169+
/tmp/sprout-relay.log
170+
if-no-files-found: ignore
83171

84172
security:
85173
name: Security

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ Thumbs.db
2121
# Scratch / working files (AI reviews, notes, drafts)
2222
.scratch/
2323

24+
# Playwright artifacts
25+
playwright-report/
26+
test-results/
27+
blob-report/
28+
2429
# sqlx offline query data (generated, not portable)
2530
.sqlx/
2631

README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,17 +147,21 @@ cargo run -p sprout-admin -- mint-token \
147147
--scopes "messages:read,messages:write,channels:read"
148148
```
149149

150-
Outputs a bearer token. Set it as `SPROUT_API_TOKEN` for the MCP server.
150+
Save the `nsec...` private key and API token from the output. They are shown only once.
151151

152-
**6. Connect an agent via MCP**
152+
**6. Launch an agent with the MCP extension**
153153

154154
```bash
155155
SPROUT_RELAY_URL=ws://localhost:3000 \
156156
SPROUT_API_TOKEN=<token> \
157-
cargo run -p sprout-mcp
157+
SPROUT_PRIVATE_KEY=nsec1... \
158+
goose run --no-profile \
159+
--with-extension "cargo run -p sprout-mcp --bin sprout-mcp-server" \
160+
--instructions "List available Sprout channels."
158161
```
159162

160-
The MCP server speaks stdio JSON-RPC. Wire it into any MCP-compatible agent host.
163+
`sprout-mcp-server` is a stdio MCP extension, so start it through a host such as Goose rather than
164+
as a standalone user-facing process. See [TESTING.md](TESTING.md) for the full multi-agent flow.
161165

162166
**7. Run the desktop app (optional)**
163167

@@ -262,9 +266,11 @@ just reset # ⚠️ Wipe all data and recreate environment
262266
```bash
263267
cargo run -p sprout-relay
264268
cargo run -p sprout-admin -- --help
265-
cargo run -p sprout-mcp
269+
cargo run -p sprout-mcp --bin sprout-mcp-server
266270
```
267271

272+
`sprout-mcp-server` is normally launched by Goose or another MCP host.
273+
268274
**Database migrations** live in `migrations/`. The relay applies them automatically on startup.
269275
To run manually: `just migrate` (uses `sqlx` CLI if available, falls back to `docker exec`).
270276

desktop/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ node_modules
1111
.pnpm-store
1212
dist
1313
dist-ssr
14+
playwright-report
15+
test-results
1416
*.local
1517

1618
# Editor directories and files

desktop/package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
"check": "biome check .",
1313
"format": "biome format --write .",
1414
"preview": "vite preview",
15-
"tauri": "tauri"
15+
"tauri": "tauri",
16+
"test:e2e": "pnpm build && playwright test",
17+
"test:e2e:smoke": "pnpm build && playwright test --project=smoke",
18+
"test:e2e:integration": "pnpm build && playwright test --project=integration",
19+
"test:e2e:report": "playwright show-report"
1620
},
1721
"dependencies": {
1822
"@radix-ui/react-dialog": "^1.1.15",
@@ -35,11 +39,14 @@
3539
},
3640
"devDependencies": {
3741
"@biomejs/biome": "^2.4.6",
42+
"@noble/hashes": "^2.0.1",
43+
"@playwright/test": "^1.58.2",
3844
"@tauri-apps/cli": "^2",
3945
"@types/react": "^19.1.8",
4046
"@types/react-dom": "^19.1.6",
4147
"@vitejs/plugin-react": "^4.6.0",
4248
"autoprefixer": "^10.4.27",
49+
"nostr-tools": "^2.23.3",
4350
"postcss": "^8.5.8",
4451
"tailwindcss": "^3.4.17",
4552
"tailwindcss-animate": "^1.0.7",

desktop/playwright.config.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { defineConfig, devices } from "@playwright/test";
2+
3+
export default defineConfig({
4+
testDir: "./tests/e2e",
5+
timeout: 30_000,
6+
retries: process.env.CI ? 2 : 0,
7+
workers: 1,
8+
reporter: [
9+
["list"],
10+
["html", { open: "never", outputFolder: "playwright-report" }],
11+
],
12+
use: {
13+
baseURL: "http://127.0.0.1:4173",
14+
screenshot: "only-on-failure",
15+
trace: "on-first-retry",
16+
video: "retain-on-failure",
17+
},
18+
projects: [
19+
{
20+
name: "smoke",
21+
testMatch: "**/smoke.spec.ts",
22+
use: {
23+
...devices["Desktop Chrome"],
24+
},
25+
},
26+
{
27+
name: "integration",
28+
testMatch: "**/stream.spec.ts",
29+
use: {
30+
...devices["Desktop Chrome"],
31+
},
32+
},
33+
],
34+
webServer: {
35+
command: "python3 -m http.server 4173 -d dist",
36+
cwd: ".",
37+
reuseExistingServer: !process.env.CI,
38+
url: "http://127.0.0.1:4173",
39+
},
40+
});

0 commit comments

Comments
 (0)