@ai-qa/workflow 2.0.16 → 2.0.18

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.
@@ -0,0 +1,101 @@
1
+ <% layout = 'layouts/main' %>
2
+ <% title = 'Terminal' %>
3
+
4
+ <div class="page-header">
5
+ <h1>🖥️ Terminal</h1>
6
+ <div class="header-actions">
7
+ <% if (typeof projects !== 'undefined' && projects.length > 1) { %>
8
+ <select id="project-select" class="form-input" style="width:auto;" onchange="window.location='/terminal?project='+this.value">
9
+ <% projects.forEach(p => { %>
10
+ <option value="<%= p.id %>" <%= project && project.id === p.id ? 'selected' : '' %>><%= p.name %></option>
11
+ <% }) %>
12
+ </select>
13
+ <% } %>
14
+ <button class="btn btn-sm btn-danger" onclick="clearTerminal()">🗑️ Clear</button>
15
+ </div>
16
+ </div>
17
+
18
+ <div class="card">
19
+ <h3>⚡ Quick Commands</h3>
20
+ <div style="display:flex;gap:0.5rem;flex-wrap:wrap;margin-bottom:1rem;">
21
+ <button class="btn btn-sm" onclick="runCommand('npx playwright test')">▶ Run All Tests</button>
22
+ <button class="btn btn-sm" onclick="runCommand('npm run qa:report')">📝 Generate Report</button>
23
+ <button class="btn btn-sm" onclick="runCommand('npx allure generate allure-results --clean -o allure-report')">📈 Generate Allure</button>
24
+ <button class="btn btn-sm" onclick="runCommand('npm run qa:status')">📊 Status</button>
25
+ <button class="btn btn-sm" onclick="runCommand('npx playwright show-report')">📋 Open HTML Report</button>
26
+ </div>
27
+ <form id="terminal-form" style="display:flex;gap:0.5rem;">
28
+ <input type="text" id="cmd-input" class="form-input" placeholder="Enter a command (e.g., npx playwright test)" style="flex:1;font-family:var(--font-mono);font-size:0.85rem;" autofocus>
29
+ <button type="submit" class="btn btn-primary" style="white-space:nowrap;">▶ Run</button>
30
+ </form>
31
+ </div>
32
+
33
+ <div class="card" style="padding:0;overflow:hidden;">
34
+ <div style="background:var(--surface-dark);padding:0.75rem 1.25rem;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--border-strong);">
35
+ <span style="color:#e5e7eb;font-family:var(--font-mono);font-size:0.8rem;font-weight:600;">Console Output</span>
36
+ <span id="terminal-status" style="color:var(--text-disabled);font-family:var(--font-mono);font-size:0.75rem;">Ready</span>
37
+ </div>
38
+ <pre id="terminal-output" class="code-block" style="border:none;border-radius:0;max-height:500px;min-height:200px;margin:0;font-size:0.8rem;"><%= project ? `Ready — project: ${project.name}\nType a command or click a quick action above.` : 'No project configured.' %></pre>
39
+ </div>
40
+
41
+ <script>
42
+ document.getElementById('terminal-form').addEventListener('submit', async (e) => {
43
+ e.preventDefault();
44
+ const cmd = document.getElementById('cmd-input').value.trim();
45
+ if (!cmd) return;
46
+ runCommand(cmd);
47
+ });
48
+
49
+ async function runCommand(command) {
50
+ const output = document.getElementById('terminal-output');
51
+ const status = document.getElementById('terminal-status');
52
+ const input = document.getElementById('cmd-input');
53
+
54
+ output.textContent += `\n\n$ ${command}\n`;
55
+ status.textContent = '⏳ Running...';
56
+ output.scrollTop = output.scrollHeight;
57
+
58
+ try {
59
+ const res = await fetch('/terminal/run?project=<%= project ? project.id : '' %>', {
60
+ method: 'POST',
61
+ headers: { 'Content-Type': 'application/json' },
62
+ body: JSON.stringify({ command }),
63
+ });
64
+
65
+ if (!res.body) {
66
+ output.textContent += 'Error: No response stream\n';
67
+ status.textContent = '❌ Error';
68
+ return;
69
+ }
70
+
71
+ const reader = res.body.getReader();
72
+ const decoder = new TextDecoder('utf-8');
73
+
74
+ while (true) {
75
+ const { done, value } = await reader.read();
76
+ if (done) break;
77
+ output.textContent += decoder.decode(value, { stream: true });
78
+ output.scrollTop = output.scrollHeight;
79
+ }
80
+
81
+ const lastLine = output.textContent.split('\n').pop() || '';
82
+ if (lastLine.includes('SUCCESS')) {
83
+ status.textContent = '✅ Completed';
84
+ } else if (lastLine.includes('FAILED')) {
85
+ status.textContent = '❌ Failed';
86
+ } else {
87
+ status.textContent = '✅ Done';
88
+ }
89
+
90
+ if (input) input.value = '';
91
+ } catch (err) {
92
+ output.textContent += `\nConnection error: ${err.message}\n`;
93
+ status.textContent = '❌ Error';
94
+ }
95
+ }
96
+
97
+ function clearTerminal() {
98
+ document.getElementById('terminal-output').textContent = 'Terminal cleared.';
99
+ document.getElementById('terminal-status').textContent = 'Ready';
100
+ }
101
+ </script>
@@ -2,7 +2,7 @@
2
2
  <% title = project ? 'Test Data - ' + project.name : 'Test Data Management' %>
3
3
 
4
4
  <div class="page-header">
5
- <h1>Test Data Management</h1>
5
+ <h1>Test Data & Artifacts</h1>
6
6
  <div class="header-actions">
7
7
  <% if (typeof projects !== 'undefined' && projects.length > 1) { %>
8
8
  <select id="project-select" class="form-input" style="width:auto;" onchange="window.location='/data?project='+this.value">
@@ -17,14 +17,53 @@
17
17
  </div>
18
18
  </div>
19
19
 
20
- <div class="alerts" id="alert-container"></div>
20
+ <% if (project) { %>
21
+ <!-- ─── Test Specs ─── -->
22
+ <% if (testSpecs && testSpecs.length > 0) { %>
23
+ <div class="card card-lavender">
24
+ <h3>🧪 Test Spec Files <span class="badge badge-project" style="margin-left:0.5rem;"><%= testSpecs.length %></span></h3>
25
+ <% testSpecs.forEach(spec => { %>
26
+ <details style="margin-bottom:0.75rem;border:1px solid var(--border);border-radius:var(--radius-md);padding:0.75rem;">
27
+ <summary style="cursor:pointer;font-weight:600;font-family:var(--font-mono);font-size:0.9rem;">
28
+ <%= spec.name %>
29
+ <a href="/data/spec/<%= spec.name %>?project=<%= project.id %>" class="btn btn-sm" style="margin-left:0.5rem;" download>📥 Download</a>
30
+ <a href="/stories?project=<%= project.id %>" class="btn btn-sm">▶ Execute</a>
31
+ </summary>
32
+ <pre class="code-block" style="margin-top:0.75rem;max-height:400px;font-size:0.75rem;"><%= spec.content %></pre>
33
+ </details>
34
+ <% }) %>
35
+ </div>
36
+ <% } else { %>
37
+ <div class="card">
38
+ <h3>🧪 Test Spec Files</h3>
39
+ <p style="color:var(--text-muted);">Aucun fichier de test trouvé. Générez des tests depuis la page <a href="/stories?project=<%= project.id %>">Stories</a>.</p>
40
+ </div>
41
+ <% } %>
21
42
 
43
+ <!-- ─── Test Plans ─── -->
44
+ <% if (testPlans && testPlans.length > 0) { %>
45
+ <div class="card card-peach">
46
+ <h3>📋 Test Plan Files <span class="badge badge-project" style="margin-left:0.5rem;"><%= testPlans.length %></span></h3>
47
+ <% testPlans.forEach(plan => { %>
48
+ <details style="margin-bottom:0.75rem;border:1px solid var(--border);border-radius:var(--radius-md);padding:0.75rem;">
49
+ <summary style="cursor:pointer;font-weight:600;font-family:var(--font-mono);font-size:0.9rem;">
50
+ <%= plan.name %>
51
+ <a href="/data/plan/<%= plan.name %>?project=<%= project.id %>" class="btn btn-sm" style="margin-left:0.5rem;" download>📥 Download</a>
52
+ </summary>
53
+ <div class="markdown-content" style="margin-top:0.75rem;font-size:0.85rem;" data-md="<%= encodeURIComponent(plan.content) %>"></div>
54
+ </details>
55
+ <% }) %>
56
+ </div>
57
+ <% } %>
58
+ <% } %>
59
+
60
+ <!-- ─── Generate Test Data ─── -->
22
61
  <div class="row" style="margin-bottom:2rem;">
23
62
  <div class="col col-40">
24
- <div class="card card-lavender">
63
+ <div class="card card-cream">
25
64
  <h3>⚡ Generate Test Data</h3>
26
65
  <p style="color: var(--text-muted); font-size: 0.85rem; margin-bottom: 1.25rem;">
27
- Auto-generate realistic synthetic mock datasets for your QA pipeline.
66
+ Auto-generate synthetic mock datasets for your QA pipeline.
28
67
  </p>
29
68
  <form id="data-form" class="form">
30
69
  <div class="form-group">
@@ -68,15 +107,11 @@
68
107
  </div>
69
108
 
70
109
  <div class="card">
71
- <h3>ℹ️ About Test Data Management</h3>
110
+ <h3>ℹ️ About Test Data</h3>
72
111
  <p style="color: var(--text-muted); font-size: 0.88rem; line-height:1.5;">
73
- Generated test data is stored directly in your connected project's <code>data/</code> folder as structured JSON files. These datasets can be easily:
112
+ Test spec files (<code>.spec.ts</code>) and plans (<code>.md</code>) are read directly from your project.
113
+ Generated datasets are stored in <code>qa-dashboard/data/</code> as JSON files.
74
114
  </p>
75
- <ul style="color: var(--text-muted); font-size: 0.88rem; padding-left: 1.5rem; margin-top: 0.5rem; line-height:1.6;">
76
- <li>Read dynamically inside Playwright test scenarios using <code>fs.readFileSync()</code></li>
77
- <li>Injected directly into a localized sandbox database before test suite runs</li>
78
- <li>Exported or synced for cross-team quality assurance consistency</li>
79
- </ul>
80
115
  </div>
81
116
 
82
117
  <script>
@@ -85,18 +120,11 @@ document.getElementById('data-form').addEventListener('submit', async (e) => {
85
120
  const type = document.getElementById('data-type').value;
86
121
  const count = document.getElementById('data-count').value;
87
122
  const output = document.getElementById('data-output');
88
-
89
123
  output.style.display = 'block';
90
- output.textContent = 'Generating realistic mock data...';
124
+ output.textContent = 'Generating...';
91
125
  output.className = 'output-box output-running';
92
-
93
- const res = await fetch('/data/generate', {
94
- method: 'POST',
95
- headers: { 'Content-Type': 'application/json' },
96
- body: JSON.stringify({ type, count })
97
- });
126
+ const res = await fetch('/data/generate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type, count }) });
98
127
  const data = await res.json();
99
-
100
128
  if (data.success) {
101
129
  output.textContent = `Generated ${data.count} records → ${data.file}`;
102
130
  output.className = 'output-box output-success';
@@ -108,10 +136,19 @@ document.getElementById('data-form').addEventListener('submit', async (e) => {
108
136
  });
109
137
 
110
138
  async function deleteFile(name) {
111
- if (!confirm(`Are you sure you want to delete ${name}?`)) return;
139
+ if (!confirm(`Delete ${name}?`)) return;
112
140
  const res = await fetch('/data/' + encodeURIComponent(name), { method: 'DELETE' });
113
141
  const data = await res.json();
114
142
  if (data.success) location.reload();
115
143
  else alert('Delete failed');
116
144
  }
117
- </script>
145
+
146
+ // Render markdown for plans
147
+ document.addEventListener('DOMContentLoaded', () => {
148
+ document.querySelectorAll('[data-md]').forEach(el => {
149
+ if (typeof marked !== 'undefined') {
150
+ el.innerHTML = marked.parse(decodeURIComponent(el.dataset.md));
151
+ }
152
+ });
153
+ });
154
+ </script>
package/router.md CHANGED
@@ -39,38 +39,45 @@ Once the user provides a user story or testing request, follow this workflow. **
39
39
 
40
40
  ### Phase 1: Plan & Explore
41
41
  User says: *"Plan tests for this user story"*
42
- 1. Read `.github/agents/playwright-test-planner.agent.md`
43
- 2. Explore the app with Playwright MCP
44
- 3. Write test plan to `specs/`
45
- 4. **STOP** present the plan to the user
46
- 5. Wait for approval before continuing
42
+ 1. Read `.github/agents/playwright-test-planner.agent.md` (or `.opencode/agents/qa-planner.md`)
43
+ 2. Read `.opencode/qa-workflow-skill.md` for project context and conventions
44
+ 3. Explore the app with Playwright MCP
45
+ 4. Write test plan to `specs/`
46
+ 5. **STOP** present the plan to the user
47
+ 6. Wait for approval before continuing
47
48
 
48
49
  ### Phase 2: Generate Tests
49
50
  User says: *"Generate tests from the plan"*
50
- 1. Read `.github/agents/playwright-test-generator.agent.md`
51
- 2. Read `prompts/QAe2eprompt.md` for conventions
52
- 3. Write Playwright test files to `tests/`
53
- 4. **STOP** present the generated tests to the user
54
- 5. Wait for approval before executing
51
+ 1. Read `.github/agents/playwright-test-generator.agent.md` (or `.opencode/agents/qa-generator.md`)
52
+ 2. Read `.opencode/qa-workflow-skill.md` for Allure/Applitools/reporter setup
53
+ 3. Read `prompts/QAe2eprompt.md` for conventions
54
+ 4. Write Playwright test files to `tests/`
55
+ 5. **STOP** present the generated tests to the user
56
+ 6. Wait for approval before executing
55
57
 
56
58
  ### Phase 3: Execute
57
59
  User says: *"Execute the tests"*
58
60
  1. User runs `npm run qa:execute` (or you suggest it)
59
61
  2. Check results — did they pass or fail?
62
+ 3. Allure results are auto-generated in `allure-results/`
63
+ 4. View dashboard: `npm run dashboard` → `http://localhost:4000`
60
64
 
61
65
  ### Phase 4: Heal Failures
62
66
  If tests fail, user says: *"Fix the failing tests"*
63
- 1. Read `.github/agents/playwright-test-healer.agent.md`
64
- 2. Debug with Playwright MCP (`test_debug`, `browser_snapshot`, etc.)
65
- 3. Present diagnosis to the user (root cause + proposed 1-3 line fix)
66
- 4. **STOP** wait for user to approve the fix
67
- 5. Apply fix and re-run
68
- 6. If still failing, mark `test.fixme()` and classify as defect
67
+ 1. Read `.github/agents/playwright-test-healer.agent.md` (or `.opencode/agents/qa-healer.md`)
68
+ 2. Read `.opencode/qa-workflow-skill.md` for self-healing patterns
69
+ 3. Debug with Playwright MCP (`test_debug`, `browser_snapshot`, etc.)
70
+ 4. Present diagnosis to the user (root cause + proposed 1-3 line fix)
71
+ 5. **STOP** wait for user to approve the fix
72
+ 6. Apply fix and re-run
73
+ 7. If still failing, mark `test.fixme()` and classify as defect
69
74
 
70
75
  ### Phase 5: Report
71
76
  User says: *"Generate the report"*
72
77
  1. User runs `npm run qa:report` (or you suggest it)
73
- 2. Present the report summary to the user
78
+ 2. Or generate Allure report: `npm run qa:report:allure`
79
+ 3. Or open the QA Dashboard: `npm run dashboard`
80
+ 4. Present the report summary to the user
74
81
 
75
82
  ---
76
83
 
@@ -92,9 +99,12 @@ User says: *"Generate the report"*
92
99
 
93
100
  | User intent | Read this |
94
101
  |------------|-----------|
102
+ | General QA / test writing best practices | `.opencode/qa-workflow-skill.md` |
95
103
  | "Plan tests / Explore the app / Write a test plan" | `.github/agents/playwright-test-planner.agent.md` |
96
104
  | "Generate tests / Write test code / Create spec files" | `.github/agents/playwright-test-generator.agent.md` + `prompts/QAe2eprompt.md` |
97
105
  | "Fix failing tests / Debug / Heal" | `.github/agents/playwright-test-healer.agent.md` |
106
+ | Allure / Dashboard / Reporting | `.opencode/qa-workflow-skill.md` |
107
+ | Applitools visual testing | `.opencode/qa-workflow-skill.md` |
98
108
  | General QA requests | `prompts/general_prompt.md` |
99
109
 
100
110
  ---
@@ -1,9 +1,18 @@
1
1
  # AI QA Execution Report
2
2
 
3
3
  **Run ID**: run-2026-05-18T14-51-36
4
- **Generated**: 2026-05-18T14:51:45.958Z
4
+ **Generated**: 2026-06-09T15:03:06.572Z
5
5
  **Status**: ✅ PASSED
6
6
 
7
+
8
+ ---
9
+
10
+ ## Traceability
11
+
12
+ No traceability data available.
13
+
14
+
15
+
7
16
  ---
8
17
 
9
18
  ## Executive Summary
@@ -23,7 +32,6 @@
23
32
 
24
33
  | Test File | Scenarios |
25
34
  |-----------|-----------|
26
- | us-expense-01.spec.ts | 1 |
27
35
 
28
36
  ## Self-Healing Activity
29
37
 
package/tsconfig.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "compilerOptions": {
3
+ "types": ["node"]
4
+ }
5
+ }