mirror of
https://github.com/tiennm99/claude-code-routine-trigger.git
synced 2026-10-16 00:14:39 +00:00
102 lines
4.0 KiB
Markdown
102 lines
4.0 KiB
Markdown
---
|
|
phase: 4
|
|
title: Tests + CI
|
|
status: completed
|
|
priority: P2
|
|
effort: 2h
|
|
dependencies:
|
|
- 2
|
|
- 3
|
|
---
|
|
|
|
# Phase 4: Tests + CI
|
|
|
|
## Overview
|
|
Vitest with `@cloudflare/vitest-pool-workers` for in-Workers-runtime tests. Cover template rendering, fire client behavior (success / non-2xx / network error), token redaction. GitHub Actions CI on push.
|
|
|
|
## Requirements
|
|
- **Functional:**
|
|
- Tests cover: template substitution, missing-token rendering, fire success path, non-2xx path, fetch throws path.
|
|
- CI runs `npm test` on push to `main` and PRs.
|
|
- **Non-functional:**
|
|
- Coverage report (text summary in CI logs).
|
|
- Tests use mocked `fetch` — no real network calls (don't burn user's Anthropic quota).
|
|
- Tests written in plain JS with JSDoc, matching production code style.
|
|
- Race-free is N/A on Workers; instead assert `console.log` output never contains token.
|
|
|
|
## Architecture
|
|
|
|
### Test layout
|
|
```
|
|
worker.test.js # all tests in one file initially (KISS)
|
|
```
|
|
Split if exceeds 200 lines.
|
|
|
|
### Test cases (mirror Go daemon's test coverage)
|
|
| # | Case | Assertion |
|
|
|---|------|-----------|
|
|
| 1 | `renderText` substitutes `{LocalTime}`, `{Cron}`, `{ISO}` | output equals expected string |
|
|
| 2 | `renderText` leaves unknown `{Foo}` tokens intact | output contains `{Foo}` |
|
|
| 3 | `fireRoutine` 2xx response logs `session_url` | console captured contains `session_url` |
|
|
| 4 | `fireRoutine` 401 response logs `level:error` | captured log has `level:'error'`, `status:401` |
|
|
| 5 | `fireRoutine` `fetch` rejects (network) logs error, doesn't throw | no thrown exception, error log present |
|
|
| 6 | Token redaction | for cases 3, 4, 5: stringified logs do NOT contain token value |
|
|
| 7 | Headers correctness | mocked `fetch` receives `Authorization: Bearer ${token}`, `anthropic-version`, `anthropic-beta` |
|
|
| 8 | Body shape | request body parses as `{ "text": <rendered> }` |
|
|
| 9 | Default template when `TEXT_TEMPLATE` unset | output starts with `Scheduled trigger at ` |
|
|
| 10 | TZ defaults to UTC when `env.TZ` unset | local time formatting uses UTC |
|
|
|
|
### CI workflow
|
|
`.github/workflows/ci.yml` — single job, Node 20, runs test + wrangler dry-run as smoke gate.
|
|
|
|
## Related Code Files
|
|
- Create: `worker.test.js`
|
|
- Create: `vitest.config.js` (uses `@cloudflare/vitest-pool-workers`)
|
|
- Create: `.github/workflows/ci.yml`
|
|
|
|
## Implementation Steps
|
|
1. Install: `npm i -D vitest @cloudflare/vitest-pool-workers`.
|
|
2. Write `vitest.config.js`:
|
|
```js
|
|
import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config';
|
|
export default defineWorkersConfig({
|
|
test: { poolOptions: { workers: { wrangler: { configPath: './wrangler.toml' } } } },
|
|
});
|
|
```
|
|
3. Write `worker.test.js` covering all 10 cases. Use `vi.fn()` mock for `globalThis.fetch`. JSDoc-annotate test helper functions for IDE assist.
|
|
4. Run `npm test` — all green.
|
|
5. Write `.github/workflows/ci.yml`:
|
|
```yaml
|
|
name: ci
|
|
on:
|
|
push: { branches: [main] }
|
|
pull_request:
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-node@v4
|
|
with: { node-version: '20', cache: 'npm' }
|
|
- run: npm ci
|
|
- run: npm test
|
|
- run: npx wrangler deploy --dry-run
|
|
```
|
|
6. Push to GitHub; verify green CI.
|
|
|
|
## Success Criteria
|
|
- [ ] All 10 test cases pass locally
|
|
- [ ] `npm test` exits 0 in CI
|
|
- [ ] `wrangler deploy --dry-run` exits 0 in CI
|
|
- [ ] No real HTTP traffic generated by tests (verify by mock spy)
|
|
- [ ] Coverage ≥ 80% (track via vitest `--coverage`; not enforced as blocking gate)
|
|
|
|
## Risk Assessment
|
|
- **Workers test pool quirks:** `@cloudflare/vitest-pool-workers` requires wrangler config; ensure `wrangler.toml` validates first.
|
|
- **Mocking `fetch` inside Workers runtime:** verify pattern works — fall back to dependency-injected fetch if not.
|
|
- **Beta header pinning in tests:** assert exact value to catch accidental edits.
|
|
|
|
## Security Considerations
|
|
- Test fixtures use placeholder token `sk-ant-oat01-test-only` — never a real value.
|
|
- Test asserts logs **don't contain** the token (regression guard).
|