skopix 2.0.83 → 2.0.84

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.
@@ -1022,6 +1022,10 @@ export async function dashboardCommand(options) {
1022
1022
  const userEnv = await resolveUserSecretsEnv(currentUser && currentUser.id, teamMode);
1023
1023
  Object.assign(process.env, userEnv || {});
1024
1024
  const result = await processRecording({ steps, testName, url, provider: provider || 'gemini' });
1025
+ // Match processed steps against library — substitute known elements
1026
+ const matched = await matchStepsToLibrary(suitesDir, result.steps || []);
1027
+ result.steps = matched.steps;
1028
+ result.matchedCount = matched.count;
1025
1029
  sendJSON(res, 200, result);
1026
1030
  } catch (err) { sendJSON(res, 500, { error: err.message }); }
1027
1031
  return;
@@ -3867,6 +3871,47 @@ async function syncIssuesStatus() {
3867
3871
  // STEP LIBRARY — persistent store of reusable UI interactions
3868
3872
  // ═══════════════════════════════════════════════════════════════
3869
3873
 
3874
+ // Match recorded steps against library — substitute known elements automatically
3875
+ async function matchStepsToLibrary(suitesDir, steps) {
3876
+ const library = await listLibrarySteps(suitesDir);
3877
+ if (!library.length || !steps.length) return { steps, count: 0 };
3878
+
3879
+ let count = 0;
3880
+ const matched = steps.map(step => {
3881
+ const sSel = (step.stableSelector || step.selector || '').toLowerCase();
3882
+ if (!sSel) return step;
3883
+
3884
+ // Find matching library element
3885
+ const match = library.find(lib => {
3886
+ const lSel = (lib.stableSelector || lib.selector || '').toLowerCase();
3887
+ if (!lSel) return false;
3888
+ // Exact match
3889
+ if (sSel === lSel) return true;
3890
+ // One contains the other (handles i.fa-plus vs a[title="x"] i.fa-plus)
3891
+ if (sSel.includes(lSel) || lSel.includes(sSel)) return true;
3892
+ // Shared key tokens
3893
+ const keyTokens = lSel.match(/\.[a-z][a-z0-9_-]+|\[[\w-]+=["'][^"']+["']\]|#[a-z][a-z0-9_-]+/g) || [];
3894
+ const strongTokens = keyTokens.filter(t => t.length > 8);
3895
+ if (strongTokens.length > 0 && strongTokens.some(tok => sSel.includes(tok))) return true;
3896
+ return false;
3897
+ });
3898
+
3899
+ if (match) {
3900
+ count++;
3901
+ return {
3902
+ ...step,
3903
+ stableSelector: match.stableSelector || match.selector,
3904
+ selector: match.selector || match.stableSelector,
3905
+ description: match.name || step.description,
3906
+ libraryId: match.id,
3907
+ };
3908
+ }
3909
+ return step;
3910
+ });
3911
+
3912
+ return { steps: matched, count };
3913
+ }
3914
+
3870
3915
  const FOLDERS_FILE = () => path.join(os.homedir(), '.skopix', 'folders.yaml');
3871
3916
 
3872
3917
  async function getFolders() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skopix",
3
- "version": "2.0.83",
3
+ "version": "2.0.84",
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": {