import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' import { act, render, screen } from '@testing-library/react' import { State } from './widget-state' import { Provider } from '../provider/widget-provider' import { clearAllWidgetStores, getCaptureEl, getWidgetStore } from '../stores' beforeEach(() => clearAllWidgetStores()) afterEach(() => clearAllWidgetStores()) describe('', () => { it('renders skeleton when isLoading is true (loading wins)', () => { render( }>
content
, ) expect(screen.getByTestId('skeleton')).toBeTruthy() }) it('renders default error UI when store error is set', () => { render(
content
, ) expect(screen.getByRole('alert').textContent).toContain('boom') }) it('renders custom fallback when provided', () => { render(
{e.message}
} >
content
, ) expect(screen.getByTestId('fb').textContent).toBe('x') }) it('renders empty UI when rawData is empty (default predicate)', () => { render(
content
, ) expect(screen.getByText('NOTHING')).toBeTruthy() }) it('renders content when there is data and no error/loading', () => { render(
content
, ) expect(screen.getByTestId('ok')).toBeTruthy() }) it('catches a render error in children and routes through the error UI', () => { const spy = vi.spyOn(console, 'error').mockImplementation(() => undefined) function Bomb(): null { throw new Error('render-throw') } render( , ) expect(screen.getByRole('alert').textContent).toContain('render-throw') spy.mockRestore() }) it('uses custom fallback for render errors too (single render path)', () => { const spy = vi.spyOn(console, 'error').mockImplementation(() => undefined) function Bomb(): null { throw new Error('render-throw-2') } render(
{e.message}
} >
, ) expect(screen.getByTestId('rb').textContent).toBe('render-throw-2') spy.mockRestore() }) it('uses custom isEmpty predicate against rawData', () => { render( !!d && typeof d === 'object' && Array.isArray((d as { rows: unknown[] }).rows) && (d as { rows: unknown[] }).rows.length === 0 } >
content
, ) expect(screen.getByText('NO ROWS')).toBeTruthy() }) it('hides errors during fetch (loading wins)', () => { render( }>
content
, ) expect(screen.getByTestId('skel')).toBeTruthy() expect(screen.queryByRole('alert')).toBeNull() }) describe('captureEl registry', () => { it('registers the success-path content wrapper as captureEl', () => { render(
content
, ) const el = getCaptureEl('cap-success') expect(el).not.toBeNull() // The captured element wraps the rendered content. expect(el?.contains(screen.getByTestId('inner'))).toBe(true) }) it('does not register a captureEl on the loading branch', () => { render( }>
content
, ) expect(getCaptureEl('cap-loading')).toBeNull() }) it('does not register a captureEl on the error branch', () => { render(
content
, ) expect(getCaptureEl('cap-error')).toBeNull() }) it('does not register a captureEl on the empty branch', () => { render(
content
, ) expect(getCaptureEl('cap-empty')).toBeNull() }) it('clears the captureEl on unmount', () => { const { unmount } = render(
content
, ) expect(getCaptureEl('cap-unmount')).not.toBeNull() unmount() expect(getCaptureEl('cap-unmount')).toBeNull() }) }) describe('default isEmpty predicate', () => { it('treats an empty object literal as empty', () => { render(
content
, ) expect(screen.getByText('EMPTY')).toBeTruthy() }) it('treats an array of empty arrays as empty', () => { render(
content
, ) expect(screen.getByText('EMPTY-ROWS')).toBeTruthy() }) it('treats a populated array of non-empty sub-arrays as non-empty', () => { render(
content
, ) expect(screen.getByTestId('content')).toBeTruthy() }) }) describe('toError coercion', () => { it('coerces a string error to an Error instance', () => { render(
content
, ) expect(screen.getByRole('alert').textContent).toContain('string-msg') }) it('coerces an object-with-message to an Error instance', () => { render(
content
, ) expect(screen.getByRole('alert').textContent).toContain('object-msg') }) it('falls back to "Unknown error" for unknown shapes', () => { render(
content
, ) expect(screen.getByRole('alert').textContent).toContain('Unknown error') }) }) it('routes a transform-throw error (set by middleware) through the same UI', () => { render(
content
, ) // Simulate a transform throw setting the error field act(() => { getWidgetStore('s10').setState({ dataTransforms: [ { id: 'bad', type: 'data', order: 1, enabled: true, fn: () => { throw new Error('transform-throw') }, }, ], }) }) expect(screen.getByRole('alert').textContent).toContain('transform-throw') }) })