import * as fs from 'fs'; import * as LooksSameStub from 'looks-same'; import { Image } from './image-utils'; import { ScreenshotLocations } from './file-utils'; import Diagnostics from './diagnostics'; import { takeScreenshot } from './take-screenshot'; import { buildTextMask } from './build-text-mask'; import type { DiffOptions, IComparerOptions, SelectorType } from './options'; function looksSame(item1: Image, item2: Image, options: DiffOptions): Promise<{ equal?: boolean }> { return new Promise((resolve, reject) => { LooksSameStub(item1.getBuffer(), item2.getBuffer(), options, (error, result) => { if (error) { reject(error); } else { resolve(result); } }); }); } export async function tryGetValidScreenshot( t: TestController, element: SelectorType, options: IComparerOptions, locations: ScreenshotLocations, diag: Diagnostics, ) : Promise<{ equal: boolean; screenshot: Image | null; patchedByMaskScreenshot: Image | null; textMask: Image | null; }> { let equal = false; let attempt = 0; let currentScreenshot: Image | null = null; let patchedByMaskScreenshot: Image | null = null; let textMask: Image | null = null; if (!locations.source.exists('file')) { await takeScreenshot(t, element, locations.temp.filePath); throw new Error('etalon file not found'); } const sourceScreenshot = locations.source.read('file'); const emptyImage = sourceScreenshot.as((x) => x.fill({ r: 0, g: 0, b: 0 })); while (!equal && attempt < options.attempts) { diag.log(`Starting attempt ${attempt}`); diag.pushPrefix(`attempt${attempt}-`); if (attempt > 0) { // eslint-disable-next-line @typescript-eslint/no-loop-func const patchFileName = (fn) => `${fn}_${attempt}`; fs.unlinkSync(locations.temp.filePath); locations.temp.patchFileName(patchFileName); locations.tempText.patchFileName(patchFileName); } await takeScreenshot(t, element, locations.temp.filePath); let mask = locations.source.tryRead('mask'); currentScreenshot = locations.temp.read('file'); diag.log('0 temp clean ', currentScreenshot); textMask = await buildTextMask(options, attempt, t, element, locations, diag, currentScreenshot, emptyImage, sourceScreenshot); if (textMask) { if (mask) { mask.and(textMask); } else { mask = textMask; } } patchedByMaskScreenshot = currentScreenshot.as((x) => x.replace(sourceScreenshot, mask)); equal = (await looksSame( sourceScreenshot, patchedByMaskScreenshot, options.looksSameComparisonOptions, )).equal; diag.log('6 result', { equal }); if (!equal && attempt < options.attempts) { await t.wait(options.attemptTimeout); } attempt += 1; diag.popPrefix(); } return { equal, screenshot: currentScreenshot, patchedByMaskScreenshot, textMask, }; }