skopix 2.0.42 → 2.0.44

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.
@@ -3978,6 +3978,8 @@ async function startStepTester(testerId, url, selector, mode, steps) {
3978
3978
  border-radius:6px;padding:4px 10px;cursor:pointer;font-size:11px;font-family:monospace">▶ Next</button>
3979
3979
  <button id="__skopix_run_all" style="background:#f59e0b;border:none;color:#000;
3980
3980
  border-radius:6px;padding:4px 10px;cursor:pointer;font-size:11px;font-family:monospace;font-weight:700">▶▶ All</button>
3981
+ <button id="__skopix_stop_preview" style="background:transparent;border:1px solid #374151;color:#9ca3af;
3982
+ border-radius:6px;padding:4px 10px;cursor:pointer;font-size:11px;font-family:monospace">✕ Stop</button>
3981
3983
  </div>
3982
3984
  </div>
3983
3985
  <div id="__skopix_preview_status" style="color:#9ca3af;font-size:11px">Navigate to start, then click Run</div>
@@ -4023,6 +4025,11 @@ async function startStepTester(testerId, url, selector, mode, steps) {
4023
4025
  if (window.__skopixPreviewRunAll) window.__skopixPreviewRunAll({ fromIndex: window.__skopixPreviewCurrentStep });
4024
4026
  });
4025
4027
 
4028
+ document.getElementById('__skopix_stop_preview').addEventListener('click', (e) => {
4029
+ e.stopPropagation();
4030
+ if (window.__skopixStopPreview) window.__skopixStopPreview({});
4031
+ });
4032
+
4026
4033
  window.__skopixUpdatePreview = (index, result, status) => {
4027
4034
  window.__skopixPreviewResults[index] = result;
4028
4035
  if (result && result.passed) window.__skopixPreviewCurrentStep = index + 1;
@@ -4076,6 +4083,11 @@ async function startStepTester(testerId, url, selector, mode, steps) {
4076
4083
  }
4077
4084
  });
4078
4085
 
4086
+ await ctx.exposeFunction('__skopixStopPreview', async () => {
4087
+ try { await browser.close(); } catch {}
4088
+ stepTesterSessions.delete(testerId);
4089
+ });
4090
+
4079
4091
  } else {
4080
4092
  // STEP TESTER MODE — single step toolbar
4081
4093
  await ctx.addInitScript((sel) => {
@@ -4112,6 +4124,8 @@ async function startStepTester(testerId, url, selector, mode, steps) {
4112
4124
  border-radius:6px;padding:5px 14px;cursor:pointer;font-size:11px;font-weight:700;
4113
4125
  font-family:monospace">▶ Run</button>
4114
4126
  <span id="__skopix_result" style="font-size:13px;min-width:20px"></span>
4127
+ <button id="__skopix_stop" style="background:transparent;border:1px solid #374151;color:#9ca3af;
4128
+ border-radius:6px;padding:5px 10px;cursor:pointer;font-size:11px;font-family:monospace">✕ Stop</button>
4115
4129
  `;
4116
4130
  document.body.appendChild(tb);
4117
4131
  document.getElementById('__skopix_action').addEventListener('change', function() {
@@ -4126,27 +4140,52 @@ async function startStepTester(testerId, url, selector, mode, steps) {
4126
4140
  document.getElementById('__skopix_result').textContent = '⏳';
4127
4141
  if (window.__skopixTesterRun) window.__skopixTesterRun({ sel, action, value });
4128
4142
  });
4143
+ document.getElementById('__skopix_stop').addEventListener('click', function(e) {
4144
+ e.stopPropagation();
4145
+ if (window.__skopixTesterStop) window.__skopixTesterStop({});
4146
+ });
4129
4147
  });
4130
4148
  }, selector || '');
4131
4149
 
4132
4150
  await ctx.exposeFunction('__skopixTesterRun', async ({ sel, action, value }) => {
4133
4151
  const result = await executeStepTesterAction(page, { selector: sel, action, value });
4134
- await page.evaluate((r, sel) => {
4152
+ // Update toolbar via exposeFunction callback — more reliable than evaluate
4153
+ await page.evaluate((passed, errMsg) => {
4135
4154
  const el = document.getElementById('__skopix_result');
4136
- if (el) el.textContent = r.passed ? '✓' : '✗';
4155
+ if (el) {
4156
+ el.textContent = passed ? '✓' : '✗';
4157
+ el.style.color = passed ? '#34d399' : '#ef4444';
4158
+ }
4159
+ }, result.passed, result.error || '').catch(async () => {
4160
+ // If evaluate fails (e.g. page navigated), wait and retry once
4161
+ await new Promise(r => setTimeout(r, 500));
4162
+ await page.evaluate((passed) => {
4163
+ const el = document.getElementById('__skopix_result');
4164
+ if (el) { el.textContent = passed ? '✓' : '✗'; el.style.color = passed ? '#34d399' : '#ef4444'; }
4165
+ }, result.passed).catch(() => {});
4166
+ });
4167
+ // Highlight element
4168
+ await page.evaluate((passed, sel) => {
4137
4169
  try {
4138
4170
  const target = document.querySelector(sel);
4139
4171
  if (target) {
4140
4172
  const orig = target.style.outline;
4141
- target.style.outline = r.passed ? '3px solid #34d399' : '3px solid #ef4444';
4173
+ target.style.outline = passed ? '3px solid #34d399' : '3px solid #ef4444';
4142
4174
  setTimeout(() => { target.style.outline = orig; }, 1500);
4143
4175
  }
4144
4176
  } catch {}
4145
- }, result, sel);
4177
+ }, result.passed, sel).catch(() => {});
4178
+ });
4179
+
4180
+ await ctx.exposeFunction('__skopixTesterStop', async () => {
4181
+ try { await browser.close(); } catch {}
4182
+ stepTesterSessions.delete(testerId);
4146
4183
  });
4147
4184
  }
4148
4185
 
4149
4186
  if (url) await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 }).catch(() => {});
4187
+ // Ensure toolbar is injected on first page (DOMContentLoaded may have already fired)
4188
+ await page.evaluate(() => { if (window.__skopixTesterSelector !== undefined && !document.getElementById('__skopix_tester') && !document.getElementById('__skopix_preview')) { document.dispatchEvent(new Event('DOMContentLoaded')); } }).catch(() => {});
4150
4189
  stepTesterSessions.set(testerId, { browser, ctx, page });
4151
4190
  }
4152
4191
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skopix",
3
- "version": "2.0.42",
3
+ "version": "2.0.44",
4
4
  "description": "Browser-based QA tool — record tests by using your app, replay them deterministically, generate Playwright code automatically",
5
5
  "main": "cli/index.js",
6
6
  "bin": {