UNPKG

@cappa/core

Version:

Core Playwright screenshot functionality for Cappa

364 lines (363 loc) 10.5 kB
import { Browser, BrowserContext, Locator, Page } from "playwright-core"; import { Logger } from "@cappa/logger"; //#region src/compare.d.ts interface CompareResult { numDiffPixels: number; totalPixels: number; percentDifference: number; diffBuffer?: Buffer; passed: boolean; error?: string; differentSizes: boolean; } //#endregion //#region src/filesystem.d.ts /** * Class for interacting with the local file system to store the screenshots. */ declare class ScreenshotFileSystem { private readonly actualDir; private readonly expectedDir; private readonly diffDir; constructor(outputDir: string); clearActual(): void; clearDiff(): void; clearActualAndDiff(): void; /** * Approve a screenshot based on its actual file path. * @param actualFilePath - The path to the actual screenshot file. * @returns The paths to the actual, expected, and diff screenshot files. */ approveFromActualPath(actualFilePath: string): { actualPath: string; expectedPath: string; diffPath: string; }; /** * Approve a screenshot based on its name. * @param name - The name of the screenshot. Can include '.png' extension. * @returns The paths to the actual, expected, and diff screenshot files. */ approveByName(name: string): { actualPath: string; expectedPath: string; diffPath: string; }; /** * Approve a screenshot based on a relative path. * @param relativePath - The relative path to the screenshot. * @returns The paths to the actual, expected, and diff screenshot files. */ private approveRelative; /** * Ensure the parent directory of a file exists. If not, it creates it. * @param filePath - The path to the file. */ private ensureParentDir; /** * Remove a directory and all its contents. * @param dir - The path to the directory. */ private removeDir; /** * Get the actual directory path */ getActualDir(): string; /** * Get the expected directory path */ getExpectedDir(): string; /** * Get the diff directory path */ getDiffDir(): string; /** * Get the path to an actual screenshot file */ getActualFilePath(filename: string): string; /** * Get the path to an expected screenshot file */ getExpectedFilePath(filename: string): string; /** * Get the path to a diff screenshot file */ getDiffFilePath(filename: string): string; /** * Write a file to the actual directory */ writeActualFile(filename: string, data: Buffer): void; /** * Write a file to the diff directory */ writeDiffFile(filename: string, data: Buffer): void; /** * Check if an expected file exists */ hasExpectedFile(filename: string): boolean; /** * Read an expected file */ readExpectedFile(filename: string): Buffer; /** * Resolve the actual path of a screenshot file. * @param filePath - The path to the screenshot file. * @returns The actual path of the screenshot file. */ private resolveActualPath; } //#endregion //#region src/screenshot.d.ts interface ScreenshotCaptureDetails { filename: string; filepath?: string; comparisonResult?: CompareResult; diffImagePath?: string; skipped?: boolean; } interface ScreenshotVariantCaptureDetails extends ScreenshotCaptureDetails { id: string; label?: string; } interface ScreenshotCaptureResult { base: ScreenshotCaptureDetails; variants: ScreenshotVariantCaptureDetails[]; } interface ScreenshotCaptureExtras { saveDiffImage?: boolean; diffImageFilename?: string; variants?: Record<string, { saveDiffImage?: boolean; diffImageFilename?: string; }>; } declare class ScreenshotTool { browserType: "chromium" | "firefox" | "webkit"; headless: boolean; viewport: { width: number; height: number; }; outputDir: string; browser: Browser | null; context: BrowserContext | null; page: Page | null; concurrency: number; contexts: BrowserContext[]; pages: Page[]; diff: DiffConfig; logger: Logger; retries: number; filesystem: ScreenshotFileSystem; constructor(options: { browserType?: "chromium" | "firefox" | "webkit"; headless?: boolean; viewport?: { width: number; height: number; }; outputDir?: string; diff?: DiffConfig; retries?: number; concurrency?: number; }); /** * Initialize playwright and page */ init(): Promise<void>; /** * Closes browser * If not closed, the process will not exit */ close(): Promise<void>; /** * Navigates to a URL with "domcontentloaded" waitUntil */ goTo(page: Page, url: string): Promise<void>; /** * Takes a screenshot of the page */ takeScreenshot(page: Page, filename: string, options: ScreenshotSettings): Promise<string | undefined>; /** * Sets the viewport size and executes the action, ensuring the original viewport is restored * even if the action throws an error. */ private withViewport; /** * Takes a screenshot and returns the buffer (for comparison purposes) */ takeScreenshotBuffer(page: Page, options: ScreenshotSettings): Promise<Buffer>; takeScreenshotWithComparison(page: Page, filename: string, referenceImage: Buffer, options: ScreenshotSettings & { saveDiffImage?: boolean; diffImageFilename?: string; }): Promise<{ screenshotPath: string; comparisonResult: CompareResult; diffImagePath?: string; }>; retryScreenshot(page: Page, referenceImage: Buffer, options: ScreenshotSettings): Promise<{ screenshotPath: Buffer<ArrayBufferLike>; comparisonResult: CompareResult; passed: boolean; } | { screenshotPath: null; comparisonResult: null; passed: boolean; }>; getVariantFilename(filename: string, variant: ScreenshotVariant): string; capture(page: Page, filename: string, options: ScreenshotOptions, extras?: ScreenshotCaptureExtras): Promise<ScreenshotCaptureResult>; /** * Gets the exponential backoff delay */ getIncBackoffDelay(i: number, delay: number): number; /** * Get a page from the pool by index */ getPageFromPool(index: number): Page; } //#endregion //#region src/plugin.d.ts /** * Plugin task interface */ type PluginTask<TData = any> = { id: string; url: string; data?: TData; }; /** * Plugin function type definition (legacy) */ type PluginFunction = (screenshotTool: ScreenshotTool) => Promise<any[]>; /** * Plugin definition interface */ type PluginDef<TResult = any, TContext = any, TData = any> = { name: string; description: string; discover: (screenshotTool: ScreenshotTool) => Promise<PluginTask<TData>[]>; execute: (task: PluginTask<TData>, page: Page, screenshotTool: ScreenshotTool, context: TContext) => Promise<TResult>; initPage?: (page: Page, screenshotTool: ScreenshotTool) => Promise<TContext>; }; /** * Plugin function type definition */ type Plugin<Config = any> = (config?: Config) => PluginDef; //#endregion //#region src/types.d.ts type PossiblePromise<T> = Promise<T> | T; /** * Configuration for the comparison of images */ interface DiffConfig { /** * Matching threshold (0-1). Lower = more sensitive * Default = 0.1 * * This affects how similar a pixel needs to be in the reference image to be considered the same. */ threshold?: number; /** * Include anti-aliased pixels in diff count * Default = false * * For most users this should be false, because it makes comparisons very sensitive to sub-pixel differences of * fonts and other UI elements. */ includeAA?: boolean; /** * Use fast buffer comparison for identical images * Default = true */ fastBufferCheck?: boolean; /** * Maximum number of different pixels * Default = 0 * * The amount of pixels that can be different before the comparison fails. */ maxDiffPixels?: number; /** * Maximum percentage of pixels different * Default = 0 * * The amount of pixels that can be different before the comparison fails as a percentage of the total pixels. * 0 = no difference, 100 = 100% difference. * * Since this is a relative value, it is affected by the size of the images. A 100px image with a 10% difference * is 10 pixels different, but a 1000px image with a 10% difference is 100 pixels different. On very large full page screenshots * this can mean that small changes still slip through. */ maxDiffPercentage?: number; } /** * Config used in `cappa.config.ts` * * @example * import { defineConfig } from '@cappa/core' * export default defineConfig({ * ... * }) */ type UserConfig = { /** * The directory to save screenshots and other files in */ outputDir?: string; /** * Configuration for the comparison of images */ diff?: DiffConfig; /** * The number of times to retry a screenshot if it fails */ retries?: number; /** * The number of parallel browser contexts to use for taking screenshots */ concurrency?: number; /** * An array of Cappa plugins used for generation. * Each plugin may have additional configurable options (defined within the plugin itself). */ plugins?: Array<Plugin | PluginDef>; }; type Viewport = { width: number; height: number; }; type ScreenshotSettings = { fullPage?: boolean; delay?: number; skip?: boolean; mask?: Locator[]; omitBackground?: boolean; viewport?: Viewport; }; type ScreenshotVariant = { id: string; label?: string; filename?: string; options?: ScreenshotSettings; }; type ScreenshotOptions = ScreenshotSettings & { variants?: ScreenshotVariant[]; }; interface Screenshot { id: string; name: string; category: "new" | "deleted" | "changed" | "passed"; actualPath?: string; expectedPath?: string; diffPath?: string; approved?: boolean; } //#endregion //#region src/config.d.ts /** * Type helper to make it easier to use cappa.config.ts, or a function that returns it. The function receives a ConfigEnv object. */ declare function defineConfig(options: PossiblePromise<UserConfig | Array<UserConfig>> | (() => PossiblePromise<UserConfig | Array<UserConfig>>)): typeof options; //#endregion export { type Plugin, type PluginDef, type PluginFunction, type Screenshot, type ScreenshotCaptureDetails, type ScreenshotCaptureExtras, type ScreenshotCaptureResult, ScreenshotFileSystem, type ScreenshotOptions, type ScreenshotSettings, ScreenshotTool, type ScreenshotVariant, type ScreenshotVariantCaptureDetails, type UserConfig, type Viewport, defineConfig }; //# sourceMappingURL=index.d.ts.map