@decocms/parity 0.17.5 → 0.17.8
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/dist/cli.js +60 -21
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -38632,21 +38632,26 @@ var VIEWPORT_PRESETS = {
|
|
|
38632
38632
|
}
|
|
38633
38633
|
};
|
|
38634
38634
|
async function launchBrowser(opts = {}) {
|
|
38635
|
-
const doLaunch = () =>
|
|
38636
|
-
|
|
38637
|
-
|
|
38638
|
-
|
|
38639
|
-
|
|
38640
|
-
|
|
38641
|
-
|
|
38642
|
-
|
|
38643
|
-
|
|
38644
|
-
|
|
38635
|
+
const doLaunch = () => Promise.race([
|
|
38636
|
+
chromium.launch({
|
|
38637
|
+
headless: opts.headless ?? true,
|
|
38638
|
+
slowMo: opts.slowMo ?? 0,
|
|
38639
|
+
timeout: 30000,
|
|
38640
|
+
args: [
|
|
38641
|
+
"--disable-blink-features=AutomationControlled",
|
|
38642
|
+
"--no-sandbox",
|
|
38643
|
+
"--disable-setuid-sandbox",
|
|
38644
|
+
"--disable-gpu",
|
|
38645
|
+
"--no-zygote"
|
|
38646
|
+
]
|
|
38647
|
+
}),
|
|
38648
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Chromium launch timeout (35 s)")), 35000))
|
|
38649
|
+
]);
|
|
38645
38650
|
try {
|
|
38646
38651
|
return await doLaunch();
|
|
38647
38652
|
} catch (err) {
|
|
38648
38653
|
const msg = err.message ?? "";
|
|
38649
|
-
if (msg.includes("Timeout") || msg.includes("timed out")) {
|
|
38654
|
+
if (msg.includes("Timeout") || msg.includes("timed out") || msg.includes("Chromium launch timeout")) {
|
|
38650
38655
|
throw new Error([
|
|
38651
38656
|
"Chromium timed out while launching (30 s).",
|
|
38652
38657
|
"On macOS, try reinstalling the browser binaries:",
|
|
@@ -44509,7 +44514,7 @@ function purchaseJourneyFlow(ctx) {
|
|
|
44509
44514
|
data: { totalSteps: 0, failedSteps: 0, asymmetricSkips: 0 }
|
|
44510
44515
|
};
|
|
44511
44516
|
}
|
|
44512
|
-
const single = ctx.prodFlows.length === 0 && ctx.candFlows.
|
|
44517
|
+
const single = ctx.prodFlows.length === 0 && ctx.candFlows.some((f) => f.flow === "purchase-journey");
|
|
44513
44518
|
for (const viewport of ctx.viewports) {
|
|
44514
44519
|
const prodFlow = findFlow2(ctx.prodFlows, viewport);
|
|
44515
44520
|
const candFlow = findFlow2(ctx.candFlows, viewport);
|
|
@@ -52282,6 +52287,10 @@ async function flowPurchaseJourney(ctx) {
|
|
|
52282
52287
|
}
|
|
52283
52288
|
const spBefore9 = screenshotPath(ctx, "pj-9-checkout-before");
|
|
52284
52289
|
await screenshotStable(page, { path: spBefore9, fullPage: false });
|
|
52290
|
+
await Promise.race([
|
|
52291
|
+
dismissOverlays(page, ctx),
|
|
52292
|
+
new Promise((resolve) => setTimeout(resolve, 4000))
|
|
52293
|
+
]);
|
|
52285
52294
|
let usedSelector = checkoutHit.selector;
|
|
52286
52295
|
let clickedText = await checkoutHit.locator.innerText().catch(() => "");
|
|
52287
52296
|
let reachedCheckout = false;
|
|
@@ -52301,6 +52310,24 @@ async function flowPurchaseJourney(ctx) {
|
|
|
52301
52310
|
reachedCheckout = /\/(checkout|carrinho)(\/|$|\?)/i.test(page.url());
|
|
52302
52311
|
if (reachedCheckout)
|
|
52303
52312
|
break;
|
|
52313
|
+
if (checkoutHit) {
|
|
52314
|
+
const blocker = await dismissBlockingOverlay(page, ctx, checkoutHit.locator);
|
|
52315
|
+
if (blocker?.dismissed) {
|
|
52316
|
+
dlog2(ctx, `step 9 go-checkout: cleared blocking overlay (${blocker.method}) — retrying click`);
|
|
52317
|
+
await Promise.all([
|
|
52318
|
+
page.waitForURL(/\/(checkout|carrinho)/i, { timeout: 1e4 }).catch(() => {
|
|
52319
|
+
return;
|
|
52320
|
+
}),
|
|
52321
|
+
checkoutHit.locator.click({ timeout: 5000 }).catch(() => {
|
|
52322
|
+
return;
|
|
52323
|
+
})
|
|
52324
|
+
]);
|
|
52325
|
+
await page.waitForTimeout(1500);
|
|
52326
|
+
reachedCheckout = /\/(checkout|carrinho)(\/|$|\?)/i.test(page.url());
|
|
52327
|
+
if (reachedCheckout)
|
|
52328
|
+
break;
|
|
52329
|
+
}
|
|
52330
|
+
}
|
|
52304
52331
|
if (budget.remaining <= 0)
|
|
52305
52332
|
break;
|
|
52306
52333
|
dlog2(ctx, `step 9 go-checkout: click on \`${usedSelector}\` didn't navigate (attempt ${attempt}). URL still ${page.url()}. Asking LLM for another selector.`);
|
|
@@ -54909,13 +54936,12 @@ async function runLiveSelectorValidation(discovered, ctx) {
|
|
|
54909
54936
|
if (ctx.pdpUrl)
|
|
54910
54937
|
await runOn(ctx.pdpUrl, PDP_VALIDATION_KEYS);
|
|
54911
54938
|
await context.close();
|
|
54912
|
-
return { validated, failed: Array.from(failed) };
|
|
54939
|
+
return { validated, failed: Array.from(failed), browser };
|
|
54913
54940
|
} catch (err) {
|
|
54914
54941
|
console.warn(`[selectors] live-validation falhou (não-fatal): ${err.message}`);
|
|
54915
|
-
return null;
|
|
54916
|
-
} finally {
|
|
54917
54942
|
if (browser)
|
|
54918
54943
|
await browser.close().catch(() => {});
|
|
54944
|
+
return null;
|
|
54919
54945
|
}
|
|
54920
54946
|
}
|
|
54921
54947
|
async function runSelectorDiscoveryPass(opts) {
|
|
@@ -54927,11 +54953,12 @@ async function runSelectorDiscoveryPass(opts) {
|
|
|
54927
54953
|
else
|
|
54928
54954
|
console.warn(`[selectors] ${msg}`);
|
|
54929
54955
|
};
|
|
54956
|
+
let reusableBrowser = null;
|
|
54930
54957
|
try {
|
|
54931
54958
|
const html3 = opts.homeHtml ?? await fetchHomeHtml(url, viewport);
|
|
54932
54959
|
if (!html3) {
|
|
54933
54960
|
warn("Falha ao baixar HTML da home; usando defaults");
|
|
54934
|
-
return;
|
|
54961
|
+
return null;
|
|
54935
54962
|
}
|
|
54936
54963
|
let plpUrl;
|
|
54937
54964
|
let plpHtml;
|
|
@@ -54956,7 +54983,10 @@ async function runSelectorDiscoveryPass(opts) {
|
|
|
54956
54983
|
const discovered = await discoverSelectors({ home: url, plp: plpUrl, pdp: pdpUrl }, { home: html3, plp: plpHtml, pdp: pdpHtml }, { noCache: opts.refreshSelectors === true });
|
|
54957
54984
|
if (!discovered) {
|
|
54958
54985
|
warn("LLM não retornou seletores; usando defaults");
|
|
54959
|
-
return;
|
|
54986
|
+
return null;
|
|
54987
|
+
}
|
|
54988
|
+
if (opts.rc.plpUrlHint) {
|
|
54989
|
+
discovered.categoryLink = undefined;
|
|
54960
54990
|
}
|
|
54961
54991
|
const added = Object.entries(discovered).filter(([k, v]) => k !== "lowConfidenceKeys" && v).length;
|
|
54962
54992
|
if (spinner)
|
|
@@ -54968,6 +54998,7 @@ async function runSelectorDiscoveryPass(opts) {
|
|
|
54968
54998
|
viewport
|
|
54969
54999
|
});
|
|
54970
55000
|
if (validation) {
|
|
55001
|
+
reusableBrowser = validation.browser;
|
|
54971
55002
|
persistSelectorValidation(url, validation.validated);
|
|
54972
55003
|
for (const key of validation.failed) {
|
|
54973
55004
|
console.warn(`[selectors] descartando "${key}" — falhou na validação ao vivo (0 elementos na página onde deveria estar)`);
|
|
@@ -54993,7 +55024,12 @@ async function runSelectorDiscoveryPass(opts) {
|
|
|
54993
55024
|
spinner.succeed(`${added} seletor(es) inferido(s) pelo LLM (${validatedCount} validado(s) ao vivo)`);
|
|
54994
55025
|
} catch (err) {
|
|
54995
55026
|
warn(`Discovery falhou: ${err.message}`);
|
|
55027
|
+
if (reusableBrowser) {
|
|
55028
|
+
await reusableBrowser.close().catch(() => {});
|
|
55029
|
+
reusableBrowser = null;
|
|
55030
|
+
}
|
|
54996
55031
|
}
|
|
55032
|
+
return reusableBrowser;
|
|
54997
55033
|
}
|
|
54998
55034
|
|
|
54999
55035
|
// src/learned/platform.ts
|
|
@@ -55201,8 +55237,9 @@ async function e2eCommand(opts) {
|
|
|
55201
55237
|
}
|
|
55202
55238
|
}
|
|
55203
55239
|
const wantsAutoSelectors = opts.autoSelectors !== false && isLlmAvailable();
|
|
55240
|
+
let discoveryBrowser = null;
|
|
55204
55241
|
if (wantsAutoSelectors) {
|
|
55205
|
-
await runSelectorDiscoveryPass({
|
|
55242
|
+
discoveryBrowser = await runSelectorDiscoveryPass({
|
|
55206
55243
|
url: opts.url,
|
|
55207
55244
|
viewport: primaryViewport,
|
|
55208
55245
|
rc,
|
|
@@ -55227,12 +55264,14 @@ async function e2eCommand(opts) {
|
|
|
55227
55264
|
};
|
|
55228
55265
|
process.once("SIGINT", onSignal);
|
|
55229
55266
|
process.once("SIGTERM", onSignal);
|
|
55230
|
-
const spinner = opts.json ? null : ora4("Lançando browser…").start();
|
|
55231
|
-
let browser =
|
|
55267
|
+
const spinner = opts.json ? null : discoveryBrowser ? ora4("Iniciando fluxos…").start() : ora4("Lançando browser…").start();
|
|
55268
|
+
let browser = discoveryBrowser;
|
|
55232
55269
|
const allFlows = [];
|
|
55233
55270
|
const allPages = [];
|
|
55234
55271
|
try {
|
|
55235
|
-
browser
|
|
55272
|
+
if (!browser) {
|
|
55273
|
+
browser = await launchBrowser({ headless: true });
|
|
55274
|
+
}
|
|
55236
55275
|
for (const viewport of viewports) {
|
|
55237
55276
|
const ctx = await newContext(browser, { viewport });
|
|
55238
55277
|
await installVitalsCollector(ctx);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/parity",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.8",
|
|
4
4
|
"description": "E2E parity validator for site migrations. Compares prod vs cand and reports UI, functional, SEO, visual, and Web Vitals deltas with an LLM-ranked HTML report.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|