import type { Store } from '../state/createStore' import { createStore } from '../state/createStore' import type { Emitter } from '../events' import { createEmitter } from '../events' import type { GridColumnApi } from './column' import { createColumnApi } from './column' describe('column api', () => { let store: Store, events: Emitter, api: GridColumnApi beforeEach(() => { store = createStore() store.dispatch = jest.fn() store.getState = jest.fn() jest.spyOn(store.selectors, 'selectSort').mockReturnValue([]) jest.spyOn( store.selectors, 'selectIsMultiColumnSorting' ).mockReturnValue(false) jest.spyOn( store.selectors, 'selectIsMultiColumnSortingEnabled' ).mockReturnValue(true) jest.spyOn(store.selectors, 'selectColumnSort').mockReturnValue( undefined ) jest.spyOn(store.selectors, 'selectDefaultSort').mockReturnValue( undefined ) jest.spyOn(store.selectors, 'selectColumnMenuEnabled').mockReturnValue( true ) events = createEmitter() events.emit = jest.fn() api = createColumnApi(store, events) }) describe('toggleSort', () => { describe('when column is not yet sorted', () => { it('should start with ascending', () => { api.toggleSort('123') expect(events.emit).toHaveBeenCalledWith('onSortChange', [ { columnId: '123', direction: 'asc' }, ]) }) }) describe('when column is sorted ascending', () => { it('should switch to descending', () => { jest.mocked(store.selectors.selectColumnSort).mockReturnValue({ columnId: '123', direction: 'asc', }) api.toggleSort('123') expect(events.emit).toHaveBeenCalledWith('onSortChange', [ { columnId: '123', direction: 'desc' }, ]) }) }) describe('when column is sorted descending', () => { it('should switch to unset', () => { jest.mocked(store.selectors.selectColumnSort).mockReturnValue({ columnId: '123', direction: 'desc', }) api.toggleSort('123') expect(events.emit).toHaveBeenCalledWith('onSortChange', []) }) }) describe('when replacing sort and multi column sorting', () => { it('should start over with ascending', () => { jest.mocked(store.selectors.selectColumnSort).mockReturnValue({ columnId: '123', direction: 'desc', }) jest.mocked( store.selectors.selectIsMultiColumnSorting ).mockReturnValue(true) api.toggleSort('123', true) expect(events.emit).toHaveBeenCalledWith('onSortChange', [ { columnId: '123', direction: 'asc' }, ]) }) }) describe('when default sort direction is desc ', () => { describe('when column is the only default column', () => { it('should toggle between desc and asc and not unset', () => { jest.mocked( store.selectors.selectDefaultSort ).mockReturnValue([ { columnId: '123', direction: 'desc', }, ]) jest.mocked( store.selectors.selectColumnSort ).mockReturnValue({ columnId: '123', direction: 'desc', }) api.toggleSort('123', true) expect(events.emit).toHaveBeenCalledWith('onSortChange', [ { columnId: '123', direction: 'asc' }, ]) }) }) describe('when column is part of a multi-column sort', () => { it('should remove desc column from sort', () => { jest.mocked( store.selectors.selectIsMultiColumnSorting ).mockReturnValue(true) jest.mocked(store.selectors.selectSort).mockReturnValue([ { columnId: '123', direction: 'desc' }, { columnId: '234', direction: 'asc' }, ]) jest.mocked( store.selectors.selectDefaultSort ).mockReturnValue([ { columnId: '123', direction: 'desc', }, ]) jest.mocked( store.selectors.selectColumnSort ).mockReturnValue({ columnId: '123', direction: 'desc', }) api.toggleSort('123', false) expect(events.emit).toHaveBeenCalledWith('onSortChange', [ { columnId: '234', direction: 'asc' }, ]) }) }) describe('when column is one of multiple default columns', () => { it('should proceed to the default value', () => { jest.mocked( store.selectors.selectDefaultSort ).mockReturnValue([ { columnId: '123', direction: 'desc', }, { columnId: '234', direction: 'asc', }, ]) jest.mocked( store.selectors.selectColumnSort ).mockReturnValue({ columnId: '123', direction: 'desc', }) api.toggleSort('123', true) expect(events.emit).toHaveBeenCalledWith('onSortChange', [ { columnId: '123', direction: 'desc', }, { columnId: '234', direction: 'asc', }, ]) }) }) }) }) describe('sortColumn', () => { describe('when replacing sort', () => { it('should publish the single column', () => { api.sortColumn('123', 'asc', true) expect(events.emit).toHaveBeenCalledWith('onSortChange', [ { columnId: '123', direction: 'asc' }, ]) }) it('should publish no columns when unset and no default', () => { api.sortColumn('123', 'unset', true) expect(events.emit).toHaveBeenCalledWith('onSortChange', []) }) it('should publish defaultColumns when unset and has default', () => { jest.mocked(store.selectors.selectDefaultSort).mockReturnValue([ { columnId: '234', direction: 'asc' }, ]) api.sortColumn('123', 'unset', true) expect(events.emit).toHaveBeenCalledWith('onSortChange', [ { columnId: '234', direction: 'asc' }, ]) }) }) describe('when not replacing sort', () => { describe('if column is in sort collection', () => { it('should update direction', () => { jest.mocked(store.selectors.selectSort).mockReturnValue([ { columnId: '123', direction: 'desc' }, { columnId: '234', direction: 'asc' }, ]) api.sortColumn('123', 'asc', false) expect(events.emit).toHaveBeenCalledWith('onSortChange', [ { columnId: '123', direction: 'asc' }, { columnId: '234', direction: 'asc' }, ]) }) describe('when removing column', () => { it('should remove it from list', () => { jest.mocked(store.selectors.selectSort).mockReturnValue( [ { columnId: '123', direction: 'desc' }, { columnId: '234', direction: 'asc' }, ] ) api.sortColumn('123', 'unset', false) expect(events.emit).toHaveBeenCalledWith( 'onSortChange', [{ columnId: '234', direction: 'asc' }] ) }) it('should remove it and publish no sort if no default', () => { jest.mocked(store.selectors.selectSort).mockReturnValue( [{ columnId: '123', direction: 'desc' }] ) api.sortColumn('123', 'unset', false) expect(events.emit).toHaveBeenCalledWith( 'onSortChange', [] ) }) it('should remove it and publish default sort if default is configured', () => { jest.mocked( store.selectors.selectDefaultSort ).mockReturnValue([ { columnId: '234', direction: 'asc' }, ]) jest.mocked(store.selectors.selectSort).mockReturnValue( [{ columnId: '123', direction: 'desc' }] ) api.sortColumn('123', 'unset', false) expect(events.emit).toHaveBeenCalledWith( 'onSortChange', [{ columnId: '234', direction: 'asc' }] ) }) }) }) describe('if column is not in sort collection', () => { it('should add the column to the collection', () => { jest.mocked(store.selectors.selectSort).mockReturnValue([ { columnId: '234', direction: 'desc' }, { columnId: '345', direction: 'asc' }, ]) api.sortColumn('123', 'asc', false) expect(events.emit).toHaveBeenCalledWith('onSortChange', [ { columnId: '234', direction: 'desc' }, { columnId: '345', direction: 'asc' }, { columnId: '123', direction: 'asc' }, ]) }) }) describe('if column is not in sort collection but there are already nine columns', () => { it('should not add the column to the collection', () => { jest.mocked(store.selectors.selectSort).mockReturnValue([ { columnId: '1', direction: 'desc' }, { columnId: '2', direction: 'desc' }, { columnId: '3', direction: 'asc' }, { columnId: '4', direction: 'asc' }, { columnId: '5', direction: 'asc' }, { columnId: '6', direction: 'asc' }, { columnId: '7', direction: 'asc' }, { columnId: '8', direction: 'asc' }, { columnId: '9', direction: 'asc' }, ]) api.sortColumn('123', 'asc', false) expect(events.emit).not.toHaveBeenCalled() }) }) }) }) it('should dispatch when calling reorderColumns', () => { api.reorderColumns(['1', '2', '3']) expect(store.dispatch).toHaveBeenCalledWith({ type: 'reorderColumns', payload: ['1', '2', '3'], }) }) it('should dispatch throttled when calling resizeColumn', async () => { api.resizeColumn('1', 197) api.resizeColumn('1', 196) api.resizeColumn('1', 195) api.resizeColumn('1', 194) await new Promise((res) => setTimeout(res, 15)) api.resizeColumn('1', 193) expect(store.dispatch).toHaveBeenCalledTimes(3) /* First call */ expect(store.dispatch).toHaveBeenCalledWith({ type: 'resizeColumn', payload: { id: '1', width: 197 }, }) /* Last call before pause */ expect(store.dispatch).toHaveBeenCalledWith({ type: 'resizeColumn', payload: { id: '1', width: 194 }, }) /* Final call */ expect(store.dispatch).toHaveBeenCalledWith({ type: 'resizeColumn', payload: { id: '1', width: 193 }, }) }) it('should dispatch when callings showMenu', () => { api.showMenu({ top: 0, left: 0 }) expect(store.dispatch).toHaveBeenCalledWith({ type: 'showColumnMenu', payload: { coordinates: { top: 0, left: 0 } }, }) }) it('should dispatch when calling hideMenu', () => { api.hideMenu() expect(store.dispatch).toHaveBeenCalledWith({ type: 'hideColumnMenu', payload: undefined, }) }) it('should dispatch when calling updateColumnVisibility', () => { api.updateColumnVisibility('123', true) expect(store.dispatch).toHaveBeenCalledWith({ type: 'updateColumnVisibility', payload: { id: '123', visible: true }, }) }) })