import React from 'react';
import { mount } from 'enzyme';
import Table from '../index';
import Column from '../../Column';
import { ESCAPE_KEY, ENTER_KEY } from '../../../libs/constants';

jest.mock('../helpers/columns/getEnumerableWidth', () => jest.fn(() => 50));

const data = [
    {
        name: 'a',
        number: 23,
    },
];

const tableData = [
    {
        name: 'Pepe',
        email: 'pepe@gmail.com',
        id: '1234qwerty',
    },
    {
        name: 'John',
        email: 'john@gmail.com',
        id: '5678asdfgh',
    },
    {
        name: 'Josep',
        email: 'josep@gmail.com',
        id: '9012zxcvbn',
    },
];

const eventMap = {};
document.addEventListener = jest.fn((event, callback) => {
    eventMap[event] = callback;
});
const preventDefault = jest.fn();

describe('<Table />', () => {
    it('should not render anything if a string keyField is not passed', () => {
        const values = [undefined, null, '', 0, 123, {}, []];
        values.forEach(value => {
            const component = mount(
                <Table data={data} keyField={value}>
                    <Column field="name" header="Name" />
                </Table>,
            );
            expect(component.children().length).toBe(0);
        });
    });
    it('should return a table with one column', () => {
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" />
            </Table>,
        );

        const header = component.find('th[scope="col"]');
        const cell = component.find('th[scope="row"]');

        expect(header.text()).toBe('Name');
        expect(cell.text()).toBe('a');
    });
    it('should not add a column when showCheckboxColumn and showRowNumberColumn are not passed', () => {
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.find('th[scope="row"]').length).toBe(1);
        expect(component.find('td[role="gridcell"]').length).toBe(0);
        expect(component.find('th[scope="row"]').text()).toBe('a');
        component.setProps({
            children: [<Column field="name" header="Name" />, <Column field="number" />],
        });
        component.update();
        expect(component.find('th[scope="row"]').length).toBe(1);
        expect(component.find('td[role="gridcell"]').length).toBe(1);
        expect(component.find('th[scope="row"]').text()).toBe('a');
        expect(component.find('td[role="gridcell"]').text()).toBe('23');
    });
    it('should add a column when showCheckboxColumn is passed', () => {
        const component = mount(
            <Table data={data} keyField="name" showCheckboxColumn>
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.find('th[scope="row"]').length).toBe(1);
        expect(component.find('td[role="gridcell"]').length).toBe(1);
        component.setProps({
            children: [<Column field="name" header="Name" />, <Column field="number" />],
        });
        component.update();
        expect(component.find('th[scope="row"]').length).toBe(1);
        expect(component.find('td[role="gridcell"]').length).toBe(2);
    });
    it('should update the columns state when add a column and (showCheckboxColumn and showRowNumberColumn) are not passed', () => {
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().columns).toEqual([
            {
                field: 'name',
                header: 'Name',
                headerAlignment: undefined,
                sortable: false,
                computedWidth: 50,
                type: 'text',
                isFirstDataColumn: true,
                isEditable: false,
                onChange: expect.any(Function),
            },
        ]);
        component.setProps({
            children: [<Column field="name" header="Name" />, <Column field="number" sortable />],
        });
        component.update();
        expect(component.state().columns).toEqual([
            {
                field: 'name',
                header: 'Name',
                headerAlignment: undefined,
                sortable: false,
                computedWidth: 50,
                type: 'text',
                isFirstDataColumn: true,
                isEditable: false,
                onChange: expect.any(Function),
            },
            {
                field: 'number',
                sortable: true,
                computedWidth: 50,
                type: 'text',
                isFirstDataColumn: false,
                isEditable: false,
                onChange: expect.any(Function),
                headerAlignment: undefined,
            },
        ]);
    });
    it('should update the columns state when add a column and showCheckboxColumn is passed', () => {
        const component = mount(
            <Table data={data} keyField="name" showCheckboxColumn>
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().columns).toEqual([
            {
                computedWidth: 52,
                type: 'SELECTABLE_CHECKBOX',
                width: 52,
            },
            {
                field: 'name',
                header: 'Name',
                headerAlignment: undefined,
                sortable: false,
                computedWidth: 50,
                type: 'text',
                isFirstDataColumn: true,
                isEditable: false,
                onChange: expect.any(Function),
            },
        ]);
        component.setProps({
            children: [
                <Column field="name" header="Name" headerAlignment="right" />,
                <Column field="number" sortable />,
            ],
        });
        component.update();
        expect(component.state().columns).toEqual([
            {
                computedWidth: 52,
                type: 'SELECTABLE_CHECKBOX',
                width: 52,
            },
            {
                field: 'name',
                header: 'Name',
                headerAlignment: 'right',
                sortable: false,
                computedWidth: 50,
                type: 'text',
                isFirstDataColumn: true,
                isEditable: false,
                onChange: expect.any(Function),
            },
            {
                field: 'number',
                sortable: true,
                computedWidth: 50,
                type: 'text',
                isFirstDataColumn: false,
                isEditable: false,
                onChange: expect.any(Function),
                headerAlignment: undefined,
            },
        ]);
    });
    it('should not update the columns state when the props changed are others than children', () => {
        const columnsState = [
            {
                field: 'name',
                header: 'Name',
                headerAlignment: undefined,
                sortable: false,
                computedWidth: 50,
                type: 'text',
                isFirstDataColumn: true,
                isEditable: false,
                onChange: expect.any(Function),
            },
        ];
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().columns).toEqual(columnsState);
        component.setProps({
            data: [{ email: 'john.doe@gmail.com' }],
            sortedBy: 'email',
            sortDirection: 'asc',
        });
        component.update();
        expect(component.state().columns).toEqual(columnsState);
    });
    it('should set the right table width when resize for first time', () => {
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" />
                <Column field="number" header="Number" />
            </Table>,
        );
        const resizeBar = component.find('span.rainbow-table_header-resize-bar');
        expect(component.state().tableWidth).toBe(100);
        resizeBar.at(0).simulate('mousedown', { clientX: 100 });

        eventMap.mousemove({ clientX: 232, preventDefault });
        eventMap.mouseup({ preventDefault });
        expect(component.state().tableWidth).toBe(232);
    });
    it('should store the right columns in state when resize a column', () => {
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" />
                <Column field="number" header="Number" />
            </Table>,
        );
        const resizeBar = component.find('span.rainbow-table_header-resize-bar');
        expect(component.state().columns).toEqual([
            {
                field: 'name',
                header: 'Name',
                headerAlignment: undefined,
                computedWidth: 50,
                sortable: false,
                type: 'text',
                isFirstDataColumn: true,
                isEditable: false,
                onChange: expect.any(Function),
            },
            {
                field: 'number',
                header: 'Number',
                headerAlignment: undefined,
                computedWidth: 50,
                sortable: false,
                type: 'text',
                isFirstDataColumn: false,
                isEditable: false,
                onChange: expect.any(Function),
            },
        ]);
        resizeBar.at(0).simulate('mousedown', { clientX: 100 });

        eventMap.mousemove({ clientX: 232, preventDefault });
        eventMap.mouseup({ preventDefault });
        expect(component.state().columns).toEqual([
            {
                field: 'name',
                header: 'Name',
                headerAlignment: undefined,
                computedWidth: 182,
                isResized: true,
                sortable: false,
                type: 'text',
                isFirstDataColumn: true,
                isEditable: false,
                onChange: expect.any(Function),
            },
            {
                field: 'number',
                header: 'Number',
                headerAlignment: undefined,
                computedWidth: 50,
                sortable: false,
                type: 'text',
                isFirstDataColumn: false,
                isEditable: false,
                onChange: expect.any(Function),
            },
        ]);
    });
    it('should set the right table width when resize for second time', () => {
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" />
                <Column field="number" header="Number" />
            </Table>,
        );
        const resizeBar = component.find('span.rainbow-table_header-resize-bar');
        expect(component.state().tableWidth).toBe(100);

        resizeBar.at(0).simulate('mousedown', { clientX: 60 });
        eventMap.mousemove({ clientX: 120, preventDefault });
        eventMap.mouseup({ preventDefault });
        expect(component.state().tableWidth).toBe(160);

        resizeBar.at(0).simulate('mousedown', { clientX: 120 });
        eventMap.mousemove({ clientX: -10, preventDefault });
        eventMap.mouseup({ preventDefault });
        expect(component.state().tableWidth).toBe(100);
    });
    it('should call onSort with the right data when a sortable column header is clicked', () => {
        const onSortMock = jest.fn();
        const component = mount(
            <Table data={data} keyField="name" onSort={onSortMock}>
                <Column field="name" header="Name" sortable />
                <Column field="number" header="Number" />,
            </Table>,
        );
        const tableHeader = component.find('div.rainbow-table_header-container');
        tableHeader.at(0).simulate('click');
        expect(onSortMock).toHaveBeenCalledWith(expect.any(Object), 'name', 'asc');
    });
    it('should not call onSort when a non sortable column header is clicked', () => {
        const onSortMock = jest.fn();
        const component = mount(
            <Table data={data} keyField="name" onSort={onSortMock}>
                <Column field="name" header="Name" sortable />
                <Column field="number" header="Number" />,
            </Table>,
        );
        const tableHeader = component.find('div.rainbow-table_header-container');
        tableHeader.at(1).simulate('click');
        expect(onSortMock).not.toHaveBeenCalled();
    });
    it('should call onSort the first time with sortDireciton as "desc" and the second time as "asc" when defaultSortDirection is set to "desc"', () => {
        let sortedBy;
        let sortDirection;
        const onSortMock = jest.fn((event, field, nextSortDirection) => {
            sortedBy = field;
            sortDirection = nextSortDirection;
        });
        const component = mount(
            <Table
                data={data}
                keyField="name"
                onSort={onSortMock}
                defaultSortDirection="desc"
                sortDirection={sortDirection}
                sortedBy={sortedBy}
            >
                <Column field="name" header="Name" sortable />
            </Table>,
        );
        const tableHeader = component.find('div.rainbow-table_header-container');
        tableHeader.simulate('click');
        expect(onSortMock).toHaveBeenCalledWith(expect.any(Object), 'name', 'desc');
        component.setProps({ sortedBy, sortDirection });
        tableHeader.simulate('click');
        expect(onSortMock).toHaveBeenCalledWith(expect.any(Object), 'name', 'asc');
    });
    it('should set the right rows initially', () => {
        const component = mount(
            <Table data={tableData} keyField="id" showCheckboxColumn>
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '9012zxcvbn',
            },
        ]);
    });
    it('should set the right rows initially when there are selected columns', () => {
        const component = mount(
            <Table
                data={tableData}
                selectedRows={['5678asdfgh', '9012zxcvbn']}
                maxRowSelection={2}
                showCheckboxColumn
                keyField="id"
            >
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: true,
                isSelected: false,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '9012zxcvbn',
            },
        ]);
    });
    it('should set the right rows initially when maxRowSelection is 1', () => {
        const component = mount(
            <Table data={tableData} maxRowSelection={1} showCheckboxColumn keyField="id">
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().rows).toEqual([
            {
                inputType: 'radio',
                isDisabled: false,
                isSelected: false,
                key: '1234qwerty',
            },
            {
                inputType: 'radio',
                isDisabled: false,
                isSelected: false,
                key: '5678asdfgh',
            },
            {
                inputType: 'radio',
                isDisabled: false,
                isSelected: false,
                key: '9012zxcvbn',
            },
        ]);
    });
    it('should set the bulkSelection initially to "none" when there are not selected rows', () => {
        const component = mount(
            <Table data={tableData} showCheckboxColumn keyField="id">
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().bulkSelection).toBe('none');
    });
    it('should set the bulkSelection initially to "some" when there are one row selected', () => {
        const component = mount(
            <Table data={tableData} selectedRows={['1234qwerty']} showCheckboxColumn keyField="id">
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().bulkSelection).toBe('some');
    });
    it('should set the bulkSelection initially to "all" when all rows are selected', () => {
        const component = mount(
            <Table
                data={tableData}
                selectedRows={['1234qwerty', '5678asdfgh', '9012zxcvbn']}
                showCheckboxColumn
                keyField="id"
            >
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().bulkSelection).toBe('all');
    });
    it('should set the right state when change the maxRowSelection', () => {
        const component = mount(
            <Table
                data={tableData}
                maxRowSelection={2}
                showCheckboxColumn
                selectedRows={['1234qwerty', '5678asdfgh']}
                keyField="id"
            >
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: true,
                isSelected: false,
                key: '9012zxcvbn',
            },
        ]);
        expect(component.state().bulkSelection).toBe('all');
        component.setProps({
            maxRowSelection: 3,
        });
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '9012zxcvbn',
            },
        ]);
        expect(component.state().bulkSelection).toBe('some');
    });
    it('should set the right state when change the selectedRows', () => {
        const component = mount(
            <Table data={tableData} showCheckboxColumn selectedRows={['1234qwerty']} keyField="id">
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '9012zxcvbn',
            },
        ]);
        expect(component.state().bulkSelection).toBe('some');
        component.setProps({
            selectedRows: ['1234qwerty', '9012zxcvbn'],
        });
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '9012zxcvbn',
            },
        ]);
        expect(component.state().bulkSelection).toBe('some');
    });
    it('should fire onRowSelection with new selected data when change the selectedRows', () => {
        const onRowSelectionMockFn = jest.fn();
        const component = mount(
            <Table
                data={tableData}
                showCheckboxColumn
                onRowSelection={onRowSelectionMockFn}
                selectedRows={['1234qwerty']}
                keyField="id"
            >
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.instance().selectedRowsKeys).toEqual({
            '1234qwerty': true,
        });
        component.setProps({
            selectedRows: ['1234qwerty', '9012zxcvbn'],
        });
        expect(component.instance().selectedRowsKeys).toEqual({
            '1234qwerty': true,
            '9012zxcvbn': true,
        });
        expect(onRowSelectionMockFn).toHaveBeenCalledWith([
            { id: '1234qwerty', name: 'Pepe', email: 'pepe@gmail.com' },
            { id: '9012zxcvbn', name: 'Josep', email: 'josep@gmail.com' },
        ]);
    });
    it('should call onRowSelection with the right data when select all rows and there are selected rows', () => {
        const onRowSelectionMockFn = jest.fn();
        const component = mount(
            <Table
                data={tableData}
                showCheckboxColumn
                selectedRows={['1234qwerty']}
                onRowSelection={onRowSelectionMockFn}
                keyField="id"
            >
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '9012zxcvbn',
            },
        ]);
        const headCheckbox = component
            .find('PrimitiveCheckbox[label="select all rows"]')
            .find('input');
        headCheckbox.simulate('click');
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '9012zxcvbn',
            },
        ]);
        expect(onRowSelectionMockFn).toHaveBeenCalledWith([]);
    });
    it('should call onRowSelection with the right data when select all rows and there are not selected rows', () => {
        const onRowSelectionMockFn = jest.fn();
        const component = mount(
            <Table
                data={tableData}
                showCheckboxColumn
                onRowSelection={onRowSelectionMockFn}
                keyField="id"
            >
                <Column field="name" header="Name" />
            </Table>,
        );
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '9012zxcvbn',
            },
        ]);
        const headCheckbox = component
            .find('PrimitiveCheckbox[label="select all rows"]')
            .find('input');
        headCheckbox.simulate('click');
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '9012zxcvbn',
            },
        ]);
        expect(onRowSelectionMockFn).toHaveBeenCalledWith([
            {
                name: 'Pepe',
                email: 'pepe@gmail.com',
                id: '1234qwerty',
            },
            {
                name: 'John',
                email: 'john@gmail.com',
                id: '5678asdfgh',
            },
            {
                name: 'Josep',
                email: 'josep@gmail.com',
                id: '9012zxcvbn',
            },
        ]);
    });
    it('should call onRowSelection with the right data when select a single row and there are selected rows', () => {
        const onRowSelectionMockFn = jest.fn();
        const component = mount(
            <Table
                data={tableData}
                showCheckboxColumn
                selectedRows={['1234qwerty']}
                onRowSelection={onRowSelectionMockFn}
                keyField="id"
            >
                <Column field="name" header="Name" />
            </Table>,
        );
        const checkbox = component
            .find('Input[label="select row"]')
            .find('input')
            .at(2);
        checkbox.simulate('click');
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '9012zxcvbn',
            },
        ]);
        expect(onRowSelectionMockFn).toHaveBeenCalledWith([
            {
                name: 'Pepe',
                email: 'pepe@gmail.com',
                id: '1234qwerty',
            },
            {
                name: 'Josep',
                email: 'josep@gmail.com',
                id: '9012zxcvbn',
            },
        ]);
    });
    it('should call onRowSelection with the right data when select a single row with shiftKey pressed', () => {
        const onRowSelectionMockFn = jest.fn();
        const component = mount(
            <Table
                data={tableData}
                showCheckboxColumn
                onRowSelection={onRowSelectionMockFn}
                keyField="id"
            >
                <Column field="name" header="Name" />
            </Table>,
        );
        const firstCheckbox = component
            .find('Input[label="select row"]')
            .find('input')
            .at(0);
        const lastCheckbox = component
            .find('Input[label="select row"]')
            .find('input')
            .at(2);
        firstCheckbox.simulate('click');
        expect(component.instance().lastSelectedRowKey).toBe('1234qwerty');
        lastCheckbox.simulate('click', {
            shiftKey: true,
        });
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '9012zxcvbn',
            },
        ]);
        expect(onRowSelectionMockFn).toHaveBeenCalledWith([
            {
                name: 'Pepe',
                email: 'pepe@gmail.com',
                id: '1234qwerty',
            },
            {
                name: 'John',
                email: 'john@gmail.com',
                id: '5678asdfgh',
            },
            {
                name: 'Josep',
                email: 'josep@gmail.com',
                id: '9012zxcvbn',
            },
        ]);
    });
    it('should call onRowSelection with the right data when select a single row and maxRowSelection is 1', () => {
        const onRowSelectionMockFn = jest.fn();
        const component = mount(
            <Table
                data={tableData}
                showCheckboxColumn
                maxRowSelection={1}
                onRowSelection={onRowSelectionMockFn}
                keyField="id"
            >
                <Column field="name" header="Name" />
            </Table>,
        );
        const radio = component
            .find('Input[label="select row"]')
            .find('input')
            .at(1);
        radio.simulate('click');
        expect(component.state().rows).toEqual([
            {
                inputType: 'radio',
                isDisabled: false,
                isSelected: false,
                key: '1234qwerty',
            },
            {
                inputType: 'radio',
                isDisabled: false,
                isSelected: true,
                key: '5678asdfgh',
            },
            {
                inputType: 'radio',
                isDisabled: false,
                isSelected: false,
                key: '9012zxcvbn',
            },
        ]);
        expect(onRowSelectionMockFn).toHaveBeenCalledWith([
            {
                name: 'John',
                email: 'john@gmail.com',
                id: '5678asdfgh',
            },
        ]);
    });
    it('should call onRowSelection with the right data when deselect a single row', () => {
        const onRowSelectionMockFn = jest.fn();
        const component = mount(
            <Table
                data={tableData}
                showCheckboxColumn
                selectedRows={['1234qwerty', '5678asdfgh']}
                onRowSelection={onRowSelectionMockFn}
                keyField="id"
            >
                <Column field="name" header="Name" />
            </Table>,
        );
        const checkbox = component
            .find('Input[label="select row"]')
            .find('input')
            .at(0);
        checkbox.simulate('click');
        expect(component.state().rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '9012zxcvbn',
            },
        ]);
        expect(onRowSelectionMockFn).toHaveBeenCalledWith([
            {
                id: '5678asdfgh',
                email: 'john@gmail.com',
                name: 'John',
            },
        ]);
        expect(component.instance().lastSelectedRowKey).toBe('1234qwerty');
    });
    it('should set the right indexes when data prop changes', () => {
        const component = mount(
            <Table data={[]} showCheckboxColumn keyField="id">
                <Column field="name" header="Name" />
            </Table>,
        );
        component.setProps({
            data: tableData,
        });
        expect(component.instance().indexes).toEqual({
            '1234qwerty': { rowIndex: 0 },
            '5678asdfgh': { rowIndex: 1 },
            '9012zxcvbn': { rowIndex: 2 },
        });
    });
    it('should set the right state when data prop changes', () => {
        const component = mount(
            <Table data={[]} showCheckboxColumn keyField="id">
                <Column field="name" header="Name" />
            </Table>,
        );
        component.setProps({
            data: tableData,
        });
        const { state } = component.instance();
        expect(state.rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '9012zxcvbn',
            },
        ]);
        expect(state.bulkSelection).toBe('none');
    });
    it('should set the right state when data prop changes and have selected rows', () => {
        const component = mount(
            <Table data={[]} showCheckboxColumn selectedRows={['5678asdfgh']} keyField="id">
                <Column field="name" header="Name" />
            </Table>,
        );
        component.setProps({
            data: tableData,
        });
        const { state } = component.instance();
        expect(state.rows).toEqual([
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '1234qwerty',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: true,
                key: '5678asdfgh',
            },
            {
                inputType: 'checkbox',
                isDisabled: false,
                isSelected: false,
                key: '9012zxcvbn',
            },
        ]);
        expect(state.bulkSelection).toBe('some');
    });
    it('should set the initial selectedRowsKeys to empty object when not pass selectedRows', () => {
        const component = mount(
            <Table data={tableData} showCheckboxColumn keyField="id">
                <Column field="name" header="Name" />
                <Column field="id" header="ID" />
            </Table>,
        );
        expect(component.instance().selectedRowsKeys).toEqual({});
    });
    it('should set the right initial selectedRowsKeys when pass selectedRows', () => {
        const component = mount(
            <Table
                data={tableData}
                showCheckboxColumn
                keyField="id"
                selectedRows={['1234qwerty', '5678asdfgh', 'wrong-key']}
            >
                <Column field="name" header="Name" />
                <Column field="id" header="ID" />
            </Table>,
        );
        expect(component.instance().selectedRowsKeys).toEqual({
            '1234qwerty': true,
            '5678asdfgh': true,
        });
    });
    it('should not reset selectedRowsKeys state when pass new data prop', () => {
        const component = mount(
            <Table data={tableData} showCheckboxColumn keyField="id">
                <Column field="name" header="Name" />
                <Column field="id" header="ID" />
            </Table>,
        );
        const checkbox = component
            .find('Input[label="select row"]')
            .find('input')
            .at(1);
        checkbox.simulate('click');
        expect(component.instance().selectedRowsKeys).toEqual({
            '5678asdfgh': true,
        });
        component.setProps({
            data: [
                {
                    name: 'Pepe',
                    id: '1234qwerty',
                },
                {
                    name: 'John',
                    id: '5678asdfgh',
                },
                {
                    name: 'Josep',
                    id: '9012zxcvbn',
                },
            ],
        });
        expect(component.instance().selectedRowsKeys).toEqual({
            '5678asdfgh': true,
        });
    });
    it('should fire onRowSelection when pass new data prop that does not contains prev selected data', () => {
        const onRowSelectionMockFn = jest.fn();
        const component = mount(
            <Table
                data={tableData}
                showCheckboxColumn
                onRowSelection={onRowSelectionMockFn}
                keyField="id"
            >
                <Column field="name" header="Name" />
                <Column field="id" header="ID" />
            </Table>,
        );
        const checkbox2 = component
            .find('Input[label="select row"]')
            .find('input')
            .at(1);
        checkbox2.simulate('click');
        expect(component.instance().selectedRowsKeys).toEqual({
            '5678asdfgh': true,
        });
        expect(onRowSelectionMockFn.mock.calls[0][0]).toEqual([
            {
                id: '5678asdfgh',
                email: 'john@gmail.com',
                name: 'John',
            },
        ]);
        component.setProps({
            data: [
                {
                    name: 'Pepe',
                    id: '1234qwerty',
                },
                {
                    name: 'Josep',
                    id: '9012zxcvbn',
                },
            ],
        });
        expect(component.instance().selectedRowsKeys).toEqual({});
        expect(onRowSelectionMockFn.mock.calls[1][0]).toEqual([]);
    });
    it('should not change bulkSelection state when select all rows and then pass new data prop that remove one row', () => {
        const onRowSelectionMockFn = jest.fn();
        const component = mount(
            <Table
                data={tableData}
                showCheckboxColumn
                onRowSelection={onRowSelectionMockFn}
                keyField="id"
            >
                <Column field="name" header="Name" />
                <Column field="id" header="ID" />
            </Table>,
        );
        const headCheckbox = component
            .find('PrimitiveCheckbox[label="select all rows"]')
            .find('input');
        headCheckbox.simulate('click');
        expect(component.state('bulkSelection')).toBe('all');
        expect(component.instance().selectedRowsKeys).toEqual({
            '1234qwerty': true,
            '5678asdfgh': true,
            '9012zxcvbn': true,
        });
        component.setProps({
            data: [
                {
                    name: 'Pepe',
                    id: '1234qwerty',
                },
                {
                    name: 'Josep',
                    id: '9012zxcvbn',
                },
            ],
        });
        expect(component.state('bulkSelection')).toBe('all');
        expect(component.instance().selectedRowsKeys).toEqual({
            '1234qwerty': true,
            '9012zxcvbn': true,
        });
    });
    it('should not fire onRowSelection when set data and selectedRows after mount the component', () => {
        const onRowSelectionMockFn = jest.fn();
        const component = mount(
            <Table data={[]} showCheckboxColumn onRowSelection={onRowSelectionMockFn} keyField="id">
                <Column field="name" header="Name" />
                <Column field="id" header="ID" />
            </Table>,
        );
        component.setProps({
            data: tableData,
            selectedRows: ['1234qwerty', '5678asdfgh', '9012zxcvbn'],
        });
        expect(onRowSelectionMockFn).not.toHaveBeenCalled();
    });
    it('should set input type to "checkbox" when there is only one row', () => {
        const singleData = [{ name: 'John Doe' }];
        const component = mount(
            <Table keyField="id" data={singleData} showCheckboxColumn>
                <Column field="name" header="Name" />
            </Table>,
        );
        const input = component.find('Input[label="select row"]').find('input');
        expect(input.prop('type')).toBe('checkbox');
    });
    it('should render the right amount of columns headers with the right props', () => {
        const component = mount(
            <Table data={data} keyField="id">
                <Column field="name" header="Name" />
                <Column field="email" header="Email" />
                <Column field="id" header="User Id" />
            </Table>,
        );
        const thElements = component.find('thead').find('th');
        expect(thElements.length).toBe(3);
        thElements.forEach(th =>
            expect(th.props()).toEqual(
                expect.objectContaining({
                    'aria-label': th.text(),
                    scope: 'col',
                    tabIndex: -1,
                }),
            ),
        );
    });
    it('should render the right amount of columns headers with the right props when showCheckboxColumn is passed', () => {
        const component = mount(
            <Table data={data} keyField="id" showCheckboxColumn>
                <Column field="name" header="Name" />
                <Column field="email" header="Email" />
                <Column field="id" header="User Id" />
            </Table>,
        );
        const thElements = component.find('thead').find('th');
        expect(thElements.length).toBe(4);
        thElements.forEach((th, index) => {
            if (index === 0) {
                expect(th.props()).toEqual(
                    expect.objectContaining({
                        scope: 'col',
                        tabIndex: -1,
                    }),
                );
            } else {
                expect(th.props()).toEqual(
                    expect.objectContaining({
                        'aria-label': th.text(),
                        scope: 'col',
                        tabIndex: -1,
                    }),
                );
            }
        });
    });
    it('should render the right amount of columns headers with the right props when showRowNumberColumn is passed', () => {
        const component = mount(
            <Table data={data} keyField="id" showRowNumberColumn>
                <Column field="name" header="Name" />
                <Column field="email" header="Email" />
                <Column field="id" header="User Id" />
            </Table>,
        );
        const thElements = component.find('thead').find('th');
        expect(thElements.length).toBe(4);
        thElements.forEach((th, index) => {
            if (index === 0) {
                expect(th.props()).toEqual(
                    expect.objectContaining({
                        scope: 'col',
                        tabIndex: -1,
                    }),
                );
            } else {
                expect(th.props()).toEqual(
                    expect.objectContaining({
                        'aria-label': th.text(),
                        scope: 'col',
                        tabIndex: -1,
                    }),
                );
            }
        });
    });
    it('should render the right amount of columns headers with the right props when showCheckboxColumn and showRowNumberColumn are passed', () => {
        const component = mount(
            <Table data={data} keyField="id" showCheckboxColumn showRowNumberColumn>
                <Column field="name" header="Name" />
                <Column field="email" header="Email" />
                <Column field="id" header="User Id" />
            </Table>,
        );
        const thElements = component.find('thead').find('th');
        expect(thElements.length).toBe(5);
        thElements.forEach((th, index) => {
            if (index === 0 || index === 1) {
                expect(th.props()).toEqual(
                    expect.objectContaining({
                        scope: 'col',
                        tabIndex: -1,
                    }),
                );
            } else {
                expect(th.props()).toEqual(
                    expect.objectContaining({
                        'aria-label': th.text(),
                        scope: 'col',
                        tabIndex: -1,
                    }),
                );
            }
        });
    });
    it('should render the right amount of body cells with the right props', () => {
        const component = mount(
            <Table data={data} keyField="id">
                <Column field="name" header="Name" />
                <Column field="email" header="Email" />
                <Column field="id" header="User Id" />
            </Table>,
        );
        const firstRowChildren = component
            .find('tbody')
            .find('tr')
            .at(0)
            .children();
        expect(firstRowChildren.length).toBe(3);
        firstRowChildren.forEach((element, index) => {
            if (index === 0) {
                expect(element.find('th').props()).toEqual(
                    expect.objectContaining({
                        scope: 'row',
                        tabIndex: -1,
                        'data-label': expect.any(String),
                    }),
                );
            } else {
                expect(element.find('td').props()).toEqual(
                    expect.objectContaining({
                        role: 'gridcell',
                        tabIndex: -1,
                        'data-label': expect.any(String),
                    }),
                );
            }
        });
    });
    it('should render the right amount of body cells with the right props when showCheckboxColumn is passed', () => {
        const component = mount(
            <Table data={data} keyField="id" showCheckboxColumn>
                <Column field="name" header="Name" />
                <Column field="email" header="Email" />
                <Column field="id" header="User Id" />
            </Table>,
        );
        const firstRowChildren = component
            .find('tbody')
            .find('tr')
            .at(0)
            .children();
        expect(firstRowChildren.length).toBe(4);
        firstRowChildren.forEach((element, index) => {
            if (index === 0) {
                expect(element.find('td').props()).toEqual(
                    expect.objectContaining({
                        role: 'gridcell',
                        tabIndex: -1,
                    }),
                );
            } else if (index === 1) {
                expect(element.find('th').props()).toEqual(
                    expect.objectContaining({
                        scope: 'row',
                        tabIndex: -1,
                        'data-label': expect.any(String),
                    }),
                );
            } else {
                expect(element.find('td').props()).toEqual(
                    expect.objectContaining({
                        role: 'gridcell',
                        tabIndex: -1,
                        'data-label': expect.any(String),
                    }),
                );
            }
        });
    });
    it('should render the right amount of body cells with the right props when showRowNumberColumn is passed', () => {
        const component = mount(
            <Table data={data} keyField="id" showRowNumberColumn>
                <Column field="name" header="Name" />
                <Column field="email" header="Email" />
                <Column field="id" header="User Id" />
            </Table>,
        );
        const firstRowChildren = component
            .find('tbody')
            .find('tr')
            .at(0)
            .children();
        expect(firstRowChildren.length).toBe(4);
        firstRowChildren.forEach((element, index) => {
            if (index === 0) {
                expect(element.find('td').props()).toEqual(
                    expect.objectContaining({
                        role: 'gridcell',
                        tabIndex: -1,
                    }),
                );
            } else if (index === 1) {
                expect(element.find('th').props()).toEqual(
                    expect.objectContaining({
                        scope: 'row',
                        tabIndex: -1,
                        'data-label': expect.any(String),
                    }),
                );
            } else {
                expect(element.find('td').props()).toEqual(
                    expect.objectContaining({
                        role: 'gridcell',
                        tabIndex: -1,
                        'data-label': expect.any(String),
                    }),
                );
            }
        });
    });
    it('should render the right amount of body cells with the right props when showCheckboxColumn and showRowNumberColumn are passed', () => {
        const component = mount(
            <Table data={data} keyField="id" showCheckboxColumn showRowNumberColumn>
                <Column field="name" header="Name" />
                <Column field="email" header="Email" />
                <Column field="id" header="User Id" />
            </Table>,
        );
        const firstRowChildren = component
            .find('tbody')
            .find('tr')
            .at(0)
            .children();
        expect(firstRowChildren.length).toBe(5);
        firstRowChildren.forEach((element, index) => {
            if (index === 0 || index === 1) {
                expect(element.find('td').props()).toEqual(
                    expect.objectContaining({
                        role: 'gridcell',
                        tabIndex: -1,
                    }),
                );
            } else if (index === 2) {
                expect(element.find('th').props()).toEqual(
                    expect.objectContaining({
                        scope: 'row',
                        tabIndex: -1,
                        'data-label': expect.any(String),
                    }),
                );
            } else {
                expect(element.find('td').props()).toEqual(
                    expect.objectContaining({
                        role: 'gridcell',
                        tabIndex: -1,
                        'data-label': expect.any(String),
                    }),
                );
            }
        });
    });

    it('should return a table with EditableCell', () => {
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" isEditable />
            </Table>,
        );
        expect(component.find('EditableCell').exists()).toBe(true);
    });

    it('should render a span with the received value of the data inside the EditableCell', () => {
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" isEditable />
            </Table>,
        );
        const editableCell = component.find('EditableCell');
        const span = editableCell.find('span');
        expect(span.text().includes('a')).toBe(true);
    });

    it('should render an input with the received value when click inside the EditableCell', () => {
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" isEditable />
            </Table>,
        );
        const editableCell = component.find('EditableCell');
        const div = editableCell.find('div');
        div.simulate('click');
        const editableCellAfterClick = component.find('EditableCell');
        expect(editableCellAfterClick.find('input').prop('value')).toBe('a');
    });

    it('should render a button when click inside the EditableCell', () => {
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" isEditable />
            </Table>,
        );
        const editableCell = component.find('EditableCell');
        const div = editableCell.find('div');
        div.simulate('click');
        const editableCellAfterClick = component.find('EditableCell');
        expect(editableCellAfterClick.find('button').exists()).toBe(true);
    });

    it('should unmount the input when blur', () => {
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" isEditable />
            </Table>,
        );
        const editableCell = component.find('EditableCell');
        const div = editableCell.find('div');
        div.simulate('click');
        const editableCellAfterClick = component.find('EditableCell');
        const input = editableCellAfterClick.find('input');
        input.simulate('change', { target: { value: 'b' } });
        input.simulate('blur');
        const editableCellAfterBlur = component.find('EditableCell');
        const inputAfterBlur = editableCellAfterBlur.find('input');
        expect(inputAfterBlur.exists()).toBe(false);
    });

    it('should call onChangeMockFn when blur', () => {
        const onChangeMockFn = jest.fn();
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" isEditable onChange={onChangeMockFn} />
            </Table>,
        );
        const editableCell = component.find('EditableCell');
        const div = editableCell.find('div');
        div.simulate('click');
        const editableCellAfterClick = component.find('EditableCell');
        const input = editableCellAfterClick.find('input');
        input.simulate('change', { target: { value: 'b' } });
        input.simulate('blur');
        expect(onChangeMockFn.mock.calls.length).toBe(1);
        expect(onChangeMockFn).toBeCalledWith({ value: 'b', row: expect.any(Object) });
    });

    it('should clear the input when click in button clear', () => {
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" isEditable />
            </Table>,
        );
        const editableCell = component.find('EditableCell');
        const div = editableCell.find('div');
        div.simulate('click');
        const editableCellAfterClick = component.find('EditableCell');
        const button = editableCellAfterClick.find('button');
        button.simulate('mouseDown');
        const editableCellAfterClearClick = component.find('EditableCell');
        const input = editableCellAfterClearClick.find('input');
        expect(input.prop('value')).toBe('');
    });

    it('should unmount the input when onKey ENTER and call the onChange', () => {
        const onChangeMockFn = jest.fn();
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" isEditable onChange={onChangeMockFn} />
            </Table>,
        );
        const editableCell = component.find('EditableCell');
        const div = editableCell.find('div');
        div.simulate('click');
        const editableCellAfterClick = component.find('EditableCell');
        const input = editableCellAfterClick.find('input');
        input.simulate('change', { target: { value: 'b' } });
        input.simulate('keydown', { keyCode: ENTER_KEY });
        const editableCellAfterKeyDown = component.find('EditableCell');
        const inputAfterKeyDown = editableCellAfterKeyDown.find('input');
        expect(inputAfterKeyDown.exists()).toBe(false);
        expect(onChangeMockFn).toBeCalledWith({ value: 'b', row: expect.any(Object) });
    });

    it('should unmount the input when onKey ESCAPE and not call the onChange', () => {
        const onChangeMockFn = jest.fn();
        const component = mount(
            <Table data={data} keyField="name">
                <Column field="name" header="Name" isEditable onChange={onChangeMockFn} />
            </Table>,
        );
        const editableCell = component.find('EditableCell');
        const div = editableCell.find('div');
        div.simulate('click');
        const editableCellAfterClick = component.find('EditableCell');
        const input = editableCellAfterClick.find('input');
        input.simulate('change', { target: { value: 'b' } });
        input.simulate('keydown', { keyCode: ESCAPE_KEY });
        const editableCellAfterKeyDown = component.find('EditableCell');
        const inputAfterKeyDown = editableCellAfterKeyDown.find('input');
        expect(inputAfterKeyDown.exists()).toBe(false);
        expect(onChangeMockFn).not.toHaveBeenCalled();
    });

    it('should render a CustomComponent with the isEditable and onChange props', () => {
        const onChangeFn = () => {};
        const CustomComponent = () => {
            return <span>Hola Mundo</span>;
        };

        const component = mount(
            <Table data={data} keyField="name">
                <Column
                    field="name"
                    header="Name"
                    isEditable
                    onChange={onChangeFn}
                    component={CustomComponent}
                />
            </Table>,
        );

        const customComponent = component.find('CustomComponent');
        expect(customComponent.prop('isEditable')).toBe(true);
        expect(customComponent.prop('onChange')).toEqual(onChangeFn);
    });
});
