flexysnap 0.3.0 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flexysnap",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Flexible visual snapshot testing for Playwright, built for e-commerce.",
5
5
  "keywords": [
6
6
  "playwright",
@@ -61,9 +61,9 @@ async function annotateWireframeFile(wireframeFile, screenshotFile) {
61
61
  image: { fill: 'rgba(70, 180, 120, 0.4)', stroke: '#2EBC6F' },
62
62
  text: { fill: 'rgba(50, 130, 190, 0.4)', stroke: '#0066CC' },
63
63
  error: { fill: 'rgba(211, 47, 47, 0.4)', stroke: '#D32F2F' },
64
- missing: { fill: 'rgba(233, 30, 140, 0.4)', stroke: '#E91E8C' },
65
- extra: { fill: 'rgba(156, 39, 176, 0.4)', stroke: '#9C27B0' },
66
- shift: { fill: 'rgba(121, 85, 72, 0.4)', stroke: '#795548' }
64
+ missing: { fill: 'rgba(233, 30, 140, 0.4)', stroke: '#D32F2F' },
65
+ extra: { fill: 'rgba(156, 39, 176, 0.4)', stroke: '#D32F2F' },
66
+ shift: { fill: 'rgba(121, 85, 72, 0.4)', stroke: '#D32F2F' }
67
67
  };
68
68
 
69
69
  function determineColorKey(obj, defaultKey) {
@@ -11,16 +11,16 @@ function calculateBoundingBoxDistance(rect1, rect2) {
11
11
  Math.abs(rect1.bottom - rect2.bottom));
12
12
  }
13
13
 
14
- function createPairings(currentElements, baselineElements) {
14
+ function pairByBoundingBox(currentIndices, baselineIndices, currentElements, baselineElements) {
15
15
  const pairings = [];
16
-
17
- for (let currentIndex = 0; currentIndex < currentElements.length; currentIndex++) {
18
- for (let baselineIndex = 0; baselineIndex < baselineElements.length; baselineIndex++) {
16
+
17
+ for (const currentIndex of currentIndices) {
18
+ for (const baselineIndex of baselineIndices) {
19
19
  const distance = calculateBoundingBoxDistance(
20
20
  currentElements[currentIndex].boundingRect,
21
21
  baselineElements[baselineIndex].boundingRect
22
22
  );
23
-
23
+
24
24
  pairings.push({
25
25
  currentIndex,
26
26
  baselineIndex,
@@ -34,7 +34,7 @@ function createPairings(currentElements, baselineElements) {
34
34
  const usedCurrentIndices = new Set();
35
35
  const usedBaselineIndices = new Set();
36
36
  const matchedPairs = [];
37
-
37
+
38
38
  for (const pairing of pairings) {
39
39
  if (!usedCurrentIndices.has(pairing.currentIndex) && !usedBaselineIndices.has(pairing.baselineIndex)) {
40
40
  usedCurrentIndices.add(pairing.currentIndex);
@@ -42,21 +42,134 @@ function createPairings(currentElements, baselineElements) {
42
42
  matchedPairs.push(pairing);
43
43
  }
44
44
  }
45
-
45
+
46
+ const unmatchedCurrent = [];
47
+ for (const currentIndex of currentIndices) {
48
+ if (!usedCurrentIndices.has(currentIndex)) {
49
+ unmatchedCurrent.push(currentIndex);
50
+ }
51
+ }
52
+
53
+ const unmatchedBaseline = [];
54
+ for (const baselineIndex of baselineIndices) {
55
+ if (!usedBaselineIndices.has(baselineIndex)) {
56
+ unmatchedBaseline.push(baselineIndex);
57
+ }
58
+ }
59
+
60
+ return {
61
+ matchedPairs,
62
+ unmatchedCurrent,
63
+ unmatchedBaseline
64
+ };
65
+ }
66
+
67
+ function createPairings(currentElements, baselineElements) {
68
+ const currentIndices = currentElements.map((_, index) => index);
69
+ const baselineIndices = baselineElements.map((_, index) => index);
70
+
71
+ return pairByBoundingBox(currentIndices, baselineIndices, currentElements, baselineElements);
72
+ }
73
+
74
+ function buildTextIndexMap(texts) {
75
+ const map = new Map();
76
+ texts.forEach((textElement, index) => {
77
+ const key = textElement.text;
78
+ if (!map.has(key)) {
79
+ map.set(key, []);
80
+ }
81
+ map.get(key).push(index);
82
+ });
83
+ return map;
84
+ }
85
+
86
+ function createTextPairings(currentTexts, baselineTexts) {
87
+ const currentTextMap = buildTextIndexMap(currentTexts);
88
+ const baselineTextMap = buildTextIndexMap(baselineTexts);
89
+
90
+ const usedCurrentIndices = new Set();
91
+ const usedBaselineIndices = new Set();
92
+ const matchedPairs = [];
93
+
94
+ for (const [text, currentIndices] of currentTextMap) {
95
+ const baselineIndices = baselineTextMap.get(text);
96
+ if (currentIndices.length === 1 && baselineIndices && baselineIndices.length === 1) {
97
+ const currentIndex = currentIndices[0];
98
+ const baselineIndex = baselineIndices[0];
99
+ matchedPairs.push({
100
+ currentIndex,
101
+ baselineIndex,
102
+ distance: 0
103
+ });
104
+ usedCurrentIndices.add(currentIndex);
105
+ usedBaselineIndices.add(baselineIndex);
106
+ }
107
+ }
108
+
109
+ for (const [text, currentIndices] of currentTextMap) {
110
+ const baselineIndices = baselineTextMap.get(text) || [];
111
+ const remainingCurrentIndices = currentIndices.filter(index => !usedCurrentIndices.has(index));
112
+ const remainingBaselineIndices = baselineIndices.filter(index => !usedBaselineIndices.has(index));
113
+
114
+ if (remainingCurrentIndices.length > 0 && remainingBaselineIndices.length > 0) {
115
+ const result = pairByBoundingBox(
116
+ remainingCurrentIndices,
117
+ remainingBaselineIndices,
118
+ currentTexts,
119
+ baselineTexts
120
+ );
121
+
122
+ for (const pairing of result.matchedPairs) {
123
+ matchedPairs.push(pairing);
124
+ usedCurrentIndices.add(pairing.currentIndex);
125
+ usedBaselineIndices.add(pairing.baselineIndex);
126
+ }
127
+ }
128
+ }
129
+
130
+ const remainingCurrentIndices = [];
131
+ for (let i = 0; i < currentTexts.length; i++) {
132
+ if (!usedCurrentIndices.has(i)) {
133
+ remainingCurrentIndices.push(i);
134
+ }
135
+ }
136
+
137
+ const remainingBaselineIndices = [];
138
+ for (let i = 0; i < baselineTexts.length; i++) {
139
+ if (!usedBaselineIndices.has(i)) {
140
+ remainingBaselineIndices.push(i);
141
+ }
142
+ }
143
+
144
+ if (remainingCurrentIndices.length > 0 && remainingBaselineIndices.length > 0) {
145
+ const result = pairByBoundingBox(
146
+ remainingCurrentIndices,
147
+ remainingBaselineIndices,
148
+ currentTexts,
149
+ baselineTexts
150
+ );
151
+
152
+ for (const pairing of result.matchedPairs) {
153
+ matchedPairs.push(pairing);
154
+ usedCurrentIndices.add(pairing.currentIndex);
155
+ usedBaselineIndices.add(pairing.baselineIndex);
156
+ }
157
+ }
158
+
46
159
  const unmatchedCurrent = [];
47
- for (let i = 0; i < currentElements.length; i++) {
160
+ for (let i = 0; i < currentTexts.length; i++) {
48
161
  if (!usedCurrentIndices.has(i)) {
49
162
  unmatchedCurrent.push(i);
50
163
  }
51
164
  }
52
-
165
+
53
166
  const unmatchedBaseline = [];
54
- for (let i = 0; i < baselineElements.length; i++) {
167
+ for (let i = 0; i < baselineTexts.length; i++) {
55
168
  if (!usedBaselineIndices.has(i)) {
56
169
  unmatchedBaseline.push(i);
57
170
  }
58
171
  }
59
-
172
+
60
173
  return {
61
174
  matchedPairs,
62
175
  unmatchedCurrent,
@@ -112,7 +225,7 @@ function replaceDigitsWithPlaceholder(text) {
112
225
  }
113
226
 
114
227
  function compareTexts(baselineTexts, currentTexts, options) {
115
- const {matchedPairs, unmatchedCurrent, unmatchedBaseline} = createPairings(currentTexts, baselineTexts);
228
+ const {matchedPairs, unmatchedCurrent, unmatchedBaseline} = createTextPairings(currentTexts, baselineTexts);
116
229
 
117
230
  for (const pairing of matchedPairs) {
118
231
  const baselineText = baselineTexts[pairing.baselineIndex];