@skyramp/skyramp 1.3.16 → 1.3.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.
package/package.json
CHANGED
|
@@ -320,6 +320,7 @@ class GoJSDiagram {
|
|
|
320
320
|
anchorOffsetY = 0,
|
|
321
321
|
} = opts;
|
|
322
322
|
|
|
323
|
+
// Phase 1: Add the node via GoJS model API (no selection here).
|
|
323
324
|
await this._evaluateInFrame(([diagSel, palSel, nodeKey, nodeCat, anKey, offX, offY]) => {
|
|
324
325
|
const go = window.go;
|
|
325
326
|
if (!go) throw new Error('GoJSDiagram: GoJS not found on window');
|
|
@@ -361,6 +362,32 @@ class GoJSDiagram {
|
|
|
361
362
|
diagram.commitTransaction(txName);
|
|
362
363
|
}
|
|
363
364
|
}, [diagramSelector, paletteSelector ?? '', key, category, anchorKey ?? '', anchorOffsetX, anchorOffsetY]);
|
|
365
|
+
|
|
366
|
+
// Phase 2: Wait for GoJS to finish its layout pass after the transaction.
|
|
367
|
+
await this._page.waitForTimeout(300);
|
|
368
|
+
|
|
369
|
+
// Phase 3: Select via GoJS API (fires ChangedSelection for apps that listen to it).
|
|
370
|
+
// Returns debug info so callers can log selection state without cross-origin console issues.
|
|
371
|
+
await this._evaluateInFrame(([diagSel, nodeKey]) => {
|
|
372
|
+
const go = window.go;
|
|
373
|
+
if (!go) return { error: 'no go' };
|
|
374
|
+
const diagramDiv = document.querySelector(diagSel);
|
|
375
|
+
if (!diagramDiv) return { error: 'no div' };
|
|
376
|
+
const diagram = go.Diagram.fromDiv(diagramDiv);
|
|
377
|
+
if (!diagram) return { error: 'no diagram' };
|
|
378
|
+
const node = diagram.findNodeForKey(nodeKey);
|
|
379
|
+
if (!node) return { error: 'node not found', key: nodeKey };
|
|
380
|
+
diagram.select(node);
|
|
381
|
+
return { selected: node.isSelected, selectionCount: diagram.selection.count };
|
|
382
|
+
}, [diagramSelector, key]);
|
|
383
|
+
|
|
384
|
+
// Phase 4: Click at the node's page-level coordinates using Playwright's mouse.
|
|
385
|
+
// This fires the full browser event chain (including any overlay div handlers)
|
|
386
|
+
// for apps that rely on click events rather than GoJS's ChangedSelection.
|
|
387
|
+
// _resolveDiagramNode() computes page-level coords by combining the canvas
|
|
388
|
+
// bounding box (via Playwright) with GoJS transformDocToView() (via frame.evaluate).
|
|
389
|
+
const coords = await this._resolveDiagramNode(diagramSelector, key);
|
|
390
|
+
await this._page.mouse.click(coords.x, coords.y);
|
|
364
391
|
}
|
|
365
392
|
}
|
|
366
393
|
|
|
@@ -146,6 +146,9 @@ interface GenerateRestTestOptions {
|
|
|
146
146
|
consumerMode?: boolean;
|
|
147
147
|
providerOutput?: string;
|
|
148
148
|
consumerOutput?: string;
|
|
149
|
+
skipProvisionParents?: boolean;
|
|
150
|
+
mockPort?: number;
|
|
151
|
+
optionalFields?: boolean;
|
|
149
152
|
}
|
|
150
153
|
|
|
151
154
|
interface GenerateRestMockOptions {
|
|
@@ -172,6 +175,8 @@ interface GenerateRestMockOptions {
|
|
|
172
175
|
apiSchema?: string[];
|
|
173
176
|
traceFilePath?: string;
|
|
174
177
|
entrypoint?: string;
|
|
178
|
+
mockPort?: number;
|
|
179
|
+
optionalFields?: boolean;
|
|
175
180
|
}
|
|
176
181
|
|
|
177
182
|
interface SendScenarioOptions {
|
|
@@ -111,7 +111,8 @@ const generateRestTestWrapper = lib.func('generateRestTestWrapper', 'string', [
|
|
|
111
111
|
'string', // providerOutput (contract test)
|
|
112
112
|
'string', // consumerOutput (contract test)
|
|
113
113
|
'bool', // skipProvisionParents
|
|
114
|
-
'int'
|
|
114
|
+
'int', // mockPort
|
|
115
|
+
'bool' // optionalFields
|
|
115
116
|
]);
|
|
116
117
|
const generateRestMockWrapper = lib.func('generateRestMockWrapper', 'string', [
|
|
117
118
|
'string', // uri
|
|
@@ -136,7 +137,8 @@ const generateRestMockWrapper = lib.func('generateRestMockWrapper', 'string', [
|
|
|
136
137
|
'string', // apiSchema
|
|
137
138
|
'string', // traceFilePath
|
|
138
139
|
'string', // entryPoint
|
|
139
|
-
'int'
|
|
140
|
+
'int', // mockPort
|
|
141
|
+
'bool' // optionalFields
|
|
140
142
|
]);
|
|
141
143
|
const traceCollectWrapper = lib.func('traceCollectWrapper', 'string', ['string', 'string', 'bool', 'string', 'string']);
|
|
142
144
|
const analyzeOpenapiWrapper = lib.func('analyzeOpenapiWrapper', 'string', ['string', 'string']);
|
|
@@ -960,6 +962,7 @@ class SkyrampClient {
|
|
|
960
962
|
options.consumerOutput || "",
|
|
961
963
|
options.skipProvisionParents || false,
|
|
962
964
|
options.mockPort || 0,
|
|
965
|
+
options.optionalFields || false,
|
|
963
966
|
(err, res) => {
|
|
964
967
|
if (err) {
|
|
965
968
|
reject(err);
|
|
@@ -997,6 +1000,7 @@ class SkyrampClient {
|
|
|
997
1000
|
options.traceFilePath || "",
|
|
998
1001
|
options.entrypoint || "",
|
|
999
1002
|
options.mockPort || 0,
|
|
1003
|
+
options.optionalFields || false,
|
|
1000
1004
|
(err, res) => {
|
|
1001
1005
|
if (err) {
|
|
1002
1006
|
reject(err);
|
|
@@ -189,6 +189,11 @@ async function retryWithLLM(skyrampLocator, error) {
|
|
|
189
189
|
throw error
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
const consecutiveCount = skyrampLocator._skyrampPage.incrementConsecutiveLLMCount();
|
|
193
|
+
if (consecutiveCount >= 3) {
|
|
194
|
+
throw new Error(`LLM-based locator retry limit exceeded (${consecutiveCount} consecutive attempts). Please add "data-testid" attributes for more stable locators.`);
|
|
195
|
+
}
|
|
196
|
+
|
|
192
197
|
let locatorStr = skyrampLocator._locator.toString();
|
|
193
198
|
|
|
194
199
|
if (!shouldAttemptImprovement(errorMessage, errorType)) {
|
|
@@ -241,7 +246,8 @@ async function retryWithLLM(skyrampLocator, error) {
|
|
|
241
246
|
|
|
242
247
|
if (locatorCount == 1) {
|
|
243
248
|
const func = newLocator[skyrampLocator.execFname];
|
|
244
|
-
|
|
249
|
+
try {
|
|
250
|
+
const result = await func.call(newLocator, skyrampLocator.execParam, skyrampLocator.execArgs);
|
|
245
251
|
console.log(`✅ SUCCESS! Used selector: ${newLocator} instead of ${skyrampLocator._locator}`);
|
|
246
252
|
console.log(` ${parseErrorStack(error.stack)}`);
|
|
247
253
|
|
|
@@ -249,10 +255,10 @@ async function retryWithLLM(skyrampLocator, error) {
|
|
|
249
255
|
skyrampLocator.locatorCount = 1;
|
|
250
256
|
skyrampLocator._skyrampPage.addLLMChoices(skyrampLocator._locator, newLocator, error.stack);
|
|
251
257
|
return result;
|
|
252
|
-
}
|
|
258
|
+
} catch (innerError) {
|
|
253
259
|
// if it fails, move to the next one
|
|
254
|
-
debug(`retrying with LLM failed at ${skyrampLocator._locator} replaced by {newLocator}`,
|
|
255
|
-
}
|
|
260
|
+
debug(`retrying with LLM failed at ${skyrampLocator._locator} replaced by ${newLocator}`, innerError.name);
|
|
261
|
+
}
|
|
256
262
|
}
|
|
257
263
|
} catch {
|
|
258
264
|
continue
|
|
@@ -400,6 +406,7 @@ class SkyrampPlaywrightLocator {
|
|
|
400
406
|
// if it fails, there could be potentially a hydration issue we can retry after a little wait time
|
|
401
407
|
try {
|
|
402
408
|
return await this.execute().then(result => {
|
|
409
|
+
this._skyrampPage.resetConsecutiveLLMCount();
|
|
403
410
|
return this._skyrampPage.checkNavigation(currentUrl, result);
|
|
404
411
|
});
|
|
405
412
|
} catch (error) {
|
|
@@ -412,6 +419,7 @@ class SkyrampPlaywrightLocator {
|
|
|
412
419
|
|
|
413
420
|
// Is this really necessary?
|
|
414
421
|
await this.execute(true).then(result => {
|
|
422
|
+
this._skyrampPage.resetConsecutiveLLMCount();
|
|
415
423
|
return this._skyrampPage.checkNavigation(currentUrl, result);
|
|
416
424
|
}).catch(() => {
|
|
417
425
|
debug(` failed second time and execute previous locator ${this._previousLocator._locator} again`);
|
|
@@ -458,6 +466,7 @@ class SkyrampPlaywrightLocator {
|
|
|
458
466
|
|
|
459
467
|
// this will likely fail, but we try to get error message generated by playwright
|
|
460
468
|
return this.execute().then(result => {
|
|
469
|
+
this._skyrampPage.resetConsecutiveLLMCount();
|
|
461
470
|
return this._skyrampPage.checkNavigation(currentUrl, result);
|
|
462
471
|
}).catch(error => {
|
|
463
472
|
return this._retryWithLLM(error, this.newMultiLocatorErrorMsg());
|
|
@@ -482,6 +491,7 @@ class SkyrampPlaywrightLocator {
|
|
|
482
491
|
try {
|
|
483
492
|
// then execute the current one
|
|
484
493
|
return await this.execute().then(result => {
|
|
494
|
+
this._skyrampPage.resetConsecutiveLLMCount();
|
|
485
495
|
return this._skyrampPage.checkNavigation(currentUrl, result);
|
|
486
496
|
});
|
|
487
497
|
} catch (error) {
|
|
@@ -490,6 +500,7 @@ class SkyrampPlaywrightLocator {
|
|
|
490
500
|
// wait for some time and re execute
|
|
491
501
|
await this.wait(defaultWaitForTimeout);
|
|
492
502
|
return this.execute(true).then(result => {
|
|
503
|
+
this._skyrampPage.resetConsecutiveLLMCount();
|
|
493
504
|
return this._skyrampPage.checkNavigation(currentUrl, result);
|
|
494
505
|
}).catch(newError => {
|
|
495
506
|
return this._retryWithLLM(newError, this.newPrevHydrationErrorMsg());
|
|
@@ -517,6 +528,7 @@ class SkyrampPlaywrightLocator {
|
|
|
517
528
|
|
|
518
529
|
try {
|
|
519
530
|
return await this.execute().then(result => {
|
|
531
|
+
this._skyrampPage.resetConsecutiveLLMCount();
|
|
520
532
|
return this._skyrampPage.checkNavigation(currentUrl, result);
|
|
521
533
|
});
|
|
522
534
|
} catch (error) {
|
|
@@ -524,6 +536,7 @@ class SkyrampPlaywrightLocator {
|
|
|
524
536
|
debug(`${this._locator} failed at first try. attempting again with some timeout`);
|
|
525
537
|
await this.wait(defaultWaitForTimeout);
|
|
526
538
|
return this.execute(true).then(result=> {
|
|
539
|
+
this._skyrampPage.resetConsecutiveLLMCount();
|
|
527
540
|
return this._skyrampPage.checkNavigation(currentUrl, result);
|
|
528
541
|
}).catch(newError => {
|
|
529
542
|
if (newError.name == "TimeoutError") {
|
|
@@ -1265,6 +1278,18 @@ class SkyrampPlaywrightPage {
|
|
|
1265
1278
|
return result;
|
|
1266
1279
|
}
|
|
1267
1280
|
|
|
1281
|
+
incrementConsecutiveLLMCount() {
|
|
1282
|
+
if (this.consecutiveLLMCount == undefined) {
|
|
1283
|
+
this.consecutiveLLMCount = 0;
|
|
1284
|
+
}
|
|
1285
|
+
this.consecutiveLLMCount++;
|
|
1286
|
+
return this.consecutiveLLMCount;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
resetConsecutiveLLMCount() {
|
|
1290
|
+
this.consecutiveLLMCount = 0;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1268
1293
|
addLLMChoices(originalLocator, newLocator, stack) {
|
|
1269
1294
|
if (this.llmChoices == undefined) {
|
|
1270
1295
|
this.llmChoices = []
|