happo 6.8.0 → 6.9.0

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 (53) hide show
  1. package/dist/browser/main.js +132 -10
  2. package/dist/browser/main.js.map +2 -2
  3. package/dist/browser/takeDOMSnapshot.d.ts +7 -1
  4. package/dist/browser/takeDOMSnapshot.d.ts.map +1 -1
  5. package/dist/cli/cancelJob-Y4WJCCU6.js +10 -0
  6. package/dist/cli/{chunk-33PSYGHX.js → chunk-BESQLM5F.js} +2 -2
  7. package/dist/cli/{chunk-EDBI7VNX.js → chunk-BK32666K.js} +3 -3
  8. package/dist/cli/{chunk-WFQHO45L.js → chunk-CVX5DVCT.js} +2 -2
  9. package/dist/cli/{chunk-URV3R5XF.js → chunk-J2EA5OBW.js} +2 -2
  10. package/dist/cli/{chunk-Q6DV4AEM.js → chunk-P4EXA4AX.js} +4 -4
  11. package/dist/cli/{chunk-Q6DV4AEM.js.map → chunk-P4EXA4AX.js.map} +1 -1
  12. package/dist/cli/{chunk-CQ7QTIYV.js → chunk-R6YURZXU.js} +2 -2
  13. package/dist/cli/createAsyncComparison-CQLGQXY2.js +10 -0
  14. package/dist/cli/{createAsyncReport-62YCQXCV.js → createAsyncReport-4ZD53TJC.js} +4 -4
  15. package/dist/cli/{getFlakes-257F34EF.js → getFlakes-6ZGTWZTM.js} +4 -4
  16. package/dist/cli/main.js +11 -11
  17. package/dist/cli/package-4NRNRUE3.js +7 -0
  18. package/dist/cli/{prepareSnapRequests-R2YIHDTR.js → prepareSnapRequests-2LHSGFZV.js} +4 -4
  19. package/dist/cli/startJob-JAO5FUA2.js +10 -0
  20. package/dist/cli/{wrapper-7A35DA3L.js → wrapper-7RE2N7Y3.js} +7 -7
  21. package/dist/config/index.d.ts +18 -0
  22. package/dist/config/index.d.ts.map +1 -1
  23. package/dist/config/index.js.map +2 -2
  24. package/dist/cypress/index.d.ts.map +1 -1
  25. package/dist/cypress/index.js +187 -46
  26. package/dist/cypress/index.js.map +2 -2
  27. package/dist/cypress/task.d.ts +4 -0
  28. package/dist/cypress/task.d.ts.map +1 -1
  29. package/dist/cypress/task.js +11 -4
  30. package/dist/cypress/task.js.map +2 -2
  31. package/dist/isomorphic/types.d.ts +14 -0
  32. package/dist/isomorphic/types.d.ts.map +1 -1
  33. package/dist/playwright/index.d.ts.map +1 -1
  34. package/dist/playwright/index.js +10 -6
  35. package/dist/playwright/index.js.map +3 -3
  36. package/package.json +3 -3
  37. package/dist/cli/cancelJob-3MYHESOW.js +0 -10
  38. package/dist/cli/createAsyncComparison-MOLWGUJT.js +0 -10
  39. package/dist/cli/package-7QCVHFDF.js +0 -7
  40. package/dist/cli/startJob-6EVDORMA.js +0 -10
  41. /package/dist/cli/{cancelJob-3MYHESOW.js.map → cancelJob-Y4WJCCU6.js.map} +0 -0
  42. /package/dist/cli/{chunk-33PSYGHX.js.map → chunk-BESQLM5F.js.map} +0 -0
  43. /package/dist/cli/{chunk-EDBI7VNX.js.map → chunk-BK32666K.js.map} +0 -0
  44. /package/dist/cli/{chunk-WFQHO45L.js.map → chunk-CVX5DVCT.js.map} +0 -0
  45. /package/dist/cli/{chunk-URV3R5XF.js.map → chunk-J2EA5OBW.js.map} +0 -0
  46. /package/dist/cli/{chunk-CQ7QTIYV.js.map → chunk-R6YURZXU.js.map} +0 -0
  47. /package/dist/cli/{createAsyncComparison-MOLWGUJT.js.map → createAsyncComparison-CQLGQXY2.js.map} +0 -0
  48. /package/dist/cli/{createAsyncReport-62YCQXCV.js.map → createAsyncReport-4ZD53TJC.js.map} +0 -0
  49. /package/dist/cli/{getFlakes-257F34EF.js.map → getFlakes-6ZGTWZTM.js.map} +0 -0
  50. /package/dist/cli/{package-7QCVHFDF.js.map → package-4NRNRUE3.js.map} +0 -0
  51. /package/dist/cli/{prepareSnapRequests-R2YIHDTR.js.map → prepareSnapRequests-2LHSGFZV.js.map} +0 -0
  52. /package/dist/cli/{startJob-6EVDORMA.js.map → startJob-JAO5FUA2.js.map} +0 -0
  53. /package/dist/cli/{wrapper-7A35DA3L.js.map → wrapper-7RE2N7Y3.js.map} +0 -0
@@ -817,11 +817,12 @@ function inlineShadowRoots(element) {
817
817
  elements.unshift(...Array.from(currentElement.children));
818
818
  }
819
819
  for (const element2 of elementsToProcess) {
820
- const hiddenElement = document.createElement("happo-shadow-content");
820
+ const ownerDoc = element2.ownerDocument;
821
+ const hiddenElement = ownerDoc.createElement("happo-shadow-content");
821
822
  hiddenElement.style.display = "none";
822
823
  if (element2.shadowRoot) {
823
- for (const styleSheet of element2.shadowRoot.adoptedStyleSheets) {
824
- const styleElement = document.createElement("style");
824
+ for (const styleSheet of element2.shadowRoot.adoptedStyleSheets || []) {
825
+ const styleElement = ownerDoc.createElement("style");
825
826
  styleElement.dataset.happoInlined = "true";
826
827
  const styleContent = getContentFromStyleSheet(styleSheet);
827
828
  styleElement.textContent = styleContent;
@@ -850,13 +851,51 @@ function findSvgElementsWithSymbols(element) {
850
851
  (svg) => svg.querySelector("symbol")
851
852
  );
852
853
  }
854
+ function getTrackedHoverElement(doc) {
855
+ return doc.defaultView?.__happoHoveredElement ?? null;
856
+ }
857
+ function getTrackedActiveElement(doc) {
858
+ return doc.defaultView?.__happoActiveElement ?? null;
859
+ }
860
+ function isElementNode(root) {
861
+ return root.nodeType === 1;
862
+ }
863
+ function collectAllRoots(root) {
864
+ const roots = [root];
865
+ if (isElementNode(root) && root.shadowRoot) {
866
+ roots.push(...collectAllRoots(root.shadowRoot));
867
+ }
868
+ for (const el of root.querySelectorAll("*")) {
869
+ if (el.shadowRoot) {
870
+ roots.push(...collectAllRoots(el.shadowRoot));
871
+ }
872
+ }
873
+ return roots;
874
+ }
875
+ function getDeepActiveElement(doc) {
876
+ let el = doc.activeElement;
877
+ while (el?.shadowRoot?.activeElement) {
878
+ el = el.shadowRoot.activeElement;
879
+ }
880
+ return el;
881
+ }
882
+ var PSEUDO_STATE_ATTRS = [
883
+ { pseudo: ":hover", attrSelector: "[data-happo-hover]", datasetKey: "happoHover" },
884
+ { pseudo: ":active", attrSelector: "[data-happo-active]", datasetKey: "happoActive" },
885
+ {
886
+ pseudo: ":focus-visible",
887
+ attrSelector: "[data-happo-focus-visible]",
888
+ datasetKey: "happoFocusVisible"
889
+ }
890
+ ];
853
891
  function takeDOMSnapshot({
854
892
  doc,
855
893
  element: oneOrMoreElements,
856
894
  responsiveInlinedCanvases = false,
857
895
  transformDOM,
858
896
  handleBase64Image,
859
- strategy = "hoist"
897
+ strategy = "hoist",
898
+ autoApplyPseudoStateAttributes = false
860
899
  }) {
861
900
  if (doc == null) {
862
901
  throw new Error("doc cannot be null or undefined");
@@ -868,6 +907,7 @@ function takeDOMSnapshot({
868
907
  const allElements = transformToElementArray(oneOrMoreElements);
869
908
  const htmlParts = [];
870
909
  const assetUrls = [];
910
+ const allDocRoots = autoApplyPseudoStateAttributes ? collectAllRoots(doc) : [doc];
871
911
  for (const originalElement of allElements) {
872
912
  const { element, cleanup: canvasCleanup } = inlineCanvases(originalElement, {
873
913
  doc,
@@ -885,13 +925,55 @@ function takeDOMSnapshot({
885
925
  scriptEl.remove();
886
926
  }
887
927
  }
888
- for (const e of doc.querySelectorAll(
889
- "[data-happo-focus]"
890
- )) {
891
- delete e.dataset.happoFocus;
928
+ for (const root of allDocRoots) {
929
+ for (const e of root.querySelectorAll(
930
+ "[data-happo-focus]"
931
+ )) {
932
+ delete e.dataset.happoFocus;
933
+ }
892
934
  }
893
- if (doc.activeElement && doc.activeElement !== doc.body && isElementWithDataset(doc.activeElement)) {
894
- doc.activeElement.dataset.happoFocus = "true";
935
+ const activeElement = autoApplyPseudoStateAttributes ? getDeepActiveElement(doc) : doc.activeElement;
936
+ if (activeElement && activeElement !== doc.body && isElementWithDataset(activeElement)) {
937
+ activeElement.dataset.happoFocus = "true";
938
+ }
939
+ if (autoApplyPseudoStateAttributes) {
940
+ const elementRoots = collectAllRoots(element);
941
+ for (const { pseudo, attrSelector, datasetKey } of PSEUDO_STATE_ATTRS) {
942
+ for (const root of elementRoots) {
943
+ let matches;
944
+ let rootMatches;
945
+ try {
946
+ matches = root.querySelectorAll(pseudo);
947
+ rootMatches = isElementNode(root) && root.matches(pseudo);
948
+ } catch {
949
+ continue;
950
+ }
951
+ for (const e of root.querySelectorAll(attrSelector)) {
952
+ if (isElementWithDataset(e)) {
953
+ delete e.dataset[datasetKey];
954
+ }
955
+ }
956
+ if (isElementNode(root) && isElementWithDataset(root)) {
957
+ delete root.dataset[datasetKey];
958
+ }
959
+ for (const e of matches) {
960
+ if (isElementWithDataset(e)) {
961
+ e.dataset[datasetKey] = "true";
962
+ }
963
+ }
964
+ if (rootMatches && isElementWithDataset(root)) {
965
+ root.dataset[datasetKey] = "true";
966
+ }
967
+ }
968
+ }
969
+ const trackedHoverEl = getTrackedHoverElement(doc);
970
+ if (trackedHoverEl && isElementWithDataset(trackedHoverEl) && element.contains(trackedHoverEl)) {
971
+ trackedHoverEl.dataset.happoHover = "true";
972
+ }
973
+ const trackedActiveEl = getTrackedActiveElement(doc);
974
+ if (trackedActiveEl && isElementWithDataset(trackedActiveEl) && element.contains(trackedActiveEl)) {
975
+ trackedActiveEl.dataset.happoActive = "true";
976
+ }
895
977
  }
896
978
  inlineShadowRoots(element);
897
979
  markModalDialogs(element);
@@ -963,12 +1045,56 @@ Cypress.on("window:before:load", (win) => {
963
1045
  throw new TypeError("CSSStyleSheet is not supported in this browser");
964
1046
  }
965
1047
  applyConstructedStylesPatch(win);
1048
+ let _happoHoveredElement = null;
1049
+ let _happoActiveElement = null;
1050
+ win.document.addEventListener(
1051
+ "mouseover",
1052
+ (e) => {
1053
+ if (isEventTargetElement(e.target)) {
1054
+ _happoHoveredElement = e.target;
1055
+ }
1056
+ },
1057
+ true
1058
+ );
1059
+ win.document.addEventListener(
1060
+ "mouseout",
1061
+ (e) => {
1062
+ if (_happoHoveredElement === e.target) {
1063
+ _happoHoveredElement = null;
1064
+ }
1065
+ },
1066
+ true
1067
+ );
1068
+ win.document.addEventListener(
1069
+ "mousedown",
1070
+ (e) => {
1071
+ if (isEventTargetElement(e.target)) {
1072
+ _happoActiveElement = e.target;
1073
+ }
1074
+ },
1075
+ true
1076
+ );
1077
+ win.document.addEventListener("mouseup", () => {
1078
+ _happoActiveElement = null;
1079
+ }, true);
1080
+ Object.defineProperty(win, "__happoHoveredElement", {
1081
+ get: () => _happoHoveredElement,
1082
+ configurable: true
1083
+ });
1084
+ Object.defineProperty(win, "__happoActiveElement", {
1085
+ get: () => _happoActiveElement,
1086
+ configurable: true
1087
+ });
966
1088
  });
1089
+ function isEventTargetElement(target) {
1090
+ return target != null && "nodeType" in target && target.nodeType === 1;
1091
+ }
967
1092
  var config = {
968
1093
  responsiveInlinedCanvases: false,
969
1094
  canvasChunkSize: 2e5
970
1095
  // 800 Kb per chunk
971
1096
  };
1097
+ var cachedAutoApplyPseudoStateAttributes = null;
972
1098
  var configure = (userConfig) => {
973
1099
  config = { ...config, ...userConfig };
974
1100
  };
@@ -1002,46 +1128,61 @@ Cypress.Commands.add(
1002
1128
  if (!element) {
1003
1129
  throw new Error("element cannot be null or undefined");
1004
1130
  }
1005
- const properties = {
1006
- doc,
1007
- element,
1008
- responsiveInlinedCanvases: resInCan,
1009
- strategy: snapshotStrategy,
1010
- handleBase64Image: ({ base64Url, element: element2 }) => {
1011
- const rawBase64 = base64Url.replace(/^data:image\/png;base64,/, "");
1012
- const chunks = chunked(rawBase64, config.canvasChunkSize);
1013
- for (let i = 0; i < chunks.length; i++) {
1014
- const base64Chunk = chunks[i];
1015
- const isFirst = i === 0;
1016
- const isLast = i === chunks.length - 1;
1017
- cy.task(
1018
- "happoRegisterBase64Image",
1019
- {
1020
- base64Chunk,
1021
- src: element2.getAttribute("src"),
1022
- isFirst,
1023
- isLast
1024
- },
1025
- taskOptions
1026
- );
1131
+ const takeSnapshot = (autoApplyPseudoStateAttributes) => {
1132
+ const properties = {
1133
+ doc,
1134
+ element,
1135
+ responsiveInlinedCanvases: resInCan,
1136
+ strategy: snapshotStrategy,
1137
+ autoApplyPseudoStateAttributes,
1138
+ handleBase64Image: ({ base64Url, element: element2 }) => {
1139
+ const rawBase64 = base64Url.replace(/^data:image\/png;base64,/, "");
1140
+ const chunks = chunked(rawBase64, config.canvasChunkSize);
1141
+ for (let i = 0; i < chunks.length; i++) {
1142
+ const base64Chunk = chunks[i];
1143
+ const isFirst = i === 0;
1144
+ const isLast = i === chunks.length - 1;
1145
+ cy.task(
1146
+ "happoRegisterBase64Image",
1147
+ {
1148
+ base64Chunk,
1149
+ src: element2.getAttribute("src"),
1150
+ isFirst,
1151
+ isLast
1152
+ },
1153
+ taskOptions
1154
+ );
1155
+ }
1027
1156
  }
1157
+ };
1158
+ if (transformDOM) {
1159
+ properties.transformDOM = transformDOM;
1028
1160
  }
1161
+ const domSnapshot = takeDOMSnapshot(properties);
1162
+ cy.task(
1163
+ "happoRegisterSnapshot",
1164
+ {
1165
+ timestamp: Date.now(),
1166
+ component,
1167
+ variant,
1168
+ targets,
1169
+ ...domSnapshot
1170
+ },
1171
+ taskOptions
1172
+ );
1029
1173
  };
1030
- if (transformDOM) {
1031
- properties.transformDOM = transformDOM;
1174
+ if (cachedAutoApplyPseudoStateAttributes === null) {
1175
+ cy.task(
1176
+ "happoGetIntegrationConfig",
1177
+ null,
1178
+ { ...taskOptions, log: false }
1179
+ ).then((integrationConfig) => {
1180
+ cachedAutoApplyPseudoStateAttributes = integrationConfig?.autoApplyPseudoStateAttributes ?? false;
1181
+ takeSnapshot(cachedAutoApplyPseudoStateAttributes);
1182
+ });
1183
+ } else {
1184
+ takeSnapshot(cachedAutoApplyPseudoStateAttributes);
1032
1185
  }
1033
- const domSnapshot = takeDOMSnapshot(properties);
1034
- cy.task(
1035
- "happoRegisterSnapshot",
1036
- {
1037
- timestamp: Date.now(),
1038
- component,
1039
- variant,
1040
- targets,
1041
- ...domSnapshot
1042
- },
1043
- taskOptions
1044
- );
1045
1186
  }
1046
1187
  );
1047
1188
  export {