import type { Store } from '../state/createStore' import { createStore } from '../state/createStore' import type { Emitter } from '../events' import { createEmitter } from '../events' import type { GridSelectionApi } from './selection' import { createSelectionApi } from './selection' import { INITIAL_STATE } from '../state' describe('selection api', () => { let store: Store, events: Emitter, api: GridSelectionApi beforeEach(() => { store = createStore() store.getState = jest.fn() jest.spyOn(store.selectors, 'selectAllSelectableIds') events = createEmitter() events.emit = jest.fn() api = createSelectionApi(store, events) }) it('should emit onSelectionChange with all ids when calling selectAll', () => { jest.mocked(store.selectors.selectAllSelectableIds).mockReturnValue( new Set(['1', '2', '3']) ) api.selectAll() expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['1', '2', '3']) ) }) it('should emit onSelectionChange with no ids when calling selectNone', () => { api.selectNone() expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set([]) ) }) describe('select', () => { describe('when setting to true', () => { describe('when replaceSelection is true', () => { it('should emit onSelectionChange with only the new id', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, selection: { mode: 'multi', controlled: false, selection: new Set(['123', '234']), anchor: null, }, }) api.select('345', true, true) expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['345']) ) }) }) describe('when replaceSelection is false', () => { it('should emit onSelectionChange and add the new id to the selection', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, selection: { mode: 'multi', controlled: false, selection: new Set(['123', '234']), anchor: null, }, }) api.select('345', true, false) expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['123', '234', '345']) ) }) }) describe("when replaceSelection is false but selection mode is 'single'", () => { it('should emit onSelectionChange with only the new id', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, selection: { mode: 'single', controlled: false, selection: new Set(['123']), anchor: null, }, }) api.select('345', true, false) expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['345']) ) }) }) }) describe('when setting to false', () => { it('should emit onSelectionChange without the selected id', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, selection: { mode: 'multi', controlled: false, selection: new Set(['123', '234']), anchor: null, }, }) api.select('123', false) expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['234']) ) }) }) }) describe('range selection', () => { it('should select range from low to high', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, rows: { ...INITIAL_STATE.rows, collection: { ...INITIAL_STATE.rows.collection, ids: ['1', '2', '3', '4', '5', '6', '7', '8', '9'], }, }, selection: { mode: 'multi', controlled: false, selection: new Set(['2']), anchor: '2', }, }) api.select('8', true, false, true) expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['2', '3', '4', '5', '6', '7', '8']) ) }) it('should select range from high to low', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, rows: { ...INITIAL_STATE.rows, collection: { ...INITIAL_STATE.rows.collection, ids: ['1', '2', '3', '4', '5', '6', '7', '8', '9'], }, }, selection: { mode: 'multi', controlled: false, selection: new Set(['4']), anchor: '4', }, }) api.select('1', true, false, true) expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['1', '2', '3', '4']) ) }) it('should reverse range direction from up to down', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, rows: { ...INITIAL_STATE.rows, collection: { ...INITIAL_STATE.rows.collection, ids: ['1', '2', '3', '4', '5', '6', '7', '8', '9'], }, }, selection: { mode: 'multi', controlled: false, selection: new Set(['4', '5', '6', '7', '8', '9']), anchor: '4', }, }) api.select('1', true, false, true) expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['1', '2', '3', '4']) ) }) it('should reverse range direction from down to up', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, rows: { ...INITIAL_STATE.rows, collection: { ...INITIAL_STATE.rows.collection, ids: ['1', '2', '3', '4', '5', '6', '7', '8', '9'], }, }, selection: { mode: 'multi', controlled: false, selection: new Set(['4', '5', '6']), anchor: '6', }, }) api.select('9', true, false, true) expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['6', '7', '8', '9']) ) }) it('should handle range if anchor is not in selection', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, rows: { ...INITIAL_STATE.rows, collection: { ...INITIAL_STATE.rows.collection, ids: ['1', '2', '3', '4', '5', '6', '7', '8', '9'], }, }, selection: { mode: 'multi', controlled: false, selection: new Set(['4', '5']), anchor: '6', }, }) api.select('9', true, false, true) expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['4', '5', '6', '7', '8', '9']) ) }) it('should handle range if no anchor', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, rows: { ...INITIAL_STATE.rows, collection: { ...INITIAL_STATE.rows.collection, ids: ['1', '2', '3', '4', '5', '6', '7', '8', '9'], }, }, selection: { mode: 'multi', controlled: false, selection: new Set(['9', '7']), anchor: null, }, }) api.select('6', true, false, true) expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['6', '7', '8', '9']) ) }) it('should start range if no selection', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, rows: { ...INITIAL_STATE.rows, collection: { ...INITIAL_STATE.rows.collection, ids: ['1', '2', '3', '4', '5', '6', '7', '8', '9'], }, }, selection: { mode: 'multi', controlled: false, selection: new Set(), anchor: null, }, }) api.select('6', true, false, true) expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['6']) ) }) it('should not start range if single mode', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, rows: { ...INITIAL_STATE.rows, collection: { ...INITIAL_STATE.rows.collection, ids: ['1', '2', '3', '4', '5', '6', '7', '8', '9'], }, }, selection: { mode: 'single', controlled: false, selection: new Set(['1']), anchor: null, }, }) api.select('6', true, false, true) expect(events.emit).toHaveBeenCalledWith( 'onSelectionChange', new Set(['6']) ) }) it('should not start range if none mode', () => { jest.mocked(store.getState).mockReturnValue({ ...INITIAL_STATE, rows: { ...INITIAL_STATE.rows, collection: { ...INITIAL_STATE.rows.collection, ids: ['1', '2', '3', '4', '5', '6', '7', '8', '9'], }, }, selection: { mode: 'none', controlled: false, selection: new Set(), anchor: null, }, }) api.select('6', true, false, true) expect(events.emit).not.toHaveBeenCalled() }) }) })