@matware/e2e-runner 1.2.1 → 1.3.1
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/.claude-plugin/marketplace.json +52 -0
- package/.claude-plugin/plugin.json +17 -3
- package/.mcp.json +2 -2
- package/.opencode/commands/create-test.md +63 -0
- package/.opencode/commands/run.md +50 -0
- package/.opencode/commands/verify-issue.md +62 -0
- package/.opencode/skills/e2e-testing/SKILL.md +181 -0
- package/.opencode/skills/e2e-testing/references/action-types.md +143 -0
- package/.opencode/skills/e2e-testing/references/auth-strategies.md +91 -0
- package/.opencode/skills/e2e-testing/references/graphql.md +59 -0
- package/.opencode/skills/e2e-testing/references/issue-verification.md +59 -0
- package/.opencode/skills/e2e-testing/references/multi-pool.md +60 -0
- package/.opencode/skills/e2e-testing/references/network-debugging.md +62 -0
- package/.opencode/skills/e2e-testing/references/test-json-format.md +163 -0
- package/.opencode/skills/e2e-testing/references/troubleshooting.md +224 -0
- package/.opencode/skills/e2e-testing/references/variables.md +41 -0
- package/.opencode/skills/e2e-testing/references/visual-verification.md +89 -0
- package/LICENSE +190 -0
- package/OPENCODE.md +166 -0
- package/README.md +165 -104
- package/agents/test-creator.md +54 -1
- package/agents/test-improver.md +37 -0
- package/bin/cli.js +409 -16
- package/commands/capture.md +45 -0
- package/commands/create-test.md +16 -1
- package/opencode.json +11 -0
- package/package.json +7 -2
- package/scripts/setup-opencode.sh +113 -0
- package/skills/e2e-testing/SKILL.md +10 -3
- package/skills/e2e-testing/references/action-types.md +48 -5
- package/skills/e2e-testing/references/auth-strategies.md +91 -0
- package/skills/e2e-testing/references/graphql.md +59 -0
- package/skills/e2e-testing/references/issue-verification.md +59 -0
- package/skills/e2e-testing/references/multi-pool.md +60 -0
- package/skills/e2e-testing/references/network-debugging.md +62 -0
- package/skills/e2e-testing/references/test-json-format.md +4 -0
- package/skills/e2e-testing/references/troubleshooting.md +44 -2
- package/skills/e2e-testing/references/variables.md +41 -0
- package/skills/e2e-testing/references/visual-verification.md +89 -0
- package/src/actions.js +475 -2
- package/src/ai-generate.js +139 -8
- package/src/app-pool.js +339 -0
- package/src/config.js +266 -5
- package/src/dashboard.js +216 -17
- package/src/db.js +191 -7
- package/src/index.js +12 -9
- package/src/learner-sqlite.js +458 -0
- package/src/learner.js +78 -6
- package/src/mcp-tools.js +1348 -51
- package/src/module-resolver.js +37 -0
- package/src/narrate.js +65 -0
- package/src/pool-manager.js +229 -0
- package/src/pool.js +301 -31
- package/src/reporter.js +86 -2
- package/src/runner.js +480 -71
- package/src/sync/auth.js +354 -0
- package/src/sync/client.js +572 -0
- package/src/sync/hub-routes.js +816 -0
- package/src/sync/index.js +68 -0
- package/src/sync/middleware.js +347 -0
- package/src/sync/queue.js +209 -0
- package/src/sync/schema.js +540 -0
- package/src/verify.js +10 -7
- package/src/visual-diff.js +446 -0
- package/src/watch.js +384 -0
- package/templates/build-dashboard.js +47 -6
- package/templates/dashboard/js/api.js +62 -0
- package/templates/dashboard/js/init.js +13 -0
- package/templates/dashboard/js/keyboard.js +46 -0
- package/templates/dashboard/js/state.js +40 -0
- package/templates/dashboard/js/toast.js +41 -0
- package/templates/dashboard/js/utils.js +216 -0
- package/templates/dashboard/js/view-live.js +181 -0
- package/templates/dashboard/js/view-runs.js +676 -0
- package/templates/dashboard/js/view-tests.js +294 -0
- package/templates/dashboard/js/view-watch.js +242 -0
- package/templates/dashboard/js/websocket.js +116 -0
- package/templates/dashboard/styles/base.css +69 -0
- package/templates/dashboard/styles/components.css +117 -0
- package/templates/dashboard/styles/view-live.css +97 -0
- package/templates/dashboard/styles/view-runs.css +243 -0
- package/templates/dashboard/styles/view-tests.css +96 -0
- package/templates/dashboard/styles/view-watch.css +53 -0
- package/templates/dashboard/template.html +181 -100
- package/templates/dashboard.html +1614 -547
- package/templates/sample-test.json +0 -8
- package/templates/dashboard/app.js +0 -1152
- package/templates/dashboard/styles.css +0 -413
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/* ── Watch View: Project Cards ── */
|
|
2
|
+
.watch-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px;margin-bottom:24px}
|
|
3
|
+
.watch-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);padding:16px;transition:border-color .2s,box-shadow .2s}
|
|
4
|
+
.watch-card:hover{border-color:var(--border-hi);box-shadow:0 2px 12px rgba(0,0,0,.25)}
|
|
5
|
+
.watch-card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}
|
|
6
|
+
.watch-card-name{font-family:var(--sans);font-size:14px;font-weight:600;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}
|
|
7
|
+
.watch-card-icons{display:flex;gap:6px;flex-shrink:0;margin-left:8px}
|
|
8
|
+
.watch-card-icons .btn{padding:3px 8px;font-size:10px}
|
|
9
|
+
|
|
10
|
+
/* ── Sparkline ── */
|
|
11
|
+
.watch-sparkline{height:40px;margin-bottom:10px}
|
|
12
|
+
.watch-sparkline svg{width:100%;height:100%;display:block}
|
|
13
|
+
|
|
14
|
+
/* ── Card Footer ── */
|
|
15
|
+
.watch-card-footer{display:flex;align-items:center;justify-content:space-between;font-size:11px}
|
|
16
|
+
.watch-card-status{display:flex;align-items:center;gap:6px}
|
|
17
|
+
.watch-card-status .status-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}
|
|
18
|
+
.watch-card-status .status-dot.green{background:var(--green);box-shadow:0 0 6px var(--green)}
|
|
19
|
+
.watch-card-status .status-dot.red{background:var(--red);box-shadow:0 0 6px var(--red)}
|
|
20
|
+
.watch-card-status .status-dot.amber{background:var(--amber);box-shadow:0 0 6px var(--amber)}
|
|
21
|
+
.watch-card-status .status-dot.dim{background:var(--text3)}
|
|
22
|
+
.watch-card-rate{font-weight:600}
|
|
23
|
+
.watch-card-rate.green{color:var(--green)}
|
|
24
|
+
.watch-card-rate.amber{color:var(--amber)}
|
|
25
|
+
.watch-card-rate.red{color:var(--red)}
|
|
26
|
+
|
|
27
|
+
.watch-card-meta{display:flex;flex-direction:column;gap:4px;margin-top:10px;font-size:10px;color:var(--text3)}
|
|
28
|
+
.watch-card-meta span{display:flex;align-items:center;gap:6px}
|
|
29
|
+
.watch-card-countdown{color:var(--accent);font-weight:500;font-variant-numeric:tabular-nums}
|
|
30
|
+
.watch-card-commit{font-family:var(--mono);color:var(--text3)}
|
|
31
|
+
|
|
32
|
+
/* ── Event Log ── */
|
|
33
|
+
.watch-event-log{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);overflow:hidden}
|
|
34
|
+
.watch-event-log-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--border);background:var(--surface2)}
|
|
35
|
+
.watch-event-log-header .title{font-family:var(--sans);font-size:13px;font-weight:600}
|
|
36
|
+
.watch-event-log-body{max-height:400px;overflow-y:auto}
|
|
37
|
+
.watch-event-row{display:grid;grid-template-columns:120px 130px minmax(80px,1fr) 46px 74px 40px 52px 60px;align-items:center;gap:0;padding:7px 16px;border-bottom:1px solid var(--border);font-size:11px;transition:background .1s}
|
|
38
|
+
.watch-event-row:last-child{border-bottom:none}
|
|
39
|
+
.watch-event-row:hover{background:var(--surface2)}
|
|
40
|
+
.watch-event-row.we-header{font-size:9px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:.5px;padding:6px 16px;background:var(--surface2);border-bottom:1px solid var(--border);position:sticky;top:0;z-index:1}
|
|
41
|
+
.watch-event-row.we-header:hover{background:var(--surface2)}
|
|
42
|
+
.watch-event-time{color:var(--text3);font-variant-numeric:tabular-nums;font-family:var(--mono);font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
43
|
+
.watch-event-project{color:var(--text);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-right:8px}
|
|
44
|
+
.watch-event-suite{color:var(--accent);font-family:var(--mono);font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-right:8px}
|
|
45
|
+
.watch-event-result{justify-self:center}
|
|
46
|
+
.watch-event-counts{font-family:var(--mono);font-size:10px;color:var(--text2);white-space:nowrap;text-align:center}
|
|
47
|
+
.watch-event-counts .we-counts-ok{color:var(--green)}
|
|
48
|
+
.watch-event-rate{font-weight:600;color:var(--text2);font-variant-numeric:tabular-nums;text-align:right}
|
|
49
|
+
.watch-event-duration{color:var(--text3);font-family:var(--mono);font-size:10px;text-align:right}
|
|
50
|
+
.we-trigger{color:var(--text3);font-size:9px;padding:1px 6px;border-radius:8px;background:var(--surface3);white-space:nowrap;text-align:center;justify-self:end}
|
|
51
|
+
|
|
52
|
+
/* ── Watch Table (legacy) ── */
|
|
53
|
+
.watch-jobs-table{width:100%;border-collapse:collapse;font-size:11px}
|
|
@@ -28,20 +28,17 @@
|
|
|
28
28
|
<div class="sidebar-section">
|
|
29
29
|
<div class="sidebar-section-label">Navigation</div>
|
|
30
30
|
</div>
|
|
31
|
-
<div class="nav-item" data-view="
|
|
32
|
-
<i class="icon"
|
|
31
|
+
<div class="nav-item active" data-view="watch">
|
|
32
|
+
<i class="icon">⏲</i><span>Watch</span>
|
|
33
33
|
</div>
|
|
34
|
-
<div class="nav-item
|
|
35
|
-
<i class="icon">▷</i><span>
|
|
34
|
+
<div class="nav-item" data-view="tests">
|
|
35
|
+
<i class="icon">▷</i><span>Tests</span><span class="badge" id="badgeSuites">-</span>
|
|
36
36
|
</div>
|
|
37
37
|
<div class="nav-item" data-view="runs">
|
|
38
38
|
<i class="icon">☰</i><span>Runs</span><span class="badge" id="badgeRuns">-</span>
|
|
39
39
|
</div>
|
|
40
|
-
<div class="nav-item" data-view="
|
|
41
|
-
<i class="icon"
|
|
42
|
-
</div>
|
|
43
|
-
<div class="nav-item" data-view="learnings">
|
|
44
|
-
<i class="icon">★</i><span>Learnings</span><span class="badge" id="badgeLearnings">-</span>
|
|
40
|
+
<div class="nav-item" data-view="live" id="navLive" style="display:none">
|
|
41
|
+
<i class="icon"><span class="live-nav-dot"></span></i><span>Live</span><span class="badge" id="liveBadge" style="background:var(--purple-dim);color:var(--purple)">0</span>
|
|
45
42
|
</div>
|
|
46
43
|
|
|
47
44
|
<div class="pool-status" id="poolStatus">
|
|
@@ -50,6 +47,7 @@
|
|
|
50
47
|
<strong>Pool</strong> <span id="poolLabel">--</span>
|
|
51
48
|
</div>
|
|
52
49
|
<div class="pool-info">Sessions: <strong id="poolSessions">-/-</strong></div>
|
|
50
|
+
<div class="pool-list" id="poolList" style="display:none"></div>
|
|
53
51
|
<div class="pool-info" style="margin-top:6px">
|
|
54
52
|
<span class="ws-dot" id="wsDot" style="background:var(--red)"></span>
|
|
55
53
|
<span id="wsLabel" style="font-size:10px;color:var(--text3)">ws: connecting</span>
|
|
@@ -59,7 +57,148 @@
|
|
|
59
57
|
|
|
60
58
|
<div class="main">
|
|
61
59
|
|
|
62
|
-
<!--
|
|
60
|
+
<!-- ════════════════ Watch View (default) ════════════════ -->
|
|
61
|
+
<div class="view active" id="view-watch">
|
|
62
|
+
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px">
|
|
63
|
+
<div style="font-family:var(--sans);font-size:16px;font-weight:600">Watch</div>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="watch-grid" id="watchCards"></div>
|
|
66
|
+
<div class="watch-event-log">
|
|
67
|
+
<div class="watch-event-log-header">
|
|
68
|
+
<span class="title">Recent Runs</span>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="watch-event-log-body" id="watchEventLog"></div>
|
|
71
|
+
</div>
|
|
72
|
+
<div class="empty" id="watchEmpty" style="display:none">
|
|
73
|
+
<div class="empty-icon">⏲</div>
|
|
74
|
+
<p>No projects registered yet. Run some tests to see project cards here.</p>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<!-- ════════════════ Tests View (inner tabs: Suites / Modules / Variables) ════════════════ -->
|
|
79
|
+
<div class="view" id="view-tests">
|
|
80
|
+
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px">
|
|
81
|
+
<div style="font-family:var(--sans);font-size:16px;font-weight:600">Tests</div>
|
|
82
|
+
<div style="display:flex;gap:8px;align-items:center">
|
|
83
|
+
<label class="screencast-toggle-label" title="Enable live browser screencast during test runs">
|
|
84
|
+
<input type="checkbox" id="screencastToggle" />
|
|
85
|
+
<span>📹</span>
|
|
86
|
+
</label>
|
|
87
|
+
<button class="btn sm primary" id="btnRunAll">▷ Run All</button>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="tab-bar">
|
|
91
|
+
<button class="tab-btn active" data-tab="testsTabSuites">Suites</button>
|
|
92
|
+
<button class="tab-btn" data-tab="testsTabModules">Modules</button>
|
|
93
|
+
<button class="tab-btn" data-tab="testsTabVariables">Variables</button>
|
|
94
|
+
</div>
|
|
95
|
+
<!-- Suites tab -->
|
|
96
|
+
<div class="tab-pane active" id="testsTabSuites">
|
|
97
|
+
<div id="suiteAccordionContainer"></div>
|
|
98
|
+
<div class="suite-grid" id="suiteGrid"></div>
|
|
99
|
+
<div class="empty" id="suitesEmpty" style="display:none">
|
|
100
|
+
<div class="empty-icon">▷</div>
|
|
101
|
+
<p>No test suites found.</p>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
<!-- Modules tab -->
|
|
105
|
+
<div class="tab-pane" id="testsTabModules">
|
|
106
|
+
<div id="moduleSection"></div>
|
|
107
|
+
</div>
|
|
108
|
+
<!-- Variables tab -->
|
|
109
|
+
<div class="tab-pane" id="testsTabVariables">
|
|
110
|
+
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px">
|
|
111
|
+
<div style="font-family:var(--sans);font-size:14px;font-weight:600;color:var(--text2)">Variables</div>
|
|
112
|
+
<button class="btn sm primary" id="btnAddVar">+ Add Variable</button>
|
|
113
|
+
</div>
|
|
114
|
+
<div id="varAddForm" style="display:none"></div>
|
|
115
|
+
<div id="variablesContainer"></div>
|
|
116
|
+
<div class="empty" id="variablesEmpty" style="display:none">
|
|
117
|
+
<div class="empty-icon">⚙</div>
|
|
118
|
+
<p>No variables set. Add variables to use <code>{{var.KEY}}</code> in your tests.</p>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<!-- ════════════════ Runs View (inner tabs: History / Screenshots / Learnings) ════════════════ -->
|
|
124
|
+
<div class="view" id="view-runs">
|
|
125
|
+
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px">
|
|
126
|
+
<div style="font-family:var(--sans);font-size:16px;font-weight:600">Runs</div>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="tab-bar">
|
|
129
|
+
<button class="tab-btn active" data-tab="runsTabHistory">History</button>
|
|
130
|
+
<button class="tab-btn" data-tab="runsTabScreenshots">Screenshots<span class="badge" id="badgeScreenshots" style="margin-left:6px">-</span></button>
|
|
131
|
+
<button class="tab-btn" data-tab="runsTabLearnings" id="runsTabLearnings">Learnings<span class="badge" id="badgeLearnings" style="margin-left:6px">-</span></button>
|
|
132
|
+
</div>
|
|
133
|
+
<!-- History tab -->
|
|
134
|
+
<div class="tab-pane active" id="runsTabHistory">
|
|
135
|
+
<div class="health-banner" id="runsHealthBanner"></div>
|
|
136
|
+
<div class="card">
|
|
137
|
+
<div class="card-label">Pass Rate Trend</div>
|
|
138
|
+
<div class="chart" id="trendChart"></div>
|
|
139
|
+
</div>
|
|
140
|
+
<div class="filter-bar" id="filterBar">
|
|
141
|
+
<button class="filter-btn active" data-filter="all">All</button>
|
|
142
|
+
<button class="filter-btn" data-filter="pass">Pass</button>
|
|
143
|
+
<button class="filter-btn" data-filter="fail">Fail</button>
|
|
144
|
+
<button class="filter-btn" data-filter="mixed">Mixed</button>
|
|
145
|
+
<input type="text" id="runSearchInput" placeholder="Search suite..." spellcheck="false">
|
|
146
|
+
</div>
|
|
147
|
+
<div class="card" style="padding:0">
|
|
148
|
+
<div class="tbl-wrap">
|
|
149
|
+
<table>
|
|
150
|
+
<thead id="runsHead"><tr></tr></thead>
|
|
151
|
+
<tbody id="runsBody"></tbody>
|
|
152
|
+
</table>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
<div class="empty" id="runsEmpty" style="display:none">
|
|
156
|
+
<div class="empty-icon">☰</div>
|
|
157
|
+
<p>No runs recorded yet.</p>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
<!-- Screenshots tab -->
|
|
161
|
+
<div class="tab-pane" id="runsTabScreenshots">
|
|
162
|
+
<div class="ss-search">
|
|
163
|
+
<input type="text" id="ssHashInput" placeholder="Search by hash (e.g. ss:a3f2b1c9)" spellcheck="false">
|
|
164
|
+
<button id="ssHashBtn">Search</button>
|
|
165
|
+
</div>
|
|
166
|
+
<div id="ssSearchResult"></div>
|
|
167
|
+
<div class="gallery" id="screenshotGallery"></div>
|
|
168
|
+
<div class="empty" id="screenshotsEmpty" style="display:none">
|
|
169
|
+
<div class="empty-icon">▣</div>
|
|
170
|
+
<p>Select a project to view screenshots.</p>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
<!-- Learnings tab -->
|
|
174
|
+
<div class="tab-pane" id="runsTabLearnings">
|
|
175
|
+
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px">
|
|
176
|
+
<div style="font-family:var(--sans);font-size:14px;font-weight:600;color:var(--text2)">Learnings</div>
|
|
177
|
+
<div style="display:flex;gap:8px;align-items:center">
|
|
178
|
+
<select id="learningsDays" style="padding:5px 8px;border-radius:var(--r);border:1px solid var(--border);background:var(--surface2);color:var(--text);font-family:var(--mono);font-size:11px">
|
|
179
|
+
<option value="7">7 days</option>
|
|
180
|
+
<option value="14">14 days</option>
|
|
181
|
+
<option value="30" selected>30 days</option>
|
|
182
|
+
<option value="90">90 days</option>
|
|
183
|
+
</select>
|
|
184
|
+
<button class="btn sm" id="btnExportLearnings">Export MD</button>
|
|
185
|
+
<button class="btn sm" id="btnRefreshLearnings">Refresh</button>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
<div id="learnDash">
|
|
189
|
+
<div id="learnHero"></div>
|
|
190
|
+
<div id="learnCards" class="learn-cols"></div>
|
|
191
|
+
<div id="learnTrend"></div>
|
|
192
|
+
<div id="learnBottom" class="learn-cols"></div>
|
|
193
|
+
</div>
|
|
194
|
+
<div class="empty" id="learningsEmpty" style="display:none">
|
|
195
|
+
<div class="empty-icon">★</div>
|
|
196
|
+
<p>No learnings data yet. Run some tests to start building knowledge.</p>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<!-- ════════════════ Live View ════════════════ -->
|
|
63
202
|
<div class="view" id="view-live">
|
|
64
203
|
<div class="live-panel active" id="livePanel">
|
|
65
204
|
<div class="live-header">
|
|
@@ -78,114 +217,56 @@
|
|
|
78
217
|
<button class="live-clear-btn" id="liveClearBtn">Clear All</button>
|
|
79
218
|
</div>
|
|
80
219
|
<div class="live-progress"><div class="live-progress-fill" id="liveProgressFill" style="width:0"></div></div>
|
|
81
|
-
<div class="live-
|
|
220
|
+
<div class="live-body">
|
|
221
|
+
<div class="live-tests" id="liveTests"></div>
|
|
222
|
+
<div class="screencast-panel" id="screencastPanel" style="display:none">
|
|
223
|
+
<div class="screencast-header">
|
|
224
|
+
<span class="screencast-label">📹 Screencast</span>
|
|
225
|
+
<select id="screencastSelect" class="screencast-select"><option value="">Select test...</option></select>
|
|
226
|
+
</div>
|
|
227
|
+
<div class="screencast-viewport">
|
|
228
|
+
<img id="screencastImg" alt="Browser screencast" />
|
|
229
|
+
<div class="screencast-placeholder" id="screencastPlaceholder">Select a running test to watch</div>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
82
233
|
</div>
|
|
83
234
|
<div class="empty" id="liveEmpty">
|
|
84
235
|
<div class="empty-icon" style="font-size:48px;opacity:.3">●</div>
|
|
85
|
-
<p>No tests running. Start a test from the
|
|
236
|
+
<p>No tests running. Start a test from the Tests view or another console.</p>
|
|
86
237
|
<p style="margin-top:8px;font-size:11px;color:var(--text3)">This view activates automatically when tests are detected.</p>
|
|
87
238
|
</div>
|
|
88
239
|
</div>
|
|
89
240
|
|
|
90
|
-
|
|
91
|
-
<div class="view active" id="view-suites">
|
|
92
|
-
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px">
|
|
93
|
-
<div style="font-family:var(--sans);font-size:16px;font-weight:600">Test Suites</div>
|
|
94
|
-
<button class="btn primary" id="btnRunAll">Run All Tests</button>
|
|
95
|
-
</div>
|
|
96
|
-
<div class="suite-grid" id="suiteGrid"></div>
|
|
97
|
-
<div id="moduleSection"></div>
|
|
98
|
-
<div class="empty" id="suitesEmpty" style="display:none">
|
|
99
|
-
<div class="empty-icon">▷</div>
|
|
100
|
-
<p>No test suites found.</p>
|
|
101
|
-
</div>
|
|
102
|
-
</div>
|
|
241
|
+
</div>
|
|
103
242
|
|
|
104
|
-
|
|
105
|
-
<div class="
|
|
106
|
-
<div
|
|
107
|
-
<div
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
<button class="filter-btn" data-filter="pass">Pass</button>
|
|
116
|
-
<button class="filter-btn" data-filter="fail">Fail</button>
|
|
117
|
-
<button class="filter-btn" data-filter="mixed">Mixed</button>
|
|
118
|
-
<input type="text" id="runSearchInput" placeholder="Search suite..." spellcheck="false">
|
|
119
|
-
</div>
|
|
120
|
-
<div class="card" style="padding:0">
|
|
121
|
-
<div class="tbl-wrap">
|
|
122
|
-
<table>
|
|
123
|
-
<thead id="runsHead"><tr></tr></thead>
|
|
124
|
-
<tbody id="runsBody"></tbody>
|
|
125
|
-
</table>
|
|
243
|
+
<div class="suite-modal-overlay" id="suiteModalOverlay">
|
|
244
|
+
<div class="suite-modal" id="suiteModal">
|
|
245
|
+
<div class="suite-modal-header">
|
|
246
|
+
<div class="suite-card-icon">▷</div>
|
|
247
|
+
<div class="suite-modal-title">
|
|
248
|
+
<h2 id="suiteModalName"></h2>
|
|
249
|
+
<span id="suiteModalFile"></span>
|
|
250
|
+
</div>
|
|
251
|
+
<div class="suite-modal-actions">
|
|
252
|
+
<button class="btn sm primary" id="suiteModalRun">▷ Run</button>
|
|
253
|
+
<button class="suite-modal-close" id="suiteModalClose">×</button>
|
|
126
254
|
</div>
|
|
127
255
|
</div>
|
|
128
|
-
<div class="
|
|
129
|
-
<div class="
|
|
130
|
-
<p>No runs recorded yet.</p>
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
133
|
-
|
|
134
|
-
<!-- Learnings View -->
|
|
135
|
-
<div class="view" id="view-learnings">
|
|
136
|
-
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px">
|
|
137
|
-
<div style="font-family:var(--sans);font-size:16px;font-weight:600">Learnings</div>
|
|
138
|
-
<div style="display:flex;gap:8px;align-items:center">
|
|
139
|
-
<select id="learningsDays" style="padding:5px 8px;border-radius:var(--r);border:1px solid var(--border);background:var(--surface2);color:var(--text);font-family:var(--mono);font-size:11px">
|
|
140
|
-
<option value="7">7 days</option>
|
|
141
|
-
<option value="14">14 days</option>
|
|
142
|
-
<option value="30" selected>30 days</option>
|
|
143
|
-
<option value="90">90 days</option>
|
|
144
|
-
</select>
|
|
145
|
-
<button class="btn sm" id="btnExportLearnings">Export MD</button>
|
|
146
|
-
<button class="btn sm" id="btnRefreshLearnings">Refresh</button>
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
149
|
-
<div id="learningsOverview"></div>
|
|
150
|
-
<div id="learningsTrend"></div>
|
|
151
|
-
<div id="learningsFlaky"></div>
|
|
152
|
-
<div id="learningsSelectors"></div>
|
|
153
|
-
<div id="learningsPages"></div>
|
|
154
|
-
<div id="learningsApis"></div>
|
|
155
|
-
<div id="learningsErrors"></div>
|
|
156
|
-
<div class="empty" id="learningsEmpty" style="display:none">
|
|
157
|
-
<div class="empty-icon">★</div>
|
|
158
|
-
<p>No learnings data yet. Run some tests to start building knowledge.</p>
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
|
|
162
|
-
<!-- Screenshots View -->
|
|
163
|
-
<div class="view" id="view-screenshots">
|
|
164
|
-
<div style="font-family:var(--sans);font-size:16px;font-weight:600;margin-bottom:20px">Screenshots</div>
|
|
165
|
-
<div class="ss-search">
|
|
166
|
-
<input type="text" id="ssHashInput" placeholder="Search by hash (e.g. ss:a3f2b1c9)" spellcheck="false">
|
|
167
|
-
<button id="ssHashBtn">Search</button>
|
|
168
|
-
</div>
|
|
169
|
-
<div id="ssSearchResult"></div>
|
|
170
|
-
<div class="gallery" id="screenshotGallery"></div>
|
|
171
|
-
<div class="empty" id="screenshotsEmpty" style="display:none">
|
|
172
|
-
<div class="empty-icon">▣</div>
|
|
173
|
-
<p>Select a project to view screenshots.</p>
|
|
256
|
+
<div class="suite-modal-body" id="suiteModalBody">
|
|
257
|
+
<div class="suite-modal-loading">Loading...</div>
|
|
174
258
|
</div>
|
|
175
259
|
</div>
|
|
176
|
-
|
|
177
260
|
</div>
|
|
178
|
-
|
|
179
261
|
<div class="modal" id="modal"><img id="modalImg" src="" alt=""></div>
|
|
180
262
|
<div class="toast-container" id="toastContainer"></div>
|
|
181
263
|
<div class="kb-modal" id="kbModal">
|
|
182
264
|
<div class="kb-modal-content">
|
|
183
265
|
<h2>Keyboard Shortcuts</h2>
|
|
184
|
-
<div class="kb-row"><span class="kb-key">1</span><span class="kb-desc">
|
|
185
|
-
<div class="kb-row"><span class="kb-key">2</span><span class="kb-desc">
|
|
186
|
-
<div class="kb-row"><span class="kb-key">3</span><span class="kb-desc">
|
|
187
|
-
<div class="kb-row"><span class="kb-key">4</span><span class="kb-desc">
|
|
188
|
-
<div class="kb-row"><span class="kb-key">5</span><span class="kb-desc">Live view</span></div>
|
|
266
|
+
<div class="kb-row"><span class="kb-key">1</span><span class="kb-desc">Watch view</span></div>
|
|
267
|
+
<div class="kb-row"><span class="kb-key">2</span><span class="kb-desc">Tests view</span></div>
|
|
268
|
+
<div class="kb-row"><span class="kb-key">3</span><span class="kb-desc">Runs view</span></div>
|
|
269
|
+
<div class="kb-row"><span class="kb-key">4</span><span class="kb-desc">Live view</span></div>
|
|
189
270
|
<div class="kb-row"><span class="kb-key">j / k</span><span class="kb-desc">Navigate runs (next / previous)</span></div>
|
|
190
271
|
<div class="kb-row"><span class="kb-key">Enter</span><span class="kb-desc">Expand / collapse selected run</span></div>
|
|
191
272
|
<div class="kb-row"><span class="kb-key">Esc</span><span class="kb-desc">Close modal / collapse run</span></div>
|