skopix 2.0.67 → 2.0.69

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.
@@ -1919,6 +1919,27 @@ export async function dashboardCommand(options) {
1919
1919
  sendJSON(res, 200, result);
1920
1920
  return;
1921
1921
  }
1922
+ if (pathname === '/api/step-library/sync-selectors' && method === 'POST') {
1923
+ const { fromSelectors, toSelector, toName } = JSON.parse(await readBody(req));
1924
+ const allTests = await listAllTests(suitesDir);
1925
+ let updated = 0;
1926
+ for (const test of allTests) {
1927
+ if (!test.steps || !test.steps.length) continue;
1928
+ let changed = false;
1929
+ const newSteps = test.steps.map(step => {
1930
+ const sSel = (step.stableSelector||step.selector||'').toLowerCase();
1931
+ if (fromSelectors.includes(sSel)) {
1932
+ changed = true;
1933
+ updated++;
1934
+ return { ...step, stableSelector: toSelector, selector: toSelector, description: toName || step.description };
1935
+ }
1936
+ return step;
1937
+ });
1938
+ if (changed) await updateTest(suitesDir, test.scope, test.id, { ...test, steps: newSteps });
1939
+ }
1940
+ sendJSON(res, 200, { updated });
1941
+ return;
1942
+ }
1922
1943
  if (pathname === '/api/step-library/sync' && method === 'POST') {
1923
1944
  const result = await syncTestsToLibrary(suitesDir);
1924
1945
  sendJSON(res, 200, result);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skopix",
3
- "version": "2.0.67",
3
+ "version": "2.0.69",
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": {
@@ -5870,9 +5870,18 @@ function openMergeSteps() {
5870
5870
  // Override the confirm button
5871
5871
  const actions = document.querySelector('.confirm-actions');
5872
5872
  if (actions) {
5873
- actions.innerHTML = `
5874
- <button class="btn btn-ghost" onclick="closeConfirm()">Cancel</button>
5875
- <button class="btn btn-primary" onclick="confirmMergeSteps(${JSON.stringify(ids)})">Merge</button>`;
5873
+ const mergeBtn = document.createElement('button');
5874
+ mergeBtn.className = 'btn btn-primary';
5875
+ mergeBtn.textContent = 'Merge';
5876
+ mergeBtn.dataset.mergeIds = JSON.stringify(ids);
5877
+ mergeBtn.addEventListener('click', () => confirmMergeSteps(JSON.parse(mergeBtn.dataset.mergeIds)));
5878
+ actions.innerHTML = '';
5879
+ const cancelBtn = document.createElement('button');
5880
+ cancelBtn.className = 'btn btn-ghost';
5881
+ cancelBtn.textContent = 'Cancel';
5882
+ cancelBtn.addEventListener('click', closeConfirm);
5883
+ actions.appendChild(cancelBtn);
5884
+ actions.appendChild(mergeBtn);
5876
5885
  }
5877
5886
  document.getElementById('confirm-overlay').classList.add('open');
5878
5887
  }
@@ -5885,15 +5894,29 @@ async function confirmMergeSteps(ids) {
5885
5894
  const toDelete = selected.filter(s => s.id !== canonicalId);
5886
5895
  const totalUses = selected.reduce((sum, s) => sum + (s.usageCount||0), 0);
5887
5896
  closeConfirm();
5897
+
5898
+ // Update canonical usage count
5888
5899
  await fetch(API_BASE + '/api/step-library/' + encodeURIComponent(canonicalId), {
5889
5900
  method: 'PUT',
5890
5901
  headers: { 'Content-Type': 'application/json' },
5891
5902
  body: JSON.stringify({ ...canonical, usageCount: totalUses })
5892
5903
  });
5904
+
5905
+ // Delete the merged ones
5893
5906
  for (const s of toDelete) {
5894
5907
  await fetch(API_BASE + '/api/step-library/' + encodeURIComponent(s.id), { method: 'DELETE' });
5895
5908
  }
5896
- showToast(`Merged ${selected.length} steps into "${canonical.name}"`);
5909
+
5910
+ // Update all tests that used any of the merged selectors to use the canonical selector
5911
+ const allMergedSelectors = selected.map(s => (s.stableSelector||s.selector||'').toLowerCase());
5912
+ const canonicalSel = canonical.stableSelector || canonical.selector;
5913
+ const res = await fetch(API_BASE + '/api/step-library/sync-selectors', {
5914
+ method: 'POST',
5915
+ headers: { 'Content-Type': 'application/json' },
5916
+ body: JSON.stringify({ fromSelectors: allMergedSelectors, toSelector: canonicalSel, toName: canonical.name })
5917
+ });
5918
+ const data = await res.json();
5919
+ showToast(`Merged into "${canonical.name}" — ${data.updated || 0} test step${data.updated !== 1 ? 's' : ''} updated`);
5897
5920
  await loadLibraryView();
5898
5921
  }
5899
5922