@storywright/cli 0.5.0 → 0.5.2

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.
@@ -254,21 +254,19 @@ var LocalStorageAdapter = class {
254
254
  };
255
255
 
256
256
  // src/storage/index.ts
257
- import { createRequire } from "module";
258
- function createStorageAdapter(config) {
257
+ async function createStorageAdapter(config) {
259
258
  switch (config.provider) {
260
259
  case "local":
261
260
  return new LocalStorageAdapter(config.local.baselineDir);
262
261
  case "s3":
263
- return loadS3Adapter(config);
262
+ return await loadS3Adapter(config);
264
263
  default:
265
264
  throw new Error(`Unknown storage provider: ${config.provider}`);
266
265
  }
267
266
  }
268
- function loadS3Adapter(config) {
267
+ async function loadS3Adapter(config) {
269
268
  try {
270
- const require2 = createRequire(import.meta.url);
271
- const { S3StorageAdapter } = require2("@storywright/storage-s3");
269
+ const { S3StorageAdapter } = await import("@storywright/storage-s3");
272
270
  return new S3StorageAdapter(config.s3);
273
271
  } catch {
274
272
  throw new Error(
@@ -783,7 +781,7 @@ async function runTests(config, options = {}, cwd = process.cwd()) {
783
781
  const storybookDir = path5.resolve(cwd, config.storybook.staticDir);
784
782
  const snapshotDir = path5.join(tmpDir, "snapshots");
785
783
  await fs4.mkdir(snapshotDir, { recursive: true });
786
- const storage = createStorageAdapter(config.storage);
784
+ const storage = await createStorageAdapter(config.storage);
787
785
  const baselinePromise = storage.download({ branch: "current", destDir: snapshotDir }).catch(() => {
788
786
  logger.info("No existing baselines found");
789
787
  });
@@ -908,7 +906,16 @@ export default class extends StorywrightReporter {
908
906
  }
909
907
  }
910
908
  async function updateBaselines(config, options = {}, cwd = process.cwd()) {
911
- const result = await runTests(config, { updateSnapshots: true, diffOnly: !options.all }, cwd);
909
+ const result = await runTests(
910
+ config,
911
+ {
912
+ updateSnapshots: true,
913
+ diffOnly: !options.all,
914
+ shard: options.shard,
915
+ filter: options.filter
916
+ },
917
+ cwd
918
+ );
912
919
  if (result.exitCode !== 0) {
913
920
  logger.warn("Some tests failed during baseline update");
914
921
  }
@@ -919,7 +926,7 @@ async function updateBaselines(config, options = {}, cwd = process.cwd()) {
919
926
  logger.success(`Baselines saved to ${config.storage.local.baselineDir}`);
920
927
  }
921
928
  if (options.upload) {
922
- const storage = createStorageAdapter(config.storage);
929
+ const storage = await createStorageAdapter(config.storage);
923
930
  const baselineDir = path5.resolve(cwd, config.storage.local.baselineDir);
924
931
  await storage.upload({
925
932
  branch: "current",
@@ -972,4 +979,4 @@ export {
972
979
  runTests,
973
980
  updateBaselines
974
981
  };
975
- //# sourceMappingURL=chunk-XYP273ZX.js.map
982
+ //# sourceMappingURL=chunk-4KFNGY6R.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/index.ts","../src/config/defaults.ts","../src/config/types.ts","../src/reporter/cli-reporter.ts","../src/storage/local.ts","../src/storage/index.ts","../src/utils/logger.ts","../src/core/engine.ts","../src/playwright/config-generator.ts","../src/playwright/test-generator.ts","../src/resolver/index.ts","../src/utils/path.ts","../src/utils/process.ts","../src/core/storybook.ts"],"sourcesContent":["import { loadConfig as unconfigLoad } from 'unconfig';\nimport { DEFAULT_CONFIG } from './defaults.js';\nimport { STANDARD_BROWSERS } from './types.js';\nimport type { DeepPartial, StorywrightConfig } from './types.js';\n\nexport function defineConfig(\n\tconfig: DeepPartial<StorywrightConfig>,\n): DeepPartial<StorywrightConfig> {\n\treturn config;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction deepMerge(\n\ttarget: Record<string, unknown>,\n\tsource: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = { ...target };\n\tfor (const key of Object.keys(source)) {\n\t\tconst sourceVal = source[key];\n\t\tconst targetVal = result[key];\n\t\tif (isPlainObject(sourceVal) && isPlainObject(targetVal)) {\n\t\t\tresult[key] = deepMerge(targetVal, sourceVal);\n\t\t} else if (sourceVal !== undefined) {\n\t\t\tresult[key] = sourceVal;\n\t\t}\n\t}\n\treturn result;\n}\n\nexport async function loadConfig(\n\tcwd: string = process.cwd(),\n\toverrides?: DeepPartial<StorywrightConfig>,\n): Promise<StorywrightConfig> {\n\tconst { config: userConfig } = await unconfigLoad<DeepPartial<StorywrightConfig>>({\n\t\tsources: [\n\t\t\t{\n\t\t\t\tfiles: 'storywright.config',\n\t\t\t\textensions: ['ts', 'js', 'mjs'],\n\t\t\t},\n\t\t],\n\t\tcwd,\n\t});\n\n\tlet merged = DEFAULT_CONFIG as unknown as Record<string, unknown>;\n\tif (userConfig) {\n\t\tmerged = deepMerge(merged, userConfig as Record<string, unknown>);\n\t}\n\tif (overrides) {\n\t\tmerged = deepMerge(merged, overrides as Record<string, unknown>);\n\t}\n\tconst result = merged as unknown as StorywrightConfig;\n\tvalidateConfig(result);\n\treturn result;\n}\n\nfunction validateConfig(config: StorywrightConfig): void {\n\tfor (const browser of config.browsers) {\n\t\tconst options = config.browserOptions[browser];\n\n\t\tif (!STANDARD_BROWSERS.has(browser) && !options?.browserName) {\n\t\t\tthrow new Error(\n\t\t\t\t`Custom browser project '${browser}' requires 'browserName' in browserOptions.\\nExample:\\n browserOptions: {\\n '${browser}': { browserName: 'webkit', ... }\\n }\\nValid browserName values: 'chromium', 'firefox', 'webkit'.\\n\\nError code: SW_E_MISSING_BROWSER_NAME`,\n\t\t\t);\n\t\t}\n\n\t\tif (options?.browserName && !STANDARD_BROWSERS.has(options.browserName)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid browserName '${options.browserName}' for browser project '${browser}'.\\nValid values: 'chromium', 'firefox', 'webkit'.\\n\\nError code: SW_E_INVALID_BROWSER_NAME`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport type { StorywrightConfig, DeepPartial } from './types.js';\n","import type { StorywrightConfig } from './types.js';\n\nexport const DEFAULT_CONFIG: StorywrightConfig = {\n\tstorybook: {\n\t\tstaticDir: 'storybook-static',\n\t\tbuildCommand: 'npx storybook build --stats-json',\n\t\turl: undefined,\n\t\tcompatibility: 'auto',\n\t},\n\n\tbrowsers: ['chromium'],\n\tbrowserOptions: {},\n\n\tscreenshot: {\n\t\tfullPage: true,\n\t\tanimations: 'disabled',\n\t\tthreshold: 0.02,\n\t\tmaxDiffPixelRatio: 0.02,\n\t\tfreezeTime: '2024-01-01T00:00:00',\n\t\ttimezone: 'UTC',\n\t\tlocale: 'en-US',\n\t\tseed: 1,\n\t},\n\n\tdiffDetection: {\n\t\tenabled: true,\n\t\twatchFiles: ['package.json', 'package-lock.json', '.storybook/**/*'],\n\t\tbaseBranch: 'main',\n\t},\n\n\tstorage: {\n\t\tprovider: 'local',\n\t\tlocal: {\n\t\t\tbaselineDir: '.storywright/baselines',\n\t\t},\n\t\ts3: {\n\t\t\tbucket: '',\n\t\t\tprefix: 'storywright/baselines',\n\t\t\tregion: 'ap-northeast-1',\n\t\t\tcompression: 'zstd',\n\t\t},\n\t},\n\n\treport: {\n\t\toutputDir: '.storywright/report',\n\t\ttitle: 'Storywright Report',\n\t},\n\n\tworkers: 'auto',\n\tretries: 0,\n\n\ttimeout: {\n\t\ttest: 30000,\n\t\tnavigation: 20000,\n\t\texpect: 10000,\n\t},\n\n\tinclude: ['**'],\n\texclude: [],\n\n\thooks: {},\n};\n","import type { Page } from '@playwright/test';\n\nexport interface StorywrightConfig {\n\tstorybook: StorybookConfig;\n\tbrowsers: BrowserName[];\n\tbrowserOptions: Record<string, BrowserOption>;\n\tscreenshot: ScreenshotConfig;\n\tdiffDetection: DiffDetectionConfig;\n\tstorage: StorageConfig;\n\treport: ReportConfig;\n\tworkers: number | 'auto';\n\tretries: number;\n\ttimeout: TimeoutConfig;\n\tinclude: string[];\n\texclude: string[];\n\thooks: HooksConfig;\n}\n\nexport type BrowserName = 'chromium' | 'firefox' | 'webkit' | (string & {});\n\nexport type PlaywrightBrowserName = 'chromium' | 'firefox' | 'webkit';\n\nexport const STANDARD_BROWSERS: ReadonlySet<string> = new Set<PlaywrightBrowserName>([\n\t'chromium',\n\t'firefox',\n\t'webkit',\n]);\n\nexport interface BrowserOption {\n\tbrowserName?: PlaywrightBrowserName;\n\tviewport?: { width: number; height: number };\n\tdeviceScaleFactor?: number;\n\tisMobile?: boolean;\n\thasTouch?: boolean;\n\tuserAgent?: string;\n\texclude?: string[];\n}\n\nexport interface StorybookConfig {\n\tstaticDir: string;\n\tbuildCommand: string;\n\turl?: string;\n\tcompatibility: 'auto' | 'v8';\n}\n\nexport interface ScreenshotConfig {\n\tfullPage: boolean;\n\tanimations: 'disabled' | 'allow';\n\tthreshold: number;\n\tmaxDiffPixelRatio: number;\n\tfreezeTime: string;\n\ttimezone: string;\n\tlocale: string;\n\tseed: number;\n}\n\nexport interface DiffDetectionConfig {\n\tenabled: boolean;\n\twatchFiles: string[];\n\tbaseBranch: string;\n}\n\nexport interface StorageConfig {\n\tprovider: 'local' | 's3';\n\tlocal: LocalStorageConfig;\n\ts3: S3StorageConfig;\n}\n\nexport interface LocalStorageConfig {\n\tbaselineDir: string;\n}\n\nexport interface S3StorageConfig {\n\tbucket: string;\n\tprefix: string;\n\tregion: string;\n\tcompression: 'zstd' | 'gzip' | 'none';\n}\n\nexport interface ReportConfig {\n\toutputDir: string;\n\ttitle: string;\n}\n\nexport interface TimeoutConfig {\n\ttest: number;\n\tnavigation: number;\n\texpect: number;\n}\n\nexport interface StoryContext {\n\tid: string;\n\ttitle: string;\n\tname: string;\n}\n\nexport interface HooksConfig {\n\tbeforeScreenshot?: (page: Page, story: StoryContext) => Promise<void>;\n\tafterScreenshot?: (page: Page, story: StoryContext) => Promise<void>;\n}\n\nexport type DeepPartial<T> = {\n\t[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];\n};\n","import type { TestSummary } from '../core/types.js';\n\nexport function formatSummary(summary: TestSummary, options?: { reportPath?: string }): string {\n\tconst durationSec = Math.round(summary.duration / 1000);\n\tconst minutes = Math.floor(durationSec / 60);\n\tconst seconds = durationSec % 60;\n\tconst durationStr = minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;\n\n\tconst lines: string[] = [\n\t\t'',\n\t\t'Storywright Results',\n\t\t'\\u2550'.repeat(42),\n\t\t` Total: ${summary.total} Passed: ${summary.passed} Failed: ${summary.failed} Skipped: ${summary.skipped}`,\n\t\t` Duration: ${durationStr}`,\n\t\t` Browsers: ${summary.browsers.join(', ')}`,\n\t];\n\n\tconst newFailures = summary.failures.filter((f) => f.type === 'new');\n\tconst diffFailures = summary.failures.filter((f) => f.type !== 'new');\n\n\tif (newFailures.length > 0) {\n\t\tlines.push('');\n\t\tlines.push(' New (no baseline):');\n\t\tfor (const failure of newFailures) {\n\t\t\tlines.push(` \\u25cb ${failure.story}: ${failure.variant} (${failure.browser})`);\n\t\t}\n\t}\n\n\tif (diffFailures.length > 0) {\n\t\tlines.push('');\n\t\tlines.push(' Failed:');\n\t\tfor (const failure of diffFailures) {\n\t\t\tlines.push(` \\u2717 ${failure.story}: ${failure.variant} (${failure.browser})`);\n\t\t\tif (failure.diffRatio > 0) {\n\t\t\t\tconst pct = (failure.diffRatio * 100).toFixed(1);\n\t\t\t\tlines.push(` \\u2192 Diff: ${pct}% pixels changed`);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst reportPath = options?.reportPath ?? '.storywright/report/index.html';\n\tlines.push('');\n\tlines.push(` Report: ${reportPath}`);\n\tlines.push('\\u2550'.repeat(42));\n\tlines.push('');\n\n\treturn lines.join('\\n');\n}\n","import { execFile } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { promisify } from 'node:util';\nimport type { DownloadOptions, StorageAdapter, UploadOptions } from './types.js';\n\nconst execFileAsync = promisify(execFile);\n\nexport class LocalStorageAdapter implements StorageAdapter {\n\tconstructor(private readonly baselineDir: string) {}\n\n\tasync download(options: DownloadOptions): Promise<void> {\n\t\ttry {\n\t\t\tawait fs.access(this.baselineDir);\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t\tawait fs.cp(this.baselineDir, options.destDir, { recursive: true });\n\t}\n\n\tasync upload(options: UploadOptions): Promise<void> {\n\t\tconst resolvedSource = path.resolve(options.sourceDir);\n\t\tconst resolvedDest = path.resolve(this.baselineDir);\n\t\tif (resolvedSource === resolvedDest) {\n\t\t\treturn;\n\t\t}\n\t\tawait fs.mkdir(this.baselineDir, { recursive: true });\n\t\tawait fs.cp(options.sourceDir, this.baselineDir, { recursive: true });\n\t}\n\n\tasync exists(_branch: string): Promise<boolean> {\n\t\ttry {\n\t\t\tawait fs.access(this.baselineDir);\n\t\t\tconst entries = await fs.readdir(this.baselineDir);\n\t\t\treturn entries.length > 0;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Extract baselines from a git branch using `git ls-tree` + `git show`.\n\t * Binary-safe (PNG files) via `encoding: 'buffer'`.\n\t */\n\tasync downloadFromGit(branch: string, destDir: string, cwd: string): Promise<void> {\n\t\tconst gitPath = this.baselineDir.split(path.sep).join('/');\n\n\t\tlet lsOutput: string;\n\t\ttry {\n\t\t\tconst result = await execFileAsync(\n\t\t\t\t'git',\n\t\t\t\t['ls-tree', '-r', '--name-only', branch, '--', gitPath],\n\t\t\t\t{ cwd },\n\t\t\t);\n\t\t\tlsOutput = result.stdout;\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to list baselines from git branch '${branch}': ${error instanceof Error ? error.message : error}`,\n\t\t\t);\n\t\t}\n\n\t\tconst files = lsOutput.trim().split('\\n').filter(Boolean);\n\t\tif (files.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait fs.mkdir(destDir, { recursive: true });\n\n\t\tconst posixBaselineDir = this.baselineDir.split(path.sep).join('/').replace(/\\/+$/, '');\n\n\t\tfor (const file of files) {\n\t\t\tlet content: Buffer;\n\t\t\ttry {\n\t\t\t\tconst result = await execFileAsync('git', ['show', `${branch}:${file}`], {\n\t\t\t\t\tcwd,\n\t\t\t\t\tencoding: 'buffer' as unknown as BufferEncoding,\n\t\t\t\t\tmaxBuffer: 50 * 1024 * 1024,\n\t\t\t\t});\n\t\t\t\tcontent = result.stdout as unknown as Buffer;\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to extract '${file}' from git branch '${branch}': ${error instanceof Error ? error.message : error}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst relativePath = file.slice(posixBaselineDir.length + 1);\n\t\t\tconst destPath = path.join(destDir, ...relativePath.split('/'));\n\t\t\tawait fs.mkdir(path.dirname(destPath), { recursive: true });\n\t\t\tawait fs.writeFile(destPath, content);\n\t\t}\n\t}\n}\n","import type { StorageConfig } from '../config/types.js';\nimport { LocalStorageAdapter } from './local.js';\nimport type { StorageAdapter } from './types.js';\n\nexport async function createStorageAdapter(config: StorageConfig): Promise<StorageAdapter> {\n\tswitch (config.provider) {\n\t\tcase 'local':\n\t\t\treturn new LocalStorageAdapter(config.local.baselineDir);\n\t\tcase 's3':\n\t\t\treturn await loadS3Adapter(config);\n\t\tdefault:\n\t\t\tthrow new Error(`Unknown storage provider: ${config.provider}`);\n\t}\n}\n\nasync function loadS3Adapter(config: StorageConfig): Promise<StorageAdapter> {\n\ttry {\n\t\tconst { S3StorageAdapter } = await import('@storywright/storage-s3');\n\t\treturn new S3StorageAdapter(config.s3);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t'S3 storage adapter requires the @storywright/storage-s3 package.\\nInstall it with: pnpm add @storywright/storage-s3',\n\t\t);\n\t}\n}\n\nexport type { StorageAdapter, DownloadOptions, UploadOptions } from './types.js';\n","import { createConsola } from 'consola';\n\nconst isCI = !!(\n\tprocess.env.CI ||\n\tprocess.env.GITHUB_ACTIONS ||\n\tprocess.env.CIRCLECI ||\n\tprocess.env.GITLAB_CI\n);\n\nexport const logger = createConsola({\n\tlevel: process.env.STORYWRIGHT_DEBUG ? 5 : 3,\n});\n\nexport { isCI };\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport picomatch from 'picomatch';\nimport type { StorywrightConfig } from '../config/types.js';\nimport { generatePlaywrightConfig } from '../playwright/config-generator.js';\nimport { generateTestFile } from '../playwright/test-generator.js';\nimport { resolveAffectedStories } from '../resolver/index.js';\nimport { createStorageAdapter } from '../storage/index.js';\nimport { logger } from '../utils/logger.js';\nimport { resolveOutputDir } from '../utils/path.js';\nimport { exec } from '../utils/process.js';\nimport {\n\tbuildStorybook,\n\tdiscoverStories,\n\texcludeStoriesForBrowser,\n\tfilterStories,\n} from './storybook.js';\nimport type { Story, StoryIndex, TestSummary } from './types.js';\n\nexport interface TestOptions {\n\tdiffOnly?: boolean;\n\tshard?: string;\n\tupdateSnapshots?: boolean;\n\tfilter?: string;\n\toutputDir?: string;\n\treporters?: string[];\n}\n\nexport interface TestRunResult {\n\texitCode: number;\n\tsummary?: TestSummary;\n\treportDir?: string;\n\tsnapshotDir?: string;\n}\n\nconst STORIES_PER_FILE = 50;\n\nfunction resolveReporterPath(): string {\n\t// Resolve relative to this file's dist location\n\tconst thisDir = new URL('.', import.meta.url).pathname;\n\treturn path.resolve(thisDir, 'playwright', 'reporter.js');\n}\n\nfunction chunkStories(entries: Record<string, Story>): Record<string, Story>[] {\n\tconst keys = Object.keys(entries);\n\tif (keys.length === 0) return [{}];\n\tconst chunks: Record<string, Story>[] = [];\n\tfor (let i = 0; i < keys.length; i += STORIES_PER_FILE) {\n\t\tconst chunk: Record<string, Story> = {};\n\t\tfor (const key of keys.slice(i, i + STORIES_PER_FILE)) {\n\t\t\tchunk[key] = entries[key];\n\t\t}\n\t\tchunks.push(chunk);\n\t}\n\treturn chunks;\n}\n\nexport async function runTests(\n\tconfig: StorywrightConfig,\n\toptions: TestOptions = {},\n\tcwd: string = process.cwd(),\n): Promise<TestRunResult> {\n\tconst outputRoot = options.outputDir\n\t\t? path.resolve(cwd, options.outputDir)\n\t\t: resolveOutputDir(cwd, '.storywright');\n\tconst tmpDir = path.join(outputRoot, 'tmp');\n\tconst reportDir = options.outputDir\n\t\t? path.join(outputRoot, 'report')\n\t\t: path.resolve(cwd, config.report.outputDir);\n\tconst storybookDir = path.resolve(cwd, config.storybook.staticDir);\n\tconst snapshotDir = path.join(tmpDir, 'snapshots');\n\n\t// Prepare directories early for parallel operations\n\tawait fs.mkdir(snapshotDir, { recursive: true });\n\n\t// Start baseline download in parallel with Storybook build\n\tconst storage = await createStorageAdapter(config.storage);\n\tconst baselinePromise = storage\n\t\t.download({ branch: 'current', destDir: snapshotDir })\n\t\t.catch(() => {\n\t\t\tlogger.info('No existing baselines found');\n\t\t});\n\n\t// 1. Build Storybook if needed\n\tawait buildStorybook(config, cwd);\n\n\t// 2. Discover & filter stories\n\tlogger.start('Discovering stories...');\n\tconst allStories = await discoverStories(config, cwd);\n\tlet targetStories = filterStories(allStories, config);\n\n\t// Apply --filter option\n\tif (options.filter) {\n\t\ttargetStories = applyFilter(targetStories, options.filter);\n\t}\n\n\tlogger.info(`${Object.keys(targetStories.entries).length} stories found`);\n\n\t// 3. Diff-only: resolve affected stories (default in CI)\n\tconst effectiveDiffOnly = options.diffOnly ?? !!process.env.CI;\n\tif (effectiveDiffOnly && config.diffDetection.enabled) {\n\t\tlogger.start('Resolving dependencies...');\n\t\tconst diffResult = await resolveAffectedStories(\n\t\t\ttargetStories,\n\t\t\tconfig.diffDetection,\n\t\t\tstorybookDir,\n\t\t\tcwd,\n\t\t);\n\t\tif (!diffResult.allStories) {\n\t\t\ttargetStories = diffResult.targetStories;\n\t\t}\n\t\tlogger.info(`${Object.keys(targetStories.entries).length} stories affected by changes`);\n\t}\n\n\t// 4. Wait for baseline download to complete\n\tawait baselinePromise;\n\n\t// 5. Generate split test files for better worker distribution\n\tlet testFilePattern: string;\n\tlet testMatchByBrowser: Record<string, string> | undefined;\n\n\tconst browserExcludesExist = config.browsers.some(\n\t\t(b) => (config.browserOptions[b]?.exclude ?? []).length > 0,\n\t);\n\n\tif (browserExcludesExist) {\n\t\t// Generate per-browser test files when any browser has specific excludes\n\t\ttestMatchByBrowser = {};\n\n\t\tfor (const browser of config.browsers) {\n\t\t\tconst browserExclude = config.browserOptions[browser]?.exclude ?? [];\n\t\t\tconst browserStories = excludeStoriesForBrowser(targetStories, browserExclude);\n\n\t\t\tif (Object.keys(browserStories.entries).length === 0) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`${browser}: All stories excluded by browser-specific 'exclude' patterns. No tests will run for this browser.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst browserChunks = chunkStories(browserStories.entries);\n\n\t\t\ttestMatchByBrowser[browser] =\n\t\t\t\tbrowserChunks.length === 1\n\t\t\t\t\t? `storywright-${browser}-0.spec.ts`\n\t\t\t\t\t: `storywright-${browser}-*.spec.ts`;\n\n\t\t\tfor (let i = 0; i < browserChunks.length; i++) {\n\t\t\t\tconst chunkIndex: StoryIndex = { ...browserStories, entries: browserChunks[i] };\n\t\t\t\tconst chunkPath = path.join(tmpDir, `target-stories-${browser}-${i}.json`);\n\t\t\t\tawait fs.writeFile(chunkPath, JSON.stringify(chunkIndex));\n\n\t\t\t\tconst testContent = generateTestFile(config.screenshot, {\n\t\t\t\t\ttargetStoriesPath: chunkPath.replace(/\\\\/g, '/'),\n\t\t\t\t});\n\t\t\t\tawait fs.writeFile(path.join(tmpDir, `storywright-${browser}-${i}.spec.ts`), testContent);\n\t\t\t}\n\n\t\t\tlogger.info(\n\t\t\t\t`${browser}: ${Object.keys(browserStories.entries).length} stories, ${browserChunks.length} test file(s)`,\n\t\t\t);\n\t\t}\n\n\t\ttestFilePattern = 'storywright-*.spec.ts';\n\t} else {\n\t\t// Default: shared test files for all browsers\n\t\tconst chunks = chunkStories(targetStories.entries);\n\t\ttestFilePattern = chunks.length === 1 ? 'storywright-0.spec.ts' : 'storywright-*.spec.ts';\n\n\t\tfor (let i = 0; i < chunks.length; i++) {\n\t\t\tconst chunkIndex: StoryIndex = { ...targetStories, entries: chunks[i] };\n\t\t\tconst chunkPath = path.join(tmpDir, `target-stories-${i}.json`);\n\t\t\tawait fs.writeFile(chunkPath, JSON.stringify(chunkIndex));\n\n\t\t\tconst testContent = generateTestFile(config.screenshot, {\n\t\t\t\ttargetStoriesPath: chunkPath.replace(/\\\\/g, '/'),\n\t\t\t});\n\t\t\tawait fs.writeFile(path.join(tmpDir, `storywright-${i}.spec.ts`), testContent);\n\t\t}\n\n\t\tlogger.info(`${chunks.length} test file(s) generated`);\n\t}\n\n\t// 6. Generate Playwright config\n\tconst reporterWrapperPath = path.join(tmpDir, 'reporter.mjs');\n\tconst resolvedReporterPath = resolveReporterPath().replace(/\\\\/g, '/');\n\tconst reporterOutputDir = reportDir.replace(/\\\\/g, '/');\n\n\tawait fs.writeFile(\n\t\treporterWrapperPath,\n\t\t`import StorywrightReporter from '${resolvedReporterPath}';\\nexport default class extends StorywrightReporter {\\n constructor() { super({ outputDir: '${reporterOutputDir}' }); }\\n}\\n`,\n\t);\n\n\t// Determine Storybook URL\n\tlet actualStorybookUrl = config.storybook.url;\n\tconst needsServer = !actualStorybookUrl;\n\n\tif (needsServer) {\n\t\tactualStorybookUrl = 'http://localhost:6007';\n\t}\n\n\tconst playwrightConfig = generatePlaywrightConfig(config, {\n\t\ttmpDir: tmpDir.replace(/\\\\/g, '/'),\n\t\tstorybookUrl: actualStorybookUrl ?? 'http://localhost:6007',\n\t\tsnapshotDir: snapshotDir.replace(/\\\\/g, '/'),\n\t\treporterPath: reporterWrapperPath.replace(/\\\\/g, '/'),\n\t\ttestMatch: testFilePattern,\n\t\ttestMatchByBrowser,\n\t\tshard: options.shard,\n\t\treporters: options.reporters,\n\t});\n\n\tconst configPath = path.join(tmpDir, 'playwright.config.ts');\n\tawait fs.writeFile(configPath, playwrightConfig);\n\n\t// 7. Run Playwright tests\n\tlogger.start('Running tests...');\n\tconst args = ['playwright', 'test', '--config', configPath];\n\n\tif (options.updateSnapshots) {\n\t\targs.push('--update-snapshots');\n\t}\n\n\t// Start static server if needed\n\tlet serverProc: { kill: () => void } | undefined;\n\tif (needsServer) {\n\t\tserverProc = await startStaticServer(storybookDir, 6007);\n\t}\n\n\ttry {\n\t\tconst result = await exec('npx', args, { cwd, inherit: true });\n\n\t\t// 8. Read results\n\t\tlet summary: TestSummary | undefined;\n\t\ttry {\n\t\t\tconst summaryPath = path.join(reportDir, 'summary.json');\n\t\t\tconst summaryContent = await fs.readFile(summaryPath, 'utf-8');\n\t\t\tsummary = JSON.parse(summaryContent);\n\t\t} catch {\n\t\t\t// summary may not exist if no tests ran\n\t\t}\n\n\t\t// 9. Map exit codes per SPEC §14.2\n\t\tconst exitCode = mapExitCode(result.exitCode, summary);\n\n\t\treturn { exitCode, summary, reportDir, snapshotDir };\n\t} finally {\n\t\tserverProc?.kill();\n\t}\n}\n\nexport async function updateBaselines(\n\tconfig: StorywrightConfig,\n\toptions: { all?: boolean; upload?: boolean; shard?: string; filter?: string } = {},\n\tcwd: string = process.cwd(),\n): Promise<void> {\n\tconst result = await runTests(\n\t\tconfig,\n\t\t{\n\t\t\tupdateSnapshots: true,\n\t\t\tdiffOnly: !options.all,\n\t\t\tshard: options.shard,\n\t\t\tfilter: options.filter,\n\t\t},\n\t\tcwd,\n\t);\n\n\tif (result.exitCode !== 0) {\n\t\tlogger.warn('Some tests failed during baseline update');\n\t}\n\n\t// Save updated snapshots back to baselineDir (local disk operation)\n\tif (result.snapshotDir) {\n\t\tconst baselineDir = path.resolve(cwd, config.storage.local.baselineDir);\n\t\tawait fs.mkdir(baselineDir, { recursive: true });\n\t\tawait fs.cp(result.snapshotDir, baselineDir, { recursive: true });\n\t\tlogger.success(`Baselines saved to ${config.storage.local.baselineDir}`);\n\t}\n\n\t// --upload: upload to remote storage (S3 etc.) only when explicitly requested\n\tif (options.upload) {\n\t\tconst storage = await createStorageAdapter(config.storage);\n\t\tconst baselineDir = path.resolve(cwd, config.storage.local.baselineDir);\n\t\tawait storage.upload({\n\t\t\tbranch: 'current',\n\t\t\tsourceDir: baselineDir,\n\t\t});\n\t\tlogger.success('Baselines uploaded to remote storage');\n\t}\n}\n\nfunction applyFilter(storyIndex: StoryIndex, filter: string): StoryIndex {\n\tconst matcher = picomatch(filter);\n\tconst entries: Record<string, StoryIndex['entries'][string]> = {};\n\tfor (const [id, story] of Object.entries(storyIndex.entries)) {\n\t\tconst fullName = `${story.title}/${story.name}`;\n\t\tif (matcher(fullName) || matcher(story.title) || matcher(story.id)) {\n\t\t\tentries[id] = story;\n\t\t}\n\t}\n\treturn { ...storyIndex, entries };\n}\n\nfunction mapExitCode(playwrightCode: number, summary?: TestSummary): number {\n\t// SPEC §14.2: 0 = success (no diff), 1 = success (diff found), 2 = execution error, 130 = SIGINT\n\tif (playwrightCode === 130 || playwrightCode === 143) {\n\t\treturn 130; // SIGINT / SIGTERM\n\t}\n\tif (summary) {\n\t\tif (summary.failed > 0) return 1;\n\t\tif (summary.total === 0 && playwrightCode !== 0) return 2;\n\t\treturn 0;\n\t}\n\t// No summary = likely execution error\n\treturn playwrightCode === 0 ? 0 : 2;\n}\n\nasync function startStaticServer(dir: string, port: number): Promise<{ kill: () => void }> {\n\tconst { createServer } = await import('node:http');\n\tconst sirv = (await import('sirv')).default;\n\n\tconst handler = sirv(dir, { single: false, dev: false });\n\tconst server = createServer(handler);\n\n\tawait new Promise<void>((resolve, reject) => {\n\t\tserver.on('error', reject);\n\t\tserver.listen(port, () => resolve());\n\t});\n\n\treturn { kill: () => server.close() };\n}\n","import { STANDARD_BROWSERS } from '../config/types.js';\nimport type { BrowserOption, StorywrightConfig } from '../config/types.js';\n\nexport function generatePlaywrightConfig(\n\tconfig: StorywrightConfig,\n\toptions: {\n\t\ttmpDir: string;\n\t\tstorybookUrl: string;\n\t\tsnapshotDir: string;\n\t\treporterPath: string;\n\t\ttestMatch: string;\n\t\ttestMatchByBrowser?: Record<string, string>;\n\t\tshard?: string;\n\t\treporters?: string[];\n\t},\n): string {\n\tconst projects = config.browsers.map((browser) => {\n\t\tconst rawOptions = config.browserOptions[browser];\n\t\tconst useObj = buildBrowserUseObject(browser, rawOptions);\n\t\tconst useStr = JSON.stringify(useObj, null, '\\t\\t');\n\t\tconst testMatch = options.testMatchByBrowser?.[browser];\n\t\tconst testMatchLine = testMatch ? `\\n\\t\\t\\ttestMatch: '${escapeBackslash(testMatch)}',` : '';\n\t\treturn `\\t\\t{\n\\t\\t\\tname: '${browser}',${testMatchLine}\n\\t\\t\\tuse: ${useStr},\n\\t\\t}`;\n\t});\n\n\tconst workers = config.workers === 'auto' ? \"'100%'\" : String(config.workers);\n\n\tconst shard = options.shard\n\t\t? `\\tshard: { current: ${options.shard.split('/')[0]}, total: ${options.shard.split('/')[1]} },`\n\t\t: '';\n\n\t// Build reporter list: always include custom reporter, plus user-requested ones\n\tconst reporterEntries: string[] = [];\n\tconst requestedReporters = options.reporters ?? ['default', 'html'];\n\tfor (const r of requestedReporters) {\n\t\tif (r === 'default' || r === 'list') {\n\t\t\treporterEntries.push(\"\\t\\t['list']\");\n\t\t} else if (r !== 'html') {\n\t\t\t// Pass through other built-in Playwright reporters (dot, json, junit, etc.)\n\t\t\treporterEntries.push(`\\t\\t['${r}']`);\n\t\t}\n\t}\n\t// Always include custom storywright reporter\n\treporterEntries.push(`\\t\\t['${escapeBackslash(options.reporterPath)}']`);\n\n\tconst testMatchLine = options.testMatchByBrowser\n\t\t? ''\n\t\t: `\\ttestMatch: '${escapeBackslash(options.testMatch)}',\\n`;\n\n\treturn `import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n\\ttestDir: '${escapeBackslash(options.tmpDir)}',\n${testMatchLine}\\tsnapshotDir: '${escapeBackslash(options.snapshotDir)}',\n\\tsnapshotPathTemplate: '{snapshotDir}/{arg}-{projectName}{ext}',\n\\ttimeout: ${config.timeout.test},\n\\texpect: {\n\\t\\ttoHaveScreenshot: {\n\\t\\t\\tmaxDiffPixelRatio: ${config.screenshot.maxDiffPixelRatio},\n\\t\\t\\tthreshold: ${config.screenshot.threshold},\n\\t\\t},\n\\t\\ttimeout: ${config.timeout.expect},\n\\t},\n\\tfullyParallel: true,\n\\tforbidOnly: !!process.env.CI,\n\\tretries: ${config.retries},\n\\tworkers: ${workers},\n${shard}\n\\treporter: [\n${reporterEntries.join(',\\n')}\n\\t],\n\\tuse: {\n\\t\\tbaseURL: '${options.storybookUrl}',\n\\t\\tnavigationTimeout: ${config.timeout.navigation},\n\\t\\ttimezoneId: '${config.screenshot.timezone}',\n\\t\\tlocale: '${config.screenshot.locale}',\n\\t},\n\\tprojects: [\n${projects.join(',\\n')}\n\\t],\n});\n`;\n}\n\nfunction buildBrowserUseObject(\n\tbrowser: string,\n\trawOptions?: BrowserOption,\n): Record<string, unknown> {\n\tlet browserName: string;\n\tif (rawOptions?.browserName) {\n\t\tbrowserName = rawOptions.browserName;\n\t} else if (STANDARD_BROWSERS.has(browser)) {\n\t\tbrowserName = browser;\n\t} else {\n\t\tthrow new Error(\n\t\t\t`Cannot resolve browserName for custom browser project '${browser}'.\\n\\nError code: SW_E_INTERNAL_BROWSER_RESOLVE`,\n\t\t);\n\t}\n\tconst useObj: Record<string, unknown> = { browserName };\n\n\tif (rawOptions) {\n\t\tconst { browserName: _, exclude: __, ...rest } = rawOptions;\n\t\tObject.assign(useObj, rest);\n\t}\n\n\treturn useObj;\n}\n\nfunction escapeBackslash(str: string): string {\n\treturn str.replace(/\\\\/g, '/');\n}\n","import type { ScreenshotConfig } from '../config/types.js';\n\nexport function generateTestFile(\n\tconfig: ScreenshotConfig,\n\toptions: {\n\t\ttargetStoriesPath: string;\n\t},\n): string {\n\tconst disableAnimations = config.animations === 'disabled';\n\n\treturn `import { test, expect } from '@playwright/test';\nimport { readFileSync } from 'node:fs';\n\nconst targetList = JSON.parse(\n\\treadFileSync('${escapeBackslash(options.targetStoriesPath)}', 'utf-8'),\n);\n\ntest.describe.parallel('visual regression testing', () => {\n\\tif (Object.keys(targetList.entries).length === 0) {\n\\t\\ttest('no stories to test', () => {\n\\t\\t\\texpect(true).toBeTruthy();\n\\t\\t});\n\\t}\n\n\\tfor (const story of Object.values(targetList.entries)) {\n\\t\\ttest(\\`\\${story.title}: \\${story.name}\\`, async ({ page }) => {\n\\t\\t\\t// Freeze time for reproducibility\n\\t\\t\\tawait page.clock.install({ time: new Date('${config.freezeTime}') });\n\n\\t\\t\\t// Seed Math.random for reproducibility\n\\t\\t\\tawait page.addInitScript((seed) => {\n\\t\\t\\t\\tlet s = seed;\n\\t\\t\\t\\tMath.random = () => {\n\\t\\t\\t\\t\\ts = (s * 16807 + 0) % 2147483647;\n\\t\\t\\t\\t\\treturn (s - 1) / 2147483646;\n\\t\\t\\t\\t};\n\\t\\t\\t}, ${config.seed});\n\n\\t\\t\\tawait page.goto(\\`/iframe.html?id=\\${story.id}\\`, {\n\\t\\t\\t\\twaitUntil: 'domcontentloaded',\n\\t\\t\\t});\n${\n\tdisableAnimations\n\t\t? `\n\\t\\t\\t// Force-disable all CSS animations and transitions\n\\t\\t\\tawait page.addStyleTag({\n\\t\\t\\t\\tcontent: '*, *::before, *::after { animation-duration: 0s !important; animation-delay: 0s !important; transition-duration: 0s !important; transition-delay: 0s !important; }',\n\\t\\t\\t});\n`\n\t\t: ''\n}\n\\t\\t\\t// Wait for story to render: content inside #storybook-root OR portal content on body\n\\t\\t\\tawait page.waitForFunction(() => {\n\\t\\t\\t\\tconst root = document.getElementById('storybook-root');\n\\t\\t\\t\\tif (!root) return false;\n\\t\\t\\t\\tif (root.childElementCount > 0) return true;\n\\t\\t\\t\\t// Portal: check for elements on body that aren't part of Storybook's skeleton\n\\t\\t\\t\\tfor (const el of document.body.children) {\n\\t\\t\\t\\t\\tif (el.tagName === 'SCRIPT' || el.id === 'storybook-root' || el.id === 'storybook-docs') continue;\n\\t\\t\\t\\t\\treturn true;\n\\t\\t\\t\\t}\n\\t\\t\\t\\treturn false;\n\\t\\t\\t}, { timeout: 10000 });\n\n\\t\\t\\t// Wait for web fonts to finish loading\n\\t\\t\\tawait page.waitForFunction(() => document.fonts.ready);\n\n\\t\\t\\t// Force lazy-loaded images to eager and wait for all images with timeout\n\\t\\t\\tawait page.evaluate(async () => {\n\\t\\t\\t\\tconst lazyImages = document.querySelectorAll('img[loading=\"lazy\"]');\n\\t\\t\\t\\tfor (const img of lazyImages) {\n\\t\\t\\t\\t\\t(img as HTMLImageElement).loading = 'eager';\n\\t\\t\\t\\t}\n\n\\t\\t\\t\\tconst images = Array.from(document.images).filter((img) => !img.complete);\n\\t\\t\\t\\tawait Promise.all(\n\\t\\t\\t\\t\\timages.map(\n\\t\\t\\t\\t\\t\\t(img) =>\n\\t\\t\\t\\t\\t\\t\\tnew Promise<void>((resolve) => {\n\\t\\t\\t\\t\\t\\t\\t\\tconst timeout = setTimeout(resolve, 5000);\n\\t\\t\\t\\t\\t\\t\\t\\timg.onload = img.onerror = () => {\n\\t\\t\\t\\t\\t\\t\\t\\t\\tclearTimeout(timeout);\n\\t\\t\\t\\t\\t\\t\\t\\t\\tresolve();\n\\t\\t\\t\\t\\t\\t\\t\\t};\n\\t\\t\\t\\t\\t\\t\\t}),\n\\t\\t\\t\\t\\t),\n\\t\\t\\t\\t);\n\\t\\t\\t});\n${\n\tdisableAnimations\n\t\t? `\n\\t\\t\\t// Force opacity:1 on images to counteract fade-in effects\n\\t\\t\\tawait page.evaluate(() => {\n\\t\\t\\t\\tdocument.querySelectorAll('img').forEach((img) => {\n\\t\\t\\t\\t\\timg.style.setProperty('opacity', '1', 'important');\n\\t\\t\\t\\t});\n\\t\\t\\t});\n`\n\t\t: ''\n}\n\\t\\t\\t// Allow async renders to settle (multiple animation frames)\n\\t\\t\\tawait page.waitForFunction(\n\\t\\t\\t\\t() =>\n\\t\\t\\t\\t\\tnew Promise((resolve) => {\n\\t\\t\\t\\t\\t\\tlet count = 0;\n\\t\\t\\t\\t\\t\\tconst tick = () => {\n\\t\\t\\t\\t\\t\\t\\tif (++count >= 3) return resolve(true);\n\\t\\t\\t\\t\\t\\t\\trequestAnimationFrame(tick);\n\\t\\t\\t\\t\\t\\t};\n\\t\\t\\t\\t\\t\\trequestAnimationFrame(tick);\n\\t\\t\\t\\t\\t}),\n\\t\\t\\t);\n\n\\t\\t\\t// Final stabilization delay for layout shifts\n\\t\\t\\tawait page.waitForTimeout(200);\n\n\\t\\t\\tawait expect(page).toHaveScreenshot(\n\\t\\t\\t\\t[story.title, \\`\\${story.id}.png\\`],\n\\t\\t\\t\\t{\n\\t\\t\\t\\t\\tanimations: '${config.animations}',\n\\t\\t\\t\\t\\tfullPage: ${config.fullPage},\n\\t\\t\\t\\t\\tthreshold: ${config.threshold},\n\\t\\t\\t\\t\\tmaxDiffPixelRatio: ${config.maxDiffPixelRatio},\n\\t\\t\\t\\t},\n\\t\\t\\t);\n\\t\\t});\n\\t}\n});\n`;\n}\n\nfunction escapeBackslash(str: string): string {\n\treturn str.replace(/\\\\/g, '/');\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport picomatch from 'picomatch';\nimport { simpleGit } from 'simple-git';\nimport type { DiffDetectionConfig } from '../config/types.js';\nimport type { StatsIndex, StatsModule, StoryIndex } from '../core/types.js';\nimport { logger } from '../utils/logger.js';\nimport { normalizePath, stripLeadingDotSlash } from '../utils/path.js';\n\nexport interface DependencyResolver {\n\tgetDependencies(filePath: string): string[];\n\tgetStoriesForFiles(pathList: string[]): StoryIndex;\n}\n\nconst STORY_FILE_PATTERNS = ['.stories.', '.mdx'];\n\nfunction isStoryFile(moduleName: string): boolean {\n\treturn STORY_FILE_PATTERNS.some((p) => moduleName.includes(p));\n}\n\nexport class StorybookStatsDependencyResolver implements DependencyResolver {\n\tprivate moduleMap: Record<string, StatsModule>;\n\n\tconstructor(\n\t\tprivate statsJson: StatsIndex,\n\t\tprivate storiesJson: StoryIndex,\n\t) {\n\t\tthis.moduleMap = {};\n\t\tfor (const mod of statsJson.modules) {\n\t\t\t// Key by normalized name (primary) and normalized id (fallback)\n\t\t\tconst normalizedName = normalizePath(mod.name);\n\t\t\tthis.moduleMap[normalizedName] = mod;\n\t\t\tconst normalizedId = normalizePath(mod.id);\n\t\t\tif (normalizedId !== normalizedName) {\n\t\t\t\tthis.moduleMap[normalizedId] ??= mod;\n\t\t\t}\n\t\t}\n\t}\n\n\tgetDependencies(filePath: string): string[] {\n\t\tconst normalizedPath = normalizePath(filePath);\n\t\tconst dependencies = this.collectDependencies(normalizedPath);\n\n\t\tif (this.moduleMap[normalizedPath]) {\n\t\t\tdependencies.add(normalizedPath);\n\t\t}\n\n\t\treturn [...dependencies];\n\t}\n\n\tgetStoriesForFiles(pathList: string[]): StoryIndex {\n\t\tconst result: StoryIndex = { v: this.storiesJson.v, entries: {} };\n\n\t\tfor (const filePath of pathList) {\n\t\t\t// Finding #2 + #3: lookup via normalized moduleMap (name primary, id fallback)\n\t\t\tconst normalizedPath = normalizePath(filePath);\n\t\t\tconst stats = this.moduleMap[normalizedPath];\n\t\t\tif (!stats) continue;\n\n\t\t\t// Finding #1: collect ALL story reasons, not just first\n\t\t\tconst storyReasons = stats.reasons.filter((r) => isStoryFile(r.moduleName));\n\t\t\tfor (const reason of storyReasons) {\n\t\t\t\tconst normalizedImportPath = normalizePath(reason.moduleName);\n\t\t\t\t// Collect ALL matching story entries per reason\n\t\t\t\tfor (const storyObj of Object.values(this.storiesJson.entries)) {\n\t\t\t\t\tif (storyObj.type !== 'story') continue;\n\t\t\t\t\tif (normalizePath(storyObj.importPath) === normalizedImportPath) {\n\t\t\t\t\t\tresult.entries[storyObj.id] = storyObj;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate collectDependencies(name: string, result = new Set<string>()): Set<string> {\n\t\tconst mod = this.moduleMap[normalizePath(name)];\n\t\tif (mod) {\n\t\t\tfor (const reason of mod.reasons) {\n\t\t\t\tif (!result.has(reason.moduleName)) {\n\t\t\t\t\tresult.add(reason.moduleName);\n\t\t\t\t\tthis.collectDependencies(reason.moduleName, result);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\n\nexport interface DiffResult {\n\tallStories: boolean;\n\ttargetStories: StoryIndex;\n}\n\ninterface DiffFileEntry {\n\tfile: string;\n\tfrom?: string;\n}\n\nexport async function resolveAffectedStories(\n\tstoriesJson: StoryIndex,\n\tconfig: DiffDetectionConfig,\n\tstorybookStaticDir: string,\n\tcwd: string,\n): Promise<DiffResult> {\n\tconst git = simpleGit({ baseDir: cwd });\n\n\t// Get diff summary\n\tlet diffEntries: DiffFileEntry[];\n\ttry {\n\t\tconst mergeBase = await git.raw(['merge-base', config.baseBranch, 'HEAD']);\n\t\tconst diff = await git.diffSummary([mergeBase.trim(), 'HEAD']);\n\t\tdiffEntries = diff.files.map((f) => ({\n\t\t\tfile: f.file,\n\t\t\t// Handle renames: include both old and new paths\n\t\t\tfrom: 'from' in f ? (f as { from: string }).from : undefined,\n\t\t}));\n\t} catch {\n\t\tlogger.warn('Failed to resolve git diff, running all stories');\n\t\treturn { allStories: true, targetStories: storiesJson };\n\t}\n\n\tif (diffEntries.length === 0) {\n\t\tlogger.info('No changed files detected');\n\t\treturn { allStories: false, targetStories: { v: storiesJson.v, entries: {} } };\n\t}\n\n\t// Collect all affected paths (including rename sources)\n\tconst allPaths: string[] = [];\n\tfor (const entry of diffEntries) {\n\t\tallPaths.push(entry.file);\n\t\tif (entry.from) {\n\t\t\tallPaths.push(entry.from);\n\t\t}\n\t}\n\n\t// Check watchFiles\n\tfor (const file of allPaths) {\n\t\tfor (const pattern of config.watchFiles) {\n\t\t\tif (picomatch(pattern)(file)) {\n\t\t\t\tlogger.info(`Watch file changed: ${file}, running all stories`);\n\t\t\t\treturn { allStories: true, targetStories: storiesJson };\n\t\t\t}\n\t\t}\n\t}\n\n\t// Load stats json for dependency resolution\n\tconst statsPath = path.resolve(storybookStaticDir, 'preview-stats.json');\n\tlet statsJson: StatsIndex;\n\ttry {\n\t\tstatsJson = JSON.parse(await fs.readFile(statsPath, 'utf-8'));\n\t} catch {\n\t\tlogger.warn('preview-stats.json not found, running all stories');\n\t\treturn { allStories: true, targetStories: storiesJson };\n\t}\n\n\tconst resolver = new StorybookStatsDependencyResolver(statsJson, storiesJson);\n\tconst targetStories: StoryIndex = { v: storiesJson.v, entries: {} };\n\n\t// Direct story file matches (both .stories.* and .mdx)\n\tfor (const file of allPaths) {\n\t\tconst matchedStories = Object.values(storiesJson.entries).filter(\n\t\t\t(story) => stripLeadingDotSlash(story.importPath) === file,\n\t\t);\n\t\tfor (const story of matchedStories) {\n\t\t\ttargetStories.entries[story.id] = story;\n\t\t}\n\t}\n\n\t// Dependency-based matches\n\tfor (const file of allPaths) {\n\t\tconst deps = resolver.getDependencies(normalizePath(file));\n\t\tconst depStories = resolver.getStoriesForFiles(deps);\n\t\tfor (const [id, story] of Object.entries(depStories.entries)) {\n\t\t\ttargetStories.entries[id] = story;\n\t\t}\n\t}\n\n\tlogger.info(`Resolved ${Object.keys(targetStories.entries).length} affected stories`);\n\treturn { allStories: false, targetStories };\n}\n","import path from 'node:path';\n\nexport function normalizePath(filePath: string): string {\n\tconst normalized = filePath.replace(/\\\\/g, '/');\n\tif (normalized.startsWith('./')) {\n\t\treturn normalized;\n\t}\n\treturn `./${normalized}`;\n}\n\nexport function stripLeadingDotSlash(filePath: string): string {\n\treturn filePath.replace(/^\\.\\//, '');\n}\n\nexport function resolveOutputDir(outputDir: string, ...segments: string[]): string {\n\treturn path.resolve(outputDir, ...segments);\n}\n","import { spawn } from 'node:child_process';\n\nexport interface ExecResult {\n\texitCode: number;\n\tstdout: string;\n\tstderr: string;\n}\n\nexport function exec(\n\tcommand: string,\n\targs: string[],\n\toptions?: { cwd?: string; env?: Record<string, string>; inherit?: boolean },\n): Promise<ExecResult> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst proc = spawn(command, args, {\n\t\t\tcwd: options?.cwd,\n\t\t\tenv: { ...process.env, ...options?.env },\n\t\t\tstdio: options?.inherit ? ['ignore', 'inherit', 'inherit'] : ['ignore', 'pipe', 'pipe'],\n\t\t\tshell: false,\n\t\t});\n\n\t\tlet stdout = '';\n\t\tlet stderr = '';\n\n\t\tif (!options?.inherit) {\n\t\t\tproc.stdout?.on('data', (data: Buffer) => {\n\t\t\t\tstdout += data.toString();\n\t\t\t});\n\n\t\t\tproc.stderr?.on('data', (data: Buffer) => {\n\t\t\t\tstderr += data.toString();\n\t\t\t});\n\t\t}\n\n\t\tproc.on('error', reject);\n\n\t\tproc.on('close', (code) => {\n\t\t\tresolve({ exitCode: code ?? 1, stdout, stderr });\n\t\t});\n\t});\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport picomatch from 'picomatch';\nimport type { StorywrightConfig } from '../config/types.js';\nimport { logger } from '../utils/logger.js';\nimport { exec } from '../utils/process.js';\nimport type { Story, StoryIndex } from './types.js';\n\nexport async function buildStorybook(config: StorywrightConfig, cwd: string): Promise<void> {\n\tif (config.storybook.url) {\n\t\tlogger.info('Using running Storybook at', config.storybook.url);\n\t\treturn;\n\t}\n\n\tconst staticDir = path.resolve(cwd, config.storybook.staticDir);\n\ttry {\n\t\tawait fs.access(path.join(staticDir, 'index.json'));\n\t\tlogger.info('Storybook already built at', staticDir);\n\t\treturn;\n\t} catch {\n\t\t// need to build\n\t}\n\n\tlogger.start('Building Storybook...');\n\tconst [command, ...args] = config.storybook.buildCommand.split(' ');\n\tconst result = await exec(command, args, { cwd });\n\tif (result.exitCode !== 0) {\n\t\tthrow new Error(\n\t\t\t`Storybook build failed (exit code ${result.exitCode}):\\n${result.stderr}\\n\\nError code: SW_E_STORYBOOK_BUILD_FAILED`,\n\t\t);\n\t}\n\tlogger.success('Storybook built');\n}\n\nexport async function discoverStories(config: StorywrightConfig, cwd: string): Promise<StoryIndex> {\n\tconst staticDir = path.resolve(cwd, config.storybook.staticDir);\n\tconst indexPath = path.join(staticDir, 'index.json');\n\n\ttry {\n\t\tawait fs.access(indexPath);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`Storybook build directory not found at '${config.storybook.staticDir}/'\\n\\n Run one of the following:\\n $ npx storybook build --stats-json\\n $ npx storywright test --storybook-url http://localhost:6006\\n\\n Error code: SW_E_STORYBOOK_DIR_NOT_FOUND`,\n\t\t);\n\t}\n\n\tconst raw = JSON.parse(await fs.readFile(indexPath, 'utf-8'));\n\tconst indexJson = normalizeStoryIndex(raw, config.storybook.compatibility);\n\n\t// Version check\n\tif (indexJson.v < 4) {\n\t\tthrow new Error(\n\t\t\t'Storybook 7.x or earlier is not supported. Storywright requires Storybook 8 or later.\\n\\nError code: SW_E_STORYBOOK_UNSUPPORTED',\n\t\t);\n\t}\n\n\treturn indexJson;\n}\n\n/**\n * Parse Storybook index.json (v8+).\n */\nfunction normalizeStoryIndex(\n\traw: Record<string, unknown>,\n\t_compatibility: 'auto' | 'v8',\n): StoryIndex {\n\tconst version = typeof raw.v === 'number' ? raw.v : 0;\n\tconst entries = (raw.entries ?? {}) as Record<string, Story>;\n\n\treturn { v: version, entries };\n}\n\nexport function filterStories(storyIndex: StoryIndex, config: StorywrightConfig): StoryIndex {\n\tconst entries: Record<string, Story> = {};\n\tconst includeMatchers = config.include.map((p) => picomatch(p));\n\tconst excludeMatchers = config.exclude.map((p) => picomatch(p));\n\n\tfor (const [id, story] of Object.entries(storyIndex.entries)) {\n\t\t// Skip docs entries\n\t\tif (story.type === 'docs') continue;\n\t\tif (story.name === 'Docs') continue;\n\n\t\tconst fullName = `${story.title}/${story.name}`;\n\n\t\t// Check include patterns\n\t\tconst isIncluded = includeMatchers.some((m) => m(fullName));\n\t\tif (!isIncluded) continue;\n\n\t\t// Check exclude patterns\n\t\tconst isExcluded = excludeMatchers.some((m) => m(fullName));\n\t\tif (isExcluded) continue;\n\n\t\tentries[id] = story;\n\t}\n\n\treturn { ...storyIndex, entries };\n}\n\nexport function excludeStoriesForBrowser(\n\tstoryIndex: StoryIndex,\n\texcludePatterns: string[],\n): StoryIndex {\n\tif (excludePatterns.length === 0) {\n\t\treturn storyIndex;\n\t}\n\n\tconst excludeMatchers = excludePatterns.map((p) => picomatch(p));\n\tconst entries: Record<string, Story> = {};\n\n\tfor (const [id, story] of Object.entries(storyIndex.entries)) {\n\t\tconst fullName = `${story.title}/${story.name}`;\n\t\tconst isExcluded = excludeMatchers.some((m) => m(fullName));\n\t\tif (!isExcluded) {\n\t\t\tentries[id] = story;\n\t\t}\n\t}\n\n\treturn { ...storyIndex, entries };\n}\n"],"mappings":"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","names":["fs","path","picomatch","testMatchLine","escapeBackslash","fs","path","path","path","fs","fs","path","picomatch","path","fs","picomatch","path","fs","picomatch"]}
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  logger,
7
7
  runTests,
8
8
  updateBaselines
9
- } from "./chunk-XYP273ZX.js";
9
+ } from "./chunk-4KFNGY6R.js";
10
10
  import {
11
11
  generateHtmlReport
12
12
  } from "./chunk-HPK2VJXG.js";
@@ -31,7 +31,7 @@ var downloadCommand = defineCommand({
31
31
  },
32
32
  async run({ args }) {
33
33
  const config = await loadConfig();
34
- const storage = createStorageAdapter(config.storage);
34
+ const storage = await createStorageAdapter(config.storage);
35
35
  const destDir = path.resolve(config.storage.local.baselineDir);
36
36
  const branch = args.branch ?? "main";
37
37
  if (storage instanceof LocalStorageAdapter) {
@@ -336,11 +336,46 @@ var updateCommand = defineCommand5({
336
336
  type: "boolean",
337
337
  description: "Upload baselines after update",
338
338
  default: false
339
+ },
340
+ browsers: {
341
+ type: "string",
342
+ description: "Browsers to test (comma-separated)"
343
+ },
344
+ shard: {
345
+ type: "string",
346
+ description: "Shard specification (index/total)"
347
+ },
348
+ workers: {
349
+ type: "string",
350
+ description: "Number of parallel workers"
351
+ },
352
+ filter: {
353
+ type: "string",
354
+ description: "Filter stories by glob pattern"
355
+ },
356
+ retries: {
357
+ type: "string",
358
+ description: "Number of retries for failed tests"
339
359
  }
340
360
  },
341
361
  async run({ args }) {
342
- const config = await loadConfig();
343
- await updateBaselines(config, { all: args.all, upload: args.upload });
362
+ const overrides = {};
363
+ if (args.browsers) {
364
+ overrides.browsers = args.browsers.split(",").map((b) => b.trim());
365
+ }
366
+ if (args.workers) {
367
+ overrides.workers = args.workers === "auto" ? "auto" : Number(args.workers);
368
+ }
369
+ if (args.retries) {
370
+ overrides.retries = Number(args.retries);
371
+ }
372
+ const config = await loadConfig(process.cwd(), overrides);
373
+ await updateBaselines(config, {
374
+ all: args.all,
375
+ upload: args.upload,
376
+ shard: args.shard,
377
+ filter: args.filter
378
+ });
344
379
  }
345
380
  });
346
381
 
@@ -355,7 +390,7 @@ var uploadCommand = defineCommand6({
355
390
  args: {},
356
391
  async run() {
357
392
  const config = await loadConfig();
358
- const storage = createStorageAdapter(config.storage);
393
+ const storage = await createStorageAdapter(config.storage);
359
394
  const snapshotDir = path4.resolve(config.storage.local.baselineDir);
360
395
  logger.start("Uploading baselines...");
361
396
  await storage.upload({
@@ -370,7 +405,7 @@ var uploadCommand = defineCommand6({
370
405
  var main = defineCommand7({
371
406
  meta: {
372
407
  name: "storywright",
373
- version: "0.5.0",
408
+ version: "0.5.2",
374
409
  description: "Zero-config visual regression testing powered by Storybook + Playwright"
375
410
  },
376
411
  subCommands: {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/index.ts","../src/cli/commands/download.ts","../src/cli/commands/init.ts","../src/cli/commands/report.ts","../src/cli/commands/test.ts","../src/cli/commands/update.ts","../src/cli/commands/upload.ts"],"sourcesContent":["import { defineCommand, runMain } from 'citty';\nimport { downloadCommand } from './commands/download.js';\nimport { initCommand } from './commands/init.js';\nimport { reportCommand } from './commands/report.js';\nimport { testCommand } from './commands/test.js';\nimport { updateCommand } from './commands/update.js';\nimport { uploadCommand } from './commands/upload.js';\n\nconst main = defineCommand({\n\tmeta: {\n\t\tname: 'storywright',\n\t\tversion: __PKG_VERSION__,\n\t\tdescription: 'Zero-config visual regression testing powered by Storybook + Playwright',\n\t},\n\tsubCommands: {\n\t\ttest: testCommand,\n\t\tupdate: updateCommand,\n\t\tupload: uploadCommand,\n\t\tdownload: downloadCommand,\n\t\treport: reportCommand,\n\t\tinit: initCommand,\n\t},\n});\n\nrunMain(main);\n","import path from 'node:path';\nimport { defineCommand } from 'citty';\nimport { loadConfig } from '../../config/index.js';\nimport { createStorageAdapter } from '../../storage/index.js';\nimport { LocalStorageAdapter } from '../../storage/local.js';\nimport { logger } from '../../utils/logger.js';\n\nexport const downloadCommand = defineCommand({\n\tmeta: {\n\t\tname: 'download',\n\t\tdescription: 'Download baselines from storage',\n\t},\n\targs: {\n\t\tbranch: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Branch to download baselines from',\n\t\t\tdefault: 'main',\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst config = await loadConfig();\n\t\tconst storage = createStorageAdapter(config.storage);\n\t\tconst destDir = path.resolve(config.storage.local.baselineDir);\n\t\tconst branch = args.branch ?? 'main';\n\n\t\tif (storage instanceof LocalStorageAdapter) {\n\t\t\tlogger.start(`Extracting baselines from git branch '${branch}'...`);\n\t\t\ttry {\n\t\t\t\tawait storage.downloadFromGit(branch, destDir, process.cwd());\n\t\t\t\tlogger.success('Baselines extracted from git');\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(String(error));\n\t\t\t\tlogger.info(\n\t\t\t\t\t'Hint: ensure you are in a git repository with sufficient history (fetch-depth: 0)',\n\t\t\t\t);\n\t\t\t\tprocess.exit(2);\n\t\t\t}\n\t\t} else {\n\t\t\tlogger.start(`Downloading baselines from ${branch}...`);\n\t\t\tawait storage.download({ branch, destDir });\n\t\t\tlogger.success('Baselines downloaded');\n\t\t}\n\t},\n});\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { defineCommand } from 'citty';\nimport { logger } from '../../utils/logger.js';\n\nconst CONFIG_TEMPLATE = `import { defineConfig } from '@storywright/cli';\n\nexport default defineConfig({\n\\t// Storybook settings\n\\tstorybook: {\n\\t\\tstaticDir: 'storybook-static',\n\\t},\n\n\\t// Browsers to test\n\\tbrowsers: ['chromium'],\n\n\\t// Screenshot settings\n\\tscreenshot: {\n\\t\\tfullPage: true,\n\\t\\tanimations: 'disabled',\n\\t\\tthreshold: 0.02,\n\\t\\tmaxDiffPixelRatio: 0.02,\n\\t},\n\n\\t// Storage settings\n\\tstorage: {\n\\t\\tprovider: 'local',\n\\t},\n});\n`;\n\nexport const initCommand = defineCommand({\n\tmeta: {\n\t\tname: 'init',\n\t\tdescription: 'Initialize storywright configuration',\n\t},\n\targs: {},\n\tasync run() {\n\t\tconst configPath = path.resolve('storywright.config.ts');\n\t\ttry {\n\t\t\tawait fs.access(configPath);\n\t\t\tlogger.warn('storywright.config.ts already exists');\n\t\t\treturn;\n\t\t} catch {\n\t\t\t// file doesn't exist, create it\n\t\t}\n\n\t\tawait fs.writeFile(configPath, CONFIG_TEMPLATE);\n\t\tlogger.success('Created storywright.config.ts');\n\n\t\t// Add .storywright temp/report dirs to .gitignore if exists\n\t\t// Note: .storywright/baselines/ should be tracked by git\n\t\tconst gitignorePath = path.resolve('.gitignore');\n\t\ttry {\n\t\t\tconst content = await fs.readFile(gitignorePath, 'utf-8');\n\t\t\tif (!content.includes('.storywright')) {\n\t\t\t\tawait fs.appendFile(\n\t\t\t\t\tgitignorePath,\n\t\t\t\t\t'\\n# Storywright\\n.storywright/tmp/\\n.storywright/report/\\n',\n\t\t\t\t);\n\t\t\t\tlogger.info('Added .storywright/tmp/ and .storywright/report/ to .gitignore');\n\t\t\t}\n\t\t} catch {\n\t\t\t// no .gitignore\n\t\t}\n\t},\n});\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { defineCommand } from 'citty';\nimport picomatch from 'picomatch';\nimport { loadConfig } from '../../config/index.js';\nimport type { TestSummary } from '../../core/types.js';\nimport { generateHtmlReport } from '../../playwright/reporter.js';\nimport { logger } from '../../utils/logger.js';\n\nasync function globFiles(pattern: string, cwd: string): Promise<string[]> {\n\tconst matcher = picomatch(pattern);\n\tconst results: string[] = [];\n\n\tasync function walk(dir: string): Promise<void> {\n\t\tconst entries = await fs.readdir(dir, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = path.join(dir, entry.name);\n\t\t\tconst relativePath = path.relative(cwd, fullPath).replace(/\\\\/g, '/');\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tawait walk(fullPath);\n\t\t\t} else if (matcher(relativePath)) {\n\t\t\t\tresults.push(fullPath);\n\t\t\t}\n\t\t}\n\t}\n\n\tawait walk(cwd);\n\treturn results;\n}\n\nexport const reportCommand = defineCommand({\n\tmeta: {\n\t\tname: 'report',\n\t\tdescription: 'Generate or open the report',\n\t},\n\targs: {\n\t\topen: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Open report in browser',\n\t\t\tdefault: false,\n\t\t},\n\t\tmerge: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Merge multiple summary files',\n\t\t\tdefault: false,\n\t\t},\n\t\tfrom: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Glob pattern for summary files to merge',\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst config = await loadConfig();\n\t\tconst reportDir = path.resolve(config.report.outputDir);\n\n\t\tif (args.merge && args.from) {\n\t\t\tlogger.start('Merging reports...');\n\t\t\tconst files = await globFiles(args.from, process.cwd());\n\n\t\t\tconst merged: TestSummary = {\n\t\t\t\ttotal: 0,\n\t\t\t\tpassed: 0,\n\t\t\t\tfailed: 0,\n\t\t\t\tskipped: 0,\n\t\t\t\tduration: 0,\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tbrowsers: [],\n\t\t\t\tfailures: [],\n\t\t\t};\n\n\t\t\tfor (const file of files) {\n\t\t\t\tconst content = await fs.readFile(file, 'utf-8');\n\t\t\t\tconst summary: TestSummary = JSON.parse(content);\n\t\t\t\tmerged.total += summary.total;\n\t\t\t\tmerged.passed += summary.passed;\n\t\t\t\tmerged.failed += summary.failed;\n\t\t\t\tmerged.skipped += summary.skipped;\n\t\t\t\tmerged.duration = Math.max(merged.duration, summary.duration);\n\t\t\t\tmerged.browsers = [...new Set([...merged.browsers, ...summary.browsers])];\n\t\t\t\tmerged.failures.push(...summary.failures);\n\t\t\t}\n\n\t\t\tawait fs.mkdir(reportDir, { recursive: true });\n\t\t\tawait fs.writeFile(path.join(reportDir, 'summary.json'), JSON.stringify(merged, null, 2));\n\n\t\t\tconst html = generateHtmlReport(merged);\n\t\t\tawait fs.writeFile(path.join(reportDir, 'index.html'), html);\n\t\t\tlogger.success(`Merged ${files.length} reports → index.html generated`);\n\t\t}\n\n\t\tif (args.open) {\n\t\t\tconst reportPath = path.join(reportDir, 'index.html');\n\t\t\tconst { exec: execCb } = await import('node:child_process');\n\t\t\tconst platform = process.platform;\n\t\t\tconst cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'start' : 'xdg-open';\n\t\t\texecCb(`${cmd} ${reportPath}`);\n\t\t\tlogger.success('Report opened');\n\t\t}\n\t},\n});\n","import { defineCommand } from 'citty';\nimport { loadConfig } from '../../config/index.js';\nimport type { DeepPartial, StorywrightConfig } from '../../config/types.js';\nimport { runTests } from '../../core/engine.js';\nimport { formatSummary } from '../../reporter/cli-reporter.js';\n\nexport const testCommand = defineCommand({\n\tmeta: {\n\t\tname: 'test',\n\t\tdescription: 'Run visual regression tests',\n\t},\n\targs: {\n\t\tbrowsers: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Browsers to test (comma-separated)',\n\t\t},\n\t\tshard: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Shard specification (index/total)',\n\t\t},\n\t\t'diff-only': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Only test stories affected by git changes',\n\t\t\tdefault: false,\n\t\t},\n\t\tthreshold: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Pixel color threshold (0-1)',\n\t\t},\n\t\t'max-diff-pixel-ratio': {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Maximum diff pixel ratio (0-1)',\n\t\t},\n\t\t'storybook-url': {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'URL of running Storybook',\n\t\t},\n\t\t'storybook-dir': {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Storybook build directory',\n\t\t},\n\t\t'update-snapshots': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Update baseline snapshots',\n\t\t\tdefault: false,\n\t\t},\n\t\t'full-page': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Take full page screenshots',\n\t\t},\n\t\tworkers: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Number of parallel workers',\n\t\t},\n\t\tretries: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Number of retries for failed tests',\n\t\t},\n\t\tfilter: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Filter stories by glob pattern',\n\t\t},\n\t\t'output-dir': {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Output root directory (.storywright by default)',\n\t\t},\n\t\treporters: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Reporters (comma-separated, e.g. default,html)',\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst overrides: DeepPartial<StorywrightConfig> = {};\n\n\t\tif (args.browsers) {\n\t\t\toverrides.browsers = args.browsers.split(',').map((b) => b.trim());\n\t\t}\n\t\tif (args.threshold) {\n\t\t\toverrides.screenshot = { ...overrides.screenshot, threshold: Number(args.threshold) };\n\t\t}\n\t\tif (args['max-diff-pixel-ratio']) {\n\t\t\toverrides.screenshot = {\n\t\t\t\t...overrides.screenshot,\n\t\t\t\tmaxDiffPixelRatio: Number(args['max-diff-pixel-ratio']),\n\t\t\t};\n\t\t}\n\t\tif (args['storybook-url']) {\n\t\t\toverrides.storybook = { ...overrides.storybook, url: args['storybook-url'] };\n\t\t}\n\t\tif (args['storybook-dir']) {\n\t\t\toverrides.storybook = { ...overrides.storybook, staticDir: args['storybook-dir'] };\n\t\t}\n\t\tif (args['full-page'] !== undefined) {\n\t\t\toverrides.screenshot = { ...overrides.screenshot, fullPage: args['full-page'] };\n\t\t}\n\t\tif (args.workers) {\n\t\t\toverrides.workers = args.workers === 'auto' ? 'auto' : Number(args.workers);\n\t\t}\n\t\tif (args.retries) {\n\t\t\toverrides.retries = Number(args.retries);\n\t\t}\n\n\t\tconst config = await loadConfig(process.cwd(), overrides);\n\t\tconst result = await runTests(\n\t\t\tconfig,\n\t\t\t{\n\t\t\t\tdiffOnly: args['diff-only'],\n\t\t\t\tshard: args.shard,\n\t\t\t\tupdateSnapshots: args['update-snapshots'],\n\t\t\t\tfilter: args.filter,\n\t\t\t\toutputDir: args['output-dir'],\n\t\t\t\treporters: args.reporters?.split(',').map((r) => r.trim()),\n\t\t\t},\n\t\t\tprocess.cwd(),\n\t\t);\n\n\t\tif (result.summary) {\n\t\t\tconst reportPath = result.reportDir ? `${result.reportDir}/index.html` : undefined;\n\t\t\tconsole.log(formatSummary(result.summary, { reportPath }));\n\t\t}\n\n\t\tprocess.exit(result.exitCode);\n\t},\n});\n","import { defineCommand } from 'citty';\nimport { loadConfig } from '../../config/index.js';\nimport { updateBaselines } from '../../core/engine.js';\n\nexport const updateCommand = defineCommand({\n\tmeta: {\n\t\tname: 'update',\n\t\tdescription: 'Update baseline snapshots',\n\t},\n\targs: {\n\t\tall: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Regenerate all baselines',\n\t\t\tdefault: false,\n\t\t},\n\t\tupload: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Upload baselines after update',\n\t\t\tdefault: false,\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst config = await loadConfig();\n\t\tawait updateBaselines(config, { all: args.all, upload: args.upload });\n\t},\n});\n","import path from 'node:path';\nimport { defineCommand } from 'citty';\nimport { loadConfig } from '../../config/index.js';\nimport { createStorageAdapter } from '../../storage/index.js';\nimport { logger } from '../../utils/logger.js';\n\nexport const uploadCommand = defineCommand({\n\tmeta: {\n\t\tname: 'upload',\n\t\tdescription: 'Upload baselines to remote storage',\n\t},\n\targs: {},\n\tasync run() {\n\t\tconst config = await loadConfig();\n\t\tconst storage = createStorageAdapter(config.storage);\n\t\tconst snapshotDir = path.resolve(config.storage.local.baselineDir);\n\n\t\tlogger.start('Uploading baselines...');\n\t\tawait storage.upload({\n\t\t\tbranch: 'current',\n\t\t\tsourceDir: snapshotDir,\n\t\t});\n\t\tlogger.success('Baselines uploaded');\n\t},\n});\n"],"mappings":"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","names":["defineCommand","path","defineCommand","defineCommand","path","fs","path","defineCommand","fs","path","defineCommand","defineCommand","defineCommand","defineCommand","defineCommand","path","defineCommand","defineCommand","path","defineCommand"]}
1
+ {"version":3,"sources":["../src/cli/index.ts","../src/cli/commands/download.ts","../src/cli/commands/init.ts","../src/cli/commands/report.ts","../src/cli/commands/test.ts","../src/cli/commands/update.ts","../src/cli/commands/upload.ts"],"sourcesContent":["import { defineCommand, runMain } from 'citty';\nimport { downloadCommand } from './commands/download.js';\nimport { initCommand } from './commands/init.js';\nimport { reportCommand } from './commands/report.js';\nimport { testCommand } from './commands/test.js';\nimport { updateCommand } from './commands/update.js';\nimport { uploadCommand } from './commands/upload.js';\n\nconst main = defineCommand({\n\tmeta: {\n\t\tname: 'storywright',\n\t\tversion: __PKG_VERSION__,\n\t\tdescription: 'Zero-config visual regression testing powered by Storybook + Playwright',\n\t},\n\tsubCommands: {\n\t\ttest: testCommand,\n\t\tupdate: updateCommand,\n\t\tupload: uploadCommand,\n\t\tdownload: downloadCommand,\n\t\treport: reportCommand,\n\t\tinit: initCommand,\n\t},\n});\n\nrunMain(main);\n","import path from 'node:path';\nimport { defineCommand } from 'citty';\nimport { loadConfig } from '../../config/index.js';\nimport { createStorageAdapter } from '../../storage/index.js';\nimport { LocalStorageAdapter } from '../../storage/local.js';\nimport { logger } from '../../utils/logger.js';\n\nexport const downloadCommand = defineCommand({\n\tmeta: {\n\t\tname: 'download',\n\t\tdescription: 'Download baselines from storage',\n\t},\n\targs: {\n\t\tbranch: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Branch to download baselines from',\n\t\t\tdefault: 'main',\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst config = await loadConfig();\n\t\tconst storage = await createStorageAdapter(config.storage);\n\t\tconst destDir = path.resolve(config.storage.local.baselineDir);\n\t\tconst branch = args.branch ?? 'main';\n\n\t\tif (storage instanceof LocalStorageAdapter) {\n\t\t\tlogger.start(`Extracting baselines from git branch '${branch}'...`);\n\t\t\ttry {\n\t\t\t\tawait storage.downloadFromGit(branch, destDir, process.cwd());\n\t\t\t\tlogger.success('Baselines extracted from git');\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(String(error));\n\t\t\t\tlogger.info(\n\t\t\t\t\t'Hint: ensure you are in a git repository with sufficient history (fetch-depth: 0)',\n\t\t\t\t);\n\t\t\t\tprocess.exit(2);\n\t\t\t}\n\t\t} else {\n\t\t\tlogger.start(`Downloading baselines from ${branch}...`);\n\t\t\tawait storage.download({ branch, destDir });\n\t\t\tlogger.success('Baselines downloaded');\n\t\t}\n\t},\n});\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { defineCommand } from 'citty';\nimport { logger } from '../../utils/logger.js';\n\nconst CONFIG_TEMPLATE = `import { defineConfig } from '@storywright/cli';\n\nexport default defineConfig({\n\\t// Storybook settings\n\\tstorybook: {\n\\t\\tstaticDir: 'storybook-static',\n\\t},\n\n\\t// Browsers to test\n\\tbrowsers: ['chromium'],\n\n\\t// Screenshot settings\n\\tscreenshot: {\n\\t\\tfullPage: true,\n\\t\\tanimations: 'disabled',\n\\t\\tthreshold: 0.02,\n\\t\\tmaxDiffPixelRatio: 0.02,\n\\t},\n\n\\t// Storage settings\n\\tstorage: {\n\\t\\tprovider: 'local',\n\\t},\n});\n`;\n\nexport const initCommand = defineCommand({\n\tmeta: {\n\t\tname: 'init',\n\t\tdescription: 'Initialize storywright configuration',\n\t},\n\targs: {},\n\tasync run() {\n\t\tconst configPath = path.resolve('storywright.config.ts');\n\t\ttry {\n\t\t\tawait fs.access(configPath);\n\t\t\tlogger.warn('storywright.config.ts already exists');\n\t\t\treturn;\n\t\t} catch {\n\t\t\t// file doesn't exist, create it\n\t\t}\n\n\t\tawait fs.writeFile(configPath, CONFIG_TEMPLATE);\n\t\tlogger.success('Created storywright.config.ts');\n\n\t\t// Add .storywright temp/report dirs to .gitignore if exists\n\t\t// Note: .storywright/baselines/ should be tracked by git\n\t\tconst gitignorePath = path.resolve('.gitignore');\n\t\ttry {\n\t\t\tconst content = await fs.readFile(gitignorePath, 'utf-8');\n\t\t\tif (!content.includes('.storywright')) {\n\t\t\t\tawait fs.appendFile(\n\t\t\t\t\tgitignorePath,\n\t\t\t\t\t'\\n# Storywright\\n.storywright/tmp/\\n.storywright/report/\\n',\n\t\t\t\t);\n\t\t\t\tlogger.info('Added .storywright/tmp/ and .storywright/report/ to .gitignore');\n\t\t\t}\n\t\t} catch {\n\t\t\t// no .gitignore\n\t\t}\n\t},\n});\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { defineCommand } from 'citty';\nimport picomatch from 'picomatch';\nimport { loadConfig } from '../../config/index.js';\nimport type { TestSummary } from '../../core/types.js';\nimport { generateHtmlReport } from '../../playwright/reporter.js';\nimport { logger } from '../../utils/logger.js';\n\nasync function globFiles(pattern: string, cwd: string): Promise<string[]> {\n\tconst matcher = picomatch(pattern);\n\tconst results: string[] = [];\n\n\tasync function walk(dir: string): Promise<void> {\n\t\tconst entries = await fs.readdir(dir, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = path.join(dir, entry.name);\n\t\t\tconst relativePath = path.relative(cwd, fullPath).replace(/\\\\/g, '/');\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tawait walk(fullPath);\n\t\t\t} else if (matcher(relativePath)) {\n\t\t\t\tresults.push(fullPath);\n\t\t\t}\n\t\t}\n\t}\n\n\tawait walk(cwd);\n\treturn results;\n}\n\nexport const reportCommand = defineCommand({\n\tmeta: {\n\t\tname: 'report',\n\t\tdescription: 'Generate or open the report',\n\t},\n\targs: {\n\t\topen: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Open report in browser',\n\t\t\tdefault: false,\n\t\t},\n\t\tmerge: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Merge multiple summary files',\n\t\t\tdefault: false,\n\t\t},\n\t\tfrom: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Glob pattern for summary files to merge',\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst config = await loadConfig();\n\t\tconst reportDir = path.resolve(config.report.outputDir);\n\n\t\tif (args.merge && args.from) {\n\t\t\tlogger.start('Merging reports...');\n\t\t\tconst files = await globFiles(args.from, process.cwd());\n\n\t\t\tconst merged: TestSummary = {\n\t\t\t\ttotal: 0,\n\t\t\t\tpassed: 0,\n\t\t\t\tfailed: 0,\n\t\t\t\tskipped: 0,\n\t\t\t\tduration: 0,\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tbrowsers: [],\n\t\t\t\tfailures: [],\n\t\t\t};\n\n\t\t\tfor (const file of files) {\n\t\t\t\tconst content = await fs.readFile(file, 'utf-8');\n\t\t\t\tconst summary: TestSummary = JSON.parse(content);\n\t\t\t\tmerged.total += summary.total;\n\t\t\t\tmerged.passed += summary.passed;\n\t\t\t\tmerged.failed += summary.failed;\n\t\t\t\tmerged.skipped += summary.skipped;\n\t\t\t\tmerged.duration = Math.max(merged.duration, summary.duration);\n\t\t\t\tmerged.browsers = [...new Set([...merged.browsers, ...summary.browsers])];\n\t\t\t\tmerged.failures.push(...summary.failures);\n\t\t\t}\n\n\t\t\tawait fs.mkdir(reportDir, { recursive: true });\n\t\t\tawait fs.writeFile(path.join(reportDir, 'summary.json'), JSON.stringify(merged, null, 2));\n\n\t\t\tconst html = generateHtmlReport(merged);\n\t\t\tawait fs.writeFile(path.join(reportDir, 'index.html'), html);\n\t\t\tlogger.success(`Merged ${files.length} reports → index.html generated`);\n\t\t}\n\n\t\tif (args.open) {\n\t\t\tconst reportPath = path.join(reportDir, 'index.html');\n\t\t\tconst { exec: execCb } = await import('node:child_process');\n\t\t\tconst platform = process.platform;\n\t\t\tconst cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'start' : 'xdg-open';\n\t\t\texecCb(`${cmd} ${reportPath}`);\n\t\t\tlogger.success('Report opened');\n\t\t}\n\t},\n});\n","import { defineCommand } from 'citty';\nimport { loadConfig } from '../../config/index.js';\nimport type { DeepPartial, StorywrightConfig } from '../../config/types.js';\nimport { runTests } from '../../core/engine.js';\nimport { formatSummary } from '../../reporter/cli-reporter.js';\n\nexport const testCommand = defineCommand({\n\tmeta: {\n\t\tname: 'test',\n\t\tdescription: 'Run visual regression tests',\n\t},\n\targs: {\n\t\tbrowsers: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Browsers to test (comma-separated)',\n\t\t},\n\t\tshard: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Shard specification (index/total)',\n\t\t},\n\t\t'diff-only': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Only test stories affected by git changes',\n\t\t\tdefault: false,\n\t\t},\n\t\tthreshold: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Pixel color threshold (0-1)',\n\t\t},\n\t\t'max-diff-pixel-ratio': {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Maximum diff pixel ratio (0-1)',\n\t\t},\n\t\t'storybook-url': {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'URL of running Storybook',\n\t\t},\n\t\t'storybook-dir': {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Storybook build directory',\n\t\t},\n\t\t'update-snapshots': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Update baseline snapshots',\n\t\t\tdefault: false,\n\t\t},\n\t\t'full-page': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Take full page screenshots',\n\t\t},\n\t\tworkers: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Number of parallel workers',\n\t\t},\n\t\tretries: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Number of retries for failed tests',\n\t\t},\n\t\tfilter: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Filter stories by glob pattern',\n\t\t},\n\t\t'output-dir': {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Output root directory (.storywright by default)',\n\t\t},\n\t\treporters: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Reporters (comma-separated, e.g. default,html)',\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst overrides: DeepPartial<StorywrightConfig> = {};\n\n\t\tif (args.browsers) {\n\t\t\toverrides.browsers = args.browsers.split(',').map((b) => b.trim());\n\t\t}\n\t\tif (args.threshold) {\n\t\t\toverrides.screenshot = { ...overrides.screenshot, threshold: Number(args.threshold) };\n\t\t}\n\t\tif (args['max-diff-pixel-ratio']) {\n\t\t\toverrides.screenshot = {\n\t\t\t\t...overrides.screenshot,\n\t\t\t\tmaxDiffPixelRatio: Number(args['max-diff-pixel-ratio']),\n\t\t\t};\n\t\t}\n\t\tif (args['storybook-url']) {\n\t\t\toverrides.storybook = { ...overrides.storybook, url: args['storybook-url'] };\n\t\t}\n\t\tif (args['storybook-dir']) {\n\t\t\toverrides.storybook = { ...overrides.storybook, staticDir: args['storybook-dir'] };\n\t\t}\n\t\tif (args['full-page'] !== undefined) {\n\t\t\toverrides.screenshot = { ...overrides.screenshot, fullPage: args['full-page'] };\n\t\t}\n\t\tif (args.workers) {\n\t\t\toverrides.workers = args.workers === 'auto' ? 'auto' : Number(args.workers);\n\t\t}\n\t\tif (args.retries) {\n\t\t\toverrides.retries = Number(args.retries);\n\t\t}\n\n\t\tconst config = await loadConfig(process.cwd(), overrides);\n\t\tconst result = await runTests(\n\t\t\tconfig,\n\t\t\t{\n\t\t\t\tdiffOnly: args['diff-only'],\n\t\t\t\tshard: args.shard,\n\t\t\t\tupdateSnapshots: args['update-snapshots'],\n\t\t\t\tfilter: args.filter,\n\t\t\t\toutputDir: args['output-dir'],\n\t\t\t\treporters: args.reporters?.split(',').map((r) => r.trim()),\n\t\t\t},\n\t\t\tprocess.cwd(),\n\t\t);\n\n\t\tif (result.summary) {\n\t\t\tconst reportPath = result.reportDir ? `${result.reportDir}/index.html` : undefined;\n\t\t\tconsole.log(formatSummary(result.summary, { reportPath }));\n\t\t}\n\n\t\tprocess.exit(result.exitCode);\n\t},\n});\n","import { defineCommand } from 'citty';\nimport { loadConfig } from '../../config/index.js';\nimport type { DeepPartial, StorywrightConfig } from '../../config/types.js';\nimport { updateBaselines } from '../../core/engine.js';\n\nexport const updateCommand = defineCommand({\n\tmeta: {\n\t\tname: 'update',\n\t\tdescription: 'Update baseline snapshots',\n\t},\n\targs: {\n\t\tall: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Regenerate all baselines',\n\t\t\tdefault: false,\n\t\t},\n\t\tupload: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Upload baselines after update',\n\t\t\tdefault: false,\n\t\t},\n\t\tbrowsers: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Browsers to test (comma-separated)',\n\t\t},\n\t\tshard: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Shard specification (index/total)',\n\t\t},\n\t\tworkers: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Number of parallel workers',\n\t\t},\n\t\tfilter: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Filter stories by glob pattern',\n\t\t},\n\t\tretries: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Number of retries for failed tests',\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst overrides: DeepPartial<StorywrightConfig> = {};\n\n\t\tif (args.browsers) {\n\t\t\toverrides.browsers = args.browsers.split(',').map((b) => b.trim());\n\t\t}\n\t\tif (args.workers) {\n\t\t\toverrides.workers = args.workers === 'auto' ? 'auto' : Number(args.workers);\n\t\t}\n\t\tif (args.retries) {\n\t\t\toverrides.retries = Number(args.retries);\n\t\t}\n\n\t\tconst config = await loadConfig(process.cwd(), overrides);\n\t\tawait updateBaselines(config, {\n\t\t\tall: args.all,\n\t\t\tupload: args.upload,\n\t\t\tshard: args.shard,\n\t\t\tfilter: args.filter,\n\t\t});\n\t},\n});\n","import path from 'node:path';\nimport { defineCommand } from 'citty';\nimport { loadConfig } from '../../config/index.js';\nimport { createStorageAdapter } from '../../storage/index.js';\nimport { logger } from '../../utils/logger.js';\n\nexport const uploadCommand = defineCommand({\n\tmeta: {\n\t\tname: 'upload',\n\t\tdescription: 'Upload baselines to remote storage',\n\t},\n\targs: {},\n\tasync run() {\n\t\tconst config = await loadConfig();\n\t\tconst storage = await createStorageAdapter(config.storage);\n\t\tconst snapshotDir = path.resolve(config.storage.local.baselineDir);\n\n\t\tlogger.start('Uploading baselines...');\n\t\tawait storage.upload({\n\t\t\tbranch: 'current',\n\t\t\tsourceDir: snapshotDir,\n\t\t});\n\t\tlogger.success('Baselines uploaded');\n\t},\n});\n"],"mappings":"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","names":["defineCommand","path","defineCommand","defineCommand","path","fs","path","defineCommand","fs","path","defineCommand","defineCommand","defineCommand","defineCommand","defineCommand","path","defineCommand","defineCommand","path","defineCommand"]}
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  loadConfig,
7
7
  runTests,
8
8
  updateBaselines
9
- } from "./chunk-XYP273ZX.js";
9
+ } from "./chunk-4KFNGY6R.js";
10
10
 
11
11
  // src/core/index.ts
12
12
  import path from "path";
@@ -33,14 +33,14 @@ async function createStorywright(userConfig, cwd = process.cwd()) {
33
33
  await updateBaselines(config, { all: options.all }, cwd);
34
34
  },
35
35
  async upload() {
36
- const storage = createStorageAdapter(config.storage);
36
+ const storage = await createStorageAdapter(config.storage);
37
37
  await storage.upload({
38
38
  branch: "current",
39
39
  sourceDir: path.resolve(cwd, config.storage.local.baselineDir)
40
40
  });
41
41
  },
42
42
  async download(options = {}) {
43
- const storage = createStorageAdapter(config.storage);
43
+ const storage = await createStorageAdapter(config.storage);
44
44
  const destDir = path.resolve(cwd, config.storage.local.baselineDir);
45
45
  const branch = options.branch ?? "main";
46
46
  if (storage instanceof LocalStorageAdapter) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/index.ts"],"sourcesContent":["import path from 'node:path';\nimport { loadConfig } from '../config/index.js';\nimport type { DeepPartial, StorywrightConfig } from '../config/types.js';\nimport { formatSummary } from '../reporter/cli-reporter.js';\nimport { createStorageAdapter } from '../storage/index.js';\nimport { LocalStorageAdapter } from '../storage/local.js';\nimport { type TestRunResult, runTests, updateBaselines } from './engine.js';\n\nexport interface Storywright {\n\ttest(options?: {\n\t\tdiffOnly?: boolean;\n\t\tbrowsers?: string[];\n\t\tshard?: string;\n\t\tfilter?: string;\n\t}): Promise<TestRunResult>;\n\n\tupdate(options?: { all?: boolean }): Promise<void>;\n\tupload(): Promise<void>;\n\tdownload(options?: { branch?: string }): Promise<void>;\n\tgenerateReport(result: TestRunResult): string | undefined;\n}\n\nexport async function createStorywright(\n\tuserConfig?: DeepPartial<StorywrightConfig>,\n\tcwd: string = process.cwd(),\n): Promise<Storywright> {\n\tconst config = await loadConfig(cwd, userConfig);\n\n\treturn {\n\t\tasync test(options = {}) {\n\t\t\tconst overrides: DeepPartial<StorywrightConfig> = {};\n\t\t\tif (options.browsers) {\n\t\t\t\toverrides.browsers = options.browsers;\n\t\t\t}\n\t\t\tconst mergedConfig = options.browsers\n\t\t\t\t? await loadConfig(cwd, { ...userConfig, ...overrides })\n\t\t\t\t: config;\n\n\t\t\treturn runTests(\n\t\t\t\tmergedConfig,\n\t\t\t\t{\n\t\t\t\t\tdiffOnly: options.diffOnly,\n\t\t\t\t\tshard: options.shard,\n\t\t\t\t\tfilter: options.filter,\n\t\t\t\t},\n\t\t\t\tcwd,\n\t\t\t);\n\t\t},\n\n\t\tasync update(options = {}) {\n\t\t\tawait updateBaselines(config, { all: options.all }, cwd);\n\t\t},\n\n\t\tasync upload() {\n\t\t\tconst storage = createStorageAdapter(config.storage);\n\t\t\tawait storage.upload({\n\t\t\t\tbranch: 'current',\n\t\t\t\tsourceDir: path.resolve(cwd, config.storage.local.baselineDir),\n\t\t\t});\n\t\t},\n\n\t\tasync download(options = {}) {\n\t\t\tconst storage = createStorageAdapter(config.storage);\n\t\t\tconst destDir = path.resolve(cwd, config.storage.local.baselineDir);\n\t\t\tconst branch = options.branch ?? 'main';\n\n\t\t\tif (storage instanceof LocalStorageAdapter) {\n\t\t\t\tawait storage.downloadFromGit(branch, destDir, cwd);\n\t\t\t} else {\n\t\t\t\tawait storage.download({ branch, destDir });\n\t\t\t}\n\t\t},\n\n\t\tgenerateReport(result: TestRunResult): string | undefined {\n\t\t\tif (result.summary) {\n\t\t\t\tconst reportPath = result.reportDir ? `${result.reportDir}/index.html` : undefined;\n\t\t\t\treturn formatSummary(result.summary, { reportPath });\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t};\n}\n"],"mappings":";;;;;;;;;;;AAAA,OAAO,UAAU;AAsBjB,eAAsB,kBACrB,YACA,MAAc,QAAQ,IAAI,GACH;AACvB,QAAM,SAAS,MAAM,WAAW,KAAK,UAAU;AAE/C,SAAO;AAAA,IACN,MAAM,KAAK,UAAU,CAAC,GAAG;AACxB,YAAM,YAA4C,CAAC;AACnD,UAAI,QAAQ,UAAU;AACrB,kBAAU,WAAW,QAAQ;AAAA,MAC9B;AACA,YAAM,eAAe,QAAQ,WAC1B,MAAM,WAAW,KAAK,EAAE,GAAG,YAAY,GAAG,UAAU,CAAC,IACrD;AAEH,aAAO;AAAA,QACN;AAAA,QACA;AAAA,UACC,UAAU,QAAQ;AAAA,UAClB,OAAO,QAAQ;AAAA,UACf,QAAQ,QAAQ;AAAA,QACjB;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,IAEA,MAAM,OAAO,UAAU,CAAC,GAAG;AAC1B,YAAM,gBAAgB,QAAQ,EAAE,KAAK,QAAQ,IAAI,GAAG,GAAG;AAAA,IACxD;AAAA,IAEA,MAAM,SAAS;AACd,YAAM,UAAU,qBAAqB,OAAO,OAAO;AACnD,YAAM,QAAQ,OAAO;AAAA,QACpB,QAAQ;AAAA,QACR,WAAW,KAAK,QAAQ,KAAK,OAAO,QAAQ,MAAM,WAAW;AAAA,MAC9D,CAAC;AAAA,IACF;AAAA,IAEA,MAAM,SAAS,UAAU,CAAC,GAAG;AAC5B,YAAM,UAAU,qBAAqB,OAAO,OAAO;AACnD,YAAM,UAAU,KAAK,QAAQ,KAAK,OAAO,QAAQ,MAAM,WAAW;AAClE,YAAM,SAAS,QAAQ,UAAU;AAEjC,UAAI,mBAAmB,qBAAqB;AAC3C,cAAM,QAAQ,gBAAgB,QAAQ,SAAS,GAAG;AAAA,MACnD,OAAO;AACN,cAAM,QAAQ,SAAS,EAAE,QAAQ,QAAQ,CAAC;AAAA,MAC3C;AAAA,IACD;AAAA,IAEA,eAAe,QAA2C;AACzD,UAAI,OAAO,SAAS;AACnB,cAAM,aAAa,OAAO,YAAY,GAAG,OAAO,SAAS,gBAAgB;AACzE,eAAO,cAAc,OAAO,SAAS,EAAE,WAAW,CAAC;AAAA,MACpD;AACA,aAAO;AAAA,IACR;AAAA,EACD;AACD;","names":[]}
1
+ {"version":3,"sources":["../src/core/index.ts"],"sourcesContent":["import path from 'node:path';\nimport { loadConfig } from '../config/index.js';\nimport type { DeepPartial, StorywrightConfig } from '../config/types.js';\nimport { formatSummary } from '../reporter/cli-reporter.js';\nimport { createStorageAdapter } from '../storage/index.js';\nimport { LocalStorageAdapter } from '../storage/local.js';\nimport { type TestRunResult, runTests, updateBaselines } from './engine.js';\n\nexport interface Storywright {\n\ttest(options?: {\n\t\tdiffOnly?: boolean;\n\t\tbrowsers?: string[];\n\t\tshard?: string;\n\t\tfilter?: string;\n\t}): Promise<TestRunResult>;\n\n\tupdate(options?: { all?: boolean }): Promise<void>;\n\tupload(): Promise<void>;\n\tdownload(options?: { branch?: string }): Promise<void>;\n\tgenerateReport(result: TestRunResult): string | undefined;\n}\n\nexport async function createStorywright(\n\tuserConfig?: DeepPartial<StorywrightConfig>,\n\tcwd: string = process.cwd(),\n): Promise<Storywright> {\n\tconst config = await loadConfig(cwd, userConfig);\n\n\treturn {\n\t\tasync test(options = {}) {\n\t\t\tconst overrides: DeepPartial<StorywrightConfig> = {};\n\t\t\tif (options.browsers) {\n\t\t\t\toverrides.browsers = options.browsers;\n\t\t\t}\n\t\t\tconst mergedConfig = options.browsers\n\t\t\t\t? await loadConfig(cwd, { ...userConfig, ...overrides })\n\t\t\t\t: config;\n\n\t\t\treturn runTests(\n\t\t\t\tmergedConfig,\n\t\t\t\t{\n\t\t\t\t\tdiffOnly: options.diffOnly,\n\t\t\t\t\tshard: options.shard,\n\t\t\t\t\tfilter: options.filter,\n\t\t\t\t},\n\t\t\t\tcwd,\n\t\t\t);\n\t\t},\n\n\t\tasync update(options = {}) {\n\t\t\tawait updateBaselines(config, { all: options.all }, cwd);\n\t\t},\n\n\t\tasync upload() {\n\t\t\tconst storage = await createStorageAdapter(config.storage);\n\t\t\tawait storage.upload({\n\t\t\t\tbranch: 'current',\n\t\t\t\tsourceDir: path.resolve(cwd, config.storage.local.baselineDir),\n\t\t\t});\n\t\t},\n\n\t\tasync download(options = {}) {\n\t\t\tconst storage = await createStorageAdapter(config.storage);\n\t\t\tconst destDir = path.resolve(cwd, config.storage.local.baselineDir);\n\t\t\tconst branch = options.branch ?? 'main';\n\n\t\t\tif (storage instanceof LocalStorageAdapter) {\n\t\t\t\tawait storage.downloadFromGit(branch, destDir, cwd);\n\t\t\t} else {\n\t\t\t\tawait storage.download({ branch, destDir });\n\t\t\t}\n\t\t},\n\n\t\tgenerateReport(result: TestRunResult): string | undefined {\n\t\t\tif (result.summary) {\n\t\t\t\tconst reportPath = result.reportDir ? `${result.reportDir}/index.html` : undefined;\n\t\t\t\treturn formatSummary(result.summary, { reportPath });\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t};\n}\n"],"mappings":";;;;;;;;;;;AAAA,OAAO,UAAU;AAsBjB,eAAsB,kBACrB,YACA,MAAc,QAAQ,IAAI,GACH;AACvB,QAAM,SAAS,MAAM,WAAW,KAAK,UAAU;AAE/C,SAAO;AAAA,IACN,MAAM,KAAK,UAAU,CAAC,GAAG;AACxB,YAAM,YAA4C,CAAC;AACnD,UAAI,QAAQ,UAAU;AACrB,kBAAU,WAAW,QAAQ;AAAA,MAC9B;AACA,YAAM,eAAe,QAAQ,WAC1B,MAAM,WAAW,KAAK,EAAE,GAAG,YAAY,GAAG,UAAU,CAAC,IACrD;AAEH,aAAO;AAAA,QACN;AAAA,QACA;AAAA,UACC,UAAU,QAAQ;AAAA,UAClB,OAAO,QAAQ;AAAA,UACf,QAAQ,QAAQ;AAAA,QACjB;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,IAEA,MAAM,OAAO,UAAU,CAAC,GAAG;AAC1B,YAAM,gBAAgB,QAAQ,EAAE,KAAK,QAAQ,IAAI,GAAG,GAAG;AAAA,IACxD;AAAA,IAEA,MAAM,SAAS;AACd,YAAM,UAAU,MAAM,qBAAqB,OAAO,OAAO;AACzD,YAAM,QAAQ,OAAO;AAAA,QACpB,QAAQ;AAAA,QACR,WAAW,KAAK,QAAQ,KAAK,OAAO,QAAQ,MAAM,WAAW;AAAA,MAC9D,CAAC;AAAA,IACF;AAAA,IAEA,MAAM,SAAS,UAAU,CAAC,GAAG;AAC5B,YAAM,UAAU,MAAM,qBAAqB,OAAO,OAAO;AACzD,YAAM,UAAU,KAAK,QAAQ,KAAK,OAAO,QAAQ,MAAM,WAAW;AAClE,YAAM,SAAS,QAAQ,UAAU;AAEjC,UAAI,mBAAmB,qBAAqB;AAC3C,cAAM,QAAQ,gBAAgB,QAAQ,SAAS,GAAG;AAAA,MACnD,OAAO;AACN,cAAM,QAAQ,SAAS,EAAE,QAAQ,QAAQ,CAAC;AAAA,MAC3C;AAAA,IACD;AAAA,IAEA,eAAe,QAA2C;AACzD,UAAI,OAAO,SAAS;AACnB,cAAM,aAAa,OAAO,YAAY,GAAG,OAAO,SAAS,gBAAgB;AACzE,eAAO,cAAc,OAAO,SAAS,EAAE,WAAW,CAAC;AAAA,MACpD;AACA,aAAO;AAAA,IACR;AAAA,EACD;AACD;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storywright/cli",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Zero-config visual regression testing powered by Storybook + Playwright",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -38,7 +38,8 @@
38
38
  "@types/node": "^22.0.0",
39
39
  "@types/picomatch": "^3.0.1",
40
40
  "tsup": "^8.3.0",
41
- "typescript": "^5.6.0"
41
+ "typescript": "^5.6.0",
42
+ "@storywright/storage-s3": "1.0.1"
42
43
  },
43
44
  "peerDependencies": {
44
45
  "@playwright/test": ">=1.40.0"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/index.ts","../src/config/defaults.ts","../src/config/types.ts","../src/reporter/cli-reporter.ts","../src/storage/local.ts","../src/storage/index.ts","../src/utils/logger.ts","../src/core/engine.ts","../src/playwright/config-generator.ts","../src/playwright/test-generator.ts","../src/resolver/index.ts","../src/utils/path.ts","../src/utils/process.ts","../src/core/storybook.ts"],"sourcesContent":["import { loadConfig as unconfigLoad } from 'unconfig';\nimport { DEFAULT_CONFIG } from './defaults.js';\nimport { STANDARD_BROWSERS } from './types.js';\nimport type { DeepPartial, StorywrightConfig } from './types.js';\n\nexport function defineConfig(\n\tconfig: DeepPartial<StorywrightConfig>,\n): DeepPartial<StorywrightConfig> {\n\treturn config;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction deepMerge(\n\ttarget: Record<string, unknown>,\n\tsource: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = { ...target };\n\tfor (const key of Object.keys(source)) {\n\t\tconst sourceVal = source[key];\n\t\tconst targetVal = result[key];\n\t\tif (isPlainObject(sourceVal) && isPlainObject(targetVal)) {\n\t\t\tresult[key] = deepMerge(targetVal, sourceVal);\n\t\t} else if (sourceVal !== undefined) {\n\t\t\tresult[key] = sourceVal;\n\t\t}\n\t}\n\treturn result;\n}\n\nexport async function loadConfig(\n\tcwd: string = process.cwd(),\n\toverrides?: DeepPartial<StorywrightConfig>,\n): Promise<StorywrightConfig> {\n\tconst { config: userConfig } = await unconfigLoad<DeepPartial<StorywrightConfig>>({\n\t\tsources: [\n\t\t\t{\n\t\t\t\tfiles: 'storywright.config',\n\t\t\t\textensions: ['ts', 'js', 'mjs'],\n\t\t\t},\n\t\t],\n\t\tcwd,\n\t});\n\n\tlet merged = DEFAULT_CONFIG as unknown as Record<string, unknown>;\n\tif (userConfig) {\n\t\tmerged = deepMerge(merged, userConfig as Record<string, unknown>);\n\t}\n\tif (overrides) {\n\t\tmerged = deepMerge(merged, overrides as Record<string, unknown>);\n\t}\n\tconst result = merged as unknown as StorywrightConfig;\n\tvalidateConfig(result);\n\treturn result;\n}\n\nfunction validateConfig(config: StorywrightConfig): void {\n\tfor (const browser of config.browsers) {\n\t\tconst options = config.browserOptions[browser];\n\n\t\tif (!STANDARD_BROWSERS.has(browser) && !options?.browserName) {\n\t\t\tthrow new Error(\n\t\t\t\t`Custom browser project '${browser}' requires 'browserName' in browserOptions.\\nExample:\\n browserOptions: {\\n '${browser}': { browserName: 'webkit', ... }\\n }\\nValid browserName values: 'chromium', 'firefox', 'webkit'.\\n\\nError code: SW_E_MISSING_BROWSER_NAME`,\n\t\t\t);\n\t\t}\n\n\t\tif (options?.browserName && !STANDARD_BROWSERS.has(options.browserName)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid browserName '${options.browserName}' for browser project '${browser}'.\\nValid values: 'chromium', 'firefox', 'webkit'.\\n\\nError code: SW_E_INVALID_BROWSER_NAME`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport type { StorywrightConfig, DeepPartial } from './types.js';\n","import type { StorywrightConfig } from './types.js';\n\nexport const DEFAULT_CONFIG: StorywrightConfig = {\n\tstorybook: {\n\t\tstaticDir: 'storybook-static',\n\t\tbuildCommand: 'npx storybook build --stats-json',\n\t\turl: undefined,\n\t\tcompatibility: 'auto',\n\t},\n\n\tbrowsers: ['chromium'],\n\tbrowserOptions: {},\n\n\tscreenshot: {\n\t\tfullPage: true,\n\t\tanimations: 'disabled',\n\t\tthreshold: 0.02,\n\t\tmaxDiffPixelRatio: 0.02,\n\t\tfreezeTime: '2024-01-01T00:00:00',\n\t\ttimezone: 'UTC',\n\t\tlocale: 'en-US',\n\t\tseed: 1,\n\t},\n\n\tdiffDetection: {\n\t\tenabled: true,\n\t\twatchFiles: ['package.json', 'package-lock.json', '.storybook/**/*'],\n\t\tbaseBranch: 'main',\n\t},\n\n\tstorage: {\n\t\tprovider: 'local',\n\t\tlocal: {\n\t\t\tbaselineDir: '.storywright/baselines',\n\t\t},\n\t\ts3: {\n\t\t\tbucket: '',\n\t\t\tprefix: 'storywright/baselines',\n\t\t\tregion: 'ap-northeast-1',\n\t\t\tcompression: 'zstd',\n\t\t},\n\t},\n\n\treport: {\n\t\toutputDir: '.storywright/report',\n\t\ttitle: 'Storywright Report',\n\t},\n\n\tworkers: 'auto',\n\tretries: 0,\n\n\ttimeout: {\n\t\ttest: 30000,\n\t\tnavigation: 20000,\n\t\texpect: 10000,\n\t},\n\n\tinclude: ['**'],\n\texclude: [],\n\n\thooks: {},\n};\n","import type { Page } from '@playwright/test';\n\nexport interface StorywrightConfig {\n\tstorybook: StorybookConfig;\n\tbrowsers: BrowserName[];\n\tbrowserOptions: Record<string, BrowserOption>;\n\tscreenshot: ScreenshotConfig;\n\tdiffDetection: DiffDetectionConfig;\n\tstorage: StorageConfig;\n\treport: ReportConfig;\n\tworkers: number | 'auto';\n\tretries: number;\n\ttimeout: TimeoutConfig;\n\tinclude: string[];\n\texclude: string[];\n\thooks: HooksConfig;\n}\n\nexport type BrowserName = 'chromium' | 'firefox' | 'webkit' | (string & {});\n\nexport type PlaywrightBrowserName = 'chromium' | 'firefox' | 'webkit';\n\nexport const STANDARD_BROWSERS: ReadonlySet<string> = new Set<PlaywrightBrowserName>([\n\t'chromium',\n\t'firefox',\n\t'webkit',\n]);\n\nexport interface BrowserOption {\n\tbrowserName?: PlaywrightBrowserName;\n\tviewport?: { width: number; height: number };\n\tdeviceScaleFactor?: number;\n\tisMobile?: boolean;\n\thasTouch?: boolean;\n\tuserAgent?: string;\n\texclude?: string[];\n}\n\nexport interface StorybookConfig {\n\tstaticDir: string;\n\tbuildCommand: string;\n\turl?: string;\n\tcompatibility: 'auto' | 'v8';\n}\n\nexport interface ScreenshotConfig {\n\tfullPage: boolean;\n\tanimations: 'disabled' | 'allow';\n\tthreshold: number;\n\tmaxDiffPixelRatio: number;\n\tfreezeTime: string;\n\ttimezone: string;\n\tlocale: string;\n\tseed: number;\n}\n\nexport interface DiffDetectionConfig {\n\tenabled: boolean;\n\twatchFiles: string[];\n\tbaseBranch: string;\n}\n\nexport interface StorageConfig {\n\tprovider: 'local' | 's3';\n\tlocal: LocalStorageConfig;\n\ts3: S3StorageConfig;\n}\n\nexport interface LocalStorageConfig {\n\tbaselineDir: string;\n}\n\nexport interface S3StorageConfig {\n\tbucket: string;\n\tprefix: string;\n\tregion: string;\n\tcompression: 'zstd' | 'gzip' | 'none';\n}\n\nexport interface ReportConfig {\n\toutputDir: string;\n\ttitle: string;\n}\n\nexport interface TimeoutConfig {\n\ttest: number;\n\tnavigation: number;\n\texpect: number;\n}\n\nexport interface StoryContext {\n\tid: string;\n\ttitle: string;\n\tname: string;\n}\n\nexport interface HooksConfig {\n\tbeforeScreenshot?: (page: Page, story: StoryContext) => Promise<void>;\n\tafterScreenshot?: (page: Page, story: StoryContext) => Promise<void>;\n}\n\nexport type DeepPartial<T> = {\n\t[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];\n};\n","import type { TestSummary } from '../core/types.js';\n\nexport function formatSummary(summary: TestSummary, options?: { reportPath?: string }): string {\n\tconst durationSec = Math.round(summary.duration / 1000);\n\tconst minutes = Math.floor(durationSec / 60);\n\tconst seconds = durationSec % 60;\n\tconst durationStr = minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;\n\n\tconst lines: string[] = [\n\t\t'',\n\t\t'Storywright Results',\n\t\t'\\u2550'.repeat(42),\n\t\t` Total: ${summary.total} Passed: ${summary.passed} Failed: ${summary.failed} Skipped: ${summary.skipped}`,\n\t\t` Duration: ${durationStr}`,\n\t\t` Browsers: ${summary.browsers.join(', ')}`,\n\t];\n\n\tconst newFailures = summary.failures.filter((f) => f.type === 'new');\n\tconst diffFailures = summary.failures.filter((f) => f.type !== 'new');\n\n\tif (newFailures.length > 0) {\n\t\tlines.push('');\n\t\tlines.push(' New (no baseline):');\n\t\tfor (const failure of newFailures) {\n\t\t\tlines.push(` \\u25cb ${failure.story}: ${failure.variant} (${failure.browser})`);\n\t\t}\n\t}\n\n\tif (diffFailures.length > 0) {\n\t\tlines.push('');\n\t\tlines.push(' Failed:');\n\t\tfor (const failure of diffFailures) {\n\t\t\tlines.push(` \\u2717 ${failure.story}: ${failure.variant} (${failure.browser})`);\n\t\t\tif (failure.diffRatio > 0) {\n\t\t\t\tconst pct = (failure.diffRatio * 100).toFixed(1);\n\t\t\t\tlines.push(` \\u2192 Diff: ${pct}% pixels changed`);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst reportPath = options?.reportPath ?? '.storywright/report/index.html';\n\tlines.push('');\n\tlines.push(` Report: ${reportPath}`);\n\tlines.push('\\u2550'.repeat(42));\n\tlines.push('');\n\n\treturn lines.join('\\n');\n}\n","import { execFile } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { promisify } from 'node:util';\nimport type { DownloadOptions, StorageAdapter, UploadOptions } from './types.js';\n\nconst execFileAsync = promisify(execFile);\n\nexport class LocalStorageAdapter implements StorageAdapter {\n\tconstructor(private readonly baselineDir: string) {}\n\n\tasync download(options: DownloadOptions): Promise<void> {\n\t\ttry {\n\t\t\tawait fs.access(this.baselineDir);\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t\tawait fs.cp(this.baselineDir, options.destDir, { recursive: true });\n\t}\n\n\tasync upload(options: UploadOptions): Promise<void> {\n\t\tconst resolvedSource = path.resolve(options.sourceDir);\n\t\tconst resolvedDest = path.resolve(this.baselineDir);\n\t\tif (resolvedSource === resolvedDest) {\n\t\t\treturn;\n\t\t}\n\t\tawait fs.mkdir(this.baselineDir, { recursive: true });\n\t\tawait fs.cp(options.sourceDir, this.baselineDir, { recursive: true });\n\t}\n\n\tasync exists(_branch: string): Promise<boolean> {\n\t\ttry {\n\t\t\tawait fs.access(this.baselineDir);\n\t\t\tconst entries = await fs.readdir(this.baselineDir);\n\t\t\treturn entries.length > 0;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Extract baselines from a git branch using `git ls-tree` + `git show`.\n\t * Binary-safe (PNG files) via `encoding: 'buffer'`.\n\t */\n\tasync downloadFromGit(branch: string, destDir: string, cwd: string): Promise<void> {\n\t\tconst gitPath = this.baselineDir.split(path.sep).join('/');\n\n\t\tlet lsOutput: string;\n\t\ttry {\n\t\t\tconst result = await execFileAsync(\n\t\t\t\t'git',\n\t\t\t\t['ls-tree', '-r', '--name-only', branch, '--', gitPath],\n\t\t\t\t{ cwd },\n\t\t\t);\n\t\t\tlsOutput = result.stdout;\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to list baselines from git branch '${branch}': ${error instanceof Error ? error.message : error}`,\n\t\t\t);\n\t\t}\n\n\t\tconst files = lsOutput.trim().split('\\n').filter(Boolean);\n\t\tif (files.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait fs.mkdir(destDir, { recursive: true });\n\n\t\tconst posixBaselineDir = this.baselineDir.split(path.sep).join('/').replace(/\\/+$/, '');\n\n\t\tfor (const file of files) {\n\t\t\tlet content: Buffer;\n\t\t\ttry {\n\t\t\t\tconst result = await execFileAsync('git', ['show', `${branch}:${file}`], {\n\t\t\t\t\tcwd,\n\t\t\t\t\tencoding: 'buffer' as unknown as BufferEncoding,\n\t\t\t\t\tmaxBuffer: 50 * 1024 * 1024,\n\t\t\t\t});\n\t\t\t\tcontent = result.stdout as unknown as Buffer;\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to extract '${file}' from git branch '${branch}': ${error instanceof Error ? error.message : error}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst relativePath = file.slice(posixBaselineDir.length + 1);\n\t\t\tconst destPath = path.join(destDir, ...relativePath.split('/'));\n\t\t\tawait fs.mkdir(path.dirname(destPath), { recursive: true });\n\t\t\tawait fs.writeFile(destPath, content);\n\t\t}\n\t}\n}\n","import { createRequire } from 'node:module';\nimport type { StorageConfig } from '../config/types.js';\nimport { LocalStorageAdapter } from './local.js';\nimport type { StorageAdapter } from './types.js';\n\nexport function createStorageAdapter(config: StorageConfig): StorageAdapter {\n\tswitch (config.provider) {\n\t\tcase 'local':\n\t\t\treturn new LocalStorageAdapter(config.local.baselineDir);\n\t\tcase 's3':\n\t\t\treturn loadS3Adapter(config);\n\t\tdefault:\n\t\t\tthrow new Error(`Unknown storage provider: ${config.provider}`);\n\t}\n}\n\nfunction loadS3Adapter(config: StorageConfig): StorageAdapter {\n\ttry {\n\t\tconst require = createRequire(import.meta.url);\n\t\tconst { S3StorageAdapter } = require('@storywright/storage-s3') as {\n\t\t\tS3StorageAdapter: new (cfg: {\n\t\t\t\tbucket: string;\n\t\t\t\tprefix: string;\n\t\t\t\tregion: string;\n\t\t\t\tcompression?: string;\n\t\t\t}) => StorageAdapter;\n\t\t};\n\t\treturn new S3StorageAdapter(config.s3);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t'S3 storage adapter requires the @storywright/storage-s3 package.\\nInstall it with: pnpm add @storywright/storage-s3',\n\t\t);\n\t}\n}\n\nexport type { StorageAdapter, DownloadOptions, UploadOptions } from './types.js';\n","import { createConsola } from 'consola';\n\nconst isCI = !!(\n\tprocess.env.CI ||\n\tprocess.env.GITHUB_ACTIONS ||\n\tprocess.env.CIRCLECI ||\n\tprocess.env.GITLAB_CI\n);\n\nexport const logger = createConsola({\n\tlevel: process.env.STORYWRIGHT_DEBUG ? 5 : 3,\n});\n\nexport { isCI };\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport picomatch from 'picomatch';\nimport type { StorywrightConfig } from '../config/types.js';\nimport { generatePlaywrightConfig } from '../playwright/config-generator.js';\nimport { generateTestFile } from '../playwright/test-generator.js';\nimport { resolveAffectedStories } from '../resolver/index.js';\nimport { createStorageAdapter } from '../storage/index.js';\nimport { logger } from '../utils/logger.js';\nimport { resolveOutputDir } from '../utils/path.js';\nimport { exec } from '../utils/process.js';\nimport {\n\tbuildStorybook,\n\tdiscoverStories,\n\texcludeStoriesForBrowser,\n\tfilterStories,\n} from './storybook.js';\nimport type { Story, StoryIndex, TestSummary } from './types.js';\n\nexport interface TestOptions {\n\tdiffOnly?: boolean;\n\tshard?: string;\n\tupdateSnapshots?: boolean;\n\tfilter?: string;\n\toutputDir?: string;\n\treporters?: string[];\n}\n\nexport interface TestRunResult {\n\texitCode: number;\n\tsummary?: TestSummary;\n\treportDir?: string;\n\tsnapshotDir?: string;\n}\n\nconst STORIES_PER_FILE = 50;\n\nfunction resolveReporterPath(): string {\n\t// Resolve relative to this file's dist location\n\tconst thisDir = new URL('.', import.meta.url).pathname;\n\treturn path.resolve(thisDir, 'playwright', 'reporter.js');\n}\n\nfunction chunkStories(entries: Record<string, Story>): Record<string, Story>[] {\n\tconst keys = Object.keys(entries);\n\tif (keys.length === 0) return [{}];\n\tconst chunks: Record<string, Story>[] = [];\n\tfor (let i = 0; i < keys.length; i += STORIES_PER_FILE) {\n\t\tconst chunk: Record<string, Story> = {};\n\t\tfor (const key of keys.slice(i, i + STORIES_PER_FILE)) {\n\t\t\tchunk[key] = entries[key];\n\t\t}\n\t\tchunks.push(chunk);\n\t}\n\treturn chunks;\n}\n\nexport async function runTests(\n\tconfig: StorywrightConfig,\n\toptions: TestOptions = {},\n\tcwd: string = process.cwd(),\n): Promise<TestRunResult> {\n\tconst outputRoot = options.outputDir\n\t\t? path.resolve(cwd, options.outputDir)\n\t\t: resolveOutputDir(cwd, '.storywright');\n\tconst tmpDir = path.join(outputRoot, 'tmp');\n\tconst reportDir = options.outputDir\n\t\t? path.join(outputRoot, 'report')\n\t\t: path.resolve(cwd, config.report.outputDir);\n\tconst storybookDir = path.resolve(cwd, config.storybook.staticDir);\n\tconst snapshotDir = path.join(tmpDir, 'snapshots');\n\n\t// Prepare directories early for parallel operations\n\tawait fs.mkdir(snapshotDir, { recursive: true });\n\n\t// Start baseline download in parallel with Storybook build\n\tconst storage = createStorageAdapter(config.storage);\n\tconst baselinePromise = storage\n\t\t.download({ branch: 'current', destDir: snapshotDir })\n\t\t.catch(() => {\n\t\t\tlogger.info('No existing baselines found');\n\t\t});\n\n\t// 1. Build Storybook if needed\n\tawait buildStorybook(config, cwd);\n\n\t// 2. Discover & filter stories\n\tlogger.start('Discovering stories...');\n\tconst allStories = await discoverStories(config, cwd);\n\tlet targetStories = filterStories(allStories, config);\n\n\t// Apply --filter option\n\tif (options.filter) {\n\t\ttargetStories = applyFilter(targetStories, options.filter);\n\t}\n\n\tlogger.info(`${Object.keys(targetStories.entries).length} stories found`);\n\n\t// 3. Diff-only: resolve affected stories (default in CI)\n\tconst effectiveDiffOnly = options.diffOnly ?? !!process.env.CI;\n\tif (effectiveDiffOnly && config.diffDetection.enabled) {\n\t\tlogger.start('Resolving dependencies...');\n\t\tconst diffResult = await resolveAffectedStories(\n\t\t\ttargetStories,\n\t\t\tconfig.diffDetection,\n\t\t\tstorybookDir,\n\t\t\tcwd,\n\t\t);\n\t\tif (!diffResult.allStories) {\n\t\t\ttargetStories = diffResult.targetStories;\n\t\t}\n\t\tlogger.info(`${Object.keys(targetStories.entries).length} stories affected by changes`);\n\t}\n\n\t// 4. Wait for baseline download to complete\n\tawait baselinePromise;\n\n\t// 5. Generate split test files for better worker distribution\n\tlet testFilePattern: string;\n\tlet testMatchByBrowser: Record<string, string> | undefined;\n\n\tconst browserExcludesExist = config.browsers.some(\n\t\t(b) => (config.browserOptions[b]?.exclude ?? []).length > 0,\n\t);\n\n\tif (browserExcludesExist) {\n\t\t// Generate per-browser test files when any browser has specific excludes\n\t\ttestMatchByBrowser = {};\n\n\t\tfor (const browser of config.browsers) {\n\t\t\tconst browserExclude = config.browserOptions[browser]?.exclude ?? [];\n\t\t\tconst browserStories = excludeStoriesForBrowser(targetStories, browserExclude);\n\n\t\t\tif (Object.keys(browserStories.entries).length === 0) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`${browser}: All stories excluded by browser-specific 'exclude' patterns. No tests will run for this browser.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst browserChunks = chunkStories(browserStories.entries);\n\n\t\t\ttestMatchByBrowser[browser] =\n\t\t\t\tbrowserChunks.length === 1\n\t\t\t\t\t? `storywright-${browser}-0.spec.ts`\n\t\t\t\t\t: `storywright-${browser}-*.spec.ts`;\n\n\t\t\tfor (let i = 0; i < browserChunks.length; i++) {\n\t\t\t\tconst chunkIndex: StoryIndex = { ...browserStories, entries: browserChunks[i] };\n\t\t\t\tconst chunkPath = path.join(tmpDir, `target-stories-${browser}-${i}.json`);\n\t\t\t\tawait fs.writeFile(chunkPath, JSON.stringify(chunkIndex));\n\n\t\t\t\tconst testContent = generateTestFile(config.screenshot, {\n\t\t\t\t\ttargetStoriesPath: chunkPath.replace(/\\\\/g, '/'),\n\t\t\t\t});\n\t\t\t\tawait fs.writeFile(path.join(tmpDir, `storywright-${browser}-${i}.spec.ts`), testContent);\n\t\t\t}\n\n\t\t\tlogger.info(\n\t\t\t\t`${browser}: ${Object.keys(browserStories.entries).length} stories, ${browserChunks.length} test file(s)`,\n\t\t\t);\n\t\t}\n\n\t\ttestFilePattern = 'storywright-*.spec.ts';\n\t} else {\n\t\t// Default: shared test files for all browsers\n\t\tconst chunks = chunkStories(targetStories.entries);\n\t\ttestFilePattern = chunks.length === 1 ? 'storywright-0.spec.ts' : 'storywright-*.spec.ts';\n\n\t\tfor (let i = 0; i < chunks.length; i++) {\n\t\t\tconst chunkIndex: StoryIndex = { ...targetStories, entries: chunks[i] };\n\t\t\tconst chunkPath = path.join(tmpDir, `target-stories-${i}.json`);\n\t\t\tawait fs.writeFile(chunkPath, JSON.stringify(chunkIndex));\n\n\t\t\tconst testContent = generateTestFile(config.screenshot, {\n\t\t\t\ttargetStoriesPath: chunkPath.replace(/\\\\/g, '/'),\n\t\t\t});\n\t\t\tawait fs.writeFile(path.join(tmpDir, `storywright-${i}.spec.ts`), testContent);\n\t\t}\n\n\t\tlogger.info(`${chunks.length} test file(s) generated`);\n\t}\n\n\t// 6. Generate Playwright config\n\tconst reporterWrapperPath = path.join(tmpDir, 'reporter.mjs');\n\tconst resolvedReporterPath = resolveReporterPath().replace(/\\\\/g, '/');\n\tconst reporterOutputDir = reportDir.replace(/\\\\/g, '/');\n\n\tawait fs.writeFile(\n\t\treporterWrapperPath,\n\t\t`import StorywrightReporter from '${resolvedReporterPath}';\\nexport default class extends StorywrightReporter {\\n constructor() { super({ outputDir: '${reporterOutputDir}' }); }\\n}\\n`,\n\t);\n\n\t// Determine Storybook URL\n\tlet actualStorybookUrl = config.storybook.url;\n\tconst needsServer = !actualStorybookUrl;\n\n\tif (needsServer) {\n\t\tactualStorybookUrl = 'http://localhost:6007';\n\t}\n\n\tconst playwrightConfig = generatePlaywrightConfig(config, {\n\t\ttmpDir: tmpDir.replace(/\\\\/g, '/'),\n\t\tstorybookUrl: actualStorybookUrl ?? 'http://localhost:6007',\n\t\tsnapshotDir: snapshotDir.replace(/\\\\/g, '/'),\n\t\treporterPath: reporterWrapperPath.replace(/\\\\/g, '/'),\n\t\ttestMatch: testFilePattern,\n\t\ttestMatchByBrowser,\n\t\tshard: options.shard,\n\t\treporters: options.reporters,\n\t});\n\n\tconst configPath = path.join(tmpDir, 'playwright.config.ts');\n\tawait fs.writeFile(configPath, playwrightConfig);\n\n\t// 7. Run Playwright tests\n\tlogger.start('Running tests...');\n\tconst args = ['playwright', 'test', '--config', configPath];\n\n\tif (options.updateSnapshots) {\n\t\targs.push('--update-snapshots');\n\t}\n\n\t// Start static server if needed\n\tlet serverProc: { kill: () => void } | undefined;\n\tif (needsServer) {\n\t\tserverProc = await startStaticServer(storybookDir, 6007);\n\t}\n\n\ttry {\n\t\tconst result = await exec('npx', args, { cwd, inherit: true });\n\n\t\t// 8. Read results\n\t\tlet summary: TestSummary | undefined;\n\t\ttry {\n\t\t\tconst summaryPath = path.join(reportDir, 'summary.json');\n\t\t\tconst summaryContent = await fs.readFile(summaryPath, 'utf-8');\n\t\t\tsummary = JSON.parse(summaryContent);\n\t\t} catch {\n\t\t\t// summary may not exist if no tests ran\n\t\t}\n\n\t\t// 9. Map exit codes per SPEC §14.2\n\t\tconst exitCode = mapExitCode(result.exitCode, summary);\n\n\t\treturn { exitCode, summary, reportDir, snapshotDir };\n\t} finally {\n\t\tserverProc?.kill();\n\t}\n}\n\nexport async function updateBaselines(\n\tconfig: StorywrightConfig,\n\toptions: { all?: boolean; upload?: boolean } = {},\n\tcwd: string = process.cwd(),\n): Promise<void> {\n\tconst result = await runTests(config, { updateSnapshots: true, diffOnly: !options.all }, cwd);\n\n\tif (result.exitCode !== 0) {\n\t\tlogger.warn('Some tests failed during baseline update');\n\t}\n\n\t// Save updated snapshots back to baselineDir (local disk operation)\n\tif (result.snapshotDir) {\n\t\tconst baselineDir = path.resolve(cwd, config.storage.local.baselineDir);\n\t\tawait fs.mkdir(baselineDir, { recursive: true });\n\t\tawait fs.cp(result.snapshotDir, baselineDir, { recursive: true });\n\t\tlogger.success(`Baselines saved to ${config.storage.local.baselineDir}`);\n\t}\n\n\t// --upload: upload to remote storage (S3 etc.) only when explicitly requested\n\tif (options.upload) {\n\t\tconst storage = createStorageAdapter(config.storage);\n\t\tconst baselineDir = path.resolve(cwd, config.storage.local.baselineDir);\n\t\tawait storage.upload({\n\t\t\tbranch: 'current',\n\t\t\tsourceDir: baselineDir,\n\t\t});\n\t\tlogger.success('Baselines uploaded to remote storage');\n\t}\n}\n\nfunction applyFilter(storyIndex: StoryIndex, filter: string): StoryIndex {\n\tconst matcher = picomatch(filter);\n\tconst entries: Record<string, StoryIndex['entries'][string]> = {};\n\tfor (const [id, story] of Object.entries(storyIndex.entries)) {\n\t\tconst fullName = `${story.title}/${story.name}`;\n\t\tif (matcher(fullName) || matcher(story.title) || matcher(story.id)) {\n\t\t\tentries[id] = story;\n\t\t}\n\t}\n\treturn { ...storyIndex, entries };\n}\n\nfunction mapExitCode(playwrightCode: number, summary?: TestSummary): number {\n\t// SPEC §14.2: 0 = success (no diff), 1 = success (diff found), 2 = execution error, 130 = SIGINT\n\tif (playwrightCode === 130 || playwrightCode === 143) {\n\t\treturn 130; // SIGINT / SIGTERM\n\t}\n\tif (summary) {\n\t\tif (summary.failed > 0) return 1;\n\t\tif (summary.total === 0 && playwrightCode !== 0) return 2;\n\t\treturn 0;\n\t}\n\t// No summary = likely execution error\n\treturn playwrightCode === 0 ? 0 : 2;\n}\n\nasync function startStaticServer(dir: string, port: number): Promise<{ kill: () => void }> {\n\tconst { createServer } = await import('node:http');\n\tconst sirv = (await import('sirv')).default;\n\n\tconst handler = sirv(dir, { single: false, dev: false });\n\tconst server = createServer(handler);\n\n\tawait new Promise<void>((resolve, reject) => {\n\t\tserver.on('error', reject);\n\t\tserver.listen(port, () => resolve());\n\t});\n\n\treturn { kill: () => server.close() };\n}\n","import { STANDARD_BROWSERS } from '../config/types.js';\nimport type { BrowserOption, StorywrightConfig } from '../config/types.js';\n\nexport function generatePlaywrightConfig(\n\tconfig: StorywrightConfig,\n\toptions: {\n\t\ttmpDir: string;\n\t\tstorybookUrl: string;\n\t\tsnapshotDir: string;\n\t\treporterPath: string;\n\t\ttestMatch: string;\n\t\ttestMatchByBrowser?: Record<string, string>;\n\t\tshard?: string;\n\t\treporters?: string[];\n\t},\n): string {\n\tconst projects = config.browsers.map((browser) => {\n\t\tconst rawOptions = config.browserOptions[browser];\n\t\tconst useObj = buildBrowserUseObject(browser, rawOptions);\n\t\tconst useStr = JSON.stringify(useObj, null, '\\t\\t');\n\t\tconst testMatch = options.testMatchByBrowser?.[browser];\n\t\tconst testMatchLine = testMatch ? `\\n\\t\\t\\ttestMatch: '${escapeBackslash(testMatch)}',` : '';\n\t\treturn `\\t\\t{\n\\t\\t\\tname: '${browser}',${testMatchLine}\n\\t\\t\\tuse: ${useStr},\n\\t\\t}`;\n\t});\n\n\tconst workers = config.workers === 'auto' ? \"'100%'\" : String(config.workers);\n\n\tconst shard = options.shard\n\t\t? `\\tshard: { current: ${options.shard.split('/')[0]}, total: ${options.shard.split('/')[1]} },`\n\t\t: '';\n\n\t// Build reporter list: always include custom reporter, plus user-requested ones\n\tconst reporterEntries: string[] = [];\n\tconst requestedReporters = options.reporters ?? ['default', 'html'];\n\tfor (const r of requestedReporters) {\n\t\tif (r === 'default' || r === 'list') {\n\t\t\treporterEntries.push(\"\\t\\t['list']\");\n\t\t} else if (r !== 'html') {\n\t\t\t// Pass through other built-in Playwright reporters (dot, json, junit, etc.)\n\t\t\treporterEntries.push(`\\t\\t['${r}']`);\n\t\t}\n\t}\n\t// Always include custom storywright reporter\n\treporterEntries.push(`\\t\\t['${escapeBackslash(options.reporterPath)}']`);\n\n\tconst testMatchLine = options.testMatchByBrowser\n\t\t? ''\n\t\t: `\\ttestMatch: '${escapeBackslash(options.testMatch)}',\\n`;\n\n\treturn `import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n\\ttestDir: '${escapeBackslash(options.tmpDir)}',\n${testMatchLine}\\tsnapshotDir: '${escapeBackslash(options.snapshotDir)}',\n\\tsnapshotPathTemplate: '{snapshotDir}/{arg}-{projectName}{ext}',\n\\ttimeout: ${config.timeout.test},\n\\texpect: {\n\\t\\ttoHaveScreenshot: {\n\\t\\t\\tmaxDiffPixelRatio: ${config.screenshot.maxDiffPixelRatio},\n\\t\\t\\tthreshold: ${config.screenshot.threshold},\n\\t\\t},\n\\t\\ttimeout: ${config.timeout.expect},\n\\t},\n\\tfullyParallel: true,\n\\tforbidOnly: !!process.env.CI,\n\\tretries: ${config.retries},\n\\tworkers: ${workers},\n${shard}\n\\treporter: [\n${reporterEntries.join(',\\n')}\n\\t],\n\\tuse: {\n\\t\\tbaseURL: '${options.storybookUrl}',\n\\t\\tnavigationTimeout: ${config.timeout.navigation},\n\\t\\ttimezoneId: '${config.screenshot.timezone}',\n\\t\\tlocale: '${config.screenshot.locale}',\n\\t},\n\\tprojects: [\n${projects.join(',\\n')}\n\\t],\n});\n`;\n}\n\nfunction buildBrowserUseObject(\n\tbrowser: string,\n\trawOptions?: BrowserOption,\n): Record<string, unknown> {\n\tlet browserName: string;\n\tif (rawOptions?.browserName) {\n\t\tbrowserName = rawOptions.browserName;\n\t} else if (STANDARD_BROWSERS.has(browser)) {\n\t\tbrowserName = browser;\n\t} else {\n\t\tthrow new Error(\n\t\t\t`Cannot resolve browserName for custom browser project '${browser}'.\\n\\nError code: SW_E_INTERNAL_BROWSER_RESOLVE`,\n\t\t);\n\t}\n\tconst useObj: Record<string, unknown> = { browserName };\n\n\tif (rawOptions) {\n\t\tconst { browserName: _, exclude: __, ...rest } = rawOptions;\n\t\tObject.assign(useObj, rest);\n\t}\n\n\treturn useObj;\n}\n\nfunction escapeBackslash(str: string): string {\n\treturn str.replace(/\\\\/g, '/');\n}\n","import type { ScreenshotConfig } from '../config/types.js';\n\nexport function generateTestFile(\n\tconfig: ScreenshotConfig,\n\toptions: {\n\t\ttargetStoriesPath: string;\n\t},\n): string {\n\tconst disableAnimations = config.animations === 'disabled';\n\n\treturn `import { test, expect } from '@playwright/test';\nimport { readFileSync } from 'node:fs';\n\nconst targetList = JSON.parse(\n\\treadFileSync('${escapeBackslash(options.targetStoriesPath)}', 'utf-8'),\n);\n\ntest.describe.parallel('visual regression testing', () => {\n\\tif (Object.keys(targetList.entries).length === 0) {\n\\t\\ttest('no stories to test', () => {\n\\t\\t\\texpect(true).toBeTruthy();\n\\t\\t});\n\\t}\n\n\\tfor (const story of Object.values(targetList.entries)) {\n\\t\\ttest(\\`\\${story.title}: \\${story.name}\\`, async ({ page }) => {\n\\t\\t\\t// Freeze time for reproducibility\n\\t\\t\\tawait page.clock.install({ time: new Date('${config.freezeTime}') });\n\n\\t\\t\\t// Seed Math.random for reproducibility\n\\t\\t\\tawait page.addInitScript((seed) => {\n\\t\\t\\t\\tlet s = seed;\n\\t\\t\\t\\tMath.random = () => {\n\\t\\t\\t\\t\\ts = (s * 16807 + 0) % 2147483647;\n\\t\\t\\t\\t\\treturn (s - 1) / 2147483646;\n\\t\\t\\t\\t};\n\\t\\t\\t}, ${config.seed});\n\n\\t\\t\\tawait page.goto(\\`/iframe.html?id=\\${story.id}\\`, {\n\\t\\t\\t\\twaitUntil: 'domcontentloaded',\n\\t\\t\\t});\n${\n\tdisableAnimations\n\t\t? `\n\\t\\t\\t// Force-disable all CSS animations and transitions\n\\t\\t\\tawait page.addStyleTag({\n\\t\\t\\t\\tcontent: '*, *::before, *::after { animation-duration: 0s !important; animation-delay: 0s !important; transition-duration: 0s !important; transition-delay: 0s !important; }',\n\\t\\t\\t});\n`\n\t\t: ''\n}\n\\t\\t\\t// Wait for story to render: content inside #storybook-root OR portal content on body\n\\t\\t\\tawait page.waitForFunction(() => {\n\\t\\t\\t\\tconst root = document.getElementById('storybook-root');\n\\t\\t\\t\\tif (!root) return false;\n\\t\\t\\t\\tif (root.childElementCount > 0) return true;\n\\t\\t\\t\\t// Portal: check for elements on body that aren't part of Storybook's skeleton\n\\t\\t\\t\\tfor (const el of document.body.children) {\n\\t\\t\\t\\t\\tif (el.tagName === 'SCRIPT' || el.id === 'storybook-root' || el.id === 'storybook-docs') continue;\n\\t\\t\\t\\t\\treturn true;\n\\t\\t\\t\\t}\n\\t\\t\\t\\treturn false;\n\\t\\t\\t}, { timeout: 10000 });\n\n\\t\\t\\t// Wait for web fonts to finish loading\n\\t\\t\\tawait page.waitForFunction(() => document.fonts.ready);\n\n\\t\\t\\t// Force lazy-loaded images to eager and wait for all images with timeout\n\\t\\t\\tawait page.evaluate(async () => {\n\\t\\t\\t\\tconst lazyImages = document.querySelectorAll('img[loading=\"lazy\"]');\n\\t\\t\\t\\tfor (const img of lazyImages) {\n\\t\\t\\t\\t\\t(img as HTMLImageElement).loading = 'eager';\n\\t\\t\\t\\t}\n\n\\t\\t\\t\\tconst images = Array.from(document.images).filter((img) => !img.complete);\n\\t\\t\\t\\tawait Promise.all(\n\\t\\t\\t\\t\\timages.map(\n\\t\\t\\t\\t\\t\\t(img) =>\n\\t\\t\\t\\t\\t\\t\\tnew Promise<void>((resolve) => {\n\\t\\t\\t\\t\\t\\t\\t\\tconst timeout = setTimeout(resolve, 5000);\n\\t\\t\\t\\t\\t\\t\\t\\timg.onload = img.onerror = () => {\n\\t\\t\\t\\t\\t\\t\\t\\t\\tclearTimeout(timeout);\n\\t\\t\\t\\t\\t\\t\\t\\t\\tresolve();\n\\t\\t\\t\\t\\t\\t\\t\\t};\n\\t\\t\\t\\t\\t\\t\\t}),\n\\t\\t\\t\\t\\t),\n\\t\\t\\t\\t);\n\\t\\t\\t});\n${\n\tdisableAnimations\n\t\t? `\n\\t\\t\\t// Force opacity:1 on images to counteract fade-in effects\n\\t\\t\\tawait page.evaluate(() => {\n\\t\\t\\t\\tdocument.querySelectorAll('img').forEach((img) => {\n\\t\\t\\t\\t\\timg.style.setProperty('opacity', '1', 'important');\n\\t\\t\\t\\t});\n\\t\\t\\t});\n`\n\t\t: ''\n}\n\\t\\t\\t// Allow async renders to settle (multiple animation frames)\n\\t\\t\\tawait page.waitForFunction(\n\\t\\t\\t\\t() =>\n\\t\\t\\t\\t\\tnew Promise((resolve) => {\n\\t\\t\\t\\t\\t\\tlet count = 0;\n\\t\\t\\t\\t\\t\\tconst tick = () => {\n\\t\\t\\t\\t\\t\\t\\tif (++count >= 3) return resolve(true);\n\\t\\t\\t\\t\\t\\t\\trequestAnimationFrame(tick);\n\\t\\t\\t\\t\\t\\t};\n\\t\\t\\t\\t\\t\\trequestAnimationFrame(tick);\n\\t\\t\\t\\t\\t}),\n\\t\\t\\t);\n\n\\t\\t\\t// Final stabilization delay for layout shifts\n\\t\\t\\tawait page.waitForTimeout(200);\n\n\\t\\t\\tawait expect(page).toHaveScreenshot(\n\\t\\t\\t\\t[story.title, \\`\\${story.id}.png\\`],\n\\t\\t\\t\\t{\n\\t\\t\\t\\t\\tanimations: '${config.animations}',\n\\t\\t\\t\\t\\tfullPage: ${config.fullPage},\n\\t\\t\\t\\t\\tthreshold: ${config.threshold},\n\\t\\t\\t\\t\\tmaxDiffPixelRatio: ${config.maxDiffPixelRatio},\n\\t\\t\\t\\t},\n\\t\\t\\t);\n\\t\\t});\n\\t}\n});\n`;\n}\n\nfunction escapeBackslash(str: string): string {\n\treturn str.replace(/\\\\/g, '/');\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport picomatch from 'picomatch';\nimport { simpleGit } from 'simple-git';\nimport type { DiffDetectionConfig } from '../config/types.js';\nimport type { StatsIndex, StatsModule, StoryIndex } from '../core/types.js';\nimport { logger } from '../utils/logger.js';\nimport { normalizePath, stripLeadingDotSlash } from '../utils/path.js';\n\nexport interface DependencyResolver {\n\tgetDependencies(filePath: string): string[];\n\tgetStoriesForFiles(pathList: string[]): StoryIndex;\n}\n\nconst STORY_FILE_PATTERNS = ['.stories.', '.mdx'];\n\nfunction isStoryFile(moduleName: string): boolean {\n\treturn STORY_FILE_PATTERNS.some((p) => moduleName.includes(p));\n}\n\nexport class StorybookStatsDependencyResolver implements DependencyResolver {\n\tprivate moduleMap: Record<string, StatsModule>;\n\n\tconstructor(\n\t\tprivate statsJson: StatsIndex,\n\t\tprivate storiesJson: StoryIndex,\n\t) {\n\t\tthis.moduleMap = {};\n\t\tfor (const mod of statsJson.modules) {\n\t\t\t// Key by normalized name (primary) and normalized id (fallback)\n\t\t\tconst normalizedName = normalizePath(mod.name);\n\t\t\tthis.moduleMap[normalizedName] = mod;\n\t\t\tconst normalizedId = normalizePath(mod.id);\n\t\t\tif (normalizedId !== normalizedName) {\n\t\t\t\tthis.moduleMap[normalizedId] ??= mod;\n\t\t\t}\n\t\t}\n\t}\n\n\tgetDependencies(filePath: string): string[] {\n\t\tconst normalizedPath = normalizePath(filePath);\n\t\tconst dependencies = this.collectDependencies(normalizedPath);\n\n\t\tif (this.moduleMap[normalizedPath]) {\n\t\t\tdependencies.add(normalizedPath);\n\t\t}\n\n\t\treturn [...dependencies];\n\t}\n\n\tgetStoriesForFiles(pathList: string[]): StoryIndex {\n\t\tconst result: StoryIndex = { v: this.storiesJson.v, entries: {} };\n\n\t\tfor (const filePath of pathList) {\n\t\t\t// Finding #2 + #3: lookup via normalized moduleMap (name primary, id fallback)\n\t\t\tconst normalizedPath = normalizePath(filePath);\n\t\t\tconst stats = this.moduleMap[normalizedPath];\n\t\t\tif (!stats) continue;\n\n\t\t\t// Finding #1: collect ALL story reasons, not just first\n\t\t\tconst storyReasons = stats.reasons.filter((r) => isStoryFile(r.moduleName));\n\t\t\tfor (const reason of storyReasons) {\n\t\t\t\tconst normalizedImportPath = normalizePath(reason.moduleName);\n\t\t\t\t// Collect ALL matching story entries per reason\n\t\t\t\tfor (const storyObj of Object.values(this.storiesJson.entries)) {\n\t\t\t\t\tif (storyObj.type !== 'story') continue;\n\t\t\t\t\tif (normalizePath(storyObj.importPath) === normalizedImportPath) {\n\t\t\t\t\t\tresult.entries[storyObj.id] = storyObj;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate collectDependencies(name: string, result = new Set<string>()): Set<string> {\n\t\tconst mod = this.moduleMap[normalizePath(name)];\n\t\tif (mod) {\n\t\t\tfor (const reason of mod.reasons) {\n\t\t\t\tif (!result.has(reason.moduleName)) {\n\t\t\t\t\tresult.add(reason.moduleName);\n\t\t\t\t\tthis.collectDependencies(reason.moduleName, result);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\n\nexport interface DiffResult {\n\tallStories: boolean;\n\ttargetStories: StoryIndex;\n}\n\ninterface DiffFileEntry {\n\tfile: string;\n\tfrom?: string;\n}\n\nexport async function resolveAffectedStories(\n\tstoriesJson: StoryIndex,\n\tconfig: DiffDetectionConfig,\n\tstorybookStaticDir: string,\n\tcwd: string,\n): Promise<DiffResult> {\n\tconst git = simpleGit({ baseDir: cwd });\n\n\t// Get diff summary\n\tlet diffEntries: DiffFileEntry[];\n\ttry {\n\t\tconst mergeBase = await git.raw(['merge-base', config.baseBranch, 'HEAD']);\n\t\tconst diff = await git.diffSummary([mergeBase.trim(), 'HEAD']);\n\t\tdiffEntries = diff.files.map((f) => ({\n\t\t\tfile: f.file,\n\t\t\t// Handle renames: include both old and new paths\n\t\t\tfrom: 'from' in f ? (f as { from: string }).from : undefined,\n\t\t}));\n\t} catch {\n\t\tlogger.warn('Failed to resolve git diff, running all stories');\n\t\treturn { allStories: true, targetStories: storiesJson };\n\t}\n\n\tif (diffEntries.length === 0) {\n\t\tlogger.info('No changed files detected');\n\t\treturn { allStories: false, targetStories: { v: storiesJson.v, entries: {} } };\n\t}\n\n\t// Collect all affected paths (including rename sources)\n\tconst allPaths: string[] = [];\n\tfor (const entry of diffEntries) {\n\t\tallPaths.push(entry.file);\n\t\tif (entry.from) {\n\t\t\tallPaths.push(entry.from);\n\t\t}\n\t}\n\n\t// Check watchFiles\n\tfor (const file of allPaths) {\n\t\tfor (const pattern of config.watchFiles) {\n\t\t\tif (picomatch(pattern)(file)) {\n\t\t\t\tlogger.info(`Watch file changed: ${file}, running all stories`);\n\t\t\t\treturn { allStories: true, targetStories: storiesJson };\n\t\t\t}\n\t\t}\n\t}\n\n\t// Load stats json for dependency resolution\n\tconst statsPath = path.resolve(storybookStaticDir, 'preview-stats.json');\n\tlet statsJson: StatsIndex;\n\ttry {\n\t\tstatsJson = JSON.parse(await fs.readFile(statsPath, 'utf-8'));\n\t} catch {\n\t\tlogger.warn('preview-stats.json not found, running all stories');\n\t\treturn { allStories: true, targetStories: storiesJson };\n\t}\n\n\tconst resolver = new StorybookStatsDependencyResolver(statsJson, storiesJson);\n\tconst targetStories: StoryIndex = { v: storiesJson.v, entries: {} };\n\n\t// Direct story file matches (both .stories.* and .mdx)\n\tfor (const file of allPaths) {\n\t\tconst matchedStories = Object.values(storiesJson.entries).filter(\n\t\t\t(story) => stripLeadingDotSlash(story.importPath) === file,\n\t\t);\n\t\tfor (const story of matchedStories) {\n\t\t\ttargetStories.entries[story.id] = story;\n\t\t}\n\t}\n\n\t// Dependency-based matches\n\tfor (const file of allPaths) {\n\t\tconst deps = resolver.getDependencies(normalizePath(file));\n\t\tconst depStories = resolver.getStoriesForFiles(deps);\n\t\tfor (const [id, story] of Object.entries(depStories.entries)) {\n\t\t\ttargetStories.entries[id] = story;\n\t\t}\n\t}\n\n\tlogger.info(`Resolved ${Object.keys(targetStories.entries).length} affected stories`);\n\treturn { allStories: false, targetStories };\n}\n","import path from 'node:path';\n\nexport function normalizePath(filePath: string): string {\n\tconst normalized = filePath.replace(/\\\\/g, '/');\n\tif (normalized.startsWith('./')) {\n\t\treturn normalized;\n\t}\n\treturn `./${normalized}`;\n}\n\nexport function stripLeadingDotSlash(filePath: string): string {\n\treturn filePath.replace(/^\\.\\//, '');\n}\n\nexport function resolveOutputDir(outputDir: string, ...segments: string[]): string {\n\treturn path.resolve(outputDir, ...segments);\n}\n","import { spawn } from 'node:child_process';\n\nexport interface ExecResult {\n\texitCode: number;\n\tstdout: string;\n\tstderr: string;\n}\n\nexport function exec(\n\tcommand: string,\n\targs: string[],\n\toptions?: { cwd?: string; env?: Record<string, string>; inherit?: boolean },\n): Promise<ExecResult> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst proc = spawn(command, args, {\n\t\t\tcwd: options?.cwd,\n\t\t\tenv: { ...process.env, ...options?.env },\n\t\t\tstdio: options?.inherit ? ['ignore', 'inherit', 'inherit'] : ['ignore', 'pipe', 'pipe'],\n\t\t\tshell: false,\n\t\t});\n\n\t\tlet stdout = '';\n\t\tlet stderr = '';\n\n\t\tif (!options?.inherit) {\n\t\t\tproc.stdout?.on('data', (data: Buffer) => {\n\t\t\t\tstdout += data.toString();\n\t\t\t});\n\n\t\t\tproc.stderr?.on('data', (data: Buffer) => {\n\t\t\t\tstderr += data.toString();\n\t\t\t});\n\t\t}\n\n\t\tproc.on('error', reject);\n\n\t\tproc.on('close', (code) => {\n\t\t\tresolve({ exitCode: code ?? 1, stdout, stderr });\n\t\t});\n\t});\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport picomatch from 'picomatch';\nimport type { StorywrightConfig } from '../config/types.js';\nimport { logger } from '../utils/logger.js';\nimport { exec } from '../utils/process.js';\nimport type { Story, StoryIndex } from './types.js';\n\nexport async function buildStorybook(config: StorywrightConfig, cwd: string): Promise<void> {\n\tif (config.storybook.url) {\n\t\tlogger.info('Using running Storybook at', config.storybook.url);\n\t\treturn;\n\t}\n\n\tconst staticDir = path.resolve(cwd, config.storybook.staticDir);\n\ttry {\n\t\tawait fs.access(path.join(staticDir, 'index.json'));\n\t\tlogger.info('Storybook already built at', staticDir);\n\t\treturn;\n\t} catch {\n\t\t// need to build\n\t}\n\n\tlogger.start('Building Storybook...');\n\tconst [command, ...args] = config.storybook.buildCommand.split(' ');\n\tconst result = await exec(command, args, { cwd });\n\tif (result.exitCode !== 0) {\n\t\tthrow new Error(\n\t\t\t`Storybook build failed (exit code ${result.exitCode}):\\n${result.stderr}\\n\\nError code: SW_E_STORYBOOK_BUILD_FAILED`,\n\t\t);\n\t}\n\tlogger.success('Storybook built');\n}\n\nexport async function discoverStories(config: StorywrightConfig, cwd: string): Promise<StoryIndex> {\n\tconst staticDir = path.resolve(cwd, config.storybook.staticDir);\n\tconst indexPath = path.join(staticDir, 'index.json');\n\n\ttry {\n\t\tawait fs.access(indexPath);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`Storybook build directory not found at '${config.storybook.staticDir}/'\\n\\n Run one of the following:\\n $ npx storybook build --stats-json\\n $ npx storywright test --storybook-url http://localhost:6006\\n\\n Error code: SW_E_STORYBOOK_DIR_NOT_FOUND`,\n\t\t);\n\t}\n\n\tconst raw = JSON.parse(await fs.readFile(indexPath, 'utf-8'));\n\tconst indexJson = normalizeStoryIndex(raw, config.storybook.compatibility);\n\n\t// Version check\n\tif (indexJson.v < 4) {\n\t\tthrow new Error(\n\t\t\t'Storybook 7.x or earlier is not supported. Storywright requires Storybook 8 or later.\\n\\nError code: SW_E_STORYBOOK_UNSUPPORTED',\n\t\t);\n\t}\n\n\treturn indexJson;\n}\n\n/**\n * Parse Storybook index.json (v8+).\n */\nfunction normalizeStoryIndex(\n\traw: Record<string, unknown>,\n\t_compatibility: 'auto' | 'v8',\n): StoryIndex {\n\tconst version = typeof raw.v === 'number' ? raw.v : 0;\n\tconst entries = (raw.entries ?? {}) as Record<string, Story>;\n\n\treturn { v: version, entries };\n}\n\nexport function filterStories(storyIndex: StoryIndex, config: StorywrightConfig): StoryIndex {\n\tconst entries: Record<string, Story> = {};\n\tconst includeMatchers = config.include.map((p) => picomatch(p));\n\tconst excludeMatchers = config.exclude.map((p) => picomatch(p));\n\n\tfor (const [id, story] of Object.entries(storyIndex.entries)) {\n\t\t// Skip docs entries\n\t\tif (story.type === 'docs') continue;\n\t\tif (story.name === 'Docs') continue;\n\n\t\tconst fullName = `${story.title}/${story.name}`;\n\n\t\t// Check include patterns\n\t\tconst isIncluded = includeMatchers.some((m) => m(fullName));\n\t\tif (!isIncluded) continue;\n\n\t\t// Check exclude patterns\n\t\tconst isExcluded = excludeMatchers.some((m) => m(fullName));\n\t\tif (isExcluded) continue;\n\n\t\tentries[id] = story;\n\t}\n\n\treturn { ...storyIndex, entries };\n}\n\nexport function excludeStoriesForBrowser(\n\tstoryIndex: StoryIndex,\n\texcludePatterns: string[],\n): StoryIndex {\n\tif (excludePatterns.length === 0) {\n\t\treturn storyIndex;\n\t}\n\n\tconst excludeMatchers = excludePatterns.map((p) => picomatch(p));\n\tconst entries: Record<string, Story> = {};\n\n\tfor (const [id, story] of Object.entries(storyIndex.entries)) {\n\t\tconst fullName = `${story.title}/${story.name}`;\n\t\tconst isExcluded = excludeMatchers.some((m) => m(fullName));\n\t\tif (!isExcluded) {\n\t\t\tentries[id] = story;\n\t\t}\n\t}\n\n\treturn { ...storyIndex, entries };\n}\n"],"mappings":"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","names":["require","fs","path","picomatch","testMatchLine","escapeBackslash","fs","path","path","path","fs","fs","path","picomatch","path","fs","picomatch","path","fs","picomatch"]}