@decocms/parity 0.15.0 → 0.15.1

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/CHANGELOG.md CHANGED
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ * **Configurable `minicartPanel` selector for open-minicart reveal detection (issue #149).** `isCartUiVisible` and the title-scope sweep in `validateCartContainsTitleQuick` used a hardcoded list of name-based patterns (`[role='dialog']`, `[class*='minicart']`, etc.) to detect that the cart drawer was open. Any site built with utility-CSS (Tailwind) and `data-qa-*` testing attributes — a common modern stack — has no class/attribute those patterns can match, so detection always returns `null` and the step reports "failed" even when the drawer is genuinely open. The new `minicartPanel` selector key (`.parityrc.json`) is tried first, ahead of all hardcoded patterns. Built-in defaults cover `[data-qa-minicart]`, `[data-minicart]`, `[data-minicart-drawer]`, `[data-testid='minicart']` and common class patterns — so the `data-qa-*` case is handled out-of-the-box. Override with a single selector that matches the drawer root for your specific site.
13
+
10
14
  ## [0.15.0](https://github.com/decocms/parity/compare/v0.14.0...v0.15.0) (2026-07-27)
11
15
 
12
16
  ### Added
package/dist/cli.js CHANGED
@@ -41389,6 +41389,7 @@ var ParityRc = z.object({
41389
41389
  quantityInput: z.string().optional(),
41390
41390
  minicartCount: z.string().optional(),
41391
41391
  cartOpenedIndicator: z.string().optional(),
41392
+ minicartPanel: z.string().optional(),
41392
41393
  searchTrigger: z.string().optional(),
41393
41394
  searchInput: z.string().optional(),
41394
41395
  searchSuggestions: z.string().optional(),
@@ -49545,6 +49546,7 @@ var SelectorKey = z2.enum([
49545
49546
  "quantityInput",
49546
49547
  "minicartCount",
49547
49548
  "cartOpenedIndicator",
49549
+ "minicartPanel",
49548
49550
  "searchTrigger",
49549
49551
  "searchInput",
49550
49552
  "searchSuggestions",
@@ -49949,6 +49951,17 @@ var DEFAULT_SELECTORS = {
49949
49951
  "[role='dialog']:has-text('adicionado')",
49950
49952
  "[role='dialog']:has-text('added')"
49951
49953
  ],
49954
+ minicartPanel: [
49955
+ "[data-qa-minicart]",
49956
+ "[data-minicart]",
49957
+ "[data-minicart-drawer]",
49958
+ "[data-drawer='minicart']",
49959
+ "[data-testid='minicart']",
49960
+ "[data-testid='cart-drawer']",
49961
+ "[class*='minicart' i]",
49962
+ "[class*='cart-drawer' i]",
49963
+ "[class*='drawer-cart' i]"
49964
+ ],
49952
49965
  cartItemRow: [
49953
49966
  "[data-cart-item]",
49954
49967
  "[data-testid='cart-item']",
@@ -50750,8 +50763,10 @@ async function readCartCount(page, ctx) {
50750
50763
  }
50751
50764
  return 0;
50752
50765
  }
50753
- async function isCartUiVisible(page) {
50766
+ async function isCartUiVisible(page, ctx) {
50767
+ const configured = ctx ? [...selFor(ctx, "minicartPanel"), ...selFor(ctx, "cartOpenedIndicator")] : [];
50754
50768
  return firstVisible(page, [
50769
+ ...configured,
50755
50770
  "[role='dialog']:visible",
50756
50771
  "[aria-modal='true']:visible",
50757
50772
  "[data-minicart][aria-hidden='false']",
@@ -50837,16 +50852,17 @@ async function detectCartRevealMode(page, trigger, drawerAlreadyOpen, viewport)
50837
50852
  return "click-drawer";
50838
50853
  return "unknown";
50839
50854
  }
50840
- async function isCartRevealed(page, expectedProductTitle) {
50855
+ async function isCartRevealed(page, expectedProductTitle, ctx) {
50841
50856
  if (expectedProductTitle) {
50842
- const v = await validateCartContainsTitleQuick(page, expectedProductTitle);
50857
+ const v = await validateCartContainsTitleQuick(page, expectedProductTitle, ctx);
50843
50858
  if (v)
50844
50859
  return `title-found:${v}`;
50845
50860
  }
50846
- return isCartUiVisible(page);
50861
+ return isCartUiVisible(page, ctx);
50847
50862
  }
50848
- async function validateCartContainsTitleQuick(page, expectedTitle) {
50863
+ async function validateCartContainsTitleQuick(page, expectedTitle, ctx) {
50849
50864
  const quickSelectors = [
50865
+ ...ctx ? selFor(ctx, "minicartPanel") : [],
50850
50866
  "[role='dialog']",
50851
50867
  "[class*='minicart' i]",
50852
50868
  "[class*='cart' i]",
@@ -50883,7 +50899,7 @@ async function openMinicart(page, trigger, ctx, expectedProductTitle) {
50883
50899
  const beforeUrl = page.url();
50884
50900
  await dismissOverlays(page, ctx);
50885
50901
  await page.waitForTimeout(800);
50886
- const alreadyOpen = await isCartRevealed(page, expectedProductTitle);
50902
+ const alreadyOpen = await isCartRevealed(page, expectedProductTitle, ctx);
50887
50903
  if (alreadyOpen) {
50888
50904
  dlog2(ctx, ` openMinicart: already-open (matched ${alreadyOpen})`);
50889
50905
  return { method: "already-open", url: beforeUrl, visibleMarker: alreadyOpen };
@@ -50896,7 +50912,7 @@ async function openMinicart(page, trigger, ctx, expectedProductTitle) {
50896
50912
  return;
50897
50913
  });
50898
50914
  await page.waitForTimeout(1500);
50899
- const hoverOpened = await isCartRevealed(page, expectedProductTitle);
50915
+ const hoverOpened = await isCartRevealed(page, expectedProductTitle, ctx);
50900
50916
  if (hoverOpened) {
50901
50917
  dlog2(ctx, ` openMinicart: hover opened drawer (${hoverOpened})`);
50902
50918
  return { method: "hover", url: page.url(), visibleMarker: hoverOpened };
@@ -50921,7 +50937,7 @@ async function openMinicart(page, trigger, ctx, expectedProductTitle) {
50921
50937
  return { method: "click-navigate", url: page.url(), visibleMarker: null };
50922
50938
  }
50923
50939
  await page.waitForTimeout(800);
50924
- const tapOpened = await isCartRevealed(page, expectedProductTitle);
50940
+ const tapOpened = await isCartRevealed(page, expectedProductTitle, ctx);
50925
50941
  if (tapOpened) {
50926
50942
  dlog2(ctx, ` openMinicart: tap opened drawer (${tapOpened})`);
50927
50943
  return { method: "click", url: page.url(), visibleMarker: tapOpened };
@@ -50946,7 +50962,7 @@ async function openMinicart(page, trigger, ctx, expectedProductTitle) {
50946
50962
  return { method: "click-navigate", url: page.url(), visibleMarker: null };
50947
50963
  }
50948
50964
  await page.waitForTimeout(1500);
50949
- const clickOpened = await isCartRevealed(page, expectedProductTitle);
50965
+ const clickOpened = await isCartRevealed(page, expectedProductTitle, ctx);
50950
50966
  if (clickOpened) {
50951
50967
  dlog2(ctx, ` openMinicart: click opened drawer (${clickOpened})`);
50952
50968
  return { method: "click", url: afterClickUrl, visibleMarker: clickOpened };
@@ -50957,7 +50973,7 @@ async function openMinicart(page, trigger, ctx, expectedProductTitle) {
50957
50973
  return;
50958
50974
  });
50959
50975
  await page.waitForTimeout(1500);
50960
- const hoverOpened = await isCartRevealed(page, expectedProductTitle);
50976
+ const hoverOpened = await isCartRevealed(page, expectedProductTitle, ctx);
50961
50977
  if (hoverOpened) {
50962
50978
  dlog2(ctx, ` openMinicart: hover opened drawer (${hoverOpened})`);
50963
50979
  return { method: "hover", url: page.url(), visibleMarker: hoverOpened };
@@ -51003,7 +51019,16 @@ function titlesMatch(observed, expected) {
51003
51019
  return false;
51004
51020
  }
51005
51021
  async function validateCartContainsTitle(page, expectedTitle, ctx) {
51022
+ const panelScopedTitleSelectors = selFor(ctx, "minicartPanel").flatMap((p) => [
51023
+ `${p} a[href*='/p']`,
51024
+ `${p} [class*='name' i]`,
51025
+ `${p} [class*='title' i]`,
51026
+ `${p} [class*='product' i]`,
51027
+ `${p} [data-cart-item-name]`,
51028
+ `${p} [data-qa-product-name]`
51029
+ ]);
51006
51030
  const titleSelectors = [
51031
+ ...panelScopedTitleSelectors,
51007
51032
  "[data-cart-item-name]",
51008
51033
  "[data-cart-item] [class*='title' i]",
51009
51034
  "[data-cart-item] [class*='name' i]",
@@ -51861,7 +51886,7 @@ async function flowPurchaseJourney(ctx) {
51861
51886
  let cartOpenMethod = "failed";
51862
51887
  let miniText = "";
51863
51888
  let cartRevealMode = "unknown";
51864
- const drawerAlreadyOpen = await isCartRevealed(page, expectedProductTitle) !== null;
51889
+ const drawerAlreadyOpen = await isCartRevealed(page, expectedProductTitle, ctx) !== null;
51865
51890
  if (miniHit) {
51866
51891
  miniText = await miniHit.locator.innerText().catch(() => "");
51867
51892
  cartRevealMode = await detectCartRevealMode(page, miniHit.locator, drawerAlreadyOpen, ctx.viewport).catch(() => "unknown");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/parity",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
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",