UNPKG

@vizzly-testing/cli

Version:

Visual review platform for UI developers and designers

255 lines (233 loc) 7.29 kB
/** * Test Runner Core - Pure functions for test execution logic * * No I/O, no side effects - just data transformations. */ // ============================================================================ // Environment Building // ============================================================================ /** * Build environment variables for test process execution * @param {Object} options - Options * @param {number} options.port - Server port * @param {string} options.buildId - Build ID * @param {boolean} [options.setBaseline] - Whether to set baseline * @param {Object} [options.baseEnv] - Base environment (defaults to process.env) * @returns {Object} Environment variables object */ export function buildTestEnv({ port, buildId, setBaseline = false, baseEnv = process.env }) { return { ...baseEnv, VIZZLY_SERVER_URL: `http://localhost:${port}`, VIZZLY_BUILD_ID: buildId, VIZZLY_ENABLED: 'true', VIZZLY_SET_BASELINE: setBaseline ? 'true' : 'false' }; } /** * Build environment for disabled Vizzly (allowNoToken mode) * @param {Object} [baseEnv] - Base environment (defaults to process.env) * @returns {Object} Environment variables object */ export function buildDisabledEnv(baseEnv = process.env) { return { ...baseEnv, VIZZLY_ENABLED: 'false' }; } // ============================================================================ // Build Payload Building // ============================================================================ /** * Build API build payload from options * @param {Object} options - Run options * @param {Object} [comparisonConfig] - Comparison configuration (threshold, minClusterSize) * @returns {Object} Build payload for API */ export function buildApiBuildPayload(options, comparisonConfig = null) { let payload = { name: options.buildName || `Test Run ${new Date().toISOString()}`, branch: options.branch || 'main', environment: options.environment || 'test', commit_sha: options.commit, commit_message: options.message, github_pull_request_number: options.pullRequestNumber, parallel_id: options.parallelId }; // Only include metadata if we have meaningful config to send if (comparisonConfig?.threshold != null || comparisonConfig?.minClusterSize != null) { payload.metadata = { comparison: { threshold: comparisonConfig.threshold, minClusterSize: comparisonConfig.minClusterSize } }; } return payload; } // ============================================================================ // Mode Determination // ============================================================================ /** * Determine if we should skip Vizzly integration entirely * @param {Object} options - Options * @param {boolean} options.allowNoToken - Whether to allow running without token * @param {boolean} options.hasApiKey - Whether an API key is available * @param {boolean} options.tdd - Whether in TDD mode * @returns {boolean} True if Vizzly should be disabled */ export function shouldDisableVizzly({ allowNoToken, hasApiKey, tdd }) { return allowNoToken && !hasApiKey && !tdd; } /** * Determine build mode * @param {boolean} tdd - Whether TDD mode is enabled * @returns {'tdd'|'api'} Build mode */ export function determineBuildMode(tdd) { return tdd ? 'tdd' : 'api'; } // ============================================================================ // Result Building // ============================================================================ /** * Build result object for disabled run (no Vizzly integration) * @returns {Object} Result object */ export function buildDisabledRunResult() { return { testsPassed: 1, testsFailed: 0, screenshotsCaptured: 0 }; } /** * Build final run result object * @param {Object} options - Options * @param {string|null} options.buildId - Build ID * @param {string|null} options.buildUrl - Build URL * @param {boolean} options.testSuccess - Whether tests passed * @param {number} options.screenshotCount - Number of screenshots * @param {Object|null} options.tddResults - TDD results (comparisons, etc.) * @returns {Object} Final result object */ export function buildRunResult({ buildId, buildUrl, testSuccess, screenshotCount, tddResults }) { return { buildId, url: buildUrl, testsPassed: testSuccess ? 1 : 0, testsFailed: testSuccess ? 0 : 1, screenshotsCaptured: screenshotCount, comparisons: tddResults?.comparisons || null, failed: (tddResults?.failed || 0) > 0 }; } // ============================================================================ // Validation // ============================================================================ /** * Validate test command is provided * @param {string|undefined} testCommand - Test command to validate * @returns {{ valid: boolean, error: string|null }} */ export function validateTestCommand(testCommand) { if (!testCommand) { return { valid: false, error: 'No test command provided' }; } return { valid: true, error: null }; } /** * Validate daemon mode requirements * @param {Object} options - Options * @param {boolean} options.tdd - Whether TDD mode is enabled * @param {boolean} options.daemon - Whether daemon mode is enabled * @returns {{ valid: boolean, error: string|null }} */ export function validateDaemonMode({ tdd, daemon }) { if (!tdd || !daemon) { return { valid: false, error: 'Initialize method is only for TDD daemon mode' }; } return { valid: true, error: null }; } // ============================================================================ // Client Options Building // ============================================================================ /** * Build API client options from config * @param {Object} config - Configuration object * @returns {Object|null} Client options or null if no API key */ export function buildClientOptions(config) { if (!config?.apiKey) { return null; } return { baseUrl: config.apiUrl, token: config.apiKey, command: 'run' }; } /** * Check if API key is available * @param {Object} config - Configuration object * @returns {boolean} Whether API key exists */ export function hasApiKey(config) { return Boolean(config?.apiKey); } // ============================================================================ // Spawn Options Building // ============================================================================ /** * Build spawn options for test command execution * @param {Object} env - Environment variables * @returns {Object} Spawn options */ export function buildSpawnOptions(env) { return { env, stdio: 'inherit', shell: true }; } // ============================================================================ // Set Baseline Normalization // ============================================================================ /** * Normalize setBaseline option (handles both camelCase and kebab-case) * @param {Object} options - Options object * @returns {boolean} Whether to set baseline */ export function normalizeSetBaseline(options) { return Boolean(options?.setBaseline || options?.['set-baseline']); }