@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.
Files changed (2) hide show
  1. package/dist/cli.js +60 -21
  2. 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 = () => chromium.launch({
38636
- headless: opts.headless ?? true,
38637
- slowMo: opts.slowMo ?? 0,
38638
- timeout: 30000,
38639
- args: [
38640
- "--disable-blink-features=AutomationControlled",
38641
- "--no-sandbox",
38642
- "--disable-gpu"
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.length > 0;
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 = null;
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 = await launchBrowser({ headless: true });
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.5",
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",