diff --git a/test/aspire-integration.test.ts b/test/aspire-integration.test.ts index d54d5a99e..97eb166e4 100644 --- a/test/aspire-integration.test.ts +++ b/test/aspire-integration.test.ts @@ -15,6 +15,7 @@ import { trace, metrics } from '@opentelemetry/api'; import { NodeSDK, resources, metrics as sdkMetrics } from '@opentelemetry/sdk-node'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc'; +import { dockerSkipReason } from './helpers/skip-guards.js'; const { Resource } = resources; const { PeriodicExportingMetricReader } = sdkMetrics; @@ -23,20 +24,7 @@ const { PeriodicExportingMetricReader } = sdkMetrics; // Skip guard — bail early if Docker is unavailable or tests disabled // ============================================================================ -function dockerAvailable(): boolean { - try { - execSync('docker --version', { stdio: 'ignore' }); - return true; - } catch { - return false; - } -} - -const SKIP_REASON = process.env['SKIP_DOCKER_TESTS'] === '1' - ? 'SKIP_DOCKER_TESTS=1' - : !dockerAvailable() - ? 'Docker not available' - : null; +const SKIP_REASON = dockerSkipReason(); const CONTAINER_NAME = 'squad-aspire-dashboard'; const DASHBOARD_URL = 'http://localhost:18888'; diff --git a/test/cli/aspire.test.ts b/test/cli/aspire.test.ts index c17d7a578..d4c817c39 100644 --- a/test/cli/aspire.test.ts +++ b/test/cli/aspire.test.ts @@ -18,6 +18,13 @@ import { describe, it, expect, vi, afterEach } from 'vitest'; import { execSync } from 'child_process'; import { existsSync } from 'fs'; import { join } from 'path'; +import { dockerSkipReason } from '../helpers/skip-guards.js'; + +// =========================================================================== +// Skip guard — bail early if Docker is unavailable or tests disabled +// =========================================================================== + +const SKIP_REASON = dockerSkipReason(); // =========================================================================== // Docker availability helpers (mockable) @@ -66,7 +73,10 @@ function buildAspireStopCommands(name = 'squad-aspire-dashboard'): string[][] { // Docker availability // =========================================================================== -describe('CLI: squad aspire — Docker availability', { timeout: 30_000 }, () => { +describe.skipIf(SKIP_REASON !== null)( + `CLI: squad aspire — Docker availability (${SKIP_REASON ?? 'enabled'})`, + { timeout: 30_000 }, + () => { it('checkDockerAvailability returns version string when Docker is present', () => { const result = checkDockerAvailability(); if (result === null) { diff --git a/test/helpers/skip-guards.ts b/test/helpers/skip-guards.ts new file mode 100644 index 000000000..e200a1b3f --- /dev/null +++ b/test/helpers/skip-guards.ts @@ -0,0 +1,36 @@ +/** + * Shared test helpers for skip guards and environment detection. + * + * Provides reusable functions for detecting Docker availability, + * shell module availability, and other environment conditions + * that determine whether certain test suites should run. + */ + +import { execSync } from 'node:child_process'; + +/** + * Check if Docker is available on this machine. + * Returns true if `docker --version` succeeds within 5 seconds. + */ +export function isDockerAvailable(): boolean { + try { + execSync('docker --version', { stdio: 'ignore', timeout: 5000 }); + return true; + } catch { + return false; + } +} + +/** + * Determine skip reason for Docker-dependent tests. + * Returns null if tests should run, or a string reason to skip. + */ +export function dockerSkipReason(): string | null { + if (process.env['SKIP_DOCKER_TESTS'] === '1') { + return 'SKIP_DOCKER_TESTS=1'; + } + if (!isDockerAvailable()) { + return 'Docker not available'; + } + return null; +} diff --git a/test/template-sync.test.ts b/test/template-sync.test.ts index 66938078b..c5e27a8ca 100644 --- a/test/template-sync.test.ts +++ b/test/template-sync.test.ts @@ -153,7 +153,7 @@ describe('sync-templates.mjs script execution', () => { const output = execSync('node scripts/sync-templates.mjs', { cwd: ROOT, encoding: 'utf-8', - timeout: 30_000, + timeout: 60_000, }); expect(output).toContain('Synced'); });