Ctrl K
ComunidadGuías…

tests/cicd-setup-state.unit.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { describe, expect, it } from 'vitest'
import { ciCdDetectedAt, isAppShipping, isCiCdSetupDone, parseCiCdSetupState, resolveCiGuideContext, shouldShowCiCdNav, withCiCdMarkedDone } from '../src/utils/cicdSetupState'

const shipping = { features: { ota: { succeeded_at: '2026-10-01T00:00:00.000Z' } } }

describe('CI/CD setup state', () => {
  it.concurrent.each([
    { product: 'ota', selectedPath: 'builder', expected: 'ota' },
    { product: 'builder', selectedPath: 'ota', expected: 'builder' },
    { product: undefined, selectedPath: 'builder', expected: 'builder' },
    { product: 'invalid', selectedPath: 'ota', expected: 'ota' },
    { product: ['builder'], selectedPath: 'ota', expected: 'ota' },
  ])('resolves the product from entry context before onboarding ($product, $selectedPath)', ({ product, selectedPath, expected }) => {
    expect(resolveCiGuideContext({
      product,
      onboarding: { setup: { selected_path: selectedPath } },
    }).product).toBe(expected)
  })

  it.concurrent('uses product history for context-free visits with no selected path', () => {
    const onboarding = { features: {
      ota: { succeeded_at: '2026-10-01T00:00:00.000Z' },
      builder: { last_used_at: '2026-11-01T00:00:00.000Z' },
    } }
    expect(resolveCiGuideContext({ onboarding }).product).toBe('builder')
    expect(resolveCiGuideContext({ onboarding: {
      ...onboarding,
      features: { ...onboarding.features, ota: { started_at: '2026-11-02T00:00:00.000Z' } },
    } }).product).toBe('ota')
    expect(resolveCiGuideContext({ onboarding: {
      ...onboarding,
      setup: { selected_path: 'ota' },
    } }).product).toBe('ota')
  })

  it.concurrent.each([null, {}, { features: [] }, { setup: { selected_path: 'other' } }, {
    features: { builder: { started_at: 'invalid' }, ota: { succeeded_at: 'invalid' } },
  }])('falls back to live updates without valid context or history (%j)', (onboarding) => {
    expect(resolveCiGuideContext({ onboarding })).toEqual({ product: 'ota', platform: undefined })
  })

  it.concurrent.each(['ota', 'builder'] as const)('resumes a single %s onboarding path without a selected_path', (product) => {
    expect(resolveCiGuideContext({ onboarding: { setup: { paths: [product] } } }).product).toBe(product)
  })

  it.concurrent('carries the selected Builder platform and accepts an explicit platform override', () => {
    const onboarding = { setup: { selected_path: 'builder', selected_builder_platform: 'ios' } }
    expect(resolveCiGuideContext({ onboarding })).toEqual({ product: 'builder', platform: 'ios' })
    expect(resolveCiGuideContext({ onboarding, platform: 'android' })).toEqual({ product: 'builder', platform: 'android' })
    expect(resolveCiGuideContext({ onboarding, platform: ['android'] })).toEqual({ product: 'builder', platform: 'ios' })
    expect(resolveCiGuideContext({ onboarding: {}, product: 'builder', platform: 'invalid' })).toEqual({ product: 'builder', platform: undefined })
    expect(resolveCiGuideContext({ onboarding, product: 'ota', platform: 'android' })).toEqual({ product: 'ota', platform: undefined })
  })

  it('parses the onboarding.cicd ledger and ignores malformed values', () => {
    expect(parseCiCdSetupState({ cicd: {
      ota_detected_at: '2026-11-01T00:00:00.000Z',
      builder_detected_at: '',
      detected_via: 'ci',
      ci_provider: 'GitHub Actions',
      ota_detected_via: 'ci',
      ota_ci_provider: 'GitHub Actions',
      builder_detected_via: 'key',
      key_created_at: 42,
      marked_done_at: null,
    } })).toEqual({
      otaDetectedAt: '2026-11-01T00:00:00.000Z',
      builderDetectedAt: null,
      detectedVia: 'ci',
      ciProvider: 'GitHub Actions',
      otaDetectedVia: 'ci',
      otaCiProvider: 'GitHub Actions',
      builderDetectedVia: 'key',
      builderCiProvider: null,
      keyCreatedAt: null,
      markedDoneAt: null,
      dismissedAt: null,
    })
    expect(parseCiCdSetupState(null).detectedVia).toBeNull()
    expect(parseCiCdSetupState({ cicd: [] }).otaDetectedAt).toBeNull()
    expect(parseCiCdSetupState({ cicd: { detected_via: 'api' } }).detectedVia).toBeNull()
  })

  it('treats CI evidence or a self-report as done', () => {
    expect(isCiCdSetupDone({})).toBe(false)
    expect(isCiCdSetupDone({ cicd: { key_created_at: '2026-11-01T00:00:00.000Z' } })).toBe(false)
    expect(isCiCdSetupDone({ cicd: { builder_detected_at: '2026-11-01T00:00:00.000Z' } })).toBe(true)
    expect(isCiCdSetupDone({ cicd: { marked_done_at: '2026-11-01T00:00:00.000Z' } })).toBe(true)
    expect(ciCdDetectedAt(parseCiCdSetupState({ cicd: { ota_detected_at: '2026-11-03T00:00:00.000Z', builder_detected_at: '2026-11-02T00:00:00.000Z' } }))).toBe('2026-11-02T00:00:00.000Z')
  })

  it('only nudges shipping apps once Getting started is gone', () => {
    expect(isAppShipping({})).toBe(false)
    expect(isAppShipping(shipping)).toBe(true)
    expect(isAppShipping({ features: { builder: { succeeded_at: '2026-10-01T00:00:00.000Z' } } })).toBe(true)
    expect(isAppShipping({ setup: { outcome: 'completed' } })).toBe(true)
    expect(isAppShipping({ setup: { outcome: 'skipped' } })).toBe(false)

    expect(shouldShowCiCdNav(shipping, false)).toBe(true)
    expect(shouldShowCiCdNav(shipping, true)).toBe(false)
    expect(shouldShowCiCdNav({}, false)).toBe(false)
    expect(shouldShowCiCdNav({ ...shipping, cicd: { ota_detected_at: '2026-11-01T00:00:00.000Z' } }, false)).toBe(false)
    expect(shouldShowCiCdNav({ ...shipping, cicd: { marked_done_at: '2026-11-01T00:00:00.000Z' } }, false)).toBe(false)
    // Creating a key is progress, not proof: the nudge stays until CI ships once.
    expect(shouldShowCiCdNav({ ...shipping, cicd: { key_created_at: '2026-11-01T00:00:00.000Z', keys: ['k'] } }, false)).toBe(true)
  })

  it('marks done locally without losing other onboarding fields', () => {
    const next = withCiCdMarkedDone({ ...shipping, cicd: { keys: ['k'] } }, '2026-11-06T00:00:00.000Z') as Record<string, any>
    expect(next.features).toEqual(shipping.features)
    expect(next.cicd).toEqual({ keys: ['k'], marked_done_at: '2026-11-06T00:00:00.000Z' })
    expect((withCiCdMarkedDone(next, '2026-12-01T00:00:00.000Z') as Record<string, any>).cicd.marked_done_at).toBe('2026-11-06T00:00:00.000Z')
  })

  it.concurrent('hides dismissed reminders without counting them as configured', () => {
    const onboarding = { ...shipping, cicd: { dismissed_at: '2026-11-10T00:00:00.000Z' } }
    expect(parseCiCdSetupState(onboarding).dismissedAt).toBe('2026-11-10T00:00:00.000Z')
    expect(shouldShowCiCdNav(onboarding, false)).toBe(false)
    expect(isCiCdSetupDone(onboarding)).toBe(false)
    expect(ciCdDetectedAt(parseCiCdSetupState(onboarding))).toBeNull()
    expect(shouldShowCiCdNav({ ...shipping, cicd: { dismissed_at: null } }, false)).toBe(true)
    expect(shouldShowCiCdNav({ ...shipping, cicd: { dismissed_at: 42 } }, false)).toBe(true)
  })
})