import React from 'react'; import { act } from '@testing-library/react'; import { HotTable } from '../src/hotTable'; import { HotColumn } from '../src/hotColumn'; import { registerAllModules } from 'handsontable/registry'; import { createSpreadsheetData, RendererComponent, mockElementDimensions, sleep, EditorComponent, simulateKeyboardEvent, simulateMouseEvent, mountComponentWithRef } from './_helpers'; // register Handsontable's modules registerAllModules(); describe('Passing column settings using HotColumn', () => { it('should apply the Handsontable settings passed as HotColumn arguments to the Handsontable instance', async () => { const hotInstance = mountComponentWithRef(( )).hotInstance; expect(hotInstance.getSettings().columns[0].title).toEqual('test title'); expect(hotInstance.getCellMeta(0, 0).readOnly).toEqual(false); expect(hotInstance.getSettings().columns[1].title).toEqual(void 0); expect(hotInstance.getCellMeta(0, 1).readOnly).toEqual(true); expect(hotInstance.getSettings().licenseKey).toEqual('non-commercial-and-evaluation'); }); it('should allow to use data option as a string', async () => { const dataKeyCellValue = 'Value of key1 in row 0'; const hotInstance = mountComponentWithRef(( )).hotInstance; expect(hotInstance.getCell(0, 0).innerHTML).toEqual(dataKeyCellValue); }); it('should apply column settings through the `settings` prop', async () => { const hotInstance = mountComponentWithRef(( )).hotInstance; expect(hotInstance.getCellMeta(0, 0).readOnly).toBe(true); expect(hotInstance.getCell(-1, 0).querySelector('span').innerHTML).toBe('test'); }); }); describe('Renderer configuration using React components', () => { it('should use the renderer component as Handsontable renderer, when it\'s nested under HotColumn and assigned the \'hot-renderer\' attribute', async () => { const hotInstance = mountComponentWithRef(( )).hotInstance; expect(hotInstance.getCell(0, 0).innerHTML).toEqual('A1'); expect(hotInstance.getCell(0, 1).innerHTML).toEqual('
value: B1
'); await act(async() => { hotInstance.scrollViewportTo({ row: 99, col: 0, }); hotInstance.render(); }); await sleep(300); expect(hotInstance.getCell(99, 0).innerHTML).toEqual('A100'); expect(hotInstance.getCell(99, 1).innerHTML).toEqual('
value: B100
'); }); }); describe('Editor configuration using React components', () => { it('should use the editor component as Handsontable editor, when it\'s nested under HotTable and assigned the \'hot-editor\' attribute', async () => { const hotInstance = mountComponentWithRef(( )).hotInstance; expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('none'); await act(async () => { hotInstance.selectCell(0, 1); simulateKeyboardEvent('keydown', 13); }); expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('block'); expect(hotInstance.getDataAtCell(0, 1)).toEqual('B1'); await act(async () => { simulateMouseEvent(document.querySelector('#editorComponentContainer button'), 'click'); }); expect(hotInstance.getDataAtCell(0, 1)).toEqual('new-value'); hotInstance.getActiveEditor().close(); expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('none'); await act(async () => { hotInstance.selectCell(0, 0); simulateKeyboardEvent('keydown', 13); }); expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('none'); }); it('should be possible to reuse editor components between columns with different props passed to them', async () => { class ReusableEditor extends EditorComponent { prepare(row, col, prop, TD, originalValue, cellProperties): any { super.prepare(row, col, prop, TD, originalValue, cellProperties); this.mainElementRef.current.style.backgroundColor = this.props.background; } } const hotInstance = mountComponentWithRef(( )).hotInstance; await act(async () => { hotInstance.selectCell(0, 0); }); expect((document.querySelectorAll('#editorComponentContainer')[0] as any).style.backgroundColor).toEqual('red'); await act(async () => { simulateKeyboardEvent('keydown', 13); }); expect(hotInstance.getActiveEditor().editorComponent.mainElementRef.current.style.backgroundColor).toEqual('red'); await act(async () => { hotInstance.getActiveEditor().close(); hotInstance.selectCell(0, 1); }); expect((document.querySelectorAll('#editorComponentContainer')[1] as any).style.backgroundColor).toEqual('yellow'); await act(async () => { simulateKeyboardEvent('keydown', 13); }); expect(hotInstance.getActiveEditor().editorComponent.mainElementRef.current.style.backgroundColor).toEqual('yellow'); await act(async () => { hotInstance.selectCell(0, 0); simulateKeyboardEvent('keydown', 13); }); expect(hotInstance.getActiveEditor().editorComponent.mainElementRef.current.style.backgroundColor).toEqual('red'); hotInstance.getActiveEditor().close(); }); }); describe('Dynamic HotColumn configuration changes', () => { it('should be possible to rearrange and change the column + editor + renderer configuration dynamically', async () => { function RendererComponent2(props) { return ( <>r2: {props.value} ); } class WrapperComponent extends React.Component { constructor(props) { super(props); this.state = { setup: [ , , ] } } render() { return ( {this.state.setup} ); }; } let hotTableInstanceRef = React.createRef(); const wrapperComponentInstance = mountComponentWithRef(( )); let hotInstance = (hotTableInstanceRef.current as any).hotInstance; let editorElement = document.querySelector('#editorComponentContainer'); expect(hotInstance.getSettings().columns[0].title).toEqual('test title'); expect(hotInstance.getSettings().columns[0].className).toEqual('first-column-class-name'); expect(hotInstance.getCell(0, 0).innerHTML).toEqual('
value: A1
'); expect(hotInstance.getCell(1, 0).innerHTML).toEqual('
value: A2
'); await act(async () => { hotInstance.selectCell(0, 0); hotInstance.getActiveEditor().open(); }); expect(hotInstance.getActiveEditor().constructor.name).toEqual('CustomEditor'); expect(hotInstance.getActiveEditor().editorComponent.__proto__.constructor.name).toEqual('EditorComponent'); expect(editorElement.style.display).toEqual('block'); expect(editorElement.parentNode.style.background).toEqual('red'); expect(editorElement.parentNode.id).toEqual('editor-id-1'); expect(editorElement.parentNode.className.includes('editor-className-1')).toBe(true); await act(async () => { hotInstance.getActiveEditor().close(); }); expect(hotInstance.getSettings().columns[1].title).toEqual('test title 2'); expect(hotInstance.getSettings().columns[1].className).toEqual(void 0); expect(hotInstance.getCell(0, 1).innerHTML).toEqual('
r2: B1
'); expect(hotInstance.getCell(1, 1).innerHTML).toEqual('
r2: B2
'); hotInstance.selectCell(0, 1); expect(hotInstance.getActiveEditor().constructor.name).toEqual('TextEditor'); expect(hotInstance.getActiveEditor().editorComponent).toEqual(void 0); expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('none'); await act(async() => { wrapperComponentInstance.setState({ setup: [ , , ] }); }); await sleep(100); editorElement = document.querySelector('#editorComponentContainer'); expect(hotInstance.getSettings().columns[0].title).toEqual('test title 2'); expect(hotInstance.getSettings().columns[0].className).toEqual(void 0); expect(hotInstance.getCell(0, 0).innerHTML).toEqual('
r2: A1
'); expect(hotInstance.getCell(1, 0).innerHTML).toEqual('
r2: A2
'); await act(async () => { hotInstance.selectCell(0, 0); hotInstance.getActiveEditor().open(); }); expect(hotInstance.getActiveEditor().constructor.name).toEqual('CustomEditor'); expect(hotInstance.getActiveEditor().editorComponent.__proto__.constructor.name).toEqual('EditorComponent'); expect(editorElement.style.display).toEqual('block'); expect(editorElement.parentNode.style.background).toEqual('blue'); expect(editorElement.parentNode.id).toEqual('editor-id-2'); expect(editorElement.parentNode.className.includes('editor-className-2')).toBe(true); await act(async () => { hotInstance.getActiveEditor().close(); }); expect(hotInstance.getSettings().columns[1].title).toEqual('test title'); expect(hotInstance.getSettings().columns[1].className).toEqual('first-column-class-name'); expect(hotInstance.getCell(0, 1).innerHTML).toEqual('
value: B1
'); expect(hotInstance.getCell(1, 1).innerHTML).toEqual('
value: B2
'); await act(async () => { hotInstance.selectCell(0, 1); hotInstance.getActiveEditor().open(); }); expect(hotInstance.getActiveEditor().constructor.name).toEqual('CustomEditor'); expect(hotInstance.getActiveEditor().editorComponent.__proto__.constructor.name).toEqual('EditorComponent'); expect((document.querySelector('#editorComponentContainer') as any).style.display).toEqual('block'); await act(async () => { hotInstance.getActiveEditor().close(); }); expect(hotInstance.getSettings().licenseKey).toEqual('non-commercial-and-evaluation'); }); }); describe('Miscellaneous scenarios with `HotColumn` config', () => { it('should validate all cells correctly in a `dropdown`-typed column after populating data through it', async () => { const onAfterValidate = jasmine.createSpy('warn'); const hotInstance = mountComponentWithRef(( )).hotInstance; await act(async () => { hotInstance.populateFromArray(0, 0, [['test'], ['test2'], ['test3']]); }); await sleep(300); expect(onAfterValidate).toHaveBeenCalledTimes(3); expect(onAfterValidate).toHaveBeenCalledWith(false, 'test3', 2, 0, 'populateFromArray'); expect(onAfterValidate).toHaveBeenCalledWith(false, 'test2', 1, 0, 'populateFromArray'); expect(onAfterValidate).toHaveBeenCalledWith(false, 'test', 0, 0, 'populateFromArray'); }); });