import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' import { fireEvent, render, screen } from '@testing-library/react' import { Provider } from '../../provider/widget-provider' import { clearAllWidgetStores, getWidgetStore } from '../../stores' import { LockSelection } from './lock-selection' import { filterByLockedItems } from './transforms' beforeEach(() => clearAllWidgetStores()) afterEach(() => clearAllWidgetStores()) const DATA = [ [ { name: 'A', value: 10 }, { name: 'B', value: 20 }, { name: 'C', value: 30 }, ], ] describe('', () => { it('disables the trigger when nothing is selected and nothing is locked', () => { render( undefined} labels={{ disabled: 'Pick rows' }} /> , ) const btn = screen.getByRole('button', { name: 'Pick rows' }) expect(btn.getAttribute('disabled')).not.toBeNull() }) it('shows the lock label when selection is non-empty and not locked', () => { render( undefined} labels={{ lock: 'Lock these' }} /> , ) const btn = screen.getByRole('button', { name: 'Lock these' }) expect(btn.getAttribute('aria-pressed')).toBe('false') expect(btn.getAttribute('disabled')).toBeNull() }) it('shows the unlock label when locked and aria-pressed=true', () => { render( undefined} labels={{ unlock: 'Release' }} /> , ) const btn = screen.getByRole('button', { name: 'Release' }) expect(btn.getAttribute('aria-pressed')).toBe('true') }) it('snapshots selection on lock — onLockChange called with current selection', () => { const onLockChange = vi.fn() render( , ) fireEvent.click(screen.getByRole('button', { name: 'Lock' })) expect(onLockChange).toHaveBeenCalledTimes(1) expect(onLockChange).toHaveBeenCalledWith(['A', 'B']) }) it('clears the lock — onLockChange called with empty array', () => { const onLockChange = vi.fn() render( , ) fireEvent.click(screen.getByRole('button', { name: 'Unlock' })) expect(onLockChange).toHaveBeenCalledWith([]) }) it('registers a data transform that filters when locked, restores when unlocked', () => { const { rerender } = render( undefined} /> , ) const locked = getWidgetStore('ls6').getState().data as unknown[][] expect(locked).toEqual([[{ name: 'A', value: 10 }]]) rerender( undefined} /> , ) const unlocked = getWidgetStore('ls6').getState().data as unknown[][] // With no lockedItems and the transform disabled, the pipeline returns // raw data. All three rows should be present. expect(unlocked.flat().length).toBe(3) }) it('lets the destination feed a different lockedItems set later', () => { const { rerender } = render( undefined} /> , ) expect( (getWidgetStore('ls7').getState().data as unknown[][]).flat(), ).toEqual([{ name: 'A', value: 10 }]) rerender( undefined} /> , ) expect( (getWidgetStore('ls7').getState().data as unknown[][]).flat(), ).toEqual([ { name: 'B', value: 20 }, { name: 'C', value: 30 }, ]) }) }) describe('filterByLockedItems', () => { it('returns input unchanged when locked set is empty', () => { expect(filterByLockedItems(DATA, [])).toBe(DATA) }) it('keeps only items whose name is in the locked set, preserving series shape', () => { const out = filterByLockedItems(DATA, ['A', 'C']) as unknown[][] expect(out).toEqual([ [ { name: 'A', value: 10 }, { name: 'C', value: 30 }, ], ]) }) it('handles numeric names', () => { const data = [ [ { name: 1, value: 10 }, { name: 2, value: 20 }, ], ] expect(filterByLockedItems(data, [2])).toEqual([[{ name: 2, value: 20 }]]) }) it('returns input unchanged when input is not array-shaped', () => { expect(filterByLockedItems('nope', ['A'])).toBe('nope') }) })