@uzysjung/agent-harness 26.83.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.ko.md +279 -0
- package/README.md +306 -0
- package/dist/chunk-SDVAM5JZ.js +775 -0
- package/dist/chunk-SDVAM5JZ.js.map +1 -0
- package/dist/index.js +5412 -0
- package/dist/index.js.map +1 -0
- package/dist/trust-tier-drift.js +67 -0
- package/dist/trust-tier-drift.js.map +1 -0
- package/package.json +53 -0
- package/scripts/prune-ecc.sh +310 -0
- package/templates/CLAUDE.md +86 -0
- package/templates/agents/build-error-resolver.md +114 -0
- package/templates/agents/code-reviewer.md +237 -0
- package/templates/agents/data-analyst.md +69 -0
- package/templates/agents/plan-checker.md +118 -0
- package/templates/agents/reviewer.md +128 -0
- package/templates/agents/security-reviewer.md +108 -0
- package/templates/agents/silent-failure-hunter.md +50 -0
- package/templates/agents/strategist.md +86 -0
- package/templates/antigravity/AGENTS.md.template +58 -0
- package/templates/codex/AGENTS.md.template +94 -0
- package/templates/codex/README.md +69 -0
- package/templates/codex/config.toml.template +108 -0
- package/templates/codex/hooks/README.md +40 -0
- package/templates/codex/hooks/gate-check.sh +7 -0
- package/templates/codex/hooks/hito-counter.sh +7 -0
- package/templates/codex/hooks/session-start.sh +7 -0
- package/templates/codex/hooks/uncommitted-check.sh +7 -0
- package/templates/codex/skills/uzys-build/SKILL.md +24 -0
- package/templates/codex/skills/uzys-plan/SKILL.md +24 -0
- package/templates/codex/skills/uzys-review/SKILL.md +24 -0
- package/templates/codex/skills/uzys-ship/SKILL.md +24 -0
- package/templates/codex/skills/uzys-spec/SKILL.md +28 -0
- package/templates/codex/skills/uzys-test/SKILL.md +24 -0
- package/templates/commands/ecc/checkpoint.md +32 -0
- package/templates/commands/ecc/e2e.md +105 -0
- package/templates/commands/ecc/eval.md +88 -0
- package/templates/commands/ecc/evolve.md +7 -0
- package/templates/commands/ecc/harness-audit.md +73 -0
- package/templates/commands/ecc/instinct-status.md +8 -0
- package/templates/commands/ecc/promote.md +10 -0
- package/templates/commands/ecc/security-scan.md +10 -0
- package/templates/commands/uzys/auto.md +190 -0
- package/templates/commands/uzys/build.md +42 -0
- package/templates/commands/uzys/plan.md +55 -0
- package/templates/commands/uzys/review.md +44 -0
- package/templates/commands/uzys/ship.md +49 -0
- package/templates/commands/uzys/spec.md +93 -0
- package/templates/commands/uzys/test.md +58 -0
- package/templates/docs/PLAN.template.md +102 -0
- package/templates/hooks/agentshield-gate.sh +101 -0
- package/templates/hooks/checkpoint-snapshot.sh +115 -0
- package/templates/hooks/gate-check.sh +138 -0
- package/templates/hooks/hito-counter.sh +26 -0
- package/templates/hooks/karpathy-gate.sh +59 -0
- package/templates/hooks/mcp-pre-exec.sh +104 -0
- package/templates/hooks/protect-files.sh +41 -0
- package/templates/hooks/session-start.sh +40 -0
- package/templates/hooks/spec-drift-check.sh +86 -0
- package/templates/mcp-allowlist.example +24 -0
- package/templates/mcp.json +20 -0
- package/templates/opencode/.opencode/commands/uzys-build.md +22 -0
- package/templates/opencode/.opencode/commands/uzys-plan.md +22 -0
- package/templates/opencode/.opencode/commands/uzys-review.md +22 -0
- package/templates/opencode/.opencode/commands/uzys-ship.md +22 -0
- package/templates/opencode/.opencode/commands/uzys-spec.md +28 -0
- package/templates/opencode/.opencode/commands/uzys-test.md +22 -0
- package/templates/opencode/.opencode/plugins/uzys-harness.ts +146 -0
- package/templates/opencode/AGENTS.md.template +98 -0
- package/templates/opencode/README.md +34 -0
- package/templates/opencode/opencode.json.template +42 -0
- package/templates/project-claude/_base.md +23 -0
- package/templates/project-claude/fragments/csr-fastapi/active-rules.md +13 -0
- package/templates/project-claude/fragments/csr-fastapi/agents.md +5 -0
- package/templates/project-claude/fragments/csr-fastapi/boundaries.md +18 -0
- package/templates/project-claude/fragments/csr-fastapi/commands.md +6 -0
- package/templates/project-claude/fragments/csr-fastapi/plugins.md +2 -0
- package/templates/project-claude/fragments/csr-fastapi/skills.md +5 -0
- package/templates/project-claude/fragments/csr-fastapi/stack.md +6 -0
- package/templates/project-claude/fragments/csr-fastapi/tagline.md +1 -0
- package/templates/project-claude/fragments/csr-fastapi/workflow.md +8 -0
- package/templates/project-claude/fragments/csr-fastify/active-rules.md +13 -0
- package/templates/project-claude/fragments/csr-fastify/agents.md +5 -0
- package/templates/project-claude/fragments/csr-fastify/boundaries.md +18 -0
- package/templates/project-claude/fragments/csr-fastify/commands.md +6 -0
- package/templates/project-claude/fragments/csr-fastify/plugins.md +2 -0
- package/templates/project-claude/fragments/csr-fastify/skills.md +5 -0
- package/templates/project-claude/fragments/csr-fastify/stack.md +6 -0
- package/templates/project-claude/fragments/csr-fastify/tagline.md +1 -0
- package/templates/project-claude/fragments/csr-fastify/workflow.md +8 -0
- package/templates/project-claude/fragments/csr-supabase/active-rules.md +12 -0
- package/templates/project-claude/fragments/csr-supabase/agents.md +5 -0
- package/templates/project-claude/fragments/csr-supabase/boundaries.md +19 -0
- package/templates/project-claude/fragments/csr-supabase/commands.md +6 -0
- package/templates/project-claude/fragments/csr-supabase/plugins.md +4 -0
- package/templates/project-claude/fragments/csr-supabase/skills.md +7 -0
- package/templates/project-claude/fragments/csr-supabase/stack.md +6 -0
- package/templates/project-claude/fragments/csr-supabase/supabase-auth.md +21 -0
- package/templates/project-claude/fragments/csr-supabase/tagline.md +1 -0
- package/templates/project-claude/fragments/csr-supabase/workflow.md +8 -0
- package/templates/project-claude/fragments/data/active-rules.md +10 -0
- package/templates/project-claude/fragments/data/agents.md +6 -0
- package/templates/project-claude/fragments/data/boundaries.md +20 -0
- package/templates/project-claude/fragments/data/commands.md +6 -0
- package/templates/project-claude/fragments/data/plugins.md +2 -0
- package/templates/project-claude/fragments/data/skills.md +3 -0
- package/templates/project-claude/fragments/data/stack.md +7 -0
- package/templates/project-claude/fragments/data/tagline.md +1 -0
- package/templates/project-claude/fragments/data/workflow.md +9 -0
- package/templates/project-claude/fragments/executive/active-rules.md +6 -0
- package/templates/project-claude/fragments/executive/agents.md +6 -0
- package/templates/project-claude/fragments/executive/boundaries.md +17 -0
- package/templates/project-claude/fragments/executive/commands.md +11 -0
- package/templates/project-claude/fragments/executive/plugins.md +1 -0
- package/templates/project-claude/fragments/executive/skills.md +7 -0
- package/templates/project-claude/fragments/executive/stack.md +4 -0
- package/templates/project-claude/fragments/executive/tagline.md +1 -0
- package/templates/project-claude/fragments/executive/workflow.md +10 -0
- package/templates/project-claude/fragments/growth-marketing/active-rules.md +7 -0
- package/templates/project-claude/fragments/growth-marketing/agents.md +6 -0
- package/templates/project-claude/fragments/growth-marketing/boundaries.md +17 -0
- package/templates/project-claude/fragments/growth-marketing/commands.md +11 -0
- package/templates/project-claude/fragments/growth-marketing/plugins.md +9 -0
- package/templates/project-claude/fragments/growth-marketing/skills.md +8 -0
- package/templates/project-claude/fragments/growth-marketing/stack.md +7 -0
- package/templates/project-claude/fragments/growth-marketing/tagline.md +1 -0
- package/templates/project-claude/fragments/growth-marketing/workflow.md +11 -0
- package/templates/project-claude/fragments/project-management/active-rules.md +7 -0
- package/templates/project-claude/fragments/project-management/agents.md +6 -0
- package/templates/project-claude/fragments/project-management/boundaries.md +16 -0
- package/templates/project-claude/fragments/project-management/commands.md +10 -0
- package/templates/project-claude/fragments/project-management/plugins.md +6 -0
- package/templates/project-claude/fragments/project-management/skills.md +5 -0
- package/templates/project-claude/fragments/project-management/stack.md +4 -0
- package/templates/project-claude/fragments/project-management/tagline.md +1 -0
- package/templates/project-claude/fragments/project-management/workflow.md +12 -0
- package/templates/project-claude/fragments/ssr-htmx/active-rules.md +11 -0
- package/templates/project-claude/fragments/ssr-htmx/agents.md +5 -0
- package/templates/project-claude/fragments/ssr-htmx/boundaries.md +20 -0
- package/templates/project-claude/fragments/ssr-htmx/commands.md +6 -0
- package/templates/project-claude/fragments/ssr-htmx/plugins.md +2 -0
- package/templates/project-claude/fragments/ssr-htmx/skills.md +3 -0
- package/templates/project-claude/fragments/ssr-htmx/stack.md +6 -0
- package/templates/project-claude/fragments/ssr-htmx/tagline.md +1 -0
- package/templates/project-claude/fragments/ssr-htmx/workflow.md +8 -0
- package/templates/project-claude/fragments/ssr-nextjs/active-rules.md +12 -0
- package/templates/project-claude/fragments/ssr-nextjs/agents.md +5 -0
- package/templates/project-claude/fragments/ssr-nextjs/boundaries.md +20 -0
- package/templates/project-claude/fragments/ssr-nextjs/commands.md +6 -0
- package/templates/project-claude/fragments/ssr-nextjs/plugins.md +2 -0
- package/templates/project-claude/fragments/ssr-nextjs/skills.md +5 -0
- package/templates/project-claude/fragments/ssr-nextjs/stack.md +5 -0
- package/templates/project-claude/fragments/ssr-nextjs/tagline.md +1 -0
- package/templates/project-claude/fragments/ssr-nextjs/workflow.md +8 -0
- package/templates/project-claude/fragments/tooling/active-rules.md +11 -0
- package/templates/project-claude/fragments/tooling/agents.md +5 -0
- package/templates/project-claude/fragments/tooling/boundaries.md +17 -0
- package/templates/project-claude/fragments/tooling/commands.md +4 -0
- package/templates/project-claude/fragments/tooling/skills.md +4 -0
- package/templates/project-claude/fragments/tooling/stack.md +5 -0
- package/templates/project-claude/fragments/tooling/tagline.md +1 -0
- package/templates/project-claude/fragments/tooling/workflow.md +5 -0
- package/templates/rules/api-contract.md +33 -0
- package/templates/rules/change-management.md +80 -0
- package/templates/rules/cli-development.md +39 -0
- package/templates/rules/code-style.md +23 -0
- package/templates/rules/data-analysis.md +61 -0
- package/templates/rules/database.md +29 -0
- package/templates/rules/design-workflow.md +17 -0
- package/templates/rules/error-handling.md +23 -0
- package/templates/rules/gates-taxonomy.md +21 -0
- package/templates/rules/git-policy.md +102 -0
- package/templates/rules/htmx.md +42 -0
- package/templates/rules/nextjs.md +35 -0
- package/templates/rules/playwright-launch.md +66 -0
- package/templates/rules/pyside6.md +59 -0
- package/templates/rules/shadcn.md +33 -0
- package/templates/rules/ship-checklist.md +24 -0
- package/templates/rules/tauri.md +40 -0
- package/templates/rules/test-policy.md +62 -0
- package/templates/settings.json +71 -0
- package/templates/skills/agent-introspection-debugging/SKILL.md +153 -0
- package/templates/skills/continuous-learning-v2/SKILL.md +365 -0
- package/templates/skills/continuous-learning-v2/config.json +8 -0
- package/templates/skills/continuous-learning-v2/hooks/observe.sh +428 -0
- package/templates/skills/continuous-learning-v2/scripts/detect-project.sh +228 -0
- package/templates/skills/continuous-learning-v2/scripts/instinct-cli.py +1426 -0
- package/templates/skills/deep-research/SKILL.md +155 -0
- package/templates/skills/deep-research/agents/openai.yaml +7 -0
- package/templates/skills/e2e-testing/SKILL.md +326 -0
- package/templates/skills/e2e-testing/agents/openai.yaml +7 -0
- package/templates/skills/eval-harness/SKILL.md +279 -0
- package/templates/skills/eval-harness/agents/openai.yaml +7 -0
- package/templates/skills/gh-issue-workflow/ISSUE.template.md +58 -0
- package/templates/skills/gh-issue-workflow/SKILL.md +184 -0
- package/templates/skills/investor-materials/SKILL.md +96 -0
- package/templates/skills/investor-outreach/SKILL.md +91 -0
- package/templates/skills/market-research/SKILL.md +75 -0
- package/templates/skills/market-research/agents/openai.yaml +7 -0
- package/templates/skills/nextjs-turbopack/SKILL.md +44 -0
- package/templates/skills/north-star/NORTH_STAR.template.md +114 -0
- package/templates/skills/north-star/SKILL.md +103 -0
- package/templates/skills/python-patterns/SKILL.md +750 -0
- package/templates/skills/python-testing/SKILL.md +816 -0
- package/templates/skills/spec-scaling/SKILL.md +89 -0
- package/templates/skills/strategic-compact/SKILL.md +131 -0
- package/templates/skills/strategic-compact/suggest-compact.sh +54 -0
- package/templates/skills/ui-visual-review/SKILL.md +154 -0
- package/templates/skills/verification-loop/SKILL.md +126 -0
- package/templates/skills/verification-loop/agents/openai.yaml +7 -0
- package/templates/track-mcp-map.tsv +15 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deep-research
|
|
3
|
+
description: Multi-source deep research using firecrawl and exa MCPs. Searches the web, synthesizes findings, and delivers cited reports with source attribution. Use when the user wants thorough research on any topic with evidence and citations.
|
|
4
|
+
origin: ECC
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Deep Research
|
|
8
|
+
|
|
9
|
+
Produce thorough, cited research reports from multiple web sources using firecrawl and exa MCP tools.
|
|
10
|
+
|
|
11
|
+
## When to Activate
|
|
12
|
+
|
|
13
|
+
- User asks to research any topic in depth
|
|
14
|
+
- Competitive analysis, technology evaluation, or market sizing
|
|
15
|
+
- Due diligence on companies, investors, or technologies
|
|
16
|
+
- Any question requiring synthesis from multiple sources
|
|
17
|
+
- User says "research", "deep dive", "investigate", or "what's the current state of"
|
|
18
|
+
|
|
19
|
+
## MCP Requirements
|
|
20
|
+
|
|
21
|
+
At least one of:
|
|
22
|
+
- **firecrawl** — `firecrawl_search`, `firecrawl_scrape`, `firecrawl_crawl`
|
|
23
|
+
- **exa** — `web_search_exa`, `web_search_advanced_exa`, `crawling_exa`
|
|
24
|
+
|
|
25
|
+
Both together give the best coverage. Configure in `~/.claude.json` or `~/.codex/config.toml`.
|
|
26
|
+
|
|
27
|
+
## Workflow
|
|
28
|
+
|
|
29
|
+
### Step 1: Understand the Goal
|
|
30
|
+
|
|
31
|
+
Ask 1-2 quick clarifying questions:
|
|
32
|
+
- "What's your goal — learning, making a decision, or writing something?"
|
|
33
|
+
- "Any specific angle or depth you want?"
|
|
34
|
+
|
|
35
|
+
If the user says "just research it" — skip ahead with reasonable defaults.
|
|
36
|
+
|
|
37
|
+
### Step 2: Plan the Research
|
|
38
|
+
|
|
39
|
+
Break the topic into 3-5 research sub-questions. Example:
|
|
40
|
+
- Topic: "Impact of AI on healthcare"
|
|
41
|
+
- What are the main AI applications in healthcare today?
|
|
42
|
+
- What clinical outcomes have been measured?
|
|
43
|
+
- What are the regulatory challenges?
|
|
44
|
+
- What companies are leading this space?
|
|
45
|
+
- What's the market size and growth trajectory?
|
|
46
|
+
|
|
47
|
+
### Step 3: Execute Multi-Source Search
|
|
48
|
+
|
|
49
|
+
For EACH sub-question, search using available MCP tools:
|
|
50
|
+
|
|
51
|
+
**With firecrawl:**
|
|
52
|
+
```
|
|
53
|
+
firecrawl_search(query: "<sub-question keywords>", limit: 8)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**With exa:**
|
|
57
|
+
```
|
|
58
|
+
web_search_exa(query: "<sub-question keywords>", numResults: 8)
|
|
59
|
+
web_search_advanced_exa(query: "<keywords>", numResults: 5, startPublishedDate: "2025-01-01")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Search strategy:**
|
|
63
|
+
- Use 2-3 different keyword variations per sub-question
|
|
64
|
+
- Mix general and news-focused queries
|
|
65
|
+
- Aim for 15-30 unique sources total
|
|
66
|
+
- Prioritize: academic, official, reputable news > blogs > forums
|
|
67
|
+
|
|
68
|
+
### Step 4: Deep-Read Key Sources
|
|
69
|
+
|
|
70
|
+
For the most promising URLs, fetch full content:
|
|
71
|
+
|
|
72
|
+
**With firecrawl:**
|
|
73
|
+
```
|
|
74
|
+
firecrawl_scrape(url: "<url>")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**With exa:**
|
|
78
|
+
```
|
|
79
|
+
crawling_exa(url: "<url>", tokensNum: 5000)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Read 3-5 key sources in full for depth. Do not rely only on search snippets.
|
|
83
|
+
|
|
84
|
+
### Step 5: Synthesize and Write Report
|
|
85
|
+
|
|
86
|
+
Structure the report:
|
|
87
|
+
|
|
88
|
+
```markdown
|
|
89
|
+
# [Topic]: Research Report
|
|
90
|
+
*Generated: [date] | Sources: [N] | Confidence: [High/Medium/Low]*
|
|
91
|
+
|
|
92
|
+
## Executive Summary
|
|
93
|
+
[3-5 sentence overview of key findings]
|
|
94
|
+
|
|
95
|
+
## 1. [First Major Theme]
|
|
96
|
+
[Findings with inline citations]
|
|
97
|
+
- Key point ([Source Name](url))
|
|
98
|
+
- Supporting data ([Source Name](url))
|
|
99
|
+
|
|
100
|
+
## 2. [Second Major Theme]
|
|
101
|
+
...
|
|
102
|
+
|
|
103
|
+
## 3. [Third Major Theme]
|
|
104
|
+
...
|
|
105
|
+
|
|
106
|
+
## Key Takeaways
|
|
107
|
+
- [Actionable insight 1]
|
|
108
|
+
- [Actionable insight 2]
|
|
109
|
+
- [Actionable insight 3]
|
|
110
|
+
|
|
111
|
+
## Sources
|
|
112
|
+
1. [Title](url) — [one-line summary]
|
|
113
|
+
2. ...
|
|
114
|
+
|
|
115
|
+
## Methodology
|
|
116
|
+
Searched [N] queries across web and news. Analyzed [M] sources.
|
|
117
|
+
Sub-questions investigated: [list]
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Step 6: Deliver
|
|
121
|
+
|
|
122
|
+
- **Short topics**: Post the full report in chat
|
|
123
|
+
- **Long reports**: Post the executive summary + key takeaways, save full report to a file
|
|
124
|
+
|
|
125
|
+
## Parallel Research with Subagents
|
|
126
|
+
|
|
127
|
+
For broad topics, use Claude Code's Task tool to parallelize:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
Launch 3 research agents in parallel:
|
|
131
|
+
1. Agent 1: Research sub-questions 1-2
|
|
132
|
+
2. Agent 2: Research sub-questions 3-4
|
|
133
|
+
3. Agent 3: Research sub-question 5 + cross-cutting themes
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Each agent searches, reads sources, and returns findings. The main session synthesizes into the final report.
|
|
137
|
+
|
|
138
|
+
## Quality Rules
|
|
139
|
+
|
|
140
|
+
1. **Every claim needs a source.** No unsourced assertions.
|
|
141
|
+
2. **Cross-reference.** If only one source says it, flag it as unverified.
|
|
142
|
+
3. **Recency matters.** Prefer sources from the last 12 months.
|
|
143
|
+
4. **Acknowledge gaps.** If you couldn't find good info on a sub-question, say so.
|
|
144
|
+
5. **No hallucination.** If you don't know, say "insufficient data found."
|
|
145
|
+
6. **Separate fact from inference.** Label estimates, projections, and opinions clearly.
|
|
146
|
+
|
|
147
|
+
## Examples
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
"Research the current state of nuclear fusion energy"
|
|
151
|
+
"Deep dive into Rust vs Go for backend services in 2026"
|
|
152
|
+
"Research the best strategies for bootstrapping a SaaS business"
|
|
153
|
+
"What's happening with the US housing market right now?"
|
|
154
|
+
"Investigate the competitive landscape for AI code editors"
|
|
155
|
+
```
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "Deep Research"
|
|
3
|
+
short_description: "Multi-source deep research with firecrawl and exa MCPs"
|
|
4
|
+
brand_color: "#6366F1"
|
|
5
|
+
default_prompt: "Research the given topic using firecrawl and exa, produce a cited report"
|
|
6
|
+
policy:
|
|
7
|
+
allow_implicit_invocation: true
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: e2e-testing
|
|
3
|
+
description: Playwright E2E testing patterns, Page Object Model, configuration, CI/CD integration, artifact management, and flaky test strategies.
|
|
4
|
+
origin: ECC
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# E2E Testing Patterns
|
|
8
|
+
|
|
9
|
+
Comprehensive Playwright patterns for building stable, fast, and maintainable E2E test suites.
|
|
10
|
+
|
|
11
|
+
## Test File Organization
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
tests/
|
|
15
|
+
├── e2e/
|
|
16
|
+
│ ├── auth/
|
|
17
|
+
│ │ ├── login.spec.ts
|
|
18
|
+
│ │ ├── logout.spec.ts
|
|
19
|
+
│ │ └── register.spec.ts
|
|
20
|
+
│ ├── features/
|
|
21
|
+
│ │ ├── browse.spec.ts
|
|
22
|
+
│ │ ├── search.spec.ts
|
|
23
|
+
│ │ └── create.spec.ts
|
|
24
|
+
│ └── api/
|
|
25
|
+
│ └── endpoints.spec.ts
|
|
26
|
+
├── fixtures/
|
|
27
|
+
│ ├── auth.ts
|
|
28
|
+
│ └── data.ts
|
|
29
|
+
└── playwright.config.ts
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Page Object Model (POM)
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { Page, Locator } from '@playwright/test'
|
|
36
|
+
|
|
37
|
+
export class ItemsPage {
|
|
38
|
+
readonly page: Page
|
|
39
|
+
readonly searchInput: Locator
|
|
40
|
+
readonly itemCards: Locator
|
|
41
|
+
readonly createButton: Locator
|
|
42
|
+
|
|
43
|
+
constructor(page: Page) {
|
|
44
|
+
this.page = page
|
|
45
|
+
this.searchInput = page.locator('[data-testid="search-input"]')
|
|
46
|
+
this.itemCards = page.locator('[data-testid="item-card"]')
|
|
47
|
+
this.createButton = page.locator('[data-testid="create-btn"]')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async goto() {
|
|
51
|
+
await this.page.goto('/items')
|
|
52
|
+
await this.page.waitForLoadState('networkidle')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async search(query: string) {
|
|
56
|
+
await this.searchInput.fill(query)
|
|
57
|
+
await this.page.waitForResponse(resp => resp.url().includes('/api/search'))
|
|
58
|
+
await this.page.waitForLoadState('networkidle')
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async getItemCount() {
|
|
62
|
+
return await this.itemCards.count()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Test Structure
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { test, expect } from '@playwright/test'
|
|
71
|
+
import { ItemsPage } from '../../pages/ItemsPage'
|
|
72
|
+
|
|
73
|
+
test.describe('Item Search', () => {
|
|
74
|
+
let itemsPage: ItemsPage
|
|
75
|
+
|
|
76
|
+
test.beforeEach(async ({ page }) => {
|
|
77
|
+
itemsPage = new ItemsPage(page)
|
|
78
|
+
await itemsPage.goto()
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('should search by keyword', async ({ page }) => {
|
|
82
|
+
await itemsPage.search('test')
|
|
83
|
+
|
|
84
|
+
const count = await itemsPage.getItemCount()
|
|
85
|
+
expect(count).toBeGreaterThan(0)
|
|
86
|
+
|
|
87
|
+
await expect(itemsPage.itemCards.first()).toContainText(/test/i)
|
|
88
|
+
await page.screenshot({ path: 'artifacts/search-results.png' })
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test('should handle no results', async ({ page }) => {
|
|
92
|
+
await itemsPage.search('xyznonexistent123')
|
|
93
|
+
|
|
94
|
+
await expect(page.locator('[data-testid="no-results"]')).toBeVisible()
|
|
95
|
+
expect(await itemsPage.getItemCount()).toBe(0)
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Playwright Configuration
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { defineConfig, devices } from '@playwright/test'
|
|
104
|
+
|
|
105
|
+
export default defineConfig({
|
|
106
|
+
testDir: './tests/e2e',
|
|
107
|
+
fullyParallel: true,
|
|
108
|
+
forbidOnly: !!process.env.CI,
|
|
109
|
+
retries: process.env.CI ? 2 : 0,
|
|
110
|
+
workers: process.env.CI ? 1 : undefined,
|
|
111
|
+
reporter: [
|
|
112
|
+
['html', { outputFolder: 'playwright-report' }],
|
|
113
|
+
['junit', { outputFile: 'playwright-results.xml' }],
|
|
114
|
+
['json', { outputFile: 'playwright-results.json' }]
|
|
115
|
+
],
|
|
116
|
+
use: {
|
|
117
|
+
baseURL: process.env.BASE_URL || 'http://localhost:3000',
|
|
118
|
+
trace: 'on-first-retry',
|
|
119
|
+
screenshot: 'only-on-failure',
|
|
120
|
+
video: 'retain-on-failure',
|
|
121
|
+
actionTimeout: 10000,
|
|
122
|
+
navigationTimeout: 30000,
|
|
123
|
+
},
|
|
124
|
+
projects: [
|
|
125
|
+
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
|
|
126
|
+
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
|
|
127
|
+
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
|
|
128
|
+
{ name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
|
|
129
|
+
],
|
|
130
|
+
webServer: {
|
|
131
|
+
command: 'npm run dev',
|
|
132
|
+
url: 'http://localhost:3000',
|
|
133
|
+
reuseExistingServer: !process.env.CI,
|
|
134
|
+
timeout: 120000,
|
|
135
|
+
},
|
|
136
|
+
})
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Flaky Test Patterns
|
|
140
|
+
|
|
141
|
+
### Quarantine
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
test('flaky: complex search', async ({ page }) => {
|
|
145
|
+
test.fixme(true, 'Flaky - Issue #123')
|
|
146
|
+
// test code...
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
test('conditional skip', async ({ page }) => {
|
|
150
|
+
test.skip(process.env.CI, 'Flaky in CI - Issue #123')
|
|
151
|
+
// test code...
|
|
152
|
+
})
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Identify Flakiness
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
npx playwright test tests/search.spec.ts --repeat-each=10
|
|
159
|
+
npx playwright test tests/search.spec.ts --retries=3
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Common Causes & Fixes
|
|
163
|
+
|
|
164
|
+
**Race conditions:**
|
|
165
|
+
```typescript
|
|
166
|
+
// Bad: assumes element is ready
|
|
167
|
+
await page.click('[data-testid="button"]')
|
|
168
|
+
|
|
169
|
+
// Good: auto-wait locator
|
|
170
|
+
await page.locator('[data-testid="button"]').click()
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Network timing:**
|
|
174
|
+
```typescript
|
|
175
|
+
// Bad: arbitrary timeout
|
|
176
|
+
await page.waitForTimeout(5000)
|
|
177
|
+
|
|
178
|
+
// Good: wait for specific condition
|
|
179
|
+
await page.waitForResponse(resp => resp.url().includes('/api/data'))
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Animation timing:**
|
|
183
|
+
```typescript
|
|
184
|
+
// Bad: click during animation
|
|
185
|
+
await page.click('[data-testid="menu-item"]')
|
|
186
|
+
|
|
187
|
+
// Good: wait for stability
|
|
188
|
+
await page.locator('[data-testid="menu-item"]').waitFor({ state: 'visible' })
|
|
189
|
+
await page.waitForLoadState('networkidle')
|
|
190
|
+
await page.locator('[data-testid="menu-item"]').click()
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Artifact Management
|
|
194
|
+
|
|
195
|
+
### Screenshots
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
await page.screenshot({ path: 'artifacts/after-login.png' })
|
|
199
|
+
await page.screenshot({ path: 'artifacts/full-page.png', fullPage: true })
|
|
200
|
+
await page.locator('[data-testid="chart"]').screenshot({ path: 'artifacts/chart.png' })
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Traces
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
await browser.startTracing(page, {
|
|
207
|
+
path: 'artifacts/trace.json',
|
|
208
|
+
screenshots: true,
|
|
209
|
+
snapshots: true,
|
|
210
|
+
})
|
|
211
|
+
// ... test actions ...
|
|
212
|
+
await browser.stopTracing()
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Video
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
// In playwright.config.ts
|
|
219
|
+
use: {
|
|
220
|
+
video: 'retain-on-failure',
|
|
221
|
+
videosPath: 'artifacts/videos/'
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## CI/CD Integration
|
|
226
|
+
|
|
227
|
+
```yaml
|
|
228
|
+
# .github/workflows/e2e.yml
|
|
229
|
+
name: E2E Tests
|
|
230
|
+
on: [push, pull_request]
|
|
231
|
+
|
|
232
|
+
jobs:
|
|
233
|
+
test:
|
|
234
|
+
runs-on: ubuntu-latest
|
|
235
|
+
steps:
|
|
236
|
+
- uses: actions/checkout@v4
|
|
237
|
+
- uses: actions/setup-node@v4
|
|
238
|
+
with:
|
|
239
|
+
node-version: 20
|
|
240
|
+
- run: npm ci
|
|
241
|
+
- run: npx playwright install --with-deps
|
|
242
|
+
- run: npx playwright test
|
|
243
|
+
env:
|
|
244
|
+
BASE_URL: ${{ vars.STAGING_URL }}
|
|
245
|
+
- uses: actions/upload-artifact@v4
|
|
246
|
+
if: always()
|
|
247
|
+
with:
|
|
248
|
+
name: playwright-report
|
|
249
|
+
path: playwright-report/
|
|
250
|
+
retention-days: 30
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Test Report Template
|
|
254
|
+
|
|
255
|
+
```markdown
|
|
256
|
+
# E2E Test Report
|
|
257
|
+
|
|
258
|
+
**Date:** YYYY-MM-DD HH:MM
|
|
259
|
+
**Duration:** Xm Ys
|
|
260
|
+
**Status:** PASSING / FAILING
|
|
261
|
+
|
|
262
|
+
## Summary
|
|
263
|
+
- Total: X | Passed: Y (Z%) | Failed: A | Flaky: B | Skipped: C
|
|
264
|
+
|
|
265
|
+
## Failed Tests
|
|
266
|
+
|
|
267
|
+
### test-name
|
|
268
|
+
**File:** `tests/e2e/feature.spec.ts:45`
|
|
269
|
+
**Error:** Expected element to be visible
|
|
270
|
+
**Screenshot:** artifacts/failed.png
|
|
271
|
+
**Recommended Fix:** [description]
|
|
272
|
+
|
|
273
|
+
## Artifacts
|
|
274
|
+
- HTML Report: playwright-report/index.html
|
|
275
|
+
- Screenshots: artifacts/*.png
|
|
276
|
+
- Videos: artifacts/videos/*.webm
|
|
277
|
+
- Traces: artifacts/*.zip
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Wallet / Web3 Testing
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
test('wallet connection', async ({ page, context }) => {
|
|
284
|
+
// Mock wallet provider
|
|
285
|
+
await context.addInitScript(() => {
|
|
286
|
+
window.ethereum = {
|
|
287
|
+
isMetaMask: true,
|
|
288
|
+
request: async ({ method }) => {
|
|
289
|
+
if (method === 'eth_requestAccounts')
|
|
290
|
+
return ['0x1234567890123456789012345678901234567890']
|
|
291
|
+
if (method === 'eth_chainId') return '0x1'
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
await page.goto('/')
|
|
297
|
+
await page.locator('[data-testid="connect-wallet"]').click()
|
|
298
|
+
await expect(page.locator('[data-testid="wallet-address"]')).toContainText('0x1234')
|
|
299
|
+
})
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Financial / Critical Flow Testing
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
test('trade execution', async ({ page }) => {
|
|
306
|
+
// Skip on production — real money
|
|
307
|
+
test.skip(process.env.NODE_ENV === 'production', 'Skip on production')
|
|
308
|
+
|
|
309
|
+
await page.goto('/markets/test-market')
|
|
310
|
+
await page.locator('[data-testid="position-yes"]').click()
|
|
311
|
+
await page.locator('[data-testid="trade-amount"]').fill('1.0')
|
|
312
|
+
|
|
313
|
+
// Verify preview
|
|
314
|
+
const preview = page.locator('[data-testid="trade-preview"]')
|
|
315
|
+
await expect(preview).toContainText('1.0')
|
|
316
|
+
|
|
317
|
+
// Confirm and wait for blockchain
|
|
318
|
+
await page.locator('[data-testid="confirm-trade"]').click()
|
|
319
|
+
await page.waitForResponse(
|
|
320
|
+
resp => resp.url().includes('/api/trade') && resp.status() === 200,
|
|
321
|
+
{ timeout: 30000 }
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
await expect(page.locator('[data-testid="trade-success"]')).toBeVisible()
|
|
325
|
+
})
|
|
326
|
+
```
|