gestament 0.2.0 → 0.3.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.
- package/README.md +4 -6
- package/dist/displaySession.d.ts +18 -0
- package/dist/displaySession.d.ts.map +1 -0
- package/dist/element.d.ts +2 -2
- package/dist/errors-6gj5YuLw.cjs +36 -0
- package/dist/errors-6gj5YuLw.cjs.map +1 -0
- package/dist/errors-CCW4ATME.js +37 -0
- package/dist/errors-CCW4ATME.js.map +1 -0
- package/dist/errors.d.ts +2 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/generated/packageMetadata.d.ts +4 -4
- package/dist/gestament-config.d.ts +2 -2
- package/dist/gestament-launcher-driver.cjs +656 -0
- package/dist/gestament-launcher-driver.cjs.map +1 -0
- package/dist/gestament-launcher-driver.d.ts +13 -0
- package/dist/gestament-launcher-driver.d.ts.map +1 -0
- package/dist/gestament-launcher-driver.mjs +655 -0
- package/dist/gestament-launcher-driver.mjs.map +1 -0
- package/dist/gestament-tray-host.cjs +1 -1
- package/dist/gestament-tray-host.d.ts +2 -2
- package/dist/gestament-tray-host.mjs +1 -1
- package/dist/gestament-xvfb-pool-probe.cjs +29 -0
- package/dist/gestament-xvfb-pool-probe.cjs.map +1 -0
- package/dist/gestament-xvfb-pool-probe.d.ts +13 -0
- package/dist/gestament-xvfb-pool-probe.d.ts.map +1 -0
- package/dist/gestament-xvfb-pool-probe.mjs +28 -0
- package/dist/gestament-xvfb-pool-probe.mjs.map +1 -0
- package/dist/gestament-xvfb-worker.d.ts +2 -2
- package/dist/gestament-xvfb.cjs +8 -2
- package/dist/gestament-xvfb.cjs.map +1 -1
- package/dist/gestament-xvfb.d.ts +2 -2
- package/dist/gestament-xvfb.mjs +8 -2
- package/dist/gestament-xvfb.mjs.map +1 -1
- package/dist/index.cjs +4 -1147
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +4 -1147
- package/dist/index.mjs.map +1 -1
- package/dist/launchGtkApp-BIO_5Xjn.cjs +2479 -0
- package/dist/launchGtkApp-BIO_5Xjn.cjs.map +1 -0
- package/dist/launchGtkApp-qi1qm5G4.js +2479 -0
- package/dist/launchGtkApp-qi1qm5G4.js.map +1 -0
- package/dist/launchGtkApp.d.ts +2 -2
- package/dist/launchGtkApp.d.ts.map +1 -1
- package/dist/launcherDriverProtocol.d.ts +107 -0
- package/dist/launcherDriverProtocol.d.ts.map +1 -0
- package/dist/{native-ie_XIt1J.cjs → native-CBXaFWP-.cjs} +14 -40
- package/dist/native-CBXaFWP-.cjs.map +1 -0
- package/dist/{native-DUeVYIBs.js → native-CWdUmdty.js} +48 -74
- package/dist/native-CWdUmdty.js.map +1 -0
- package/dist/native.d.ts +4 -2
- package/dist/native.d.ts.map +1 -1
- package/dist/prerequisites-BuZST2Dy.cjs +15 -0
- package/dist/prerequisites-BuZST2Dy.cjs.map +1 -0
- package/dist/prerequisites-JB0SKPVd.js +16 -0
- package/dist/prerequisites-JB0SKPVd.js.map +1 -0
- package/dist/prerequisites.d.ts +23 -0
- package/dist/prerequisites.d.ts.map +1 -0
- package/dist/testing.cjs +3 -0
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.ts +4 -2
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.mjs +4 -1
- package/dist/testing.mjs.map +1 -1
- package/dist/tray.d.ts +2 -2
- package/dist/types.d.ts +64 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/wait-DV5gkXs8.js +113 -0
- package/dist/wait-DV5gkXs8.js.map +1 -0
- package/dist/wait-eOIz4nZm.cjs +112 -0
- package/dist/wait-eOIz4nZm.cjs.map +1 -0
- package/dist/wait.d.ts +67 -0
- package/dist/wait.d.ts.map +1 -0
- package/package.json +7 -7
- package/prebuilds/linux-arm/gtk3/node.napi.armv7.glibc.node +0 -0
- package/prebuilds/linux-arm/gtk4/node.napi.armv7.glibc.node +0 -0
- package/prebuilds/linux-arm64/gtk3/node.napi.glibc.node +0 -0
- package/prebuilds/linux-arm64/gtk4/node.napi.glibc.node +0 -0
- package/prebuilds/linux-ia32/gtk3/node.napi.glibc.node +0 -0
- package/prebuilds/linux-ia32/gtk4/node.napi.glibc.node +0 -0
- package/prebuilds/linux-riscv64/gtk3/node.napi.glibc.node +0 -0
- package/prebuilds/linux-riscv64/gtk4/node.napi.glibc.node +0 -0
- package/prebuilds/linux-x64/gtk3/node.napi.glibc.node +0 -0
- package/prebuilds/linux-x64/gtk4/node.napi.glibc.node +0 -0
- package/dist/native-DUeVYIBs.js.map +0 -1
- package/dist/native-ie_XIt1J.cjs.map +0 -1
package/dist/testing.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.mjs","sources":["../node_modules/pixelmatch/index.js","../src/testing.ts"],"sourcesContent":["/**\n * Compare two equally sized images, pixel by pixel.\n *\n * @param {Uint8Array | Uint8ClampedArray} img1 First image data.\n * @param {Uint8Array | Uint8ClampedArray} img2 Second image data.\n * @param {Uint8Array | Uint8ClampedArray | void} output Image data to write the diff to, if provided.\n * @param {number} width Input images width.\n * @param {number} height Input images height.\n *\n * @param {Object} [options]\n * @param {number} [options.threshold=0.1] Matching threshold (0 to 1); smaller is more sensitive.\n * @param {boolean} [options.includeAA=false] Whether to skip anti-aliasing detection.\n * @param {number} [options.alpha=0.1] Opacity of original image in diff output.\n * @param {[number, number, number]} [options.aaColor=[255, 255, 0]] Color of anti-aliased pixels in diff output.\n * @param {[number, number, number]} [options.diffColor=[255, 0, 0]] Color of different pixels in diff output.\n * @param {[number, number, number]} [options.diffColorAlt=options.diffColor] Whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two.\n * @param {boolean} [options.diffMask=false] Draw the diff over a transparent background (a mask).\n * @param {boolean} [options.checkerboard=true] Whether to blend semi-transparent pixels against a checkerboard pattern (true) or plain white (false) when comparing.\n *\n * @return {number} The number of mismatched pixels.\n */\nexport default function pixelmatch(img1, img2, output, width, height, options = {}) {\n const {\n threshold = 0.1,\n alpha = 0.1,\n aaColor = [255, 255, 0],\n diffColor = [255, 0, 0],\n checkerboard = true,\n includeAA, diffColorAlt, diffMask\n } = options;\n\n if (!isPixelData(img1) || !isPixelData(img2) || (output && !isPixelData(output)))\n throw new Error('Image data: Uint8Array, Uint8ClampedArray or Buffer expected.');\n\n if (img1.length !== img2.length || (output && output.length !== img1.length))\n throw new Error(`Image sizes do not match. Image 1 size: ${img1.length}, image 2 size: ${img2.length}`);\n\n if (img1.length !== width * height * 4) throw new Error(`Image data size does not match width/height. Expecting ${width * height * 4}. Got ${img1.length}`);\n\n // check if images are identical\n const len = width * height;\n const a32 = new Uint32Array(img1.buffer, img1.byteOffset, len);\n const b32 = new Uint32Array(img2.buffer, img2.byteOffset, len);\n let identical = true;\n\n for (let i = 0; i < len; i++) {\n if (a32[i] !== b32[i]) { identical = false; break; }\n }\n if (identical) { // fast path if identical\n if (output && !diffMask) {\n for (let i = 0, pos = 0; i < len; i++, pos += 4) drawGrayPixel(img1, pos, alpha, output);\n }\n return 0;\n }\n\n // maximum acceptable square distance between two colors;\n // 35215 is the maximum possible value for the YIQ difference metric\n const maxDelta = 35215 * threshold * threshold;\n const [aaR, aaG, aaB] = aaColor;\n const [diffR, diffG, diffB] = diffColor;\n const [altR, altG, altB] = diffColorAlt || diffColor;\n let diff = 0;\n\n // compare each pixel of one image against the other one\n for (let i = 0, pos = 0; i < len; i++, pos += 4) {\n // squared YUV distance between colors at this pixel position, negative if the img2 pixel is darker\n const delta = a32[i] === b32[i] ? 0 : colorDelta(img1, img2, pos, pos, checkerboard);\n\n // the color difference is above the threshold\n if (Math.abs(delta) > maxDelta) {\n const x = i % width;\n const y = (i / width) | 0;\n // check it's a real rendering difference or just anti-aliasing\n const isExcludedAA = !includeAA && (antialiased(img1, x, y, width, height, a32, b32, checkerboard) || antialiased(img2, x, y, width, height, b32, a32, checkerboard));\n if (isExcludedAA) {\n // one of the pixels is anti-aliasing; draw as yellow and do not count as difference\n // note that we do not include such pixels in a mask\n if (output && !diffMask) drawPixel(output, pos, aaR, aaG, aaB);\n\n } else {\n // found substantial difference not caused by anti-aliasing; draw it as such\n if (output) {\n if (delta < 0) {\n drawPixel(output, pos, altR, altG, altB);\n } else {\n drawPixel(output, pos, diffR, diffG, diffB);\n }\n }\n diff++;\n }\n\n } else if (output && !diffMask) {\n // pixels are similar; draw background as grayscale image blended with white\n drawGrayPixel(img1, pos, alpha, output);\n }\n }\n\n // return the number of different pixels\n return diff;\n}\n\n/** @param {Uint8Array | Uint8ClampedArray} arr */\nfunction isPixelData(arr) {\n // work around instanceof Uint8Array not working properly in some Jest environments\n return ArrayBuffer.isView(arr) && arr.BYTES_PER_ELEMENT === 1;\n}\n\n/**\n * Check if a pixel is likely a part of anti-aliasing;\n * based on \"Anti-aliased Pixel and Intensity Slope Detector\" paper by V. Vysniauskas, 2009\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n * @param {Uint32Array} a32\n * @param {Uint32Array} b32\n * @param {boolean} checkerboard\n */\nfunction antialiased(img, x1, y1, width, height, a32, b32, checkerboard) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const pos4 = (y1 * width + x1) * 4;\n // cache the center pixel's RGBA once instead of re-reading it on every neighbor comparison\n const cr = img[pos4];\n const cg = img[pos4 + 1];\n const cb = img[pos4 + 2];\n const ca = img[pos4 + 3];\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n let min = 0;\n let max = 0;\n let minX = 0;\n let minY = 0;\n let maxX = 0;\n let maxY = 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n\n // brightness delta between the center pixel and adjacent one\n const delta = brightnessDelta(img, pos4, (y * width + x) * 4, cr, cg, cb, ca, checkerboard);\n\n // count the number of equal, darker and brighter adjacent pixels\n if (delta === 0) {\n zeroes++;\n // if found more than 2 equal siblings, it's definitely not anti-aliasing\n if (zeroes > 2) return false;\n\n // remember the darkest pixel\n } else if (delta < min) {\n min = delta;\n minX = x;\n minY = y;\n\n // remember the brightest pixel\n } else if (delta > max) {\n max = delta;\n maxX = x;\n maxY = y;\n }\n }\n }\n\n // if there are no both darker and brighter pixels among siblings, it's not anti-aliasing\n if (min === 0 || max === 0) return false;\n\n // if either the darkest or the brightest pixel has 3+ equal siblings in both images\n // (definitely not anti-aliased), this pixel is anti-aliased\n return (hasManySiblings(a32, minX, minY, width, height) && hasManySiblings(b32, minX, minY, width, height)) ||\n (hasManySiblings(a32, maxX, maxY, width, height) && hasManySiblings(b32, maxX, maxY, width, height));\n}\n\n/**\n * Check if a pixel has 3+ adjacent pixels of the same color.\n * @param {Uint32Array} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n */\nfunction hasManySiblings(img, x1, y1, width, height) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const val = img[y1 * width + x1];\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n zeroes += +(val === img[y * width + x]);\n if (zeroes > 2) return true;\n }\n }\n return false;\n}\n\n/**\n * Calculate color difference according to the paper \"Measuring perceived color difference\n * using YIQ NTSC transmission color space in mobile applications\" by Y. Kotsarenko and F. Ramos.\n * Caller guarantees the two pixels differ, so the early-zero check is omitted.\n * @param {Uint8Array | Uint8ClampedArray} img1\n * @param {Uint8Array | Uint8ClampedArray} img2\n * @param {number} k\n * @param {number} m\n * @param {boolean} checkerboard\n */\nfunction colorDelta(img1, img2, k, m, checkerboard) {\n const r1 = img1[k];\n const g1 = img1[k + 1];\n const b1 = img1[k + 2];\n const a1 = img1[k + 3];\n const r2 = img2[m];\n const g2 = img2[m + 1];\n const b2 = img2[m + 2];\n const a2 = img2[m + 3];\n\n let dr = r1 - r2;\n let dg = g1 - g2;\n let db = b1 - b2;\n const da = a1 - a2;\n\n if (a1 < 255 || a2 < 255) { // blend pixels with background\n let rb = 255, gb = 255, bb = 255;\n if (checkerboard) {\n rb = 48 + 159 * (k % 2);\n gb = 48 + 159 * ((k / 1.618033988749895 | 0) % 2);\n bb = 48 + 159 * ((k / 2.618033988749895 | 0) % 2);\n }\n dr = (r1 * a1 - r2 * a2 - rb * da) / 255;\n dg = (g1 * a1 - g2 * a2 - gb * da) / 255;\n db = (b1 * a1 - b2 * a2 - bb * da) / 255;\n }\n\n const y = dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;\n const i = dr * 0.59597799 - dg * 0.27417610 - db * 0.32180189;\n const q = dr * 0.21147017 - dg * 0.52261711 + db * 0.31114694;\n\n const delta = 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;\n\n // encode whether the pixel lightens or darkens in the sign\n return y > 0 ? -delta : delta;\n}\n\n/**\n * Specialized brightness-only color delta for the anti-aliasing detector,\n * with the center pixel's RGBA hoisted out of the neighbor loop.\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} k center pixel offset\n * @param {number} m neighbor pixel offset\n * @param {number} r1\n * @param {number} g1\n * @param {number} b1\n * @param {number} a1\n * @param {boolean} checkerboard\n */\nfunction brightnessDelta(img, k, m, r1, g1, b1, a1, checkerboard) {\n const r2 = img[m];\n const g2 = img[m + 1];\n const b2 = img[m + 2];\n const a2 = img[m + 3];\n\n let dr = r1 - r2;\n let dg = g1 - g2;\n let db = b1 - b2;\n const da = a1 - a2;\n\n if (!dr && !dg && !db && !da) return 0;\n\n if (a1 < 255 || a2 < 255) {\n let rb = 255, gb = 255, bb = 255;\n if (checkerboard) {\n rb = 48 + 159 * (k % 2);\n gb = 48 + 159 * ((k / 1.618033988749895 | 0) % 2);\n bb = 48 + 159 * ((k / 2.618033988749895 | 0) % 2);\n }\n dr = (r1 * a1 - r2 * a2 - rb * da) / 255;\n dg = (g1 * a1 - g2 * a2 - gb * da) / 255;\n db = (b1 * a1 - b2 * a2 - bb * da) / 255;\n }\n\n return dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} output\n * @param {number} pos\n * @param {number} r\n * @param {number} g\n * @param {number} b\n */\nfunction drawPixel(output, pos, r, g, b) {\n output[pos] = r;\n output[pos + 1] = g;\n output[pos + 2] = b;\n output[pos + 3] = 255;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} i\n * @param {number} alpha\n * @param {Uint8Array | Uint8ClampedArray} output\n */\nfunction drawGrayPixel(img, i, alpha, output) {\n const val = 255 + (img[i] * 0.29889531 + img[i + 1] * 0.58662247 + img[i + 2] * 0.11448223 - 255) * alpha * img[i + 3] / 255;\n drawPixel(output, i, val, val, val);\n}\n","// gestament - TypeScript based test driver for GTK.\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/gestament\n\nimport { createHash } from 'node:crypto';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport pixelmatch from 'pixelmatch';\nimport { PNG } from 'pngjs';\nimport { ssim } from 'ssim.js';\nimport englishLanguageData from '@tesseract.js-data/eng';\n\nimport type { GtkCapture, GtkCaptureBounds, Releasable } from './types';\n\n/////////////////////////////////////////////////////////////////////////////////////////\n\n/** Pixel region inside a captured PNG image. */\nexport interface GtkCapturePixelRegion {\n /** Left pixel offset from the capture image origin. */\n readonly x: number;\n\n /** Top pixel offset from the capture image origin. */\n readonly y: number;\n\n /** Region width in pixels. */\n readonly width: number;\n\n /** Region height in pixels. */\n readonly height: number;\n}\n\n/**\n * Expected PNG image source for GTK capture visual assertions.\n * @remarks Strings are interpreted as filesystem paths. URL values must use the file protocol.\n */\nexport type GtkCaptureExpectedImage = Buffer | string | URL;\n\n/** Tesseract page segmentation mode used by GTK capture OCR assertions. */\nexport type GtkCaptureOcrPageSegmentationMode =\n | 'osdOnly'\n | 'autoOsd'\n | 'autoOnly'\n | 'auto'\n | 'singleColumn'\n | 'singleBlockVerticalText'\n | 'singleBlock'\n | 'singleLine'\n | 'singleWord'\n | 'circleWord'\n | 'singleChar'\n | 'sparseText'\n | 'sparseTextOsd'\n | 'rawLine';\n\n/** Worker lifecycle mode used by GTK capture OCR assertions. */\nexport type GtkCaptureOcrWorkerMode = 'perRead' | 'shared';\n\n/** Cache mode passed to Tesseract.js language data loading. */\nexport type GtkCaptureOcrCacheMethod =\n | 'write'\n | 'readOnly'\n | 'refresh'\n | 'none';\n\n/** Defaults shared by GTK capture OCR assertions. */\nexport interface GtkCaptureOcrDefaults {\n /**\n * Tesseract.js worker lifecycle mode.\n * @remarks The default is perRead, which creates and terminates a worker for each OCR read.\n */\n readonly workerMode?: GtkCaptureOcrWorkerMode;\n\n /**\n * OCR language code or language code list.\n * @remarks The default is eng. Multiple languages are joined with + for Tesseract.js.\n */\n readonly languages?: string | readonly string[];\n\n /**\n * Tesseract.js core path.\n * @remarks Omit to use Tesseract.js defaults.\n */\n readonly corePath?: string;\n\n /**\n * Tesseract.js worker script path.\n * @remarks Omit to use Tesseract.js defaults.\n */\n readonly workerPath?: string;\n\n /**\n * Language data path passed to Tesseract.js.\n * @remarks Omit to use bundled English traineddata when languages is eng.\n */\n readonly langPath?: string;\n\n /**\n * Language data cache path passed to Tesseract.js.\n * @remarks Omit to let the selected cacheMethod decide whether Tesseract.js writes a cache file.\n */\n readonly cachePath?: string;\n\n /**\n * Language data cache behavior passed to Tesseract.js.\n * @remarks The default is none when bundled English traineddata is used.\n */\n readonly cacheMethod?: GtkCaptureOcrCacheMethod;\n\n /**\n * Whether language data is gzipped.\n * @remarks The default follows the selected language data source.\n */\n readonly gzip?: boolean;\n}\n\n/** Output settings shared by GTK capture assertions. */\nexport interface GtkCaptureResultOutputOptions {\n /**\n * Output directory used as the base path for actual, expected, diff, and metadata files.\n * @remarks Output files are written only when outputResultPath or GESTAMENT_VISUAL_OUTPUT_RESULT_PATH is specified.\n */\n readonly outputResultPath?: string;\n\n /**\n * Artifact variant, usually a GTK backend or platform name.\n * @remarks This value does not enable artifact output by itself.\n */\n readonly variant?: string;\n}\n\n/** Defaults shared by GTK capture visual and OCR assertions. */\nexport interface GtkCaptureVisualDefaults extends GtkCaptureResultOutputOptions {\n /**\n * Defaults for OCR assertions.\n * @remarks OCR workers are created lazily only when an OCR assertion is used.\n */\n readonly ocr?: GtkCaptureOcrDefaults;\n}\n\n/** Options shared by visual comparison assertions. */\nexport interface GtkCaptureVisualComparisonOptions extends GtkCaptureResultOutputOptions {\n /** Region to compare. Omit to compare the full capture image. */\n readonly region?: GtkCapturePixelRegion;\n\n /** Regions to ignore during comparison. Coordinates use the full capture image. */\n readonly masks?: readonly GtkCapturePixelRegion[];\n}\n\n/** Options for pixel-difference based capture comparison. */\nexport interface GtkCaptureLookSimilarOptions extends GtkCaptureVisualComparisonOptions {\n /** Pixelmatch color threshold from 0 to 1. */\n readonly threshold?: number;\n\n /** Maximum allowed mismatched pixel count. */\n readonly maxDiffPixels?: number;\n\n /** Maximum allowed mismatched pixel ratio from 0 to 1. */\n readonly maxDiffRatio?: number;\n}\n\n/** Options for structural-similarity (SSIM) based capture comparison. */\nexport interface GtkCaptureSimilarityOptions extends GtkCaptureVisualComparisonOptions {\n /** Minimum allowed MSSIM score from 0 to 1. */\n readonly minSimilarity?: number;\n}\n\n/** Image preprocessing options applied before OCR recognition. */\nexport interface GtkCaptureOcrPreprocessOptions {\n /**\n * Nearest-neighbor scale factor applied after cropping.\n * @remarks The default is 1.\n */\n readonly scale?: number;\n\n /**\n * Converts RGB pixels to Rec. 709 luminance before OCR.\n * @remarks Thresholding also uses luminance even when this is false.\n */\n readonly grayscale?: boolean;\n\n /**\n * Converts luminance values to black or white using this threshold from 0 to 255.\n * @remarks Omit to keep continuous color or grayscale values.\n */\n readonly threshold?: number;\n\n /**\n * Inverts RGB values after grayscale or threshold processing.\n * @remarks Alpha values are preserved.\n */\n readonly invert?: boolean;\n}\n\n/** Options for reading text from a GTK capture with OCR. */\nexport interface GtkCaptureOcrOptions extends GtkCaptureResultOutputOptions {\n /** Region to pass to OCR. Omit to read the full capture image. */\n readonly region?: GtkCapturePixelRegion;\n\n /**\n * Tesseract page segmentation modes to try.\n * @remarks The default tries singleBlock, sparseText, singleLine, and singleWord.\n */\n readonly pageSegmentationModes?: readonly GtkCaptureOcrPageSegmentationMode[];\n\n /** Image preprocessing applied before OCR recognition. */\n readonly preprocess?: GtkCaptureOcrPreprocessOptions;\n\n /**\n * Additional Tesseract worker parameters applied before each recognition attempt.\n * @remarks tessedit_pageseg_mode is overwritten for each selected pageSegmentationMode.\n */\n readonly parameters?: Readonly<Record<string, string>>;\n}\n\n/** Options applied when matching OCR text against an expected value. */\nexport interface GtkCaptureOcrTextAssertionOptions {\n /**\n * Whether string expectations are case-sensitive.\n * @remarks The default is false. Regular expressions use their own flags.\n */\n readonly caseSensitive?: boolean;\n\n /**\n * Whether OCR text whitespace is collapsed before matching.\n * @remarks The default is true.\n */\n readonly normalizeWhitespace?: boolean;\n\n /**\n * Minimum confidence required for a matching OCR attempt.\n * @remarks Omit to accept any confidence value returned by Tesseract.js.\n */\n readonly minConfidence?: number;\n}\n\n/** Options for asserting OCR text directly from a GTK capture. */\nexport interface GtkCaptureOcrAssertionOptions\n extends GtkCaptureOcrOptions, GtkCaptureOcrTextAssertionOptions {}\n\n/** Common result fields returned by GTK capture visual assertions. */\nexport interface GtkCaptureVisualResult {\n /** Whether the assertion passed. */\n readonly pass: boolean;\n\n /** Output directory for this assertion call, present when result output is enabled. */\n readonly outputResultPath?: string;\n\n /** Saved actual PNG path, present when result output is enabled. */\n readonly actualImagePath?: string;\n\n /** Saved metadata JSON path, present when result output is enabled. */\n readonly metadataJsonPath?: string;\n\n /** Saved expected PNG path, present when failure output was generated. */\n readonly expectedImagePath?: string;\n\n /** Saved diff PNG path, present when a diff image was generated. */\n readonly diffImagePath?: string;\n}\n\n/** Result returned by pixel-difference based capture comparison. */\nexport interface GtkCaptureLookSimilarResult extends GtkCaptureVisualResult {\n /** Number of mismatched pixels after region and mask processing. */\n readonly diffPixels: number;\n\n /** Mismatched pixel ratio after region and mask processing. */\n readonly diffRatio: number;\n\n /** Number of pixels included in the comparison region. */\n readonly totalPixels: number;\n}\n\n/** Result returned by structural-similarity based capture comparison. */\nexport interface GtkCaptureSimilarityResult extends GtkCaptureVisualResult {\n /** MSSIM score returned by ssim.js. */\n readonly similarity: number;\n\n /** Diagnostic mismatched pixel count generated by pixelmatch. */\n readonly diffPixels: number;\n\n /** Diagnostic mismatched pixel ratio generated by pixelmatch. */\n readonly diffRatio: number;\n\n /** Number of pixels included in the comparison region. */\n readonly totalPixels: number;\n}\n\n/** One OCR recognition attempt for a GTK capture. */\nexport interface GtkCaptureOcrAttempt {\n /** Page segmentation mode used for this attempt. */\n readonly pageSegmentationMode: GtkCaptureOcrPageSegmentationMode;\n\n /** Raw text returned by Tesseract.js. */\n readonly text: string;\n\n /** Whitespace-normalized text returned by Tesseract.js. */\n readonly normalizedText: string;\n\n /** Confidence score returned by Tesseract.js. */\n readonly confidence: number;\n}\n\n/** Result returned by OCR text assertions. */\nexport interface GtkCaptureOcrResult extends GtkCaptureVisualResult {\n /** Raw text selected from the best OCR attempt. */\n readonly text: string;\n\n /** Whitespace-normalized text selected from the best OCR attempt. */\n readonly normalizedText: string;\n\n /** Confidence score from the selected OCR attempt. */\n readonly confidence: number;\n\n /** Page segmentation mode from the selected OCR attempt. */\n readonly pageSegmentationMode: GtkCaptureOcrPageSegmentationMode;\n\n /** All OCR recognition attempts produced for this assertion. */\n readonly attempts: readonly GtkCaptureOcrAttempt[];\n\n /** Expected OCR text matcher as a diagnostic string. */\n readonly expectedText: string;\n\n /** Saved OCR input PNG path, present when result output is enabled. */\n readonly ocrInputImagePath?: string;\n}\n\n/** OCR text read from a GTK capture and reusable for multiple assertions. */\nexport interface GtkCaptureOcrText {\n /** Raw text selected from the best OCR attempt. */\n readonly text: string;\n\n /** Whitespace-normalized text selected from the best OCR attempt. */\n readonly normalizedText: string;\n\n /** Confidence score from the selected OCR attempt. */\n readonly confidence: number;\n\n /** Page segmentation mode from the selected OCR attempt. */\n readonly pageSegmentationMode: GtkCaptureOcrPageSegmentationMode;\n\n /** All OCR recognition attempts produced for this read. */\n readonly attempts: readonly GtkCaptureOcrAttempt[];\n\n /** Output directory for this OCR read, present when result output is enabled. */\n readonly outputResultPath?: string;\n\n /** Saved actual PNG path, present when result output is enabled. */\n readonly actualImagePath?: string;\n\n /** Saved OCR input PNG path, present when result output is enabled. */\n readonly ocrInputImagePath?: string;\n\n /** Saved metadata JSON path, present when result output is enabled. */\n readonly metadataJsonPath?: string;\n\n /**\n * Asserts that this OCR text contains the expected string or matches the expected regular expression.\n * @param expected Expected string or regular expression.\n * @param options Text matching options.\n * @returns OCR assertion result when the assertion passes.\n */\n readonly toContainText: (\n expected: string | RegExp,\n options?: GtkCaptureOcrTextAssertionOptions\n ) => Promise<GtkCaptureOcrResult>;\n}\n\n/** Error thrown by GTK capture visual assertions. */\nexport interface GtkCaptureVisualError<\n Result extends GtkCaptureVisualResult = GtkCaptureVisualResult,\n> extends Error {\n /** Assertion result and artifact paths available at the failure point. */\n readonly result: Result;\n}\n\n/** Assertion object for a single GTK capture image. */\nexport interface GtkCaptureExpectation {\n /**\n * Compares the capture against an expected PNG image with pixel-level tolerance.\n * @param expectedImage Expected PNG image as a buffer, path string, or file URL.\n * @param options Comparison options.\n * @returns Comparison result when the assertion passes.\n */\n readonly toLookSimilar: (\n expectedImage: GtkCaptureExpectedImage,\n options?: GtkCaptureLookSimilarOptions\n ) => Promise<GtkCaptureLookSimilarResult>;\n\n /**\n * Compares the capture against an expected PNG image with structural similarity (SSIM).\n * @param expectedImage Expected PNG image as a buffer, path string, or file URL.\n * @param options Comparison options.\n * @returns Comparison result when the assertion passes.\n */\n readonly toHaveSimilarity: (\n expectedImage: GtkCaptureExpectedImage,\n options?: GtkCaptureSimilarityOptions\n ) => Promise<GtkCaptureSimilarityResult>;\n\n /**\n * Reads text from the capture with OCR and asserts that it contains expected text.\n * @param expected Expected string or regular expression.\n * @param options OCR and text matching options.\n * @returns OCR assertion result when the assertion passes.\n */\n readonly toContainText: (\n expected: string | RegExp,\n options?: GtkCaptureOcrAssertionOptions\n ) => Promise<GtkCaptureOcrResult>;\n\n /**\n * Reads text from the capture with OCR for reusable text assertions.\n * @param options OCR options.\n * @returns OCR text object that can run multiple assertions without recognizing again.\n */\n readonly readText: (\n options?: GtkCaptureOcrOptions\n ) => Promise<GtkCaptureOcrText>;\n}\n\n/** Factory for GTK capture visual assertions. */\nexport interface GtkCaptureExpect extends Releasable {\n /**\n * Creates an assertion object for a captured GTK image.\n * @param capture GTK capture to assert.\n * @param name Artifact name.\n * @returns Assertion object for the capture.\n */\n readonly expectCapture: (\n capture: GtkCapture,\n name: string\n ) => GtkCaptureExpectation;\n}\n\ninterface ResolvedDefaults {\n readonly outputResultPath: string;\n readonly variant: string;\n}\n\ninterface EnabledComparisonContext {\n readonly actualImagePath: string;\n readonly outputResultPath: string;\n readonly artifactsEnabled: true;\n readonly expectedImagePath: string;\n readonly diffImagePath: string;\n readonly metadataJsonPath: string;\n readonly ocrInputImagePath: string;\n readonly resolved: ResolvedDefaults;\n}\n\ninterface DisabledComparisonContext {\n readonly artifactsEnabled: false;\n}\n\ntype ComparisonContext = EnabledComparisonContext | DisabledComparisonContext;\n\ninterface DecodedPng {\n readonly data: Buffer;\n readonly height: number;\n readonly width: number;\n}\n\ninterface LoadedExpectedImage {\n readonly data: Buffer;\n readonly source: 'buffer' | 'path' | 'file-url';\n readonly sourcePath: string | undefined;\n}\n\ninterface PreparedComparison {\n readonly actualData: Uint8Array;\n readonly expectedData: Uint8Array;\n readonly height: number;\n readonly totalPixels: number;\n readonly width: number;\n}\n\ninterface ResolvedLookSimilarOptions {\n readonly maxDiffPixels: number | undefined;\n readonly maxDiffRatio: number;\n readonly threshold: number;\n}\n\ninterface ResolvedSimilarityOptions {\n readonly minSimilarity: number;\n}\n\ninterface ResolvedOcrOptions {\n readonly pageSegmentationModes: readonly GtkCaptureOcrPageSegmentationMode[];\n readonly parameters: Readonly<Record<string, string>>;\n readonly preprocess: Required<GtkCaptureOcrPreprocessOptions>;\n readonly region: GtkCapturePixelRegion;\n}\n\ninterface PreparedOcrImage {\n readonly image: Buffer;\n readonly preprocess: Required<GtkCaptureOcrPreprocessOptions>;\n readonly region: GtkCapturePixelRegion;\n}\n\ninterface LoadedTesseractModule {\n readonly createWorker: (\n languages?: string | readonly string[],\n oem?: number,\n options?: Partial<TesseractWorkerOptions>\n ) => Promise<TesseractWorker>;\n}\n\ninterface TesseractWorkerOptions {\n cacheMethod: string;\n cachePath: string;\n corePath: string;\n gzip: boolean;\n langPath: string;\n logger: (message: unknown) => void;\n workerPath: string;\n}\n\ninterface TesseractWorker {\n readonly recognize: (image: Buffer) => Promise<{\n readonly data: {\n readonly confidence: number;\n readonly text: string;\n };\n }>;\n readonly setParameters: (\n parameters: Readonly<Record<string, string>>\n ) => Promise<unknown>;\n readonly terminate: () => Promise<unknown>;\n}\n\ninterface OcrWorkerController {\n readonly recognize: (\n preparedImage: PreparedOcrImage,\n options: ResolvedOcrOptions\n ) => Promise<readonly GtkCaptureOcrAttempt[]>;\n readonly release: () => Promise<void>;\n}\n\ninterface OcrTextData {\n readonly actualImagePath: string | undefined;\n readonly attempts: readonly GtkCaptureOcrAttempt[];\n readonly confidence: number;\n readonly metadataJsonPath: string | undefined;\n readonly normalizedText: string;\n readonly ocrInputImagePath: string | undefined;\n readonly outputResultPath: string | undefined;\n readonly pageSegmentationMode: GtkCaptureOcrPageSegmentationMode;\n readonly text: string;\n}\n\nconst padNumber = (value: number, width: number): string =>\n value.toString().padStart(width, '0');\n\nconst hashText = (value: string): string =>\n createHash('sha256').update(value).digest('hex').slice(0, 10);\n\nconst defaultOcrPageSegmentationModes = [\n 'singleBlock',\n 'sparseText',\n 'singleLine',\n 'singleWord',\n] as const satisfies readonly GtkCaptureOcrPageSegmentationMode[];\n\nconst pageSegmentationModeValues: Record<\n GtkCaptureOcrPageSegmentationMode,\n string\n> = {\n auto: '3',\n autoOnly: '2',\n autoOsd: '1',\n circleWord: '9',\n osdOnly: '0',\n rawLine: '13',\n singleBlock: '6',\n singleBlockVerticalText: '5',\n singleChar: '10',\n singleColumn: '4',\n singleLine: '7',\n singleWord: '8',\n sparseText: '11',\n sparseTextOsd: '12',\n};\n\nlet tesseractModulePromise: Promise<LoadedTesseractModule> | undefined;\n\nconst loadTesseractModule = async (): Promise<LoadedTesseractModule> => {\n tesseractModulePromise ??= import('tesseract.js').then((loaded) => {\n const module = loaded as unknown as\n | LoadedTesseractModule\n | { readonly default: LoadedTesseractModule };\n return 'default' in module ? module.default : module;\n });\n return tesseractModulePromise;\n};\n\nconst normalizePathSegment = (value: string, fallback: string): string => {\n const trimmed = value.trim();\n const normalized = trimmed\n .replace(/[\\x00-\\x1f<>:\"/\\\\|?*]+/g, '_')\n .replace(/\\s+/g, '_')\n .replace(/_+/g, '_')\n .replace(/^_+|_+$/g, '');\n if (normalized.length === 0) {\n return fallback;\n }\n if (normalized.length <= 140) {\n return normalized;\n }\n return `${normalized.slice(0, 129)}-${hashText(normalized)}`;\n};\n\nconst serializeBounds = (\n bounds: GtkCaptureBounds\n): Record<keyof GtkCaptureBounds, number> => ({\n height: bounds.height,\n width: bounds.width,\n x: bounds.x,\n y: bounds.y,\n});\n\nconst resolveDefaults = (\n defaults: GtkCaptureVisualDefaults,\n options: GtkCaptureResultOutputOptions | undefined\n): ResolvedDefaults | undefined => {\n const outputResultPath =\n options?.outputResultPath ??\n defaults.outputResultPath ??\n process.env.GESTAMENT_VISUAL_OUTPUT_RESULT_PATH;\n if (outputResultPath === undefined) {\n return undefined;\n }\n\n return {\n outputResultPath: resolve(outputResultPath),\n variant:\n options?.variant ??\n defaults.variant ??\n process.env.GESTAMENT_VISUAL_VARIANT ??\n process.env.GESTAMENT_TEST_BACKEND ??\n 'default',\n };\n};\n\nconst loadExpectedImage = async (\n expectedImage: GtkCaptureExpectedImage\n): Promise<LoadedExpectedImage> => {\n if (Buffer.isBuffer(expectedImage)) {\n return {\n data: expectedImage,\n source: 'buffer',\n sourcePath: undefined,\n };\n }\n\n if (typeof expectedImage === 'string') {\n const sourcePath = resolve(expectedImage);\n return {\n data: await readFile(sourcePath),\n source: 'path',\n sourcePath,\n };\n }\n\n if (expectedImage.protocol !== 'file:') {\n throw new TypeError('expectedImage URL must use the file: protocol.');\n }\n\n const sourcePath = fileURLToPath(expectedImage);\n return {\n data: await readFile(sourcePath),\n source: 'file-url',\n sourcePath,\n };\n};\n\nconst decodePng = (image: Buffer): DecodedPng => {\n const png = PNG.sync.read(image);\n return {\n data: png.data,\n height: png.height,\n width: png.width,\n };\n};\n\nconst validateCaptureImage = (capture: GtkCapture, png: DecodedPng): void => {\n if (\n png.width !== capture.visibleBounds.width ||\n png.height !== capture.visibleBounds.height\n ) {\n throw new Error(\n `Capture PNG size ${png.width}x${png.height} does not match visible bounds ${capture.visibleBounds.width}x${capture.visibleBounds.height}.`\n );\n }\n};\n\nconst validateFiniteInteger = (value: number, label: string): void => {\n if (!Number.isInteger(value)) {\n throw new TypeError(`${label} must be an integer.`);\n }\n};\n\nconst validateRegion = (\n region: GtkCapturePixelRegion,\n imageWidth: number,\n imageHeight: number,\n label: string\n): void => {\n validateFiniteInteger(region.x, `${label}.x`);\n validateFiniteInteger(region.y, `${label}.y`);\n validateFiniteInteger(region.width, `${label}.width`);\n validateFiniteInteger(region.height, `${label}.height`);\n if (region.x < 0 || region.y < 0) {\n throw new TypeError(`${label} origin must be inside the capture image.`);\n }\n if (region.width <= 0 || region.height <= 0) {\n throw new TypeError(`${label} size must be positive.`);\n }\n if (\n region.x + region.width > imageWidth ||\n region.y + region.height > imageHeight\n ) {\n throw new TypeError(`${label} must be inside the capture image.`);\n }\n};\n\nconst validateRatio = (value: number, label: string): void => {\n if (!Number.isFinite(value) || value < 0 || value > 1) {\n throw new TypeError(`${label} must be a number from 0 to 1.`);\n }\n};\n\nconst validateNonNegativeInteger = (value: number, label: string): void => {\n if (!Number.isInteger(value) || value < 0) {\n throw new TypeError(`${label} must be a non-negative integer.`);\n }\n};\n\nconst getComparisonRegion = (\n options: GtkCaptureVisualComparisonOptions | undefined,\n imageWidth: number,\n imageHeight: number\n): GtkCapturePixelRegion => {\n const region =\n options?.region ??\n ({ height: imageHeight, width: imageWidth, x: 0, y: 0 } as const);\n validateRegion(region, imageWidth, imageHeight, 'region');\n return region;\n};\n\nconst validateMasks = (\n masks: readonly GtkCapturePixelRegion[] | undefined,\n imageWidth: number,\n imageHeight: number\n): void => {\n if (masks === undefined) {\n return;\n }\n for (const [index, mask] of masks.entries()) {\n validateRegion(mask, imageWidth, imageHeight, `masks[${index}]`);\n }\n};\n\nconst copyRegionData = (\n source: DecodedPng,\n region: GtkCapturePixelRegion\n): Uint8Array => {\n const data = new Uint8Array(region.width * region.height * 4);\n for (let y = 0; y < region.height; y += 1) {\n const sourceStart = ((region.y + y) * source.width + region.x) * 4;\n const sourceEnd = sourceStart + region.width * 4;\n const targetStart = y * region.width * 4;\n data.set(source.data.subarray(sourceStart, sourceEnd), targetStart);\n }\n return data;\n};\n\nconst applyMasks = (\n actualData: Uint8Array,\n expectedData: Uint8Array,\n region: GtkCapturePixelRegion,\n masks: readonly GtkCapturePixelRegion[] | undefined\n): void => {\n if (masks === undefined) {\n return;\n }\n for (const mask of masks) {\n const left = Math.max(region.x, mask.x);\n const top = Math.max(region.y, mask.y);\n const right = Math.min(region.x + region.width, mask.x + mask.width);\n const bottom = Math.min(region.y + region.height, mask.y + mask.height);\n if (left >= right || top >= bottom) {\n continue;\n }\n for (let y = top; y < bottom; y += 1) {\n for (let x = left; x < right; x += 1) {\n const index = ((y - region.y) * region.width + (x - region.x)) * 4;\n actualData[index] = 0;\n actualData[index + 1] = 0;\n actualData[index + 2] = 0;\n actualData[index + 3] = 0;\n expectedData[index] = 0;\n expectedData[index + 1] = 0;\n expectedData[index + 2] = 0;\n expectedData[index + 3] = 0;\n }\n }\n }\n};\n\nconst prepareComparison = (\n actualPng: DecodedPng,\n expectedPng: DecodedPng,\n options: GtkCaptureVisualComparisonOptions | undefined\n): PreparedComparison => {\n if (\n actualPng.width !== expectedPng.width ||\n actualPng.height !== expectedPng.height\n ) {\n throw new Error(\n `Expected image size ${expectedPng.width}x${expectedPng.height} does not match actual capture size ${actualPng.width}x${actualPng.height}.`\n );\n }\n\n const region = getComparisonRegion(\n options,\n actualPng.width,\n actualPng.height\n );\n validateMasks(options?.masks, actualPng.width, actualPng.height);\n\n const actualData = copyRegionData(actualPng, region);\n const expectedData = copyRegionData(expectedPng, region);\n applyMasks(actualData, expectedData, region, options?.masks);\n\n return {\n actualData,\n expectedData,\n height: region.height,\n totalPixels: region.width * region.height,\n width: region.width,\n };\n};\n\nconst createDiffPng = (\n comparison: PreparedComparison,\n threshold: number\n): {\n readonly diffPixels: number;\n readonly diffPng: PNG;\n} => {\n const diffPng = new PNG({\n height: comparison.height,\n width: comparison.width,\n });\n const diffPixels = pixelmatch(\n comparison.expectedData,\n comparison.actualData,\n diffPng.data,\n comparison.width,\n comparison.height,\n { threshold }\n );\n return {\n diffPixels,\n diffPng,\n };\n};\n\nconst createContext = async (\n defaults: GtkCaptureVisualDefaults,\n options: GtkCaptureResultOutputOptions | undefined,\n name: string,\n counter: number\n): Promise<ComparisonContext> => {\n const resolved = resolveDefaults(defaults, options);\n if (resolved === undefined) {\n return {\n artifactsEnabled: false,\n };\n }\n\n const safeVariant = normalizePathSegment(resolved.variant, 'default');\n const safeName = normalizePathSegment(name, 'capture');\n const outputResultPath = join(\n resolved.outputResultPath,\n safeVariant,\n `${safeName}-${padNumber(counter, 6)}`\n );\n await mkdir(outputResultPath, { recursive: true });\n return {\n actualImagePath: join(outputResultPath, 'actual.png'),\n outputResultPath,\n artifactsEnabled: true,\n diffImagePath: join(outputResultPath, 'diff.png'),\n expectedImagePath: join(outputResultPath, 'expected.png'),\n metadataJsonPath: join(outputResultPath, 'metadata.json'),\n ocrInputImagePath: join(outputResultPath, 'ocr-input.png'),\n resolved,\n };\n};\n\nconst writeMetadata = async (\n context: EnabledComparisonContext,\n capture: GtkCapture,\n name: string,\n matcher: string,\n options: GtkCaptureVisualComparisonOptions | undefined,\n expectedImage: LoadedExpectedImage\n): Promise<void> => {\n await writeFile(\n context.metadataJsonPath,\n `${JSON.stringify(\n {\n bounds: serializeBounds(capture.bounds),\n clipped: capture.clipped,\n expectedImageSource: expectedImage.source,\n expectedImageSourcePath: expectedImage.sourcePath,\n imageBytes: capture.image.length,\n matcher,\n masks: options?.masks,\n name,\n region: options?.region,\n variant: context.resolved.variant,\n visibleBounds: serializeBounds(capture.visibleBounds),\n },\n undefined,\n 2\n )}\\n`\n );\n};\n\nconst createVisualError = <Result extends GtkCaptureVisualResult>(\n message: string,\n result: Result\n): GtkCaptureVisualError<Result> =>\n Object.assign(new Error(message), {\n result,\n });\n\nconst saveActualAndMetadata = async (\n context: ComparisonContext,\n capture: GtkCapture,\n name: string,\n matcher: string,\n options: GtkCaptureVisualComparisonOptions | undefined,\n expectedImage: LoadedExpectedImage\n): Promise<void> => {\n if (!context.artifactsEnabled) {\n return;\n }\n\n await writeFile(context.actualImagePath, capture.image);\n await writeMetadata(context, capture, name, matcher, options, expectedImage);\n};\n\nconst buildBaseResult = (\n context: ComparisonContext\n): GtkCaptureVisualResult => {\n if (!context.artifactsEnabled) {\n return {\n pass: true,\n };\n }\n\n return {\n actualImagePath: context.actualImagePath,\n outputResultPath: context.outputResultPath,\n metadataJsonPath: context.metadataJsonPath,\n pass: true,\n };\n};\n\nconst writeFailureArtifacts = async (\n context: ComparisonContext,\n expectedImage: Buffer,\n diffPng: PNG\n): Promise<\n Pick<GtkCaptureVisualResult, 'diffImagePath' | 'expectedImagePath'>\n> => {\n if (!context.artifactsEnabled) {\n return {};\n }\n\n await writeFile(context.expectedImagePath, expectedImage);\n await writeFile(context.diffImagePath, PNG.sync.write(diffPng));\n return {\n diffImagePath: context.diffImagePath,\n expectedImagePath: context.expectedImagePath,\n };\n};\n\nconst isLookSimilarPass = (\n diffPixels: number,\n diffRatio: number,\n options: ResolvedLookSimilarOptions\n): boolean => {\n const ratioPass = diffRatio <= options.maxDiffRatio;\n const pixelsPass =\n options.maxDiffPixels === undefined || diffPixels <= options.maxDiffPixels;\n return ratioPass && pixelsPass;\n};\n\nconst resolveLookSimilarOptions = (\n options: GtkCaptureLookSimilarOptions | undefined\n): ResolvedLookSimilarOptions => {\n const resolved = {\n maxDiffPixels: options?.maxDiffPixels,\n maxDiffRatio: options?.maxDiffRatio ?? 0.01,\n threshold: options?.threshold ?? 0.1,\n };\n validateRatio(resolved.threshold, 'threshold');\n validateRatio(resolved.maxDiffRatio, 'maxDiffRatio');\n if (resolved.maxDiffPixels !== undefined) {\n validateNonNegativeInteger(resolved.maxDiffPixels, 'maxDiffPixels');\n }\n return resolved;\n};\n\nconst resolveSimilarityOptions = (\n options: GtkCaptureSimilarityOptions | undefined\n): ResolvedSimilarityOptions => {\n const resolved = {\n minSimilarity: options?.minSimilarity ?? 0.985,\n };\n validateRatio(resolved.minSimilarity, 'minSimilarity');\n return resolved;\n};\n\nconst validateOcrPageSegmentationMode = (\n value: GtkCaptureOcrPageSegmentationMode,\n label: string\n): void => {\n if (!(value in pageSegmentationModeValues)) {\n throw new TypeError(\n `${label} must be a supported OCR page segmentation mode.`\n );\n }\n};\n\nconst validateThreshold = (value: number, label: string): void => {\n if (!Number.isInteger(value) || value < 0 || value > 255) {\n throw new TypeError(`${label} must be an integer from 0 to 255.`);\n }\n};\n\nconst validatePositiveInteger = (value: number, label: string): void => {\n if (!Number.isInteger(value) || value <= 0) {\n throw new TypeError(`${label} must be a positive integer.`);\n }\n};\n\nconst normalizeWhitespace = (value: string): string =>\n value.replace(/\\s+/g, ' ').trim();\n\nconst resolveOcrPreprocessOptions = (\n options: GtkCaptureOcrPreprocessOptions | undefined\n): Required<GtkCaptureOcrPreprocessOptions> => {\n const resolved = {\n grayscale: options?.grayscale ?? false,\n invert: options?.invert ?? false,\n scale: options?.scale ?? 1,\n threshold: options?.threshold ?? -1,\n };\n validatePositiveInteger(resolved.scale, 'preprocess.scale');\n if (resolved.threshold !== -1) {\n validateThreshold(resolved.threshold, 'preprocess.threshold');\n }\n return resolved;\n};\n\nconst resolveOcrOptions = (\n options: GtkCaptureOcrOptions | undefined,\n imageWidth: number,\n imageHeight: number\n): ResolvedOcrOptions => {\n const pageSegmentationModes =\n options?.pageSegmentationModes ?? defaultOcrPageSegmentationModes;\n if (pageSegmentationModes.length === 0) {\n throw new TypeError('pageSegmentationModes must not be empty.');\n }\n for (const [index, mode] of pageSegmentationModes.entries()) {\n validateOcrPageSegmentationMode(mode, `pageSegmentationModes[${index}]`);\n }\n const region =\n options?.region ??\n ({ height: imageHeight, width: imageWidth, x: 0, y: 0 } as const);\n validateRegion(region, imageWidth, imageHeight, 'region');\n return {\n pageSegmentationModes,\n parameters: options?.parameters ?? {},\n preprocess: resolveOcrPreprocessOptions(options?.preprocess),\n region,\n };\n};\n\nconst hasOcrPreprocessing = (\n options: Required<GtkCaptureOcrPreprocessOptions>,\n region: GtkCapturePixelRegion,\n imageWidth: number,\n imageHeight: number\n): boolean =>\n options.grayscale ||\n options.invert ||\n options.scale !== 1 ||\n options.threshold !== -1 ||\n region.x !== 0 ||\n region.y !== 0 ||\n region.width !== imageWidth ||\n region.height !== imageHeight;\n\nconst getLuminance = (red: number, green: number, blue: number): number =>\n Math.round(red * 0.2126 + green * 0.7152 + blue * 0.0722);\n\nconst prepareOcrImage = (\n originalImage: Buffer,\n png: DecodedPng,\n options: ResolvedOcrOptions\n): PreparedOcrImage => {\n if (\n !hasOcrPreprocessing(\n options.preprocess,\n options.region,\n png.width,\n png.height\n )\n ) {\n return {\n image: originalImage,\n preprocess: options.preprocess,\n region: options.region,\n };\n }\n\n const output = new PNG({\n height: options.region.height * options.preprocess.scale,\n width: options.region.width * options.preprocess.scale,\n });\n for (let y = 0; y < output.height; y += 1) {\n for (let x = 0; x < output.width; x += 1) {\n const sourceX =\n options.region.x + Math.floor(x / options.preprocess.scale);\n const sourceY =\n options.region.y + Math.floor(y / options.preprocess.scale);\n const sourceIndex = (sourceY * png.width + sourceX) * 4;\n const targetIndex = (y * output.width + x) * 4;\n const red = png.data[sourceIndex]!;\n const green = png.data[sourceIndex + 1]!;\n const blue = png.data[sourceIndex + 2]!;\n const alpha = png.data[sourceIndex + 3]!;\n const luminance = getLuminance(red, green, blue);\n const thresholded =\n options.preprocess.threshold === -1\n ? luminance\n : luminance >= options.preprocess.threshold\n ? 255\n : 0;\n const value =\n options.preprocess.grayscale || options.preprocess.threshold !== -1\n ? thresholded\n : undefined;\n output.data[targetIndex] = options.preprocess.invert\n ? 255 - (value ?? red)\n : (value ?? red);\n output.data[targetIndex + 1] = options.preprocess.invert\n ? 255 - (value ?? green)\n : (value ?? green);\n output.data[targetIndex + 2] = options.preprocess.invert\n ? 255 - (value ?? blue)\n : (value ?? blue);\n output.data[targetIndex + 3] = alpha;\n }\n }\n\n return {\n image: PNG.sync.write(output),\n preprocess: options.preprocess,\n region: options.region,\n };\n};\n\nconst isEnglishOnlyLanguage = (\n languages: string | readonly string[] | undefined\n): boolean => {\n if (languages === undefined) {\n return true;\n }\n if (typeof languages === 'string') {\n return languages === 'eng';\n }\n return languages.length === 1 && languages[0] === 'eng';\n};\n\nconst resolveOcrWorkerOptions = (\n defaults: GtkCaptureOcrDefaults | undefined\n): {\n readonly languages: string | readonly string[];\n readonly options: Partial<TesseractWorkerOptions>;\n} => {\n const languages =\n defaults?.languages === undefined\n ? englishLanguageData.code\n : typeof defaults.languages === 'string'\n ? defaults.languages\n : [...defaults.languages];\n const useBundledEnglishData =\n defaults?.langPath === undefined && isEnglishOnlyLanguage(languages);\n const workerOptions: Partial<TesseractWorkerOptions> = {\n logger: () => undefined,\n };\n if (defaults?.cachePath !== undefined) {\n workerOptions.cachePath = defaults.cachePath;\n }\n if (defaults?.corePath !== undefined) {\n workerOptions.corePath = defaults.corePath;\n }\n if (defaults?.workerPath !== undefined) {\n workerOptions.workerPath = defaults.workerPath;\n }\n if (defaults?.langPath !== undefined) {\n workerOptions.langPath = defaults.langPath;\n } else if (useBundledEnglishData) {\n workerOptions.langPath = englishLanguageData.langPath;\n }\n if (defaults?.gzip !== undefined) {\n workerOptions.gzip = defaults.gzip;\n } else if (useBundledEnglishData) {\n workerOptions.gzip = englishLanguageData.gzip;\n }\n if (defaults?.cacheMethod !== undefined) {\n workerOptions.cacheMethod = defaults.cacheMethod;\n } else if (useBundledEnglishData) {\n workerOptions.cacheMethod = 'none';\n }\n return {\n languages,\n options: workerOptions,\n };\n};\n\nconst createOcrWorker = async (\n defaults: GtkCaptureOcrDefaults | undefined\n): Promise<TesseractWorker> => {\n const tesseract = await loadTesseractModule();\n const resolved = resolveOcrWorkerOptions(defaults);\n return await tesseract.createWorker(\n resolved.languages,\n undefined,\n resolved.options\n );\n};\n\nconst recognizeWithWorker = async (\n worker: TesseractWorker,\n preparedImage: PreparedOcrImage,\n options: ResolvedOcrOptions\n): Promise<readonly GtkCaptureOcrAttempt[]> => {\n const attempts: GtkCaptureOcrAttempt[] = [];\n for (const pageSegmentationMode of options.pageSegmentationModes) {\n await worker.setParameters({\n ...options.parameters,\n tessedit_pageseg_mode: pageSegmentationModeValues[pageSegmentationMode],\n });\n const recognized = await worker.recognize(preparedImage.image);\n attempts.push({\n confidence: Number.isFinite(recognized.data.confidence)\n ? recognized.data.confidence\n : 0,\n normalizedText: normalizeWhitespace(recognized.data.text),\n pageSegmentationMode,\n text: recognized.data.text,\n });\n }\n return attempts;\n};\n\nconst createOcrWorkerController = (\n defaults: GtkCaptureOcrDefaults | undefined\n): OcrWorkerController => {\n if (defaults?.workerMode !== 'shared') {\n return {\n recognize: async (\n preparedImage: PreparedOcrImage,\n options: ResolvedOcrOptions\n ): Promise<readonly GtkCaptureOcrAttempt[]> => {\n const worker = await createOcrWorker(defaults);\n try {\n return await recognizeWithWorker(worker, preparedImage, options);\n } finally {\n await worker.terminate();\n }\n },\n release: async (): Promise<void> => undefined,\n };\n }\n\n let workerPromise: Promise<TesseractWorker> | undefined;\n let queue: Promise<void> = Promise.resolve();\n const getWorker = (): Promise<TesseractWorker> => {\n workerPromise ??= createOcrWorker(defaults);\n return workerPromise;\n };\n const enqueue = async <T>(operation: () => Promise<T>): Promise<T> => {\n const previous = queue;\n let resolveNext: () => void = () => undefined;\n queue = new Promise<void>((resolve) => {\n resolveNext = resolve;\n });\n await previous;\n try {\n return await operation();\n } finally {\n resolveNext();\n }\n };\n\n return {\n recognize: async (\n preparedImage: PreparedOcrImage,\n options: ResolvedOcrOptions\n ): Promise<readonly GtkCaptureOcrAttempt[]> =>\n await enqueue(async () =>\n recognizeWithWorker(await getWorker(), preparedImage, options)\n ),\n release: async (): Promise<void> => {\n await queue;\n if (workerPromise === undefined) {\n return;\n }\n const worker = await workerPromise;\n workerPromise = undefined;\n await worker.terminate();\n },\n };\n};\n\nconst validateConfidence = (value: number, label: string): void => {\n if (!Number.isFinite(value) || value < 0 || value > 100) {\n throw new TypeError(`${label} must be a number from 0 to 100.`);\n }\n};\n\nconst formatExpectedText = (expected: string | RegExp): string =>\n typeof expected === 'string' ? expected : expected.toString();\n\nconst serializeExpectedText = (\n expected: string | RegExp | undefined\n):\n | {\n readonly type: 'string';\n readonly value: string;\n }\n | {\n readonly flags: string;\n readonly source: string;\n readonly type: 'regexp';\n }\n | undefined => {\n if (expected === undefined) {\n return undefined;\n }\n if (typeof expected === 'string') {\n return {\n type: 'string',\n value: expected,\n };\n }\n return {\n flags: expected.flags,\n source: expected.source,\n type: 'regexp',\n };\n};\n\nconst selectBestOcrAttempt = (\n attempts: readonly GtkCaptureOcrAttempt[]\n): GtkCaptureOcrAttempt => {\n const [firstAttempt] = attempts;\n if (firstAttempt === undefined) {\n throw new Error('OCR did not return any recognition attempts.');\n }\n return attempts.reduce((best, current) =>\n current.confidence > best.confidence ? current : best\n );\n};\n\nconst createOcrTextData = (\n context: ComparisonContext,\n attempts: readonly GtkCaptureOcrAttempt[]\n): OcrTextData => {\n const bestAttempt = selectBestOcrAttempt(attempts);\n if (!context.artifactsEnabled) {\n return {\n actualImagePath: undefined,\n attempts,\n confidence: bestAttempt.confidence,\n metadataJsonPath: undefined,\n normalizedText: bestAttempt.normalizedText,\n ocrInputImagePath: undefined,\n outputResultPath: undefined,\n pageSegmentationMode: bestAttempt.pageSegmentationMode,\n text: bestAttempt.text,\n };\n }\n return {\n actualImagePath: context.actualImagePath,\n attempts,\n confidence: bestAttempt.confidence,\n metadataJsonPath: context.metadataJsonPath,\n normalizedText: bestAttempt.normalizedText,\n ocrInputImagePath: context.ocrInputImagePath,\n outputResultPath: context.outputResultPath,\n pageSegmentationMode: bestAttempt.pageSegmentationMode,\n text: bestAttempt.text,\n };\n};\n\nconst writeOcrMetadata = async (\n context: EnabledComparisonContext,\n capture: GtkCapture,\n name: string,\n matcher: string,\n options: GtkCaptureOcrOptions | undefined,\n preparedImage: PreparedOcrImage,\n attempts: readonly GtkCaptureOcrAttempt[],\n expected: string | RegExp | undefined\n): Promise<void> => {\n await writeFile(\n context.metadataJsonPath,\n `${JSON.stringify(\n {\n attempts,\n bounds: serializeBounds(capture.bounds),\n clipped: capture.clipped,\n expectedText: serializeExpectedText(expected),\n imageBytes: capture.image.length,\n matcher,\n name,\n ocrInputBytes: preparedImage.image.length,\n pageSegmentationModes: options?.pageSegmentationModes,\n parameters: options?.parameters,\n preprocess: preparedImage.preprocess,\n region: preparedImage.region,\n variant: context.resolved.variant,\n visibleBounds: serializeBounds(capture.visibleBounds),\n },\n undefined,\n 2\n )}\\n`\n );\n};\n\nconst saveOcrArtifactsAndMetadata = async (\n context: ComparisonContext,\n capture: GtkCapture,\n name: string,\n matcher: string,\n options: GtkCaptureOcrOptions | undefined,\n preparedImage: PreparedOcrImage,\n attempts: readonly GtkCaptureOcrAttempt[],\n expected: string | RegExp | undefined\n): Promise<void> => {\n if (!context.artifactsEnabled) {\n return;\n }\n\n await writeFile(context.actualImagePath, capture.image);\n await writeFile(context.ocrInputImagePath, preparedImage.image);\n await writeOcrMetadata(\n context,\n capture,\n name,\n matcher,\n options,\n preparedImage,\n attempts,\n expected\n );\n};\n\nconst matchOcrAttempt = (\n attempt: GtkCaptureOcrAttempt,\n expected: string | RegExp,\n options: GtkCaptureOcrTextAssertionOptions | undefined\n): boolean => {\n const normalize = options?.normalizeWhitespace ?? true;\n const candidate = normalize ? attempt.normalizedText : attempt.text;\n const minConfidence = options?.minConfidence;\n if (minConfidence !== undefined) {\n validateConfidence(minConfidence, 'minConfidence');\n if (attempt.confidence < minConfidence) {\n return false;\n }\n }\n\n if (typeof expected === 'string') {\n if (expected.length === 0) {\n throw new TypeError('expected text must not be empty.');\n }\n const expectedText = normalize ? normalizeWhitespace(expected) : expected;\n if (expectedText.length === 0) {\n throw new TypeError(\n 'expected text must not be empty after normalization.'\n );\n }\n if (options?.caseSensitive ?? false) {\n return candidate.includes(expectedText);\n }\n return candidate\n .toLocaleLowerCase()\n .includes(expectedText.toLocaleLowerCase());\n }\n\n expected.lastIndex = 0;\n const matched = expected.test(candidate);\n expected.lastIndex = 0;\n return matched;\n};\n\nconst createOcrResult = (\n data: OcrTextData,\n expected: string | RegExp,\n pass: boolean,\n selectedAttempt: GtkCaptureOcrAttempt\n): GtkCaptureOcrResult => {\n const artifactPaths =\n data.outputResultPath === undefined\n ? {}\n : {\n actualImagePath: data.actualImagePath!,\n metadataJsonPath: data.metadataJsonPath!,\n ocrInputImagePath: data.ocrInputImagePath!,\n outputResultPath: data.outputResultPath,\n };\n return {\n ...artifactPaths,\n attempts: data.attempts,\n confidence: selectedAttempt.confidence,\n expectedText: formatExpectedText(expected),\n normalizedText: selectedAttempt.normalizedText,\n pageSegmentationMode: selectedAttempt.pageSegmentationMode,\n pass,\n text: selectedAttempt.text,\n };\n};\n\nconst assertOcrText = async (\n data: OcrTextData,\n expected: string | RegExp,\n options: GtkCaptureOcrTextAssertionOptions | undefined\n): Promise<GtkCaptureOcrResult> => {\n const matchedAttempt = data.attempts.find((attempt) =>\n matchOcrAttempt(attempt, expected, options)\n );\n if (matchedAttempt !== undefined) {\n return createOcrResult(data, expected, true, matchedAttempt);\n }\n\n const bestAttempt = selectBestOcrAttempt(data.attempts);\n const failedResult = createOcrResult(data, expected, false, bestAttempt);\n throw createVisualError(\n `Capture OCR text did not contain ${formatExpectedText(\n expected\n )}. Recognized text: ${JSON.stringify(bestAttempt.normalizedText)}.`,\n failedResult\n );\n};\n\nconst createOcrText = (data: OcrTextData): GtkCaptureOcrText => {\n const artifactPaths =\n data.outputResultPath === undefined\n ? {}\n : {\n actualImagePath: data.actualImagePath!,\n metadataJsonPath: data.metadataJsonPath!,\n ocrInputImagePath: data.ocrInputImagePath!,\n outputResultPath: data.outputResultPath,\n };\n return {\n ...artifactPaths,\n attempts: data.attempts,\n confidence: data.confidence,\n normalizedText: data.normalizedText,\n pageSegmentationMode: data.pageSegmentationMode,\n text: data.text,\n toContainText: async (\n expected: string | RegExp,\n options?: GtkCaptureOcrTextAssertionOptions\n ): Promise<GtkCaptureOcrResult> =>\n await assertOcrText(data, expected, options),\n };\n};\n\nconst readCaptureText = async (\n defaults: GtkCaptureVisualDefaults,\n nextCounter: () => number,\n workerController: OcrWorkerController,\n capture: GtkCapture,\n name: string,\n matcher: string,\n options: GtkCaptureOcrOptions | undefined,\n expected: string | RegExp | undefined\n): Promise<GtkCaptureOcrText> => {\n const context = await createContext(defaults, options, name, nextCounter());\n const actualPng = decodePng(capture.image);\n validateCaptureImage(capture, actualPng);\n const ocrOptions = resolveOcrOptions(\n options,\n actualPng.width,\n actualPng.height\n );\n const preparedImage = prepareOcrImage(capture.image, actualPng, ocrOptions);\n const attempts = await workerController.recognize(preparedImage, ocrOptions);\n await saveOcrArtifactsAndMetadata(\n context,\n capture,\n name,\n matcher,\n options,\n preparedImage,\n attempts,\n expected\n );\n return createOcrText(createOcrTextData(context, attempts));\n};\n\nconst createLookSimilarAssertion = (\n defaults: GtkCaptureVisualDefaults,\n nextCounter: () => number,\n capture: GtkCapture,\n name: string\n): ((\n expectedImage: GtkCaptureExpectedImage,\n options?: GtkCaptureLookSimilarOptions\n) => Promise<GtkCaptureLookSimilarResult>) => {\n const toLookSimilar = async (\n expectedImage: GtkCaptureExpectedImage,\n options?: GtkCaptureLookSimilarOptions\n ): Promise<GtkCaptureLookSimilarResult> => {\n const context = await createContext(defaults, options, name, nextCounter());\n const actualPng = decodePng(capture.image);\n validateCaptureImage(capture, actualPng);\n const loadedExpectedImage = await loadExpectedImage(expectedImage);\n const expectedPng = decodePng(loadedExpectedImage.data);\n await saveActualAndMetadata(\n context,\n capture,\n name,\n 'toLookSimilar',\n options,\n loadedExpectedImage\n );\n\n const comparisonOptions = resolveLookSimilarOptions(options);\n const comparison = prepareComparison(actualPng, expectedPng, options);\n const { diffPixels, diffPng } = createDiffPng(\n comparison,\n comparisonOptions.threshold\n );\n const diffRatio = diffPixels / comparison.totalPixels;\n const result: GtkCaptureLookSimilarResult = {\n ...buildBaseResult(context),\n diffPixels,\n diffRatio,\n totalPixels: comparison.totalPixels,\n };\n\n if (isLookSimilarPass(diffPixels, diffRatio, comparisonOptions)) {\n return result;\n }\n\n const failureArtifacts = await writeFailureArtifacts(\n context,\n loadedExpectedImage.data,\n diffPng\n );\n const failedResult: GtkCaptureLookSimilarResult = {\n ...result,\n ...failureArtifacts,\n pass: false,\n };\n throw createVisualError(\n `Capture image differs: ${diffPixels} pixels (${diffRatio.toFixed(\n 6\n )}) exceeded maxDiffRatio ${comparisonOptions.maxDiffRatio}${\n comparisonOptions.maxDiffPixels === undefined\n ? ''\n : ` and maxDiffPixels ${comparisonOptions.maxDiffPixels}`\n }.`,\n failedResult\n );\n };\n return toLookSimilar;\n};\n\nconst createSimilarityAssertion = (\n defaults: GtkCaptureVisualDefaults,\n nextCounter: () => number,\n capture: GtkCapture,\n name: string\n): ((\n expectedImage: GtkCaptureExpectedImage,\n options?: GtkCaptureSimilarityOptions\n) => Promise<GtkCaptureSimilarityResult>) => {\n const toHaveSimilarity = async (\n expectedImage: GtkCaptureExpectedImage,\n options?: GtkCaptureSimilarityOptions\n ): Promise<GtkCaptureSimilarityResult> => {\n const context = await createContext(defaults, options, name, nextCounter());\n const actualPng = decodePng(capture.image);\n validateCaptureImage(capture, actualPng);\n const loadedExpectedImage = await loadExpectedImage(expectedImage);\n const expectedPng = decodePng(loadedExpectedImage.data);\n await saveActualAndMetadata(\n context,\n capture,\n name,\n 'toHaveSimilarity',\n options,\n loadedExpectedImage\n );\n\n const comparisonOptions = resolveSimilarityOptions(options);\n const comparison = prepareComparison(actualPng, expectedPng, options);\n const similarity = ssim(\n {\n data: new Uint8ClampedArray(comparison.expectedData),\n height: comparison.height,\n width: comparison.width,\n },\n {\n data: new Uint8ClampedArray(comparison.actualData),\n height: comparison.height,\n width: comparison.width,\n }\n ).mssim;\n const { diffPixels, diffPng } = createDiffPng(comparison, 0.1);\n const diffRatio = diffPixels / comparison.totalPixels;\n const result: GtkCaptureSimilarityResult = {\n ...buildBaseResult(context),\n diffPixels,\n diffRatio,\n similarity,\n totalPixels: comparison.totalPixels,\n };\n\n if (similarity >= comparisonOptions.minSimilarity) {\n return result;\n }\n\n const failureArtifacts = await writeFailureArtifacts(\n context,\n loadedExpectedImage.data,\n diffPng\n );\n const failedResult: GtkCaptureSimilarityResult = {\n ...result,\n ...failureArtifacts,\n pass: false,\n };\n throw createVisualError(\n `Capture image similarity ${similarity.toFixed(\n 6\n )} is below minSimilarity ${comparisonOptions.minSimilarity}.`,\n failedResult\n );\n };\n return toHaveSimilarity;\n};\n\nconst createReadTextAssertion = (\n defaults: GtkCaptureVisualDefaults,\n nextCounter: () => number,\n workerController: OcrWorkerController,\n capture: GtkCapture,\n name: string\n): ((options?: GtkCaptureOcrOptions) => Promise<GtkCaptureOcrText>) => {\n const readText = async (\n options?: GtkCaptureOcrOptions\n ): Promise<GtkCaptureOcrText> =>\n await readCaptureText(\n defaults,\n nextCounter,\n workerController,\n capture,\n name,\n 'readText',\n options,\n undefined\n );\n return readText;\n};\n\nconst createContainTextAssertion = (\n defaults: GtkCaptureVisualDefaults,\n nextCounter: () => number,\n workerController: OcrWorkerController,\n capture: GtkCapture,\n name: string\n): ((\n expected: string | RegExp,\n options?: GtkCaptureOcrAssertionOptions\n) => Promise<GtkCaptureOcrResult>) => {\n const toContainText = async (\n expected: string | RegExp,\n options?: GtkCaptureOcrAssertionOptions\n ): Promise<GtkCaptureOcrResult> => {\n const ocrText = await readCaptureText(\n defaults,\n nextCounter,\n workerController,\n capture,\n name,\n 'toContainText',\n options,\n expected\n );\n return await ocrText.toContainText(expected, options);\n };\n return toContainText;\n};\n\n/////////////////////////////////////////////////////////////////////////////////////////\n\n/**\n * Creates GTK capture visual assertion helpers with shared defaults.\n * @param defaults Default artifact and variant settings.\n * @returns GTK capture assertion helper.\n */\nexport const createGtkCaptureExpect = (\n defaults?: GtkCaptureVisualDefaults\n): GtkCaptureExpect => {\n const resolvedDefaults = defaults ?? {};\n const workerController = createOcrWorkerController(resolvedDefaults.ocr);\n let counter = 0;\n const nextCounter = (): number => {\n const value = counter;\n counter += 1;\n return value;\n };\n const release = async (): Promise<void> => {\n await workerController.release();\n };\n const expectCapture = (\n capture: GtkCapture,\n name: string\n ): GtkCaptureExpectation => ({\n readText: createReadTextAssertion(\n resolvedDefaults,\n nextCounter,\n workerController,\n capture,\n name\n ),\n toContainText: createContainTextAssertion(\n resolvedDefaults,\n nextCounter,\n workerController,\n capture,\n name\n ),\n toHaveSimilarity: createSimilarityAssertion(\n resolvedDefaults,\n nextCounter,\n capture,\n name\n ),\n toLookSimilar: createLookSimilarAssertion(\n resolvedDefaults,\n nextCounter,\n capture,\n name\n ),\n });\n return {\n expectCapture,\n release,\n [Symbol.asyncDispose]: release,\n };\n};\n\nconst defaultGtkCaptureExpect = createGtkCaptureExpect();\n\n/**\n * Creates an assertion object for a captured GTK image.\n * @param capture GTK capture to assert.\n * @param name Artifact name.\n * @returns Assertion object for the capture.\n */\nexport const expectCapture = (\n capture: GtkCapture,\n name: string\n): GtkCaptureExpectation =>\n defaultGtkCaptureExpect.expectCapture(capture, name);\n"],"names":["pixelmatch","sourcePath","resolve","expectCapture"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"testing.mjs","sources":["../node_modules/pixelmatch/index.js","../src/testing.ts"],"sourcesContent":["/**\n * Compare two equally sized images, pixel by pixel.\n *\n * @param {Uint8Array | Uint8ClampedArray} img1 First image data.\n * @param {Uint8Array | Uint8ClampedArray} img2 Second image data.\n * @param {Uint8Array | Uint8ClampedArray | void} output Image data to write the diff to, if provided.\n * @param {number} width Input images width.\n * @param {number} height Input images height.\n *\n * @param {Object} [options]\n * @param {number} [options.threshold=0.1] Matching threshold (0 to 1); smaller is more sensitive.\n * @param {boolean} [options.includeAA=false] Whether to skip anti-aliasing detection.\n * @param {number} [options.alpha=0.1] Opacity of original image in diff output.\n * @param {[number, number, number]} [options.aaColor=[255, 255, 0]] Color of anti-aliased pixels in diff output.\n * @param {[number, number, number]} [options.diffColor=[255, 0, 0]] Color of different pixels in diff output.\n * @param {[number, number, number]} [options.diffColorAlt=options.diffColor] Whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two.\n * @param {boolean} [options.diffMask=false] Draw the diff over a transparent background (a mask).\n * @param {boolean} [options.checkerboard=true] Whether to blend semi-transparent pixels against a checkerboard pattern (true) or plain white (false) when comparing.\n *\n * @return {number} The number of mismatched pixels.\n */\nexport default function pixelmatch(img1, img2, output, width, height, options = {}) {\n const {\n threshold = 0.1,\n alpha = 0.1,\n aaColor = [255, 255, 0],\n diffColor = [255, 0, 0],\n checkerboard = true,\n includeAA, diffColorAlt, diffMask\n } = options;\n\n if (!isPixelData(img1) || !isPixelData(img2) || (output && !isPixelData(output)))\n throw new Error('Image data: Uint8Array, Uint8ClampedArray or Buffer expected.');\n\n if (img1.length !== img2.length || (output && output.length !== img1.length))\n throw new Error(`Image sizes do not match. Image 1 size: ${img1.length}, image 2 size: ${img2.length}`);\n\n if (img1.length !== width * height * 4) throw new Error(`Image data size does not match width/height. Expecting ${width * height * 4}. Got ${img1.length}`);\n\n // check if images are identical\n const len = width * height;\n const a32 = new Uint32Array(img1.buffer, img1.byteOffset, len);\n const b32 = new Uint32Array(img2.buffer, img2.byteOffset, len);\n let identical = true;\n\n for (let i = 0; i < len; i++) {\n if (a32[i] !== b32[i]) { identical = false; break; }\n }\n if (identical) { // fast path if identical\n if (output && !diffMask) {\n for (let i = 0, pos = 0; i < len; i++, pos += 4) drawGrayPixel(img1, pos, alpha, output);\n }\n return 0;\n }\n\n // maximum acceptable square distance between two colors;\n // 35215 is the maximum possible value for the YIQ difference metric\n const maxDelta = 35215 * threshold * threshold;\n const [aaR, aaG, aaB] = aaColor;\n const [diffR, diffG, diffB] = diffColor;\n const [altR, altG, altB] = diffColorAlt || diffColor;\n let diff = 0;\n\n // compare each pixel of one image against the other one\n for (let i = 0, pos = 0; i < len; i++, pos += 4) {\n // squared YUV distance between colors at this pixel position, negative if the img2 pixel is darker\n const delta = a32[i] === b32[i] ? 0 : colorDelta(img1, img2, pos, pos, checkerboard);\n\n // the color difference is above the threshold\n if (Math.abs(delta) > maxDelta) {\n const x = i % width;\n const y = (i / width) | 0;\n // check it's a real rendering difference or just anti-aliasing\n const isExcludedAA = !includeAA && (antialiased(img1, x, y, width, height, a32, b32, checkerboard) || antialiased(img2, x, y, width, height, b32, a32, checkerboard));\n if (isExcludedAA) {\n // one of the pixels is anti-aliasing; draw as yellow and do not count as difference\n // note that we do not include such pixels in a mask\n if (output && !diffMask) drawPixel(output, pos, aaR, aaG, aaB);\n\n } else {\n // found substantial difference not caused by anti-aliasing; draw it as such\n if (output) {\n if (delta < 0) {\n drawPixel(output, pos, altR, altG, altB);\n } else {\n drawPixel(output, pos, diffR, diffG, diffB);\n }\n }\n diff++;\n }\n\n } else if (output && !diffMask) {\n // pixels are similar; draw background as grayscale image blended with white\n drawGrayPixel(img1, pos, alpha, output);\n }\n }\n\n // return the number of different pixels\n return diff;\n}\n\n/** @param {Uint8Array | Uint8ClampedArray} arr */\nfunction isPixelData(arr) {\n // work around instanceof Uint8Array not working properly in some Jest environments\n return ArrayBuffer.isView(arr) && arr.BYTES_PER_ELEMENT === 1;\n}\n\n/**\n * Check if a pixel is likely a part of anti-aliasing;\n * based on \"Anti-aliased Pixel and Intensity Slope Detector\" paper by V. Vysniauskas, 2009\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n * @param {Uint32Array} a32\n * @param {Uint32Array} b32\n * @param {boolean} checkerboard\n */\nfunction antialiased(img, x1, y1, width, height, a32, b32, checkerboard) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const pos4 = (y1 * width + x1) * 4;\n // cache the center pixel's RGBA once instead of re-reading it on every neighbor comparison\n const cr = img[pos4];\n const cg = img[pos4 + 1];\n const cb = img[pos4 + 2];\n const ca = img[pos4 + 3];\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n let min = 0;\n let max = 0;\n let minX = 0;\n let minY = 0;\n let maxX = 0;\n let maxY = 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n\n // brightness delta between the center pixel and adjacent one\n const delta = brightnessDelta(img, pos4, (y * width + x) * 4, cr, cg, cb, ca, checkerboard);\n\n // count the number of equal, darker and brighter adjacent pixels\n if (delta === 0) {\n zeroes++;\n // if found more than 2 equal siblings, it's definitely not anti-aliasing\n if (zeroes > 2) return false;\n\n // remember the darkest pixel\n } else if (delta < min) {\n min = delta;\n minX = x;\n minY = y;\n\n // remember the brightest pixel\n } else if (delta > max) {\n max = delta;\n maxX = x;\n maxY = y;\n }\n }\n }\n\n // if there are no both darker and brighter pixels among siblings, it's not anti-aliasing\n if (min === 0 || max === 0) return false;\n\n // if either the darkest or the brightest pixel has 3+ equal siblings in both images\n // (definitely not anti-aliased), this pixel is anti-aliased\n return (hasManySiblings(a32, minX, minY, width, height) && hasManySiblings(b32, minX, minY, width, height)) ||\n (hasManySiblings(a32, maxX, maxY, width, height) && hasManySiblings(b32, maxX, maxY, width, height));\n}\n\n/**\n * Check if a pixel has 3+ adjacent pixels of the same color.\n * @param {Uint32Array} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n */\nfunction hasManySiblings(img, x1, y1, width, height) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const val = img[y1 * width + x1];\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n zeroes += +(val === img[y * width + x]);\n if (zeroes > 2) return true;\n }\n }\n return false;\n}\n\n/**\n * Calculate color difference according to the paper \"Measuring perceived color difference\n * using YIQ NTSC transmission color space in mobile applications\" by Y. Kotsarenko and F. Ramos.\n * Caller guarantees the two pixels differ, so the early-zero check is omitted.\n * @param {Uint8Array | Uint8ClampedArray} img1\n * @param {Uint8Array | Uint8ClampedArray} img2\n * @param {number} k\n * @param {number} m\n * @param {boolean} checkerboard\n */\nfunction colorDelta(img1, img2, k, m, checkerboard) {\n const r1 = img1[k];\n const g1 = img1[k + 1];\n const b1 = img1[k + 2];\n const a1 = img1[k + 3];\n const r2 = img2[m];\n const g2 = img2[m + 1];\n const b2 = img2[m + 2];\n const a2 = img2[m + 3];\n\n let dr = r1 - r2;\n let dg = g1 - g2;\n let db = b1 - b2;\n const da = a1 - a2;\n\n if (a1 < 255 || a2 < 255) { // blend pixels with background\n let rb = 255, gb = 255, bb = 255;\n if (checkerboard) {\n rb = 48 + 159 * (k % 2);\n gb = 48 + 159 * ((k / 1.618033988749895 | 0) % 2);\n bb = 48 + 159 * ((k / 2.618033988749895 | 0) % 2);\n }\n dr = (r1 * a1 - r2 * a2 - rb * da) / 255;\n dg = (g1 * a1 - g2 * a2 - gb * da) / 255;\n db = (b1 * a1 - b2 * a2 - bb * da) / 255;\n }\n\n const y = dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;\n const i = dr * 0.59597799 - dg * 0.27417610 - db * 0.32180189;\n const q = dr * 0.21147017 - dg * 0.52261711 + db * 0.31114694;\n\n const delta = 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;\n\n // encode whether the pixel lightens or darkens in the sign\n return y > 0 ? -delta : delta;\n}\n\n/**\n * Specialized brightness-only color delta for the anti-aliasing detector,\n * with the center pixel's RGBA hoisted out of the neighbor loop.\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} k center pixel offset\n * @param {number} m neighbor pixel offset\n * @param {number} r1\n * @param {number} g1\n * @param {number} b1\n * @param {number} a1\n * @param {boolean} checkerboard\n */\nfunction brightnessDelta(img, k, m, r1, g1, b1, a1, checkerboard) {\n const r2 = img[m];\n const g2 = img[m + 1];\n const b2 = img[m + 2];\n const a2 = img[m + 3];\n\n let dr = r1 - r2;\n let dg = g1 - g2;\n let db = b1 - b2;\n const da = a1 - a2;\n\n if (!dr && !dg && !db && !da) return 0;\n\n if (a1 < 255 || a2 < 255) {\n let rb = 255, gb = 255, bb = 255;\n if (checkerboard) {\n rb = 48 + 159 * (k % 2);\n gb = 48 + 159 * ((k / 1.618033988749895 | 0) % 2);\n bb = 48 + 159 * ((k / 2.618033988749895 | 0) % 2);\n }\n dr = (r1 * a1 - r2 * a2 - rb * da) / 255;\n dg = (g1 * a1 - g2 * a2 - gb * da) / 255;\n db = (b1 * a1 - b2 * a2 - bb * da) / 255;\n }\n\n return dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} output\n * @param {number} pos\n * @param {number} r\n * @param {number} g\n * @param {number} b\n */\nfunction drawPixel(output, pos, r, g, b) {\n output[pos] = r;\n output[pos + 1] = g;\n output[pos + 2] = b;\n output[pos + 3] = 255;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} i\n * @param {number} alpha\n * @param {Uint8Array | Uint8ClampedArray} output\n */\nfunction drawGrayPixel(img, i, alpha, output) {\n const val = 255 + (img[i] * 0.29889531 + img[i + 1] * 0.58662247 + img[i + 2] * 0.11448223 - 255) * alpha * img[i + 3] / 255;\n drawPixel(output, i, val, val, val);\n}\n","// gestament - TypeScript based test driver for GTK.\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/gestament\n\nimport { createHash } from 'node:crypto';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport pixelmatch from 'pixelmatch';\nimport { PNG } from 'pngjs';\nimport { ssim } from 'ssim.js';\nimport englishLanguageData from '@tesseract.js-data/eng';\n\nimport type { GtkCapture, GtkCaptureBounds, Releasable } from './types';\nexport type { GtkWaitOptions } from './wait';\nexport { toPass, waitForResult } from './wait';\n\n/////////////////////////////////////////////////////////////////////////////////////////\n\n/** Pixel region inside a captured PNG image. */\nexport interface GtkCapturePixelRegion {\n /** Left pixel offset from the capture image origin. */\n readonly x: number;\n\n /** Top pixel offset from the capture image origin. */\n readonly y: number;\n\n /** Region width in pixels. */\n readonly width: number;\n\n /** Region height in pixels. */\n readonly height: number;\n}\n\n/**\n * Expected PNG image source for GTK capture visual assertions.\n * @remarks Strings are interpreted as filesystem paths. URL values must use the file protocol.\n */\nexport type GtkCaptureExpectedImage = Buffer | string | URL;\n\n/** Tesseract page segmentation mode used by GTK capture OCR assertions. */\nexport type GtkCaptureOcrPageSegmentationMode =\n | 'osdOnly'\n | 'autoOsd'\n | 'autoOnly'\n | 'auto'\n | 'singleColumn'\n | 'singleBlockVerticalText'\n | 'singleBlock'\n | 'singleLine'\n | 'singleWord'\n | 'circleWord'\n | 'singleChar'\n | 'sparseText'\n | 'sparseTextOsd'\n | 'rawLine';\n\n/** Worker lifecycle mode used by GTK capture OCR assertions. */\nexport type GtkCaptureOcrWorkerMode = 'perRead' | 'shared';\n\n/** Cache mode passed to Tesseract.js language data loading. */\nexport type GtkCaptureOcrCacheMethod =\n | 'write'\n | 'readOnly'\n | 'refresh'\n | 'none';\n\n/** Defaults shared by GTK capture OCR assertions. */\nexport interface GtkCaptureOcrDefaults {\n /**\n * Tesseract.js worker lifecycle mode.\n * @remarks The default is perRead, which creates and terminates a worker for each OCR read.\n */\n readonly workerMode?: GtkCaptureOcrWorkerMode;\n\n /**\n * OCR language code or language code list.\n * @remarks The default is eng. Multiple languages are joined with + for Tesseract.js.\n */\n readonly languages?: string | readonly string[];\n\n /**\n * Tesseract.js core path.\n * @remarks Omit to use Tesseract.js defaults.\n */\n readonly corePath?: string;\n\n /**\n * Tesseract.js worker script path.\n * @remarks Omit to use Tesseract.js defaults.\n */\n readonly workerPath?: string;\n\n /**\n * Language data path passed to Tesseract.js.\n * @remarks Omit to use bundled English traineddata when languages is eng.\n */\n readonly langPath?: string;\n\n /**\n * Language data cache path passed to Tesseract.js.\n * @remarks Omit to let the selected cacheMethod decide whether Tesseract.js writes a cache file.\n */\n readonly cachePath?: string;\n\n /**\n * Language data cache behavior passed to Tesseract.js.\n * @remarks The default is none when bundled English traineddata is used.\n */\n readonly cacheMethod?: GtkCaptureOcrCacheMethod;\n\n /**\n * Whether language data is gzipped.\n * @remarks The default follows the selected language data source.\n */\n readonly gzip?: boolean;\n}\n\n/** Output settings shared by GTK capture assertions. */\nexport interface GtkCaptureResultOutputOptions {\n /**\n * Output directory used as the base path for actual, expected, diff, and metadata files.\n * @remarks Output files are written only when outputResultPath or GESTAMENT_VISUAL_OUTPUT_RESULT_PATH is specified.\n */\n readonly outputResultPath?: string;\n\n /**\n * Artifact variant, usually a GTK backend or platform name.\n * @remarks This value does not enable artifact output by itself.\n */\n readonly variant?: string;\n}\n\n/** Defaults shared by GTK capture visual and OCR assertions. */\nexport interface GtkCaptureVisualDefaults extends GtkCaptureResultOutputOptions {\n /**\n * Defaults for OCR assertions.\n * @remarks OCR workers are created lazily only when an OCR assertion is used.\n */\n readonly ocr?: GtkCaptureOcrDefaults;\n}\n\n/** Options shared by visual comparison assertions. */\nexport interface GtkCaptureVisualComparisonOptions extends GtkCaptureResultOutputOptions {\n /** Region to compare. Omit to compare the full capture image. */\n readonly region?: GtkCapturePixelRegion;\n\n /** Regions to ignore during comparison. Coordinates use the full capture image. */\n readonly masks?: readonly GtkCapturePixelRegion[];\n}\n\n/** Options for pixel-difference based capture comparison. */\nexport interface GtkCaptureLookSimilarOptions extends GtkCaptureVisualComparisonOptions {\n /** Pixelmatch color threshold from 0 to 1. */\n readonly threshold?: number;\n\n /** Maximum allowed mismatched pixel count. */\n readonly maxDiffPixels?: number;\n\n /** Maximum allowed mismatched pixel ratio from 0 to 1. */\n readonly maxDiffRatio?: number;\n}\n\n/** Options for structural-similarity (SSIM) based capture comparison. */\nexport interface GtkCaptureSimilarityOptions extends GtkCaptureVisualComparisonOptions {\n /** Minimum allowed MSSIM score from 0 to 1. */\n readonly minSimilarity?: number;\n}\n\n/** Image preprocessing options applied before OCR recognition. */\nexport interface GtkCaptureOcrPreprocessOptions {\n /**\n * Nearest-neighbor scale factor applied after cropping.\n * @remarks The default is 1.\n */\n readonly scale?: number;\n\n /**\n * Converts RGB pixels to Rec. 709 luminance before OCR.\n * @remarks Thresholding also uses luminance even when this is false.\n */\n readonly grayscale?: boolean;\n\n /**\n * Converts luminance values to black or white using this threshold from 0 to 255.\n * @remarks Omit to keep continuous color or grayscale values.\n */\n readonly threshold?: number;\n\n /**\n * Inverts RGB values after grayscale or threshold processing.\n * @remarks Alpha values are preserved.\n */\n readonly invert?: boolean;\n}\n\n/** Options for reading text from a GTK capture with OCR. */\nexport interface GtkCaptureOcrOptions extends GtkCaptureResultOutputOptions {\n /** Region to pass to OCR. Omit to read the full capture image. */\n readonly region?: GtkCapturePixelRegion;\n\n /**\n * Tesseract page segmentation modes to try.\n * @remarks The default tries singleBlock, sparseText, singleLine, and singleWord.\n */\n readonly pageSegmentationModes?: readonly GtkCaptureOcrPageSegmentationMode[];\n\n /** Image preprocessing applied before OCR recognition. */\n readonly preprocess?: GtkCaptureOcrPreprocessOptions;\n\n /**\n * Additional Tesseract worker parameters applied before each recognition attempt.\n * @remarks tessedit_pageseg_mode is overwritten for each selected pageSegmentationMode.\n */\n readonly parameters?: Readonly<Record<string, string>>;\n}\n\n/** Options applied when matching OCR text against an expected value. */\nexport interface GtkCaptureOcrTextAssertionOptions {\n /**\n * Whether string expectations are case-sensitive.\n * @remarks The default is false. Regular expressions use their own flags.\n */\n readonly caseSensitive?: boolean;\n\n /**\n * Whether OCR text whitespace is collapsed before matching.\n * @remarks The default is true.\n */\n readonly normalizeWhitespace?: boolean;\n\n /**\n * Minimum confidence required for a matching OCR attempt.\n * @remarks Omit to accept any confidence value returned by Tesseract.js.\n */\n readonly minConfidence?: number;\n}\n\n/** Options for asserting OCR text directly from a GTK capture. */\nexport interface GtkCaptureOcrAssertionOptions\n extends GtkCaptureOcrOptions, GtkCaptureOcrTextAssertionOptions {}\n\n/** Common result fields returned by GTK capture visual assertions. */\nexport interface GtkCaptureVisualResult {\n /** Whether the assertion passed. */\n readonly pass: boolean;\n\n /** Output directory for this assertion call, present when result output is enabled. */\n readonly outputResultPath?: string;\n\n /** Saved actual PNG path, present when result output is enabled. */\n readonly actualImagePath?: string;\n\n /** Saved metadata JSON path, present when result output is enabled. */\n readonly metadataJsonPath?: string;\n\n /** Saved expected PNG path, present when failure output was generated. */\n readonly expectedImagePath?: string;\n\n /** Saved diff PNG path, present when a diff image was generated. */\n readonly diffImagePath?: string;\n}\n\n/** Result returned by pixel-difference based capture comparison. */\nexport interface GtkCaptureLookSimilarResult extends GtkCaptureVisualResult {\n /** Number of mismatched pixels after region and mask processing. */\n readonly diffPixels: number;\n\n /** Mismatched pixel ratio after region and mask processing. */\n readonly diffRatio: number;\n\n /** Number of pixels included in the comparison region. */\n readonly totalPixels: number;\n}\n\n/** Result returned by structural-similarity based capture comparison. */\nexport interface GtkCaptureSimilarityResult extends GtkCaptureVisualResult {\n /** MSSIM score returned by ssim.js. */\n readonly similarity: number;\n\n /** Diagnostic mismatched pixel count generated by pixelmatch. */\n readonly diffPixels: number;\n\n /** Diagnostic mismatched pixel ratio generated by pixelmatch. */\n readonly diffRatio: number;\n\n /** Number of pixels included in the comparison region. */\n readonly totalPixels: number;\n}\n\n/** One OCR recognition attempt for a GTK capture. */\nexport interface GtkCaptureOcrAttempt {\n /** Page segmentation mode used for this attempt. */\n readonly pageSegmentationMode: GtkCaptureOcrPageSegmentationMode;\n\n /** Raw text returned by Tesseract.js. */\n readonly text: string;\n\n /** Whitespace-normalized text returned by Tesseract.js. */\n readonly normalizedText: string;\n\n /** Confidence score returned by Tesseract.js. */\n readonly confidence: number;\n}\n\n/** Result returned by OCR text assertions. */\nexport interface GtkCaptureOcrResult extends GtkCaptureVisualResult {\n /** Raw text selected from the best OCR attempt. */\n readonly text: string;\n\n /** Whitespace-normalized text selected from the best OCR attempt. */\n readonly normalizedText: string;\n\n /** Confidence score from the selected OCR attempt. */\n readonly confidence: number;\n\n /** Page segmentation mode from the selected OCR attempt. */\n readonly pageSegmentationMode: GtkCaptureOcrPageSegmentationMode;\n\n /** All OCR recognition attempts produced for this assertion. */\n readonly attempts: readonly GtkCaptureOcrAttempt[];\n\n /** Expected OCR text matcher as a diagnostic string. */\n readonly expectedText: string;\n\n /** Saved OCR input PNG path, present when result output is enabled. */\n readonly ocrInputImagePath?: string;\n}\n\n/** OCR text read from a GTK capture and reusable for multiple assertions. */\nexport interface GtkCaptureOcrText {\n /** Raw text selected from the best OCR attempt. */\n readonly text: string;\n\n /** Whitespace-normalized text selected from the best OCR attempt. */\n readonly normalizedText: string;\n\n /** Confidence score from the selected OCR attempt. */\n readonly confidence: number;\n\n /** Page segmentation mode from the selected OCR attempt. */\n readonly pageSegmentationMode: GtkCaptureOcrPageSegmentationMode;\n\n /** All OCR recognition attempts produced for this read. */\n readonly attempts: readonly GtkCaptureOcrAttempt[];\n\n /** Output directory for this OCR read, present when result output is enabled. */\n readonly outputResultPath?: string;\n\n /** Saved actual PNG path, present when result output is enabled. */\n readonly actualImagePath?: string;\n\n /** Saved OCR input PNG path, present when result output is enabled. */\n readonly ocrInputImagePath?: string;\n\n /** Saved metadata JSON path, present when result output is enabled. */\n readonly metadataJsonPath?: string;\n\n /**\n * Asserts that this OCR text contains the expected string or matches the expected regular expression.\n * @param expected Expected string or regular expression.\n * @param options Text matching options.\n * @returns OCR assertion result when the assertion passes.\n */\n readonly toContainText: (\n expected: string | RegExp,\n options?: GtkCaptureOcrTextAssertionOptions\n ) => Promise<GtkCaptureOcrResult>;\n}\n\n/** Error thrown by GTK capture visual assertions. */\nexport interface GtkCaptureVisualError<\n Result extends GtkCaptureVisualResult = GtkCaptureVisualResult,\n> extends Error {\n /** Assertion result and artifact paths available at the failure point. */\n readonly result: Result;\n}\n\n/** Assertion object for a single GTK capture image. */\nexport interface GtkCaptureExpectation {\n /**\n * Compares the capture against an expected PNG image with pixel-level tolerance.\n * @param expectedImage Expected PNG image as a buffer, path string, or file URL.\n * @param options Comparison options.\n * @returns Comparison result when the assertion passes.\n */\n readonly toLookSimilar: (\n expectedImage: GtkCaptureExpectedImage,\n options?: GtkCaptureLookSimilarOptions\n ) => Promise<GtkCaptureLookSimilarResult>;\n\n /**\n * Compares the capture against an expected PNG image with structural similarity (SSIM).\n * @param expectedImage Expected PNG image as a buffer, path string, or file URL.\n * @param options Comparison options.\n * @returns Comparison result when the assertion passes.\n */\n readonly toHaveSimilarity: (\n expectedImage: GtkCaptureExpectedImage,\n options?: GtkCaptureSimilarityOptions\n ) => Promise<GtkCaptureSimilarityResult>;\n\n /**\n * Reads text from the capture with OCR and asserts that it contains expected text.\n * @param expected Expected string or regular expression.\n * @param options OCR and text matching options.\n * @returns OCR assertion result when the assertion passes.\n */\n readonly toContainText: (\n expected: string | RegExp,\n options?: GtkCaptureOcrAssertionOptions\n ) => Promise<GtkCaptureOcrResult>;\n\n /**\n * Reads text from the capture with OCR for reusable text assertions.\n * @param options OCR options.\n * @returns OCR text object that can run multiple assertions without recognizing again.\n */\n readonly readText: (\n options?: GtkCaptureOcrOptions\n ) => Promise<GtkCaptureOcrText>;\n}\n\n/** Factory for GTK capture visual assertions. */\nexport interface GtkCaptureExpect extends Releasable {\n /**\n * Creates an assertion object for a captured GTK image.\n * @param capture GTK capture to assert.\n * @param name Artifact name.\n * @returns Assertion object for the capture.\n */\n readonly expectCapture: (\n capture: GtkCapture,\n name: string\n ) => GtkCaptureExpectation;\n}\n\ninterface ResolvedDefaults {\n readonly outputResultPath: string;\n readonly variant: string;\n}\n\ninterface EnabledComparisonContext {\n readonly actualImagePath: string;\n readonly outputResultPath: string;\n readonly artifactsEnabled: true;\n readonly expectedImagePath: string;\n readonly diffImagePath: string;\n readonly metadataJsonPath: string;\n readonly ocrInputImagePath: string;\n readonly resolved: ResolvedDefaults;\n}\n\ninterface DisabledComparisonContext {\n readonly artifactsEnabled: false;\n}\n\ntype ComparisonContext = EnabledComparisonContext | DisabledComparisonContext;\n\ninterface DecodedPng {\n readonly data: Buffer;\n readonly height: number;\n readonly width: number;\n}\n\ninterface LoadedExpectedImage {\n readonly data: Buffer;\n readonly source: 'buffer' | 'path' | 'file-url';\n readonly sourcePath: string | undefined;\n}\n\ninterface PreparedComparison {\n readonly actualData: Uint8Array;\n readonly expectedData: Uint8Array;\n readonly height: number;\n readonly totalPixels: number;\n readonly width: number;\n}\n\ninterface ResolvedLookSimilarOptions {\n readonly maxDiffPixels: number | undefined;\n readonly maxDiffRatio: number;\n readonly threshold: number;\n}\n\ninterface ResolvedSimilarityOptions {\n readonly minSimilarity: number;\n}\n\ninterface ResolvedOcrOptions {\n readonly pageSegmentationModes: readonly GtkCaptureOcrPageSegmentationMode[];\n readonly parameters: Readonly<Record<string, string>>;\n readonly preprocess: Required<GtkCaptureOcrPreprocessOptions>;\n readonly region: GtkCapturePixelRegion;\n}\n\ninterface PreparedOcrImage {\n readonly image: Buffer;\n readonly preprocess: Required<GtkCaptureOcrPreprocessOptions>;\n readonly region: GtkCapturePixelRegion;\n}\n\ninterface LoadedTesseractModule {\n readonly createWorker: (\n languages?: string | readonly string[],\n oem?: number,\n options?: Partial<TesseractWorkerOptions>\n ) => Promise<TesseractWorker>;\n}\n\ninterface TesseractWorkerOptions {\n cacheMethod: string;\n cachePath: string;\n corePath: string;\n gzip: boolean;\n langPath: string;\n logger: (message: unknown) => void;\n workerPath: string;\n}\n\ninterface TesseractWorker {\n readonly recognize: (image: Buffer) => Promise<{\n readonly data: {\n readonly confidence: number;\n readonly text: string;\n };\n }>;\n readonly setParameters: (\n parameters: Readonly<Record<string, string>>\n ) => Promise<unknown>;\n readonly terminate: () => Promise<unknown>;\n}\n\ninterface OcrWorkerController {\n readonly recognize: (\n preparedImage: PreparedOcrImage,\n options: ResolvedOcrOptions\n ) => Promise<readonly GtkCaptureOcrAttempt[]>;\n readonly release: () => Promise<void>;\n}\n\ninterface OcrTextData {\n readonly actualImagePath: string | undefined;\n readonly attempts: readonly GtkCaptureOcrAttempt[];\n readonly confidence: number;\n readonly metadataJsonPath: string | undefined;\n readonly normalizedText: string;\n readonly ocrInputImagePath: string | undefined;\n readonly outputResultPath: string | undefined;\n readonly pageSegmentationMode: GtkCaptureOcrPageSegmentationMode;\n readonly text: string;\n}\n\nconst padNumber = (value: number, width: number): string =>\n value.toString().padStart(width, '0');\n\nconst hashText = (value: string): string =>\n createHash('sha256').update(value).digest('hex').slice(0, 10);\n\nconst defaultOcrPageSegmentationModes = [\n 'singleBlock',\n 'sparseText',\n 'singleLine',\n 'singleWord',\n] as const satisfies readonly GtkCaptureOcrPageSegmentationMode[];\n\nconst pageSegmentationModeValues: Record<\n GtkCaptureOcrPageSegmentationMode,\n string\n> = {\n auto: '3',\n autoOnly: '2',\n autoOsd: '1',\n circleWord: '9',\n osdOnly: '0',\n rawLine: '13',\n singleBlock: '6',\n singleBlockVerticalText: '5',\n singleChar: '10',\n singleColumn: '4',\n singleLine: '7',\n singleWord: '8',\n sparseText: '11',\n sparseTextOsd: '12',\n};\n\nlet tesseractModulePromise: Promise<LoadedTesseractModule> | undefined;\n\nconst loadTesseractModule = async (): Promise<LoadedTesseractModule> => {\n tesseractModulePromise ??= import('tesseract.js').then((loaded) => {\n const module = loaded as unknown as\n | LoadedTesseractModule\n | { readonly default: LoadedTesseractModule };\n return 'default' in module ? module.default : module;\n });\n return tesseractModulePromise;\n};\n\nconst normalizePathSegment = (value: string, fallback: string): string => {\n const trimmed = value.trim();\n const normalized = trimmed\n .replace(/[\\x00-\\x1f<>:\"/\\\\|?*]+/g, '_')\n .replace(/\\s+/g, '_')\n .replace(/_+/g, '_')\n .replace(/^_+|_+$/g, '');\n if (normalized.length === 0) {\n return fallback;\n }\n if (normalized.length <= 140) {\n return normalized;\n }\n return `${normalized.slice(0, 129)}-${hashText(normalized)}`;\n};\n\nconst serializeBounds = (\n bounds: GtkCaptureBounds\n): Record<keyof GtkCaptureBounds, number> => ({\n height: bounds.height,\n width: bounds.width,\n x: bounds.x,\n y: bounds.y,\n});\n\nconst resolveDefaults = (\n defaults: GtkCaptureVisualDefaults,\n options: GtkCaptureResultOutputOptions | undefined\n): ResolvedDefaults | undefined => {\n const outputResultPath =\n options?.outputResultPath ??\n defaults.outputResultPath ??\n process.env.GESTAMENT_VISUAL_OUTPUT_RESULT_PATH;\n if (outputResultPath === undefined) {\n return undefined;\n }\n\n return {\n outputResultPath: resolve(outputResultPath),\n variant:\n options?.variant ??\n defaults.variant ??\n process.env.GESTAMENT_VISUAL_VARIANT ??\n process.env.GESTAMENT_TEST_BACKEND ??\n 'default',\n };\n};\n\nconst loadExpectedImage = async (\n expectedImage: GtkCaptureExpectedImage\n): Promise<LoadedExpectedImage> => {\n if (Buffer.isBuffer(expectedImage)) {\n return {\n data: expectedImage,\n source: 'buffer',\n sourcePath: undefined,\n };\n }\n\n if (typeof expectedImage === 'string') {\n const sourcePath = resolve(expectedImage);\n return {\n data: await readFile(sourcePath),\n source: 'path',\n sourcePath,\n };\n }\n\n if (expectedImage.protocol !== 'file:') {\n throw new TypeError('expectedImage URL must use the file: protocol.');\n }\n\n const sourcePath = fileURLToPath(expectedImage);\n return {\n data: await readFile(sourcePath),\n source: 'file-url',\n sourcePath,\n };\n};\n\nconst decodePng = (image: Buffer): DecodedPng => {\n const png = PNG.sync.read(image);\n return {\n data: png.data,\n height: png.height,\n width: png.width,\n };\n};\n\nconst validateCaptureImage = (capture: GtkCapture, png: DecodedPng): void => {\n if (\n png.width !== capture.visibleBounds.width ||\n png.height !== capture.visibleBounds.height\n ) {\n throw new Error(\n `Capture PNG size ${png.width}x${png.height} does not match visible bounds ${capture.visibleBounds.width}x${capture.visibleBounds.height}.`\n );\n }\n};\n\nconst validateFiniteInteger = (value: number, label: string): void => {\n if (!Number.isInteger(value)) {\n throw new TypeError(`${label} must be an integer.`);\n }\n};\n\nconst validateRegion = (\n region: GtkCapturePixelRegion,\n imageWidth: number,\n imageHeight: number,\n label: string\n): void => {\n validateFiniteInteger(region.x, `${label}.x`);\n validateFiniteInteger(region.y, `${label}.y`);\n validateFiniteInteger(region.width, `${label}.width`);\n validateFiniteInteger(region.height, `${label}.height`);\n if (region.x < 0 || region.y < 0) {\n throw new TypeError(`${label} origin must be inside the capture image.`);\n }\n if (region.width <= 0 || region.height <= 0) {\n throw new TypeError(`${label} size must be positive.`);\n }\n if (\n region.x + region.width > imageWidth ||\n region.y + region.height > imageHeight\n ) {\n throw new TypeError(`${label} must be inside the capture image.`);\n }\n};\n\nconst validateRatio = (value: number, label: string): void => {\n if (!Number.isFinite(value) || value < 0 || value > 1) {\n throw new TypeError(`${label} must be a number from 0 to 1.`);\n }\n};\n\nconst validateNonNegativeInteger = (value: number, label: string): void => {\n if (!Number.isInteger(value) || value < 0) {\n throw new TypeError(`${label} must be a non-negative integer.`);\n }\n};\n\nconst getComparisonRegion = (\n options: GtkCaptureVisualComparisonOptions | undefined,\n imageWidth: number,\n imageHeight: number\n): GtkCapturePixelRegion => {\n const region =\n options?.region ??\n ({ height: imageHeight, width: imageWidth, x: 0, y: 0 } as const);\n validateRegion(region, imageWidth, imageHeight, 'region');\n return region;\n};\n\nconst validateMasks = (\n masks: readonly GtkCapturePixelRegion[] | undefined,\n imageWidth: number,\n imageHeight: number\n): void => {\n if (masks === undefined) {\n return;\n }\n for (const [index, mask] of masks.entries()) {\n validateRegion(mask, imageWidth, imageHeight, `masks[${index}]`);\n }\n};\n\nconst copyRegionData = (\n source: DecodedPng,\n region: GtkCapturePixelRegion\n): Uint8Array => {\n const data = new Uint8Array(region.width * region.height * 4);\n for (let y = 0; y < region.height; y += 1) {\n const sourceStart = ((region.y + y) * source.width + region.x) * 4;\n const sourceEnd = sourceStart + region.width * 4;\n const targetStart = y * region.width * 4;\n data.set(source.data.subarray(sourceStart, sourceEnd), targetStart);\n }\n return data;\n};\n\nconst applyMasks = (\n actualData: Uint8Array,\n expectedData: Uint8Array,\n region: GtkCapturePixelRegion,\n masks: readonly GtkCapturePixelRegion[] | undefined\n): void => {\n if (masks === undefined) {\n return;\n }\n for (const mask of masks) {\n const left = Math.max(region.x, mask.x);\n const top = Math.max(region.y, mask.y);\n const right = Math.min(region.x + region.width, mask.x + mask.width);\n const bottom = Math.min(region.y + region.height, mask.y + mask.height);\n if (left >= right || top >= bottom) {\n continue;\n }\n for (let y = top; y < bottom; y += 1) {\n for (let x = left; x < right; x += 1) {\n const index = ((y - region.y) * region.width + (x - region.x)) * 4;\n actualData[index] = 0;\n actualData[index + 1] = 0;\n actualData[index + 2] = 0;\n actualData[index + 3] = 0;\n expectedData[index] = 0;\n expectedData[index + 1] = 0;\n expectedData[index + 2] = 0;\n expectedData[index + 3] = 0;\n }\n }\n }\n};\n\nconst prepareComparison = (\n actualPng: DecodedPng,\n expectedPng: DecodedPng,\n options: GtkCaptureVisualComparisonOptions | undefined\n): PreparedComparison => {\n if (\n actualPng.width !== expectedPng.width ||\n actualPng.height !== expectedPng.height\n ) {\n throw new Error(\n `Expected image size ${expectedPng.width}x${expectedPng.height} does not match actual capture size ${actualPng.width}x${actualPng.height}.`\n );\n }\n\n const region = getComparisonRegion(\n options,\n actualPng.width,\n actualPng.height\n );\n validateMasks(options?.masks, actualPng.width, actualPng.height);\n\n const actualData = copyRegionData(actualPng, region);\n const expectedData = copyRegionData(expectedPng, region);\n applyMasks(actualData, expectedData, region, options?.masks);\n\n return {\n actualData,\n expectedData,\n height: region.height,\n totalPixels: region.width * region.height,\n width: region.width,\n };\n};\n\nconst createDiffPng = (\n comparison: PreparedComparison,\n threshold: number\n): {\n readonly diffPixels: number;\n readonly diffPng: PNG;\n} => {\n const diffPng = new PNG({\n height: comparison.height,\n width: comparison.width,\n });\n const diffPixels = pixelmatch(\n comparison.expectedData,\n comparison.actualData,\n diffPng.data,\n comparison.width,\n comparison.height,\n { threshold }\n );\n return {\n diffPixels,\n diffPng,\n };\n};\n\nconst createContext = async (\n defaults: GtkCaptureVisualDefaults,\n options: GtkCaptureResultOutputOptions | undefined,\n name: string,\n counter: number\n): Promise<ComparisonContext> => {\n const resolved = resolveDefaults(defaults, options);\n if (resolved === undefined) {\n return {\n artifactsEnabled: false,\n };\n }\n\n const safeVariant = normalizePathSegment(resolved.variant, 'default');\n const safeName = normalizePathSegment(name, 'capture');\n const outputResultPath = join(\n resolved.outputResultPath,\n safeVariant,\n `${safeName}-${padNumber(counter, 6)}`\n );\n await mkdir(outputResultPath, { recursive: true });\n return {\n actualImagePath: join(outputResultPath, 'actual.png'),\n outputResultPath,\n artifactsEnabled: true,\n diffImagePath: join(outputResultPath, 'diff.png'),\n expectedImagePath: join(outputResultPath, 'expected.png'),\n metadataJsonPath: join(outputResultPath, 'metadata.json'),\n ocrInputImagePath: join(outputResultPath, 'ocr-input.png'),\n resolved,\n };\n};\n\nconst writeMetadata = async (\n context: EnabledComparisonContext,\n capture: GtkCapture,\n name: string,\n matcher: string,\n options: GtkCaptureVisualComparisonOptions | undefined,\n expectedImage: LoadedExpectedImage\n): Promise<void> => {\n await writeFile(\n context.metadataJsonPath,\n `${JSON.stringify(\n {\n bounds: serializeBounds(capture.bounds),\n clipped: capture.clipped,\n expectedImageSource: expectedImage.source,\n expectedImageSourcePath: expectedImage.sourcePath,\n imageBytes: capture.image.length,\n matcher,\n masks: options?.masks,\n name,\n region: options?.region,\n variant: context.resolved.variant,\n visibleBounds: serializeBounds(capture.visibleBounds),\n },\n undefined,\n 2\n )}\\n`\n );\n};\n\nconst createVisualError = <Result extends GtkCaptureVisualResult>(\n message: string,\n result: Result\n): GtkCaptureVisualError<Result> =>\n Object.assign(new Error(message), {\n result,\n });\n\nconst saveActualAndMetadata = async (\n context: ComparisonContext,\n capture: GtkCapture,\n name: string,\n matcher: string,\n options: GtkCaptureVisualComparisonOptions | undefined,\n expectedImage: LoadedExpectedImage\n): Promise<void> => {\n if (!context.artifactsEnabled) {\n return;\n }\n\n await writeFile(context.actualImagePath, capture.image);\n await writeMetadata(context, capture, name, matcher, options, expectedImage);\n};\n\nconst buildBaseResult = (\n context: ComparisonContext\n): GtkCaptureVisualResult => {\n if (!context.artifactsEnabled) {\n return {\n pass: true,\n };\n }\n\n return {\n actualImagePath: context.actualImagePath,\n outputResultPath: context.outputResultPath,\n metadataJsonPath: context.metadataJsonPath,\n pass: true,\n };\n};\n\nconst writeFailureArtifacts = async (\n context: ComparisonContext,\n expectedImage: Buffer,\n diffPng: PNG\n): Promise<\n Pick<GtkCaptureVisualResult, 'diffImagePath' | 'expectedImagePath'>\n> => {\n if (!context.artifactsEnabled) {\n return {};\n }\n\n await writeFile(context.expectedImagePath, expectedImage);\n await writeFile(context.diffImagePath, PNG.sync.write(diffPng));\n return {\n diffImagePath: context.diffImagePath,\n expectedImagePath: context.expectedImagePath,\n };\n};\n\nconst isLookSimilarPass = (\n diffPixels: number,\n diffRatio: number,\n options: ResolvedLookSimilarOptions\n): boolean => {\n const ratioPass = diffRatio <= options.maxDiffRatio;\n const pixelsPass =\n options.maxDiffPixels === undefined || diffPixels <= options.maxDiffPixels;\n return ratioPass && pixelsPass;\n};\n\nconst resolveLookSimilarOptions = (\n options: GtkCaptureLookSimilarOptions | undefined\n): ResolvedLookSimilarOptions => {\n const resolved = {\n maxDiffPixels: options?.maxDiffPixels,\n maxDiffRatio: options?.maxDiffRatio ?? 0.01,\n threshold: options?.threshold ?? 0.1,\n };\n validateRatio(resolved.threshold, 'threshold');\n validateRatio(resolved.maxDiffRatio, 'maxDiffRatio');\n if (resolved.maxDiffPixels !== undefined) {\n validateNonNegativeInteger(resolved.maxDiffPixels, 'maxDiffPixels');\n }\n return resolved;\n};\n\nconst resolveSimilarityOptions = (\n options: GtkCaptureSimilarityOptions | undefined\n): ResolvedSimilarityOptions => {\n const resolved = {\n minSimilarity: options?.minSimilarity ?? 0.985,\n };\n validateRatio(resolved.minSimilarity, 'minSimilarity');\n return resolved;\n};\n\nconst validateOcrPageSegmentationMode = (\n value: GtkCaptureOcrPageSegmentationMode,\n label: string\n): void => {\n if (!(value in pageSegmentationModeValues)) {\n throw new TypeError(\n `${label} must be a supported OCR page segmentation mode.`\n );\n }\n};\n\nconst validateThreshold = (value: number, label: string): void => {\n if (!Number.isInteger(value) || value < 0 || value > 255) {\n throw new TypeError(`${label} must be an integer from 0 to 255.`);\n }\n};\n\nconst validatePositiveInteger = (value: number, label: string): void => {\n if (!Number.isInteger(value) || value <= 0) {\n throw new TypeError(`${label} must be a positive integer.`);\n }\n};\n\nconst normalizeWhitespace = (value: string): string =>\n value.replace(/\\s+/g, ' ').trim();\n\nconst resolveOcrPreprocessOptions = (\n options: GtkCaptureOcrPreprocessOptions | undefined\n): Required<GtkCaptureOcrPreprocessOptions> => {\n const resolved = {\n grayscale: options?.grayscale ?? false,\n invert: options?.invert ?? false,\n scale: options?.scale ?? 1,\n threshold: options?.threshold ?? -1,\n };\n validatePositiveInteger(resolved.scale, 'preprocess.scale');\n if (resolved.threshold !== -1) {\n validateThreshold(resolved.threshold, 'preprocess.threshold');\n }\n return resolved;\n};\n\nconst resolveOcrOptions = (\n options: GtkCaptureOcrOptions | undefined,\n imageWidth: number,\n imageHeight: number\n): ResolvedOcrOptions => {\n const pageSegmentationModes =\n options?.pageSegmentationModes ?? defaultOcrPageSegmentationModes;\n if (pageSegmentationModes.length === 0) {\n throw new TypeError('pageSegmentationModes must not be empty.');\n }\n for (const [index, mode] of pageSegmentationModes.entries()) {\n validateOcrPageSegmentationMode(mode, `pageSegmentationModes[${index}]`);\n }\n const region =\n options?.region ??\n ({ height: imageHeight, width: imageWidth, x: 0, y: 0 } as const);\n validateRegion(region, imageWidth, imageHeight, 'region');\n return {\n pageSegmentationModes,\n parameters: options?.parameters ?? {},\n preprocess: resolveOcrPreprocessOptions(options?.preprocess),\n region,\n };\n};\n\nconst hasOcrPreprocessing = (\n options: Required<GtkCaptureOcrPreprocessOptions>,\n region: GtkCapturePixelRegion,\n imageWidth: number,\n imageHeight: number\n): boolean =>\n options.grayscale ||\n options.invert ||\n options.scale !== 1 ||\n options.threshold !== -1 ||\n region.x !== 0 ||\n region.y !== 0 ||\n region.width !== imageWidth ||\n region.height !== imageHeight;\n\nconst getLuminance = (red: number, green: number, blue: number): number =>\n Math.round(red * 0.2126 + green * 0.7152 + blue * 0.0722);\n\nconst prepareOcrImage = (\n originalImage: Buffer,\n png: DecodedPng,\n options: ResolvedOcrOptions\n): PreparedOcrImage => {\n if (\n !hasOcrPreprocessing(\n options.preprocess,\n options.region,\n png.width,\n png.height\n )\n ) {\n return {\n image: originalImage,\n preprocess: options.preprocess,\n region: options.region,\n };\n }\n\n const output = new PNG({\n height: options.region.height * options.preprocess.scale,\n width: options.region.width * options.preprocess.scale,\n });\n for (let y = 0; y < output.height; y += 1) {\n for (let x = 0; x < output.width; x += 1) {\n const sourceX =\n options.region.x + Math.floor(x / options.preprocess.scale);\n const sourceY =\n options.region.y + Math.floor(y / options.preprocess.scale);\n const sourceIndex = (sourceY * png.width + sourceX) * 4;\n const targetIndex = (y * output.width + x) * 4;\n const red = png.data[sourceIndex]!;\n const green = png.data[sourceIndex + 1]!;\n const blue = png.data[sourceIndex + 2]!;\n const alpha = png.data[sourceIndex + 3]!;\n const luminance = getLuminance(red, green, blue);\n const thresholded =\n options.preprocess.threshold === -1\n ? luminance\n : luminance >= options.preprocess.threshold\n ? 255\n : 0;\n const value =\n options.preprocess.grayscale || options.preprocess.threshold !== -1\n ? thresholded\n : undefined;\n output.data[targetIndex] = options.preprocess.invert\n ? 255 - (value ?? red)\n : (value ?? red);\n output.data[targetIndex + 1] = options.preprocess.invert\n ? 255 - (value ?? green)\n : (value ?? green);\n output.data[targetIndex + 2] = options.preprocess.invert\n ? 255 - (value ?? blue)\n : (value ?? blue);\n output.data[targetIndex + 3] = alpha;\n }\n }\n\n return {\n image: PNG.sync.write(output),\n preprocess: options.preprocess,\n region: options.region,\n };\n};\n\nconst isEnglishOnlyLanguage = (\n languages: string | readonly string[] | undefined\n): boolean => {\n if (languages === undefined) {\n return true;\n }\n if (typeof languages === 'string') {\n return languages === 'eng';\n }\n return languages.length === 1 && languages[0] === 'eng';\n};\n\nconst resolveOcrWorkerOptions = (\n defaults: GtkCaptureOcrDefaults | undefined\n): {\n readonly languages: string | readonly string[];\n readonly options: Partial<TesseractWorkerOptions>;\n} => {\n const languages =\n defaults?.languages === undefined\n ? englishLanguageData.code\n : typeof defaults.languages === 'string'\n ? defaults.languages\n : [...defaults.languages];\n const useBundledEnglishData =\n defaults?.langPath === undefined && isEnglishOnlyLanguage(languages);\n const workerOptions: Partial<TesseractWorkerOptions> = {\n logger: () => undefined,\n };\n if (defaults?.cachePath !== undefined) {\n workerOptions.cachePath = defaults.cachePath;\n }\n if (defaults?.corePath !== undefined) {\n workerOptions.corePath = defaults.corePath;\n }\n if (defaults?.workerPath !== undefined) {\n workerOptions.workerPath = defaults.workerPath;\n }\n if (defaults?.langPath !== undefined) {\n workerOptions.langPath = defaults.langPath;\n } else if (useBundledEnglishData) {\n workerOptions.langPath = englishLanguageData.langPath;\n }\n if (defaults?.gzip !== undefined) {\n workerOptions.gzip = defaults.gzip;\n } else if (useBundledEnglishData) {\n workerOptions.gzip = englishLanguageData.gzip;\n }\n if (defaults?.cacheMethod !== undefined) {\n workerOptions.cacheMethod = defaults.cacheMethod;\n } else if (useBundledEnglishData) {\n workerOptions.cacheMethod = 'none';\n }\n return {\n languages,\n options: workerOptions,\n };\n};\n\nconst createOcrWorker = async (\n defaults: GtkCaptureOcrDefaults | undefined\n): Promise<TesseractWorker> => {\n const tesseract = await loadTesseractModule();\n const resolved = resolveOcrWorkerOptions(defaults);\n return await tesseract.createWorker(\n resolved.languages,\n undefined,\n resolved.options\n );\n};\n\nconst recognizeWithWorker = async (\n worker: TesseractWorker,\n preparedImage: PreparedOcrImage,\n options: ResolvedOcrOptions\n): Promise<readonly GtkCaptureOcrAttempt[]> => {\n const attempts: GtkCaptureOcrAttempt[] = [];\n for (const pageSegmentationMode of options.pageSegmentationModes) {\n await worker.setParameters({\n ...options.parameters,\n tessedit_pageseg_mode: pageSegmentationModeValues[pageSegmentationMode],\n });\n const recognized = await worker.recognize(preparedImage.image);\n attempts.push({\n confidence: Number.isFinite(recognized.data.confidence)\n ? recognized.data.confidence\n : 0,\n normalizedText: normalizeWhitespace(recognized.data.text),\n pageSegmentationMode,\n text: recognized.data.text,\n });\n }\n return attempts;\n};\n\nconst createOcrWorkerController = (\n defaults: GtkCaptureOcrDefaults | undefined\n): OcrWorkerController => {\n if (defaults?.workerMode !== 'shared') {\n return {\n recognize: async (\n preparedImage: PreparedOcrImage,\n options: ResolvedOcrOptions\n ): Promise<readonly GtkCaptureOcrAttempt[]> => {\n const worker = await createOcrWorker(defaults);\n try {\n return await recognizeWithWorker(worker, preparedImage, options);\n } finally {\n await worker.terminate();\n }\n },\n release: async (): Promise<void> => undefined,\n };\n }\n\n let workerPromise: Promise<TesseractWorker> | undefined;\n let queue: Promise<void> = Promise.resolve();\n const getWorker = (): Promise<TesseractWorker> => {\n workerPromise ??= createOcrWorker(defaults);\n return workerPromise;\n };\n const enqueue = async <T>(operation: () => Promise<T>): Promise<T> => {\n const previous = queue;\n let resolveNext: () => void = () => undefined;\n queue = new Promise<void>((resolve) => {\n resolveNext = resolve;\n });\n await previous;\n try {\n return await operation();\n } finally {\n resolveNext();\n }\n };\n\n return {\n recognize: async (\n preparedImage: PreparedOcrImage,\n options: ResolvedOcrOptions\n ): Promise<readonly GtkCaptureOcrAttempt[]> =>\n await enqueue(async () =>\n recognizeWithWorker(await getWorker(), preparedImage, options)\n ),\n release: async (): Promise<void> => {\n await queue;\n if (workerPromise === undefined) {\n return;\n }\n const worker = await workerPromise;\n workerPromise = undefined;\n await worker.terminate();\n },\n };\n};\n\nconst validateConfidence = (value: number, label: string): void => {\n if (!Number.isFinite(value) || value < 0 || value > 100) {\n throw new TypeError(`${label} must be a number from 0 to 100.`);\n }\n};\n\nconst formatExpectedText = (expected: string | RegExp): string =>\n typeof expected === 'string' ? expected : expected.toString();\n\nconst serializeExpectedText = (\n expected: string | RegExp | undefined\n):\n | {\n readonly type: 'string';\n readonly value: string;\n }\n | {\n readonly flags: string;\n readonly source: string;\n readonly type: 'regexp';\n }\n | undefined => {\n if (expected === undefined) {\n return undefined;\n }\n if (typeof expected === 'string') {\n return {\n type: 'string',\n value: expected,\n };\n }\n return {\n flags: expected.flags,\n source: expected.source,\n type: 'regexp',\n };\n};\n\nconst selectBestOcrAttempt = (\n attempts: readonly GtkCaptureOcrAttempt[]\n): GtkCaptureOcrAttempt => {\n const [firstAttempt] = attempts;\n if (firstAttempt === undefined) {\n throw new Error('OCR did not return any recognition attempts.');\n }\n return attempts.reduce((best, current) =>\n current.confidence > best.confidence ? current : best\n );\n};\n\nconst createOcrTextData = (\n context: ComparisonContext,\n attempts: readonly GtkCaptureOcrAttempt[]\n): OcrTextData => {\n const bestAttempt = selectBestOcrAttempt(attempts);\n if (!context.artifactsEnabled) {\n return {\n actualImagePath: undefined,\n attempts,\n confidence: bestAttempt.confidence,\n metadataJsonPath: undefined,\n normalizedText: bestAttempt.normalizedText,\n ocrInputImagePath: undefined,\n outputResultPath: undefined,\n pageSegmentationMode: bestAttempt.pageSegmentationMode,\n text: bestAttempt.text,\n };\n }\n return {\n actualImagePath: context.actualImagePath,\n attempts,\n confidence: bestAttempt.confidence,\n metadataJsonPath: context.metadataJsonPath,\n normalizedText: bestAttempt.normalizedText,\n ocrInputImagePath: context.ocrInputImagePath,\n outputResultPath: context.outputResultPath,\n pageSegmentationMode: bestAttempt.pageSegmentationMode,\n text: bestAttempt.text,\n };\n};\n\nconst writeOcrMetadata = async (\n context: EnabledComparisonContext,\n capture: GtkCapture,\n name: string,\n matcher: string,\n options: GtkCaptureOcrOptions | undefined,\n preparedImage: PreparedOcrImage,\n attempts: readonly GtkCaptureOcrAttempt[],\n expected: string | RegExp | undefined\n): Promise<void> => {\n await writeFile(\n context.metadataJsonPath,\n `${JSON.stringify(\n {\n attempts,\n bounds: serializeBounds(capture.bounds),\n clipped: capture.clipped,\n expectedText: serializeExpectedText(expected),\n imageBytes: capture.image.length,\n matcher,\n name,\n ocrInputBytes: preparedImage.image.length,\n pageSegmentationModes: options?.pageSegmentationModes,\n parameters: options?.parameters,\n preprocess: preparedImage.preprocess,\n region: preparedImage.region,\n variant: context.resolved.variant,\n visibleBounds: serializeBounds(capture.visibleBounds),\n },\n undefined,\n 2\n )}\\n`\n );\n};\n\nconst saveOcrArtifactsAndMetadata = async (\n context: ComparisonContext,\n capture: GtkCapture,\n name: string,\n matcher: string,\n options: GtkCaptureOcrOptions | undefined,\n preparedImage: PreparedOcrImage,\n attempts: readonly GtkCaptureOcrAttempt[],\n expected: string | RegExp | undefined\n): Promise<void> => {\n if (!context.artifactsEnabled) {\n return;\n }\n\n await writeFile(context.actualImagePath, capture.image);\n await writeFile(context.ocrInputImagePath, preparedImage.image);\n await writeOcrMetadata(\n context,\n capture,\n name,\n matcher,\n options,\n preparedImage,\n attempts,\n expected\n );\n};\n\nconst matchOcrAttempt = (\n attempt: GtkCaptureOcrAttempt,\n expected: string | RegExp,\n options: GtkCaptureOcrTextAssertionOptions | undefined\n): boolean => {\n const normalize = options?.normalizeWhitespace ?? true;\n const candidate = normalize ? attempt.normalizedText : attempt.text;\n const minConfidence = options?.minConfidence;\n if (minConfidence !== undefined) {\n validateConfidence(minConfidence, 'minConfidence');\n if (attempt.confidence < minConfidence) {\n return false;\n }\n }\n\n if (typeof expected === 'string') {\n if (expected.length === 0) {\n throw new TypeError('expected text must not be empty.');\n }\n const expectedText = normalize ? normalizeWhitespace(expected) : expected;\n if (expectedText.length === 0) {\n throw new TypeError(\n 'expected text must not be empty after normalization.'\n );\n }\n if (options?.caseSensitive ?? false) {\n return candidate.includes(expectedText);\n }\n return candidate\n .toLocaleLowerCase()\n .includes(expectedText.toLocaleLowerCase());\n }\n\n expected.lastIndex = 0;\n const matched = expected.test(candidate);\n expected.lastIndex = 0;\n return matched;\n};\n\nconst createOcrResult = (\n data: OcrTextData,\n expected: string | RegExp,\n pass: boolean,\n selectedAttempt: GtkCaptureOcrAttempt\n): GtkCaptureOcrResult => {\n const artifactPaths =\n data.outputResultPath === undefined\n ? {}\n : {\n actualImagePath: data.actualImagePath!,\n metadataJsonPath: data.metadataJsonPath!,\n ocrInputImagePath: data.ocrInputImagePath!,\n outputResultPath: data.outputResultPath,\n };\n return {\n ...artifactPaths,\n attempts: data.attempts,\n confidence: selectedAttempt.confidence,\n expectedText: formatExpectedText(expected),\n normalizedText: selectedAttempt.normalizedText,\n pageSegmentationMode: selectedAttempt.pageSegmentationMode,\n pass,\n text: selectedAttempt.text,\n };\n};\n\nconst assertOcrText = async (\n data: OcrTextData,\n expected: string | RegExp,\n options: GtkCaptureOcrTextAssertionOptions | undefined\n): Promise<GtkCaptureOcrResult> => {\n const matchedAttempt = data.attempts.find((attempt) =>\n matchOcrAttempt(attempt, expected, options)\n );\n if (matchedAttempt !== undefined) {\n return createOcrResult(data, expected, true, matchedAttempt);\n }\n\n const bestAttempt = selectBestOcrAttempt(data.attempts);\n const failedResult = createOcrResult(data, expected, false, bestAttempt);\n throw createVisualError(\n `Capture OCR text did not contain ${formatExpectedText(\n expected\n )}. Recognized text: ${JSON.stringify(bestAttempt.normalizedText)}.`,\n failedResult\n );\n};\n\nconst createOcrText = (data: OcrTextData): GtkCaptureOcrText => {\n const artifactPaths =\n data.outputResultPath === undefined\n ? {}\n : {\n actualImagePath: data.actualImagePath!,\n metadataJsonPath: data.metadataJsonPath!,\n ocrInputImagePath: data.ocrInputImagePath!,\n outputResultPath: data.outputResultPath,\n };\n return {\n ...artifactPaths,\n attempts: data.attempts,\n confidence: data.confidence,\n normalizedText: data.normalizedText,\n pageSegmentationMode: data.pageSegmentationMode,\n text: data.text,\n toContainText: async (\n expected: string | RegExp,\n options?: GtkCaptureOcrTextAssertionOptions\n ): Promise<GtkCaptureOcrResult> =>\n await assertOcrText(data, expected, options),\n };\n};\n\nconst readCaptureText = async (\n defaults: GtkCaptureVisualDefaults,\n nextCounter: () => number,\n workerController: OcrWorkerController,\n capture: GtkCapture,\n name: string,\n matcher: string,\n options: GtkCaptureOcrOptions | undefined,\n expected: string | RegExp | undefined\n): Promise<GtkCaptureOcrText> => {\n const context = await createContext(defaults, options, name, nextCounter());\n const actualPng = decodePng(capture.image);\n validateCaptureImage(capture, actualPng);\n const ocrOptions = resolveOcrOptions(\n options,\n actualPng.width,\n actualPng.height\n );\n const preparedImage = prepareOcrImage(capture.image, actualPng, ocrOptions);\n const attempts = await workerController.recognize(preparedImage, ocrOptions);\n await saveOcrArtifactsAndMetadata(\n context,\n capture,\n name,\n matcher,\n options,\n preparedImage,\n attempts,\n expected\n );\n return createOcrText(createOcrTextData(context, attempts));\n};\n\nconst createLookSimilarAssertion = (\n defaults: GtkCaptureVisualDefaults,\n nextCounter: () => number,\n capture: GtkCapture,\n name: string\n): ((\n expectedImage: GtkCaptureExpectedImage,\n options?: GtkCaptureLookSimilarOptions\n) => Promise<GtkCaptureLookSimilarResult>) => {\n const toLookSimilar = async (\n expectedImage: GtkCaptureExpectedImage,\n options?: GtkCaptureLookSimilarOptions\n ): Promise<GtkCaptureLookSimilarResult> => {\n const context = await createContext(defaults, options, name, nextCounter());\n const actualPng = decodePng(capture.image);\n validateCaptureImage(capture, actualPng);\n const loadedExpectedImage = await loadExpectedImage(expectedImage);\n const expectedPng = decodePng(loadedExpectedImage.data);\n await saveActualAndMetadata(\n context,\n capture,\n name,\n 'toLookSimilar',\n options,\n loadedExpectedImage\n );\n\n const comparisonOptions = resolveLookSimilarOptions(options);\n const comparison = prepareComparison(actualPng, expectedPng, options);\n const { diffPixels, diffPng } = createDiffPng(\n comparison,\n comparisonOptions.threshold\n );\n const diffRatio = diffPixels / comparison.totalPixels;\n const result: GtkCaptureLookSimilarResult = {\n ...buildBaseResult(context),\n diffPixels,\n diffRatio,\n totalPixels: comparison.totalPixels,\n };\n\n if (isLookSimilarPass(diffPixels, diffRatio, comparisonOptions)) {\n return result;\n }\n\n const failureArtifacts = await writeFailureArtifacts(\n context,\n loadedExpectedImage.data,\n diffPng\n );\n const failedResult: GtkCaptureLookSimilarResult = {\n ...result,\n ...failureArtifacts,\n pass: false,\n };\n throw createVisualError(\n `Capture image differs: ${diffPixels} pixels (${diffRatio.toFixed(\n 6\n )}) exceeded maxDiffRatio ${comparisonOptions.maxDiffRatio}${\n comparisonOptions.maxDiffPixels === undefined\n ? ''\n : ` and maxDiffPixels ${comparisonOptions.maxDiffPixels}`\n }.`,\n failedResult\n );\n };\n return toLookSimilar;\n};\n\nconst createSimilarityAssertion = (\n defaults: GtkCaptureVisualDefaults,\n nextCounter: () => number,\n capture: GtkCapture,\n name: string\n): ((\n expectedImage: GtkCaptureExpectedImage,\n options?: GtkCaptureSimilarityOptions\n) => Promise<GtkCaptureSimilarityResult>) => {\n const toHaveSimilarity = async (\n expectedImage: GtkCaptureExpectedImage,\n options?: GtkCaptureSimilarityOptions\n ): Promise<GtkCaptureSimilarityResult> => {\n const context = await createContext(defaults, options, name, nextCounter());\n const actualPng = decodePng(capture.image);\n validateCaptureImage(capture, actualPng);\n const loadedExpectedImage = await loadExpectedImage(expectedImage);\n const expectedPng = decodePng(loadedExpectedImage.data);\n await saveActualAndMetadata(\n context,\n capture,\n name,\n 'toHaveSimilarity',\n options,\n loadedExpectedImage\n );\n\n const comparisonOptions = resolveSimilarityOptions(options);\n const comparison = prepareComparison(actualPng, expectedPng, options);\n const similarity = ssim(\n {\n data: new Uint8ClampedArray(comparison.expectedData),\n height: comparison.height,\n width: comparison.width,\n },\n {\n data: new Uint8ClampedArray(comparison.actualData),\n height: comparison.height,\n width: comparison.width,\n }\n ).mssim;\n const { diffPixels, diffPng } = createDiffPng(comparison, 0.1);\n const diffRatio = diffPixels / comparison.totalPixels;\n const result: GtkCaptureSimilarityResult = {\n ...buildBaseResult(context),\n diffPixels,\n diffRatio,\n similarity,\n totalPixels: comparison.totalPixels,\n };\n\n if (similarity >= comparisonOptions.minSimilarity) {\n return result;\n }\n\n const failureArtifacts = await writeFailureArtifacts(\n context,\n loadedExpectedImage.data,\n diffPng\n );\n const failedResult: GtkCaptureSimilarityResult = {\n ...result,\n ...failureArtifacts,\n pass: false,\n };\n throw createVisualError(\n `Capture image similarity ${similarity.toFixed(\n 6\n )} is below minSimilarity ${comparisonOptions.minSimilarity}.`,\n failedResult\n );\n };\n return toHaveSimilarity;\n};\n\nconst createReadTextAssertion = (\n defaults: GtkCaptureVisualDefaults,\n nextCounter: () => number,\n workerController: OcrWorkerController,\n capture: GtkCapture,\n name: string\n): ((options?: GtkCaptureOcrOptions) => Promise<GtkCaptureOcrText>) => {\n const readText = async (\n options?: GtkCaptureOcrOptions\n ): Promise<GtkCaptureOcrText> =>\n await readCaptureText(\n defaults,\n nextCounter,\n workerController,\n capture,\n name,\n 'readText',\n options,\n undefined\n );\n return readText;\n};\n\nconst createContainTextAssertion = (\n defaults: GtkCaptureVisualDefaults,\n nextCounter: () => number,\n workerController: OcrWorkerController,\n capture: GtkCapture,\n name: string\n): ((\n expected: string | RegExp,\n options?: GtkCaptureOcrAssertionOptions\n) => Promise<GtkCaptureOcrResult>) => {\n const toContainText = async (\n expected: string | RegExp,\n options?: GtkCaptureOcrAssertionOptions\n ): Promise<GtkCaptureOcrResult> => {\n const ocrText = await readCaptureText(\n defaults,\n nextCounter,\n workerController,\n capture,\n name,\n 'toContainText',\n options,\n expected\n );\n return await ocrText.toContainText(expected, options);\n };\n return toContainText;\n};\n\n/////////////////////////////////////////////////////////////////////////////////////////\n\n/**\n * Creates GTK capture visual assertion helpers with shared defaults.\n * @param defaults Default artifact and variant settings.\n * @returns GTK capture assertion helper.\n */\nexport const createGtkCaptureExpect = (\n defaults?: GtkCaptureVisualDefaults\n): GtkCaptureExpect => {\n const resolvedDefaults = defaults ?? {};\n const workerController = createOcrWorkerController(resolvedDefaults.ocr);\n let counter = 0;\n const nextCounter = (): number => {\n const value = counter;\n counter += 1;\n return value;\n };\n const release = async (): Promise<void> => {\n await workerController.release();\n };\n const expectCapture = (\n capture: GtkCapture,\n name: string\n ): GtkCaptureExpectation => ({\n readText: createReadTextAssertion(\n resolvedDefaults,\n nextCounter,\n workerController,\n capture,\n name\n ),\n toContainText: createContainTextAssertion(\n resolvedDefaults,\n nextCounter,\n workerController,\n capture,\n name\n ),\n toHaveSimilarity: createSimilarityAssertion(\n resolvedDefaults,\n nextCounter,\n capture,\n name\n ),\n toLookSimilar: createLookSimilarAssertion(\n resolvedDefaults,\n nextCounter,\n capture,\n name\n ),\n });\n return {\n expectCapture,\n release,\n [Symbol.asyncDispose]: release,\n };\n};\n\nconst defaultGtkCaptureExpect = createGtkCaptureExpect();\n\n/**\n * Creates an assertion object for a captured GTK image.\n * @param capture GTK capture to assert.\n * @param name Artifact name.\n * @returns Assertion object for the capture.\n */\nexport const expectCapture = (\n capture: GtkCapture,\n name: string\n): GtkCaptureExpectation =>\n defaultGtkCaptureExpect.expectCapture(capture, name);\n"],"names":["pixelmatch","sourcePath","resolve","expectCapture"],"mappings":"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","x_google_ignoreList":[0]}
|
package/dist/tray.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* name: gestament
|
|
3
|
-
* version: 0.
|
|
3
|
+
* version: 0.3.0
|
|
4
4
|
* description: TypeScript based test driver for GTK
|
|
5
5
|
* author: Kouji Matsui (@kekyo@mi.kekyo.net)
|
|
6
6
|
* license: MIT
|
|
7
7
|
* repository.url: https://github.com/kekyo/gestament.git
|
|
8
|
-
* git.commit.hash:
|
|
8
|
+
* git.commit.hash: c15fe3b28fb1c2fb73504c57773b1ee751cbf8c4
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { NativeTrayItem } from './native.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* name: gestament
|
|
3
|
-
* version: 0.
|
|
3
|
+
* version: 0.3.0
|
|
4
4
|
* description: TypeScript based test driver for GTK
|
|
5
5
|
* author: Kouji Matsui (@kekyo@mi.kekyo.net)
|
|
6
6
|
* license: MIT
|
|
7
7
|
* repository.url: https://github.com/kekyo/gestament.git
|
|
8
|
-
* git.commit.hash:
|
|
8
|
+
* git.commit.hash: c15fe3b28fb1c2fb73504c57773b1ee751cbf8c4
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/** Error code values reported by the GTK automation library. */
|
|
@@ -801,6 +801,33 @@ export interface Releasable extends AsyncDisposable {
|
|
|
801
801
|
* Node.js child_process environment handling.
|
|
802
802
|
*/
|
|
803
803
|
export type GtkAppEnvironment = Readonly<Record<string, string | undefined>>;
|
|
804
|
+
/**
|
|
805
|
+
* Display environment used by a reusable GTK application launcher.
|
|
806
|
+
*/
|
|
807
|
+
export type GtkAppDisplay = 'xvfb' | 'host';
|
|
808
|
+
/**
|
|
809
|
+
* Xvfb session pooling options used by a reusable GTK application launcher.
|
|
810
|
+
*/
|
|
811
|
+
export interface GtkXvfbPool {
|
|
812
|
+
/**
|
|
813
|
+
* Resource reuse mode.
|
|
814
|
+
*
|
|
815
|
+
* @remarks
|
|
816
|
+
* 'xvfb' reuses only the Xvfb process. 'all' also reuses the DBus session,
|
|
817
|
+
* launcher driver, and tray host, and can carry more state between launches.
|
|
818
|
+
*/
|
|
819
|
+
readonly type: 'xvfb' | 'all';
|
|
820
|
+
/**
|
|
821
|
+
* Maximum idle sessions retained for each reusable condition.
|
|
822
|
+
* Default is 1. 0 disables retaining idle sessions for the key being released.
|
|
823
|
+
*/
|
|
824
|
+
readonly maxIdlePerKey?: number | undefined;
|
|
825
|
+
/**
|
|
826
|
+
* Maximum idle sessions retained across all reusable conditions.
|
|
827
|
+
* Default is 4. 0 disables retaining idle sessions for the key being released.
|
|
828
|
+
*/
|
|
829
|
+
readonly maxIdleTotal?: number | undefined;
|
|
830
|
+
}
|
|
804
831
|
/**
|
|
805
832
|
* Options used when launching a GTK application.
|
|
806
833
|
*/
|
|
@@ -919,6 +946,41 @@ export interface GtkAppLauncherOptions {
|
|
|
919
946
|
* Environment overrides passed to every launched application.
|
|
920
947
|
*/
|
|
921
948
|
readonly env?: GtkAppEnvironment | undefined;
|
|
949
|
+
/**
|
|
950
|
+
* Display environment used for launched GTK applications.
|
|
951
|
+
* Default is 'xvfb'.
|
|
952
|
+
*
|
|
953
|
+
* @remarks
|
|
954
|
+
* host uses the current DISPLAY or WAYLAND_DISPLAY. When neither exists,
|
|
955
|
+
* host falls back to 'xvfb'.
|
|
956
|
+
*/
|
|
957
|
+
readonly display?: GtkAppDisplay | undefined;
|
|
958
|
+
/**
|
|
959
|
+
* Xvfb screen geometry used when the effective display is xvfb.
|
|
960
|
+
* Default is '1280x720x24'.
|
|
961
|
+
*/
|
|
962
|
+
readonly xvfbScreen?: string | undefined;
|
|
963
|
+
/**
|
|
964
|
+
* Whether to run gestament's StatusNotifier tray host with Xvfb.
|
|
965
|
+
* Default is true.
|
|
966
|
+
*/
|
|
967
|
+
readonly xvfbTrayHost?: boolean | undefined;
|
|
968
|
+
/**
|
|
969
|
+
* Xvfb process pooling options used when the effective display is xvfb.
|
|
970
|
+
* Default is undefined, which disables pooling.
|
|
971
|
+
*/
|
|
972
|
+
readonly xvfbPool?: GtkXvfbPool | undefined;
|
|
973
|
+
/**
|
|
974
|
+
* GSettings backend passed to every launched application.
|
|
975
|
+
* Default is 'memory'. null (NOT backend name) leaves GSETTINGS_BACKEND unset.
|
|
976
|
+
* GSettings backend variations are 'memory', 'dconf', 'keyfile' and etc.
|
|
977
|
+
*/
|
|
978
|
+
readonly gsettings?: string | null | undefined;
|
|
979
|
+
/**
|
|
980
|
+
* GTK theme passed to every launched application.
|
|
981
|
+
* Default is 'Adwaita'. null leaves GTK_THEME unset.
|
|
982
|
+
*/
|
|
983
|
+
readonly theme?: string | null | undefined;
|
|
922
984
|
/**
|
|
923
985
|
* Timeout used by operations that wait for the application or elements.
|
|
924
986
|
* Default is 10000msec (10sec).
|