import dedent from 'dedent' import { extractAutoSnapshotOptions } from '../../auto_snapshots/_extract_auto_snapshot_options.ts' import type { SnapshotMeta } from '../../auto_snapshots/snapshot_meta.ts' import type { SetupVisSuiteCommand } from '../../shared/commands.types.ts' import type { ComparisonMethod, SetupVisOptions } from '../../shared/types.ts' import { shouldTakeSnapshot } from '../snapshot/should_take_snapshot.ts' import { toTaskId } from '../task/task_id.ts' import { ctx } from './_ctx.ts' import { resolveSubject } from './resolve_subject.ts' export function autoSnapshotMatcher | unknown = unknown>( commands: SetupVisSuiteCommand, expect: any, ) { let subject: string | undefined return { async setup() { subject = (await commands.setupVisSuite()).subject }, createMatcher | unknown = unknown>( themes: Record< string, boolean | ((options: SnapshotMeta & M & GM) => Promise | Promise | boolean | void) >, suiteDefaults?: Pick, 'createMissingBaseline'> | undefined, ) { return async function matchImageSnapshot() { const test = ctx.getCurrentTest() const meta = extractAutoSnapshotOptions(test) if (!shouldTakeSnapshot(meta)) return const errors: Array<[string, Error]> = [] for (const themeId in themes) { try { await new Promise((a) => setTimeout(a, 10)) const theme = themes[themeId] const r = typeof theme === 'function' ? await theme(meta! as any) : theme if (r === false) continue const effectiveCreateMissingBaseline = meta != null && Object.hasOwn(meta as object, 'createMissingBaseline') ? (meta as { createMissingBaseline?: boolean }).createMissingBaseline : suiteDefaults?.createMissingBaseline await expect(resolveSubject(meta?.subject ?? subject)).toMatchImageSnapshot({ ...meta, snapshotKey: meta?.snapshotKey ?? themeId, ...(effectiveCreateMissingBaseline !== undefined ? { createMissingBaseline: effectiveCreateMissingBaseline } : {}), }) } catch (error) { errors.push([themeId, error as Error]) } } if (errors.length > 0) { if (errors.length === 1) throw errors[0]![1] const taskId = toTaskId(test!) throw new AggregateError( errors.map(([, e]) => e), dedent`Snapshot \`${taskId}\` mismatched ${errors .map(([themeId, error]) => { return `Theme \`${themeId}\` failed: ${error.message}` }) .join('\n\n')}`, ) } } }, } }