File size: 2,960 Bytes
0f4d9ea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { render, screen } from '@testing-library/react'
import { I18nProvider } from '../i18n'
import { FederatedStatusCard } from './FederatedStatusCard'
import * as ai from '../api/ai'

vi.mock('../api/ai')

const status: ai.FederatedStatus = {
  client_type: 'SYNTHETIC_SERVER_SIMULATION',
  real_device_training: 'NOT_IMPLEMENTED',
  native_local_only_training: 'NOT_IMPLEMENTED',
  real_user_data_used: false,
  federation: 'SIMULATED',
  secure_aggregation: 'DESIGN_ONLY',
  differential_privacy: 'SIMULATED',
  differential_privacy_detail: {
    differential_privacy: 'SIMULATED', budget_exhausted: true, candidate_privacy_eligibility: 'ineligible',
    cumulative_epsilon: 38.76, budget_epsilon: 8, production_privacy_guarantee: false, note: 'simulated only',
  },
  automatic_model_promotion: false, affects_payment_authorization: false,
  candidate_status: 'candidate', candidate_promotable: false,
  disclaimer: 'Server-side simulation using synthetic clients; not real cross-device federated learning.',
  label: 'SIMULATED', aggregators: ['coordinate_median', 'fedavg', 'trimmed_mean'],
}

const renderCard = (detailed = false) =>
  render(<I18nProvider initial="en"><FederatedStatusCard detailed={detailed} /></I18nProvider>)

describe('FederatedStatusCard', () => {
  beforeEach(() => { vi.spyOn(ai, 'federatedStatus').mockResolvedValue(status) })
  afterEach(() => vi.restoreAllMocks())

  it('reports synthetic server simulation + design-only + not-implemented labels', async () => {
    renderCard()
    expect(await screen.findByTestId('fed-label-client_type')).toHaveTextContent('SYNTHETIC_SERVER_SIMULATION')
    expect(screen.getByTestId('fed-label-secure_aggregation')).toHaveTextContent('DESIGN_ONLY')
    expect(screen.getByTestId('fed-label-real_device_training')).toHaveTextContent('NOT_IMPLEMENTED')
    expect(screen.getByTestId('fed-label-native_local_only_training')).toHaveTextContent('NOT_IMPLEMENTED')
  })

  it('surfaces the exhausted simulated DP budget as a warning', async () => {
    renderCard()
    expect(await screen.findByTestId('dp-exhausted')).toHaveTextContent(/budget is exhausted/i)
    expect(screen.getByTestId('dp-exhausted')).toHaveTextContent(/not a production privacy guarantee/i)
  })

  it('never claims data stays on the device', async () => {
    const { container } = renderCard(true)
    await screen.findByTestId('federated-status')
    expect(container.textContent).not.toMatch(/stays (only )?on your (phone|device)/i)
    expect(container.textContent).not.toMatch(/never leaves your device/i)
  })

  it('detailed mode states the candidate is not promotable and clients are synthetic', async () => {
    renderCard(true)
    expect(await screen.findByTestId('fed-not-promotable')).toHaveTextContent(/not promotable/i)
    expect(screen.getByTestId('fed-synthetic')).toHaveTextContent(/no real user data is used/i)
  })
})