import { describe, test, expect, beforeEach } from 'vitest' import { render, screen } from '@testing-library/react' import { FormulaUI } from './formula-ui' import { useWidgetStore } from '../stores/widget-store' import type { FormulaWidgetState } from './types' describe('FormulaUI', () => { beforeEach(() => { useWidgetStore.getState().clearWidgets() }) test('renders empty container when widget does not exist', () => { const { container } = render() // Box wrapper is rendered but Row returns null for missing widget expect(container.firstChild?.childNodes.length).toBe(0) }) test('renders with single data item', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 100, prefix: '$', suffix: 'USD' }], }) render() expect(screen.getByText('$')).toBeTruthy() expect(screen.getByText('100')).toBeTruthy() expect(screen.getByText('USD')).toBeTruthy() }) test('renders with multiple data items', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [ { value: 100, prefix: '$' }, { value: 200, suffix: '%' }, { value: 300 }, ], }) render() expect(screen.getByText('$')).toBeTruthy() expect(screen.getByText('100')).toBeTruthy() expect(screen.getByText('200')).toBeTruthy() expect(screen.getByText('%')).toBeTruthy() expect(screen.getByText('300')).toBeTruthy() }) test('renders Prefix component for each item', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [ { value: 100, prefix: 'Item 1:' }, { value: 200, prefix: 'Item 2:' }, ], }) render() expect(screen.getByText('Item 1:')).toBeTruthy() expect(screen.getByText('Item 2:')).toBeTruthy() }) test('renders Value component for each item', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 100 }, { value: 200 }], }) render() expect(screen.getByText('100')).toBeTruthy() expect(screen.getByText('200')).toBeTruthy() }) test('renders Suffix component for each item', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [ { value: 100, suffix: 'units' }, { value: 200, suffix: 'items' }, ], }) render() expect(screen.getByText('units')).toBeTruthy() expect(screen.getByText('items')).toBeTruthy() }) test('renders in correct order: Prefix, Value, Suffix', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 100, prefix: '$', suffix: 'USD' }], }) const { container } = render() const items = container.querySelectorAll('.MuiTypography-root') expect(items.length).toBe(3) expect(items[0]?.textContent).toBe('$') expect(items[1]?.textContent).toBe('100') expect(items[2]?.textContent).toBe('USD') }) test('handles data without prefix', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 100, suffix: 'USD' }], }) render() expect(screen.queryByText('$')).toBeNull() expect(screen.getByText('100')).toBeTruthy() expect(screen.getByText('USD')).toBeTruthy() }) test('handles data without suffix', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 100, prefix: '$' }], }) render() expect(screen.getByText('$')).toBeTruthy() expect(screen.getByText('100')).toBeTruthy() // Suffix should not be rendered const items = screen.queryAllByText('USD') expect(items.length).toBe(0) }) test('handles data with only value', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 100 }], }) render() expect(screen.getByText('100')).toBeTruthy() }) test('handles empty data array', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [], }) const { container } = render() // Row component returns null for empty data, Box wrapper still rendered expect(container.firstChild?.childNodes.length).toBe(0) }) test('handles undefined data', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', }) const { container } = render() // Row component returns null for undefined data, Box wrapper still rendered expect(container.firstChild?.childNodes.length).toBe(0) }) test('passes correct index to child components', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [ { value: 100, prefix: 'First' }, { value: 200, prefix: 'Second' }, { value: 300, prefix: 'Third' }, ], }) render() expect(screen.getByText('First')).toBeTruthy() expect(screen.getByText('100')).toBeTruthy() expect(screen.getByText('Second')).toBeTruthy() expect(screen.getByText('200')).toBeTruthy() expect(screen.getByText('Third')).toBeTruthy() expect(screen.getByText('300')).toBeTruthy() }) test('renders with data containing colors', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [ { value: 100, color: '#FF0000' }, { value: 200, color: '#00FF00' }, ], }) render() expect(screen.getByText('100')).toBeTruthy() expect(screen.getByText('200')).toBeTruthy() }) test('renders with negative values', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: -100, prefix: '-' }], }) render() expect(screen.getByText('-')).toBeTruthy() expect(screen.getByText('-100')).toBeTruthy() }) test('renders with zero value', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 0 }], }) render() expect(screen.getByText('0')).toBeTruthy() }) test('renders with decimal values', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 123.456, suffix: 'km' }], }) render() expect(screen.getByText('123.456')).toBeTruthy() expect(screen.getByText('km')).toBeTruthy() }) test('renders with large values', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 1000000000, prefix: '$' }], }) render() expect(screen.getByText('$')).toBeTruthy() expect(screen.getByText('1000000000')).toBeTruthy() }) test('updates when widget data changes', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 100 }], }) const { rerender } = render() expect(screen.getByText('100')).toBeTruthy() useWidgetStore.getState().setWidget('test-formula', { data: [{ value: 200 }], }) rerender() expect(screen.queryByText('100')).toBeNull() expect(screen.getByText('200')).toBeTruthy() }) test('handles widget removal gracefully', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 100 }], }) const { container, rerender } = render() expect(screen.getByText('100')).toBeTruthy() useWidgetStore.getState().removeWidget('test-formula') rerender() // Box wrapper still rendered but Row returns null expect(container.firstChild?.childNodes.length).toBe(0) }) test('renders with empty string prefix', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 100, prefix: '' }], }) const { container } = render() // Empty prefix should not render expect(container.firstChild).toBeTruthy() expect(screen.getByText('100')).toBeTruthy() }) test('renders with empty string suffix', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 100, suffix: '' }], }) const { container } = render() // Empty suffix should not render expect(container.firstChild).toBeTruthy() expect(screen.getByText('100')).toBeTruthy() }) test('renders multiple rows for multiple data items', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [ { value: 100, prefix: 'A' }, { value: 200, prefix: 'B' }, { value: 300, prefix: 'C' }, ], }) const { container } = render() // Each data item should create a row const rows = container.querySelectorAll('[class*="MuiBox-root"]') expect(rows.length).toBeGreaterThan(0) }) test('renders with single series in array', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 100, suffix: 'units' }], series: [{ name: 'Category A' }], }) render() expect(screen.getByText('C')).toBeTruthy() // Avatar shows first letter expect(screen.getByText('100')).toBeTruthy() }) test('renders with series and custom color', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [{ value: 100 }], series: [{ name: 'Sales', color: '#FF0000' }], }) const { container } = render() const avatar = container.querySelector('.MuiAvatar-root') expect(avatar).toBeTruthy() expect(screen.getByText('S')).toBeTruthy() // First letter of 'Sales' }) test('renders with array of series matching data indices', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [ { value: 100, suffix: 'units' }, { value: 200, suffix: 'items' }, { value: 300, suffix: 'pieces' }, ], series: [ { name: 'Alpha', color: '#FF0000' }, { name: 'Beta', color: '#00FF00' }, { name: 'Gamma', color: '#0000FF' }, ], }) render() expect(screen.getByText('A')).toBeTruthy() // Alpha expect(screen.getByText('B')).toBeTruthy() // Beta expect(screen.getByText('G')).toBeTruthy() // Gamma expect(screen.getByText('100')).toBeTruthy() expect(screen.getByText('200')).toBeTruthy() expect(screen.getByText('300')).toBeTruthy() }) test('renders partial series array - only shows series for available indices', () => { useWidgetStore.getState().setWidget('test-formula', { type: 'formula', data: [ { value: 100, suffix: 'units' }, { value: 200, suffix: 'items' }, { value: 300, suffix: 'pieces' }, ], series: [{ name: 'Only First', color: '#FF0000' }], }) render() // Only first row should have series avatar expect(screen.getByText('O')).toBeTruthy() // Only First expect(screen.getByText('100')).toBeTruthy() expect(screen.getByText('200')).toBeTruthy() expect(screen.getByText('300')).toBeTruthy() }) })