// @vitest-environment happy-dom
//
// Detail-dialog display mapping: the read-only `ViewValue` must render values
// with the SAME "pro" display logic as the table (shared `display-value.tsx`
// primitives), keyed off the stamped display type (`cellStyle ?? type`):
// - served option → colored badge with the localized label,
// - `cellStyle:'url'` on a text column → clickable external link (new tab),
// - `cellStyle:'status'` bare token (kanban stage) → colored, translated pill,
// - a `labels`/`tags` array → a row of badges (never a raw mini-table / JSON).
import { afterEach, describe, expect, it, vi } from 'vitest'
import { cleanup, render, screen } from '@testing-library/react'
// Identity-ish translator with a tiny stage dictionary, matching how the host
// resolves an addon's i18n keys (t(token, { defaultValue })).
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (k: string, opts?: any) =>
k === 'backlog' ? 'Pendiente' : opts?.defaultValue ?? k,
i18n: { language: 'es' },
}),
}))
import { ViewValue } from '../dialogs/dynamic-record'
afterEach(cleanup)
describe('ViewValue — detail dialog display mapping', () => {
it('renders a served option as a colored badge with the localized label', () => {
render(
)
const badge = screen.getByText('Almacenable')
expect(badge).toBeTruthy()
// Never the raw enum token.
expect(screen.queryByText('storable')).toBeNull()
})
it('renders a cellStyle:url text column as a clickable external link', () => {
const { container } = render(
)
const link = container.querySelector('a') as HTMLAnchorElement
expect(link).toBeTruthy()
expect(link.getAttribute('href')).toBe('https://github.com/asteby/x')
expect(link.getAttribute('target')).toBe('_blank')
})
it('renders a bare stage token (cellStyle:status) as a translated colored pill', () => {
const { container } = render(
)
// Localized via the manifest i18n key, not the raw "backlog".
expect(screen.getByText('Pendiente')).toBeTruthy()
expect(container.textContent).not.toContain('backlog')
// Colored: the badge carries an inline background style.
const styled = container.querySelector('[style*="background"]')
expect(styled).toBeTruthy()
})
it('renders a labels array (cellStyle:tags) as a row of badges', () => {
render(
)
expect(screen.getByText('bug')).toBeTruthy()
expect(screen.getByText('urgent')).toBeTruthy()
})
it('renders label objects with color as colored badges', () => {
render(
)
expect(screen.getByText('Bug')).toBeTruthy()
expect(screen.getByText('P1')).toBeTruthy()
})
it('keeps the "—" empty marker for an empty labels array', () => {
const { container } = render(
)
expect(container.textContent).toContain('—')
})
it('renders plain text external_id without a relation initials avatar', () => {
const { container } = render(
)
expect(screen.getByText('6a8c931523ea7')).toBeTruthy()
// Must NOT render the InitialsAvatar lead ("6" chip) used for FKs.
expect(container.querySelector('[data-slot="avatar"]')).toBeNull()
expect(container.textContent).not.toMatch(/^6\s*6a8c/)
})
it('renders nested provider_data objects as pretty JSON, not key: {…}', () => {
render(
)
expect(screen.getByText('03')).toBeTruthy()
expect(screen.getByText(/"Folio": 950/)).toBeTruthy()
expect(screen.queryByText(/Inv:\s*\{\.\.\.\}/i)).toBeNull()
})
})