337 lines
9.6 KiB
TypeScript
337 lines
9.6 KiB
TypeScript
import React from 'react';
|
|
import { act } from '@testing-library/react';
|
|
import { HotTable } from '../src/hotTable';
|
|
import { HotColumn } from '../src/hotColumn';
|
|
import {
|
|
createSpreadsheetData,
|
|
mockElementDimensions,
|
|
mountComponentWithRef,
|
|
sleep,
|
|
} from './_helpers';
|
|
import { HOT_DESTROYED_WARNING } from "../src/helpers";
|
|
import { BaseEditorComponent } from '../src/baseEditorComponent';
|
|
|
|
describe('Subcomponent state', () => {
|
|
it('should be possible to set the state of the renderer components passed to HotTable and HotColumn', async () => {
|
|
class RendererComponent2 extends React.Component<any, any, any> {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
value: 'initial'
|
|
}
|
|
}
|
|
|
|
render(): React.ReactElement<string> {
|
|
return (
|
|
<>
|
|
{this.state.value}
|
|
</>
|
|
);
|
|
}
|
|
}
|
|
|
|
let zeroRendererInstance = null;
|
|
let oneRendererInstance = null;
|
|
|
|
const hotInstance = mountComponentWithRef((
|
|
<HotTable licenseKey="non-commercial-and-evaluation"
|
|
id="test-hot"
|
|
data={createSpreadsheetData(3, 2)}
|
|
width={300}
|
|
height={300}
|
|
rowHeights={23}
|
|
colWidths={50}
|
|
autoRowSize={false}
|
|
autoColumnSize={false}
|
|
init={function () {
|
|
mockElementDimensions(this.rootElement, 300, 300);
|
|
}}>
|
|
<RendererComponent2 ref={function (instance) {
|
|
if (instance && instance.props.row === 0 && instance.props.col === 0) {
|
|
zeroRendererInstance = instance;
|
|
}
|
|
}} hot-renderer></RendererComponent2>
|
|
<HotColumn/>
|
|
<HotColumn>
|
|
<RendererComponent2 ref={function (instance) {
|
|
if (instance && instance.props.row === 0 && instance.props.col === 1) {
|
|
oneRendererInstance = instance;
|
|
}
|
|
}} hot-renderer></RendererComponent2>
|
|
</HotColumn>
|
|
</HotTable>
|
|
)).hotInstance;
|
|
|
|
expect(hotInstance.getCell(0, 0).innerHTML).toEqual('<div>initial</div>');
|
|
expect(hotInstance.getCell(0, 1).innerHTML).toEqual('<div>initial</div>');
|
|
|
|
await act(async () => {
|
|
zeroRendererInstance.setState({
|
|
value: 'altered'
|
|
});
|
|
|
|
oneRendererInstance.setState({
|
|
value: 'altered as well'
|
|
});
|
|
});
|
|
|
|
expect(hotInstance.getCell(0, 0).innerHTML).toEqual('<div>altered</div>');
|
|
expect(hotInstance.getCell(0, 1).innerHTML).toEqual('<div>altered as well</div>');
|
|
});
|
|
|
|
it('should be possible to set the state of the editor components passed to HotTable and HotColumn', async () => {
|
|
class RendererEditor2 extends BaseEditorComponent {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
value: 'initial'
|
|
}
|
|
}
|
|
|
|
render(): React.ReactElement<string> {
|
|
return (
|
|
<div id={this.props.editorId}>
|
|
{this.state.value}
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
let globalEditorInstance = null;
|
|
let columnEditorInstance = null;
|
|
|
|
mountComponentWithRef((
|
|
<HotTable licenseKey="non-commercial-and-evaluation"
|
|
id="test-hot"
|
|
data={createSpreadsheetData(3, 2)}
|
|
width={300}
|
|
height={300}
|
|
rowHeights={23}
|
|
colWidths={50}
|
|
init={function () {
|
|
mockElementDimensions(this.rootElement, 300, 300);
|
|
}}>
|
|
<RendererEditor2 editorId={'first-editor'} ref={function (instance) {
|
|
globalEditorInstance = instance;
|
|
}} hot-editor></RendererEditor2>
|
|
<HotColumn/>
|
|
<HotColumn>
|
|
<RendererEditor2 editorId={'second-editor'} ref={function (instance) {
|
|
columnEditorInstance = instance;
|
|
}} hot-editor></RendererEditor2>
|
|
</HotColumn>
|
|
</HotTable>
|
|
));
|
|
|
|
expect(document.querySelector('#first-editor').innerHTML).toEqual('initial');
|
|
expect(document.querySelector('#second-editor').innerHTML).toEqual('initial');
|
|
|
|
await act(async () => {
|
|
globalEditorInstance.setState({
|
|
value: 'altered'
|
|
});
|
|
|
|
columnEditorInstance.setState({
|
|
value: 'altered as well'
|
|
});
|
|
});
|
|
|
|
expect(document.querySelector('#first-editor').innerHTML).toEqual('altered');
|
|
expect(document.querySelector('#second-editor').innerHTML).toEqual('altered as well');
|
|
});
|
|
});
|
|
|
|
describe('Component lifecyle', () => {
|
|
it('renderer components should trigger their lifecycle methods', async () => {
|
|
class RendererComponent2 extends React.Component<any, any, any> {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
rendererCounters.set(`${this.props.row}-${this.props.col}`, {
|
|
didMount: 0,
|
|
willUnmount: 0
|
|
});
|
|
}
|
|
|
|
componentDidMount(): void {
|
|
const counters = rendererCounters.get(`${this.props.row}-${this.props.col}`);
|
|
counters.didMount++;
|
|
}
|
|
|
|
componentWillUnmount(): void {
|
|
const counters = rendererCounters.get(`${this.props.row}-${this.props.col}`);
|
|
counters.willUnmount++;
|
|
}
|
|
|
|
render(): React.ReactElement<string> {
|
|
return (
|
|
<>
|
|
test
|
|
</>
|
|
);
|
|
}
|
|
}
|
|
|
|
let secondGo = false;
|
|
const rendererRefs = new Map();
|
|
const rendererCounters = new Map();
|
|
|
|
const hotInstance = mountComponentWithRef((
|
|
<HotTable licenseKey="non-commercial-and-evaluation"
|
|
id="test-hot"
|
|
data={createSpreadsheetData(3, 2)}
|
|
width={300}
|
|
height={300}
|
|
rowHeights={23}
|
|
colWidths={50}
|
|
autoRowSize={false}
|
|
autoColumnSize={false}
|
|
init={function () {
|
|
mockElementDimensions(this.rootElement, 300, 300);
|
|
}}>
|
|
<RendererComponent2 ref={function (instance) {
|
|
if (!secondGo && instance) {
|
|
rendererRefs.set(`${instance.props.row}-${instance.props.col}`, instance);
|
|
}
|
|
}} hot-renderer></RendererComponent2>
|
|
<HotColumn/>
|
|
<HotColumn>
|
|
<RendererComponent2 ref={function (instance) {
|
|
if (!secondGo && instance) {
|
|
rendererRefs.set(`${instance.props.row}-${instance.props.col}`, instance);
|
|
}
|
|
}} hot-renderer></RendererComponent2>
|
|
</HotColumn>
|
|
</HotTable>
|
|
), false).hotInstance;
|
|
|
|
rendererCounters.forEach((counters) => {
|
|
expect(counters.didMount).toEqual(1);
|
|
expect(counters.willUnmount).toEqual(0);
|
|
});
|
|
|
|
secondGo = true;
|
|
|
|
await act(async () => {
|
|
hotInstance.render();
|
|
});
|
|
|
|
await sleep(300);
|
|
|
|
rendererCounters.forEach((counters) => {
|
|
expect(counters.didMount).toEqual(1);
|
|
expect(counters.willUnmount).toEqual(0);
|
|
});
|
|
});
|
|
|
|
it('editor components should trigger their lifecycle methods', async () => {
|
|
class EditorComponent2 extends BaseEditorComponent {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
editorCounters.set(`${this.props.row}-${this.props.col}`, {
|
|
didMount: 0,
|
|
willUnmount: 0
|
|
});
|
|
}
|
|
|
|
componentDidMount(): void {
|
|
const counters = editorCounters.get(`${this.props.row}-${this.props.col}`);
|
|
counters.didMount++;
|
|
}
|
|
|
|
componentWillUnmount(): void {
|
|
const counters = editorCounters.get(`${this.props.row}-${this.props.col}`);
|
|
counters.willUnmount++;
|
|
}
|
|
|
|
render(): React.ReactElement<string> {
|
|
return (
|
|
<>
|
|
test
|
|
</>
|
|
);
|
|
}
|
|
}
|
|
|
|
let secondGo = false;
|
|
const editorRefs = new Map();
|
|
const editorCounters = new Map();
|
|
const childrenArray = [
|
|
<EditorComponent2 ref={function (instance) {
|
|
if (!secondGo && instance) {
|
|
editorRefs.set(`EditorComponent2`, instance);
|
|
}
|
|
}} hot-editor key={Math.random()}></EditorComponent2>
|
|
];
|
|
|
|
const hotTableInstance = mountComponentWithRef((
|
|
<HotTable licenseKey="non-commercial-and-evaluation"
|
|
id="test-hot"
|
|
data={createSpreadsheetData(3, 2)}
|
|
width={300}
|
|
height={300}
|
|
rowHeights={23}
|
|
colWidths={50}
|
|
init={function () {
|
|
mockElementDimensions(this.rootElement, 300, 300);
|
|
}}>
|
|
{childrenArray}
|
|
</HotTable>
|
|
), false);
|
|
|
|
editorCounters.forEach((counters) => {
|
|
expect(counters.didMount).toEqual(1);
|
|
expect(counters.willUnmount).toEqual(0);
|
|
});
|
|
|
|
secondGo = true;
|
|
|
|
childrenArray.length = 0;
|
|
|
|
await act(async () => {
|
|
hotTableInstance.forceUpdate();
|
|
});
|
|
|
|
await sleep(100);
|
|
|
|
editorCounters.forEach((counters) => {
|
|
expect(counters.didMount).toEqual(1);
|
|
expect(counters.willUnmount).toEqual(1);
|
|
});
|
|
});
|
|
|
|
it('should display a warning and not throw any errors, when the underlying Handsontable instance ' +
|
|
'has been destroyed', async () => {
|
|
const warnFunc = console.warn;
|
|
const warnCalls = [];
|
|
|
|
const componentInstance = mountComponentWithRef((
|
|
<HotTable
|
|
id="test-hot"
|
|
data={[[2]]}
|
|
licenseKey="non-commercial-and-evaluation"
|
|
/>
|
|
));
|
|
|
|
console.warn = (warningMessage) => {
|
|
warnCalls.push(warningMessage);
|
|
};
|
|
|
|
expect(componentInstance.hotInstance.isDestroyed).toEqual(false);
|
|
|
|
componentInstance.hotInstance.destroy();
|
|
|
|
expect(componentInstance.hotInstance).toEqual(null);
|
|
|
|
expect(warnCalls.length).toBeGreaterThan(0);
|
|
warnCalls.forEach((message) => {
|
|
expect(message).toEqual(HOT_DESTROYED_WARNING);
|
|
});
|
|
|
|
console.warn = warnFunc;
|
|
});
|
|
});
|