tests/build-tracking-helpers.unit.test.ts
Rama main · réplica de lectura del repositorio original.
import { describe, expect, it } from 'vitest'
import { classifyBuildTransition, mapBuildFailureCategory } from '../supabase/functions/_backend/utils/build_tracking.ts'
import { getBuilderXcodeVersion } from '../supabase/functions/_backend/utils/builder_machine.ts'
describe('classifyBuildTransition', () => {
it.concurrent.each([
['pending', 'running', false, 'started'],
['queued', 'running', false, 'started'],
['running', 'succeeded', false, 'succeeded'],
['pending', 'succeeded', false, 'succeeded'],
['running', 'failed', false, 'failed'],
['running', 'failed', true, 'timed_out'],
['running', 'succeeded', true, 'timed_out'],
// timeout overrides no-change
['running', 'running', true, 'timed_out'],
// previous already terminal (idempotency), even with timeoutApplied
['succeeded', 'succeeded', false, null],
['failed', 'failed', false, null],
['cancelled', 'cancelled', false, null],
['expired', 'expired', false, null],
['released', 'released', false, null],
['failed', 'failed', true, null],
// no state change
['pending', 'pending', false, null],
['running', 'running', false, null],
] as const)('%s -> %s (timeoutApplied=%s) is %s', (previous, next, timeoutApplied, expected) => {
expect(classifyBuildTransition({ previous, next, timeoutApplied })).toBe(expected)
})
})
describe('mapBuildFailureCategory', () => {
it.concurrent('returns timeout when the timeout flag is set', () => {
expect(mapBuildFailureCategory({ timeoutApplied: true, errorMessage: null })).toBe('timeout')
})
it.concurrent('returns validation_error for validation-style messages', () => {
expect(mapBuildFailureCategory({ timeoutApplied: false, errorMessage: 'Invalid build_mode value' })).toBe('validation_error')
expect(mapBuildFailureCategory({ timeoutApplied: false, errorMessage: 'missing credentials' })).toBe('validation_error')
})
it.concurrent('returns builder_error when there is any other non-empty error', () => {
expect(mapBuildFailureCategory({ timeoutApplied: false, errorMessage: 'gradle compile failed' })).toBe('builder_error')
})
it.concurrent('returns unknown when timeoutApplied is false and error is empty', () => {
expect(mapBuildFailureCategory({ timeoutApplied: false, errorMessage: null })).toBe('unknown')
expect(mapBuildFailureCategory({ timeoutApplied: false, errorMessage: '' })).toBe('unknown')
})
})
describe('getBuilderXcodeVersion', () => {
it.concurrent('reads the Xcode version reported by the builder', () => {
expect(getBuilderXcodeVersion({ backend: 'mac', xcode_version: '26.1', macos_version: '15.6' })).toBe('26.1')
expect(getBuilderXcodeVersion({ backend: 'linux', xcode_version: '27' })).toBe('27')
})
it.concurrent('ignores missing or malformed versions', () => {
expect(getBuilderXcodeVersion(null)).toBeNull()
expect(getBuilderXcodeVersion({})).toBeNull()
expect(getBuilderXcodeVersion({ xcode_version: 26 })).toBeNull()
expect(getBuilderXcodeVersion({ xcode_version: 'Xcode 26.1' })).toBeNull()
})
})