UNPKG

creevey

Version:

Cross-browser screenshot testing tool for Storybook with fancy UI Runner

75 lines (67 loc) 2.64 kB
import path from 'path'; import { Dirent, mkdirSync, copyFileSync, readdirSync } from 'fs'; import micromatch from 'micromatch'; import { Config, isDefined } from '../types.js'; import { tryToLoadTestsData } from './utils.js'; const actualRegex = /^(.*)-actual-(\d+)\.png$/i; function approve( dirents: Dirent[], srcPath: string, dstPath: string, testPaths: string[][] | null, isMatch: (value: string) => boolean, ): void { dirents .filter((dirent) => dirent.isFile()) .map((dirent) => actualRegex.exec(dirent.name)) .filter(isDefined) .filter( ([fileName, imageName]) => !testPaths || (testPaths.find(([token]) => token == imageName) && isMatch(path.join(srcPath, fileName))), ) .reduce( (images, [, imageName, retry]) => Number(retry) > (images.get(imageName) ?? -1) ? images.set(imageName, Number(retry)) : images, new Map<string, number>(), ) .forEach((retry, imageName) => { mkdirSync(dstPath, { recursive: true }); copyFileSync(path.join(srcPath, `${imageName}-actual-${retry}.png`), path.join(dstPath, `${imageName}.png`)); }); } function traverse( srcPath: string, dstPath: string, testPaths: string[][] | null, isMatch: (value: string) => boolean, ): void { const dirents = readdirSync(srcPath, { withFileTypes: true }); approve(dirents, srcPath, dstPath, testPaths, isMatch); dirents .filter((dirent) => dirent.isDirectory()) .map( (dirent) => [ dirent.name, testPaths?.map(([token, ...restPath]) => (token == dirent.name ? restPath : null)).filter(isDefined), ] as [string, string[][] | null], ) .filter(([, paths]) => !paths || paths.length > 0) .forEach(([dirname, paths]) => { traverse(path.join(srcPath, dirname), path.join(dstPath, dirname), paths, isMatch); }); } export function update(config: Config, grepPattern?: string): void { const { reportDir, screenDir } = config; const isMatch = grepPattern ? micromatch.matcher(grepPattern, { contains: true }) : () => true; const testsMeta = tryToLoadTestsData(`${reportDir}/tests.json`); const testsReport = tryToLoadTestsData(`${reportDir}/data.js`); let testPaths: string[][] | null = null; if (testsMeta && testsReport) { testPaths = Object.values(testsMeta) .filter(isDefined) .filter(({ id }) => testsReport[id]?.status == 'failed') .map(({ storyPath, testName, browser }) => [...storyPath, ...(testName ? [testName] : []), browser]); } traverse(reportDir, screenDir, testPaths, (value: string) => isMatch(path.relative(reportDir, value))); }