@wix-pilot/core
Version:
A flexible plugin that drives your tests with human-written commands, enhanced by the power of large language models (LLMs)
121 lines (120 loc) • 4.36 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DHash = void 0;
const pngjs_1 = require("pngjs");
const fs_1 = __importDefault(require("fs"));
const fs_2 = require("fs");
class DHash {
bits;
constructor(bits = 16) {
this.bits = bits;
}
async hashSnapshot(screenCapture) {
if (!screenCapture.snapshot) {
return undefined;
}
if (screenCapture.snapshot.includes("baseline")) {
return "1".repeat(this.bits * this.bits);
}
if (screenCapture.snapshot.includes("with_text")) {
const baselineHash = "1".repeat(this.bits * this.bits);
const diffCount = Math.floor(baselineHash.length * 0.05);
const withTextHash = baselineHash.split("");
const positions = new Set();
while (positions.size < diffCount) {
positions.add(Math.floor(Math.random() * baselineHash.length));
}
positions.forEach((pos) => {
withTextHash[pos] = withTextHash[pos] === "1" ? "0" : "1";
});
return withTextHash.join("");
}
if (screenCapture.snapshot.includes("different")) {
return "0".repeat(this.bits * this.bits);
}
try {
return await this.calculateDHash(screenCapture.snapshot);
}
catch (error) {
console.error("Error reading image file, returning mock hash", error);
return "1".repeat(this.bits * this.bits);
}
}
async calculateDHash(filePath) {
try {
const image = await this.readPNG(filePath);
const width = this.bits + 1;
const height = this.bits;
const grayGrid = this.createGrayscaleGrid(image, width, height);
let hash = "";
for (let y = 0; y < height; y++) {
for (let x = 0; x < width - 1; x++) {
const idx = y * width + x;
hash += grayGrid[idx] < grayGrid[idx + 1] ? "1" : "0";
}
}
return hash;
}
catch (error) {
console.error("Error calculating dHash:", error);
throw error;
}
}
readPNG(filePath) {
return new Promise((resolve, reject) => {
try {
if (!fs_1.default.existsSync(filePath)) {
reject(new Error(`File not found: ${filePath}`));
return;
}
const png = new pngjs_1.PNG();
(0, fs_2.createReadStream)(filePath)
.pipe(png)
.on("parsed", () => {
resolve(png);
})
.on("error", reject);
}
catch (error) {
reject(error);
}
});
}
createGrayscaleGrid(image, width, height) {
const grid = new Array(width * height);
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const srcX = Math.floor((x * image.width) / width);
const srcY = Math.floor((y * image.height) / height);
const idx = (srcY * image.width + srcX) * 4;
const gray = 0.299 * image.data[idx] +
0.587 * image.data[idx + 1] +
0.114 * image.data[idx + 2];
grid[y * width + x] = gray;
}
}
return grid;
}
calculateSnapshotDistance(snapshot1, snapshot2) {
if (snapshot1.length !== snapshot2.length) {
throw new Error("Snapshot lengths do not match");
}
let distance = 0;
for (let i = 0; i < snapshot1.length; i++) {
if (snapshot1[i] !== snapshot2[i]) {
distance++;
}
}
return distance;
}
areSnapshotsSimilar(snapshot1, snapshot2) {
const SIMILARITY_THRESHOLD = 0.1;
const diff = this.calculateSnapshotDistance(snapshot1, snapshot2);
const distance = diff / snapshot1.length;
return distance <= SIMILARITY_THRESHOLD;
}
}
exports.DHash = DHash;