flexysnap 0.1.2-alpha.2 → 0.1.3-alpha.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.1.2-alpha.2",
3
+ "version": "0.1.3-alpha.1",
4
4
  "description": "Flexible visual snapshot testing for Playwright, built for e-commerce.",
5
5
  "keywords": [
6
6
  "playwright",
@@ -44,12 +44,9 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@playwright/test": "^1.61.1",
47
- "canvas": "^3.2.3",
48
- "glob": "^13.0.6",
49
- "playwright": "^1.61.1",
50
- "sharp": "^0.35.3"
47
+ "canvas": "^3.2.3"
51
48
  },
52
49
  "devDependencies": {
53
50
  "eslint": "^9.9.0"
54
51
  }
55
- }
52
+ }
@@ -1,7 +1,20 @@
1
- import sharp from 'sharp';
2
1
  import fs from 'fs';
3
2
  import path from 'path';
4
- import { createCanvas } from 'canvas';
3
+ import { createCanvas, loadImage } from 'canvas';
4
+
5
+ function applyGrayscale(ctx, width, height) {
6
+ const imageData = ctx.getImageData(0, 0, width, height);
7
+ const data = imageData.data;
8
+
9
+ for (let i = 0; i < data.length; i += 4) {
10
+ const gray = Math.round(0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2]);
11
+ data[i] = gray;
12
+ data[i + 1] = gray;
13
+ data[i + 2] = gray;
14
+ }
15
+
16
+ ctx.putImageData(imageData, 0, 0);
17
+ }
5
18
 
6
19
  async function annotateWireframeFile(wireframeFile, screenshotFile) {
7
20
  if (!fs.existsSync(wireframeFile)) {
@@ -17,13 +30,16 @@ async function annotateWireframeFile(wireframeFile, screenshotFile) {
17
30
  const wireframeContent = fs.readFileSync(wireframeFile, 'utf-8');
18
31
  const wireframe = JSON.parse(wireframeContent);
19
32
 
20
- const metadata = await sharp(screenshotFile).metadata();
21
- const width = metadata.width;
22
- const height = metadata.height;
33
+ const screenshot = await loadImage(screenshotFile);
34
+ const width = screenshot.width;
35
+ const height = screenshot.height;
23
36
 
24
37
  const canvas = createCanvas(width, height);
25
38
  const ctx = canvas.getContext('2d');
26
39
 
40
+ ctx.drawImage(screenshot, 0, 0);
41
+ applyGrayscale(ctx, width, height);
42
+
27
43
  const colors = {
28
44
  box: { fill: 'rgba(220, 160, 40, 0.4)', stroke: '#E6A500' },
29
45
  image: { fill: 'rgba(70, 180, 120, 0.4)', stroke: '#2EBC6F' },
@@ -70,19 +86,11 @@ async function annotateWireframeFile(wireframeFile, screenshotFile) {
70
86
  }
71
87
  }
72
88
 
73
- const overlayBuffer = canvas.toBuffer('image/png');
74
-
75
89
  const outputDir = path.dirname(screenshotFile);
76
90
  const basename = path.basename(screenshotFile, '.png');
77
91
  const outputPath = path.join(outputDir, `${basename}_wireframe.png`);
78
92
 
79
- await sharp(screenshotFile)
80
- .grayscale()
81
- .composite([{
82
- input: overlayBuffer,
83
- blend: 'over'
84
- }])
85
- .toFile(outputPath);
93
+ fs.writeFileSync(outputPath, canvas.toBuffer('image/png'));
86
94
 
87
95
  console.log(`Annotated wireframe saved to: ${outputPath}`);
88
96
  }
package/src/cli.js CHANGED
File without changes
package/src/index.js CHANGED
@@ -4,7 +4,9 @@ export {
4
4
  click,
5
5
  hover,
6
6
  fill,
7
+ selectOption,
7
8
  rehover,
9
+ scrollToTopOfElement,
8
10
  setClosePopups,
9
11
  logTimestamp,
10
12
  setBaseUrl
package/src/testUtils.js CHANGED
@@ -140,6 +140,25 @@ async function rehover(page) {
140
140
  }
141
141
  }
142
142
 
143
+ async function scrollToTopOfElement(page, target, offset = 0) {
144
+ const locator = typeof target === 'string' ? page.locator(target) : target;
145
+ await locator.waitFor({ state: 'attached' });
146
+
147
+ const targetScrollY = await locator.evaluate((element, scrollOffset) => {
148
+ const rect = element.getBoundingClientRect();
149
+ return rect.top + window.scrollY - scrollOffset;
150
+ }, offset);
151
+
152
+ const maxScrollY = await page.evaluate(() => document.body.scrollHeight - window.innerHeight);
153
+ const finalScrollY = Math.max(0, Math.min(targetScrollY, maxScrollY));
154
+
155
+ await page.evaluate((scrollY) => window.scrollTo(0, scrollY), finalScrollY);
156
+ await page.waitForTimeout(500);
157
+ logTimestamp(`Scrolled to position: ${finalScrollY}`);
158
+
159
+ return finalScrollY;
160
+ }
161
+
143
162
  async function fill(page, field, value) {
144
163
  let locator;
145
164
  if (typeof field === 'string') {
@@ -153,13 +172,29 @@ async function fill(page, field, value) {
153
172
 
154
173
  }
155
174
 
175
+ async function selectOption(page, field, value) {
176
+ let locator;
177
+ if (typeof field === 'string') {
178
+ const selector = `select[name="${field}"]`;
179
+ locator = page.locator(selector);
180
+ } else {
181
+ locator = field;
182
+ }
183
+ await click(page, locator);
184
+ await locator.selectOption({ label: value });
185
+ logTimestamp('selecting ' + value + ' on ' + locator);
186
+ await page.waitForTimeout(500);
187
+ }
188
+
156
189
  export {
157
190
  waitForCompleteLoad,
158
191
  highlightedClick,
159
192
  click,
160
193
  hover,
161
194
  fill,
195
+ selectOption,
162
196
  rehover,
197
+ scrollToTopOfElement,
163
198
  setClosePopups,
164
199
  logTimestamp,
165
200
  setBaseUrl
@@ -1,18 +1,25 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { logTimestamp } from './testUtils.js';
4
- import sharp from 'sharp';
4
+ import { loadImage, createCanvas } from 'canvas';
5
5
  import { areWireframesStable } from './wireframeStability.js';
6
6
 
7
7
  async function getRGBHistogramFromBuffer(buffer) {
8
- const {data, info} = await sharp(buffer)
9
- .raw()
10
- .toBuffer({resolveWithObject: true});
8
+ const image = await loadImage(buffer);
9
+ const canvas = createCanvas(image.width, image.height);
10
+ const ctx = canvas.getContext('2d');
11
+ ctx.drawImage(image, 0, 0);
12
+
13
+ const { data } = ctx.getImageData(0, 0, image.width, image.height);
11
14
 
12
15
  const histogram = new Array(48).fill(0);
13
- const pixelCount = info.width * info.height;
16
+ const pixelCount = image.width * image.height;
17
+
18
+ if (pixelCount === 0) {
19
+ return histogram;
20
+ }
14
21
 
15
- for (let i = 0; i < data.length; i += info.channels) {
22
+ for (let i = 0; i < data.length; i += 4) {
16
23
  histogram[Math.floor(data[i] / 16)]++;
17
24
  histogram[Math.floor(data[i + 1] / 16) + 16]++;
18
25
  histogram[Math.floor(data[i + 2] / 16) + 32]++;