import type { GridState } from '..' import { jest } from '@jest/globals' import type { StoreSimpleSelectors } from '../selectors' import type { SelectCurrentFocus, SelectHasFocus } from './focus' import generateSelectors from './focus' import type { GridRowId } from '../../types' import type { GridFocusState } from '../reducer/focus' import type { SelectColumnSpanByRowId } from './row' const state = {} as GridState describe('compositeSelectors - focus', () => { let selectCurrentFocus: SelectCurrentFocus let selectHasFocus: SelectHasFocus let selectRowIds: jest.Mock<(state: GridState) => GridRowId[]> let selectRawCurrentFocus: jest.Mock< StoreSimpleSelectors['selectRawCurrentFocus'] > let selectHeaderHierarchy: jest.Mock< StoreSimpleSelectors['selectHeaderHierarchy'] > let selectUnsortedColumnIds: jest.Mock< StoreSimpleSelectors['selectUnsortedColumnIds'] > let selectHeaderRowIds: jest.Mock<(state: GridState) => GridRowId[]> let selectHiddenIds: jest.Mock let selectAreHeadersHidden: jest.Mock< StoreSimpleSelectors['selectAreHeadersHidden'] > let selectColumnSpanByRowId: jest.Mock beforeEach(() => { selectRowIds = jest .fn<(state: GridState) => GridRowId[]>() .mockReturnValue(['1', '2', '3']) selectHeaderRowIds = jest .fn<(state: GridState) => GridRowId[]>() .mockReturnValue(['0']) selectUnsortedColumnIds = jest .fn() .mockReturnValue(['column1', 'column2', 'column3', 'column4']) selectRawCurrentFocus = jest .fn() .mockReturnValue({ area: 'header', columnId: 'column1', rowId: '0', subFocus: 'first', }) selectHeaderHierarchy = jest .fn() .mockReturnValue({ groups: [], levels: 0 }) selectHiddenIds = jest .fn() .mockReturnValue([]) selectAreHeadersHidden = jest .fn() .mockReturnValue(false) selectColumnSpanByRowId = jest .fn() .mockReturnValue(null) ;({ selectCurrentFocus, selectHasFocus } = generateSelectors( { selectUnsortedColumnIds, selectRawCurrentFocus, selectHeaderHierarchy, selectHiddenIds, selectAreHeadersHidden, }, selectRowIds, selectHeaderRowIds, selectColumnSpanByRowId )) }) describe('selectCurrentFocus', () => { it('should return the focus unchanged if all values are valid', () => { const currentFocus: GridFocusState['focus'] = { area: 'body', columnId: 'column1', rowId: '1', subFocus: 'first', } selectRawCurrentFocus.mockReturnValue(currentFocus) expect(selectCurrentFocus(state)).toBe(currentFocus) }) it('should set area to header if row is missing', () => { selectRawCurrentFocus.mockReturnValue({ area: 'body', columnId: 'column1', rowId: '5', subFocus: 'first', }) expect(selectCurrentFocus(state)).toEqual({ area: 'header', columnId: 'column1', rowId: '0', subFocus: 'first', }) }) it('should set column to first visible if columnId is hidden', () => { selectRawCurrentFocus.mockReturnValue({ area: 'body', columnId: 'column1', rowId: '1', subFocus: 'first', }) selectHiddenIds.mockReturnValue(['column1']) expect(selectCurrentFocus(state)).toEqual({ area: 'body', columnId: 'column2', rowId: '1', subFocus: 'first', }) }) it('should set fix columnId if columnId is missing', () => { selectRawCurrentFocus.mockReturnValue({ area: 'body', columnId: 'column5', rowId: '1', subFocus: 'first', }) expect(selectCurrentFocus(state)).toEqual({ area: 'body', columnId: 'column1', rowId: '1', subFocus: 'first', }) }) it('should set area to body if focus is in header but headers are hidden', () => { selectRawCurrentFocus.mockReturnValue({ area: 'header', columnId: 'column1', rowId: '0', subFocus: 'first', }) selectAreHeadersHidden.mockReturnValue(true) expect(selectCurrentFocus(state)).toEqual({ area: 'body', columnId: 'column1', rowId: '1', subFocus: 'first', }) }) }) describe('selectHasFocus', () => { it('should return true if columnId and rowId match', () => { expect(selectHasFocus(state, 'column1', 'header', '0')).toBe(true) }) it('should return true if columnId is within columnSpan', () => { const currentFocus: GridFocusState['focus'] = { area: 'body', // Actual focus is on column 4, but only column 3 is rendered and evaluated // as the focus column columnId: 'column4', rowId: '1', subFocus: 'first', } selectRawCurrentFocus.mockReturnValue(currentFocus) selectColumnSpanByRowId.mockReturnValue( new Map([ [ 'column3', { id: 'column3', positionColumnIds: ['column3', 'column4'], }, ], ]) ) expect(selectHasFocus(state, 'column3', 'body', '1')).toBe(true) }) it('should return false if columnId or rowId do not match', () => { expect(selectHasFocus(state, 'column2', 'header', '0')).toBe(false) expect(selectHasFocus(state, 'column1', 'header', '1')).toBe(false) }) it('should return true if group has column within span', () => { const currentFocus: GridFocusState['focus'] = { area: 'header', columnId: 'column3', rowId: '0', subFocus: 'first', } selectRawCurrentFocus.mockReturnValue(currentFocus) selectHeaderHierarchy.mockReturnValue({ levels: 1, groups: [ { id: 'group1', level: 1, childIds: ['column1', 'column2', 'column3'], columnIds: ['column1', 'column2', 'column3'], parentIds: [], width: 2, }, ], }) expect(selectHasFocus(state, 'group1', 'header', '0')).toBe(true) }) it('should return true if group has column as grand-child within span', () => { const currentFocus: GridFocusState['focus'] = { area: 'header', columnId: 'column3', rowId: '0', subFocus: 'first', } selectRawCurrentFocus.mockReturnValue(currentFocus) selectHeaderHierarchy.mockReturnValue({ levels: 2, groups: [ { id: 'top-group', level: 2, childIds: ['group1', 'group2'], columnIds: ['column1', 'column2', 'column3'], parentIds: [], width: 3, }, { id: 'group1', level: 1, childIds: ['column1', 'column2'], columnIds: ['column1', 'column2'], parentIds: ['top-group'], width: 2, }, { id: 'group2', level: 1, childIds: ['column3'], columnIds: ['column3'], parentIds: ['top-group'], width: 1, }, ], }) expect(selectHasFocus(state, 'top-group', 'header', '0')).toBe(true) }) }) })