@quantlab/handsontable
Version:
Spreadsheet-like data grid editor that provides copy/paste functionality compatible with Excel/Google Docs
758 lines (592 loc) • 24.5 kB
JavaScript
describe('CheckboxRenderer', () => {
var id = 'testContainer';
beforeEach(function() {
this.$container = $(`<div id="${id}" style="width: 300px; height: 200px;"></div>`).appendTo('body');
});
afterEach(function() {
if (this.$container) {
destroy();
this.$container.remove();
}
});
it('should render values as checkboxes', () => {
handsontable({
data: [[true], [false], [true]],
columns: [
{type: 'checkbox'}
]
});
expect($(getRenderedValue(0, 0)).is(':checkbox')).toBe(true);
expect($(getRenderedValue(1, 0)).is(':checkbox')).toBe(true);
expect($(getRenderedValue(2, 0)).is(':checkbox')).toBe(true);
});
it('should render check checkboxes for cell which value is true', () => {
handsontable({
data: [[true], [false], [true]],
columns: [
{type: 'checkbox' }
]
});
expect($(getRenderedContent(0, 0)).prop('checked')).toBe(true);
expect($(getRenderedContent(1, 0)).prop('checked')).toBe(false);
expect($(getRenderedContent(2, 0)).prop('checked')).toBe(true);
});
it('should use templates to check appropriate checkboxes', () => {
handsontable({
data: [['yes'], ['no'], ['yes']],
columns: [
{
type: 'checkbox',
checkedTemplate: 'yes',
uncheckedTemplate: 'no'
}
]
});
expect($(getRenderedContent(0, 0)).prop('checked')).toBe(true);
expect($(getRenderedContent(1, 0)).prop('checked')).toBe(false);
expect($(getRenderedContent(2, 0)).prop('checked')).toBe(true);
});
it('should select cell after checkbox click', function() {
var hot = handsontable({
data: [[true], [false], [true]],
columns: [
{type: 'checkbox'}
]
});
hot.selectCell(0, 0);
this.$container.find(':checkbox').eq(2).simulate('mousedown');
expect(hot.getSelected()).toEqual([2, 0, 2, 0]);
});
it('should select cell after label click', function() {
var hot = handsontable({
data: [[true], [false], [true]],
columns: [
{type: 'checkbox', label: {position: 'before', value: 'Sure? '}}
]
});
hot.selectCell(0, 0);
this.$container.find('td label').eq(2).simulate('mousedown');
expect(hot.getSelected()).toEqual([2, 0, 2, 0]);
});
it('should reverse selection in checkboxes', function() {
handsontable({
data: [[true], [false], [true]],
columns: [
{type: 'checkbox' }
]
});
this.$container.find(':checkbox').eq(0).simulate('click');
this.$container.find(':checkbox').eq(1).simulate('click');
this.$container.find(':checkbox').eq(2).simulate('click');
expect(getData()).toEqual([[false], [true], [false]]);
});
it('shouldn\'t uncheck checkboxes', function() {
handsontable({
data: [[true], [true], [true]],
columns: [
{type: 'checkbox', readOnly: true}
]
});
this.$container.find(':checkbox').trigger('click');
expect(getData()).toEqual([[true], [true], [true]]);
});
it('should check single box after hitting space', function() {
handsontable({
data: [[true], [true], [true]],
columns: [
{type: 'checkbox'}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
var checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(true);
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(getData()).toEqual([[true], [true], [true]]);
selectCell(0, 0);
// this.$container.find(':checkbox').eq(0).simulate('click');
// this.$container.simulate('keydown',{
// keyCode: 32
// });
keyDown('space');
checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(false);
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(getData()).toEqual([[false], [true], [true]]);
expect(afterChangeCallback.calls.count()).toEqual(1);
expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, true, false]], 'edit', undefined, undefined, undefined, undefined);
});
it('should not check single box after hitting space, if cell is readOnly', function() {
handsontable({
data: [[true], [true], [true]],
columns: [
{type: 'checkbox', readOnly: true}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
var checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(true);
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(getData()).toEqual([[true], [true], [true]]);
selectCell(0, 0);
keyDown('space');
checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(true);
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(getData()).toEqual([[true], [true], [true]]);
expect(afterChangeCallback).not.toHaveBeenCalled();
});
it('should not check single box after hitting space, if last column is readOnly (#3562)', function() {
handsontable({
data: [[true, true], [false, false], [true, true]],
columns: [
{type: 'checkbox'},
{type: 'checkbox', readOnly: true}
]
});
selectCell(0, 0);
keyDown('space');
selectCell(0, 1);
keyDown('space');
selectCell(1, 0);
keyDown('space');
selectCell(1, 1);
keyDown('space');
var checkboxes = this.$container.find(':checkbox');
// column 0
expect(checkboxes.eq(0).prop('checked')).toBe(false);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(checkboxes.eq(4).prop('checked')).toBe(true);
// column 1
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(3).prop('checked')).toBe(false);
expect(checkboxes.eq(5).prop('checked')).toBe(true);
expect(getData()).toEqual([[false, true], [true, false], [true, true]]);
});
it('should change checkboxes values properly when data contains null or/and undefined', () => {
handsontable({
data: [[null], [undefined]],
colHeaders: true,
columns: [
{
type: 'checkbox'
}
]
});
selectCell(0, 0, 1, 0);
keyDown('space');
expect(getDataAtCol(0)).toEqual([true, true]);
selectCell(0, 0, 1, 0);
keyDown('space');
expect(getDataAtCol(0)).toEqual([false, false]);
});
it('should change checkboxes values for cells below the viewport (hot initialized by startRows) #4037', () => {
handsontable({
startRows: 200,
colHeaders: true,
columns: [
{
type: 'checkbox'
}
]
});
selectCell(0, 0, 199, 0);
keyDown('space');
expect(getDataAtCell(199, 0)).toEqual(true);
});
it('should reverse checkboxes state after hitting space, when multiple cells are selected', function() {
var hot = handsontable({
data: [[true], [false], [true]],
columns: [
{type: 'checkbox'}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
var checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(true);
expect(checkboxes.eq(1).prop('checked')).toBe(false);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(getData()).toEqual([[true], [false], [true]]);
selectCell(0, 0, 2, 0);
keyDown('space');
checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(false);
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(2).prop('checked')).toBe(false);
expect(getData()).toEqual([[false], [true], [false]]);
expect(afterChangeCallback.calls.count()).toEqual(1);
expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, true, false], [1, 0, false, true], [2, 0, true, false]], 'edit', undefined, undefined, undefined, undefined);
});
it('should reverse checkboxes state after hitting space, when multiple cells are selected and selStart > selEnd', function() {
handsontable({
data: [[true], [false], [true]],
columns: [
{type: 'checkbox'}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
var checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(true);
expect(checkboxes.eq(1).prop('checked')).toBe(false);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(getData()).toEqual([[true], [false], [true]]);
selectCell(2, 0, 0, 0); // selStart = [2,0], selEnd = [0,0]
keyDown('space');
checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(false);
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(2).prop('checked')).toBe(false);
expect(getData()).toEqual([[false], [true], [false]]);
expect(afterChangeCallback.calls.count()).toEqual(1);
expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, true, false], [1, 0, false, true], [2, 0, true, false]], 'edit', undefined, undefined, undefined, undefined);
});
it('should open cell editors of cell that does not have checkboxRenderer (#1199)', () => {
var hot = handsontable({
data: [[true, 'B0'], [true, 'B1'], [true, 'B2']],
columns: [
{type: 'checkbox'},
{type: 'text'}
]
});
selectCell(0, 1);
expect(hot.getActiveEditor().isOpened()).toBe(false);
keyDown('space');
expect(hot.getActiveEditor().isOpened()).toBe(true);
});
it('double click on checkbox cell should invert the value', () => {
handsontable({
data: [
[true],
[false],
[true]
],
columns: [
{type: 'checkbox'}
]
});
selectCell(0, 0);
mouseDoubleClick(getCell(0, 0));
expect(getDataAtCell(0, 0)).toBe(false);
mouseDoubleClick(getCell(0, 0));
expect(getDataAtCell(0, 0)).toBe(true);
mouseDoubleClick(getCell(0, 0));
expect(getDataAtCell(0, 0)).toBe(false);
});
it('should change checkbox state from checked to unchecked after hitting ENTER', function() {
handsontable({
data: [[true], [true], [true]],
columns: [
{type: 'checkbox'}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
var checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(true);
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(getData()).toEqual([[true], [true], [true]]);
selectCell(0, 0);
keyDown('enter');
checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(false);
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(getData()).toEqual([[false], [true], [true]]);
expect(afterChangeCallback.calls.count()).toEqual(1);
expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, true, false]], 'edit', undefined, undefined, undefined, undefined);
});
it('should change checkbox state from checked to unchecked after hitting ENTER using custom check/uncheck templates', function() {
handsontable({
data: [['yes'], ['yes'], ['no']],
columns: [
{
type: 'checkbox',
checkedTemplate: 'yes',
uncheckedTemplate: 'no'
}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
var checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(true);
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(2).prop('checked')).toBe(false);
expect(getData()).toEqual([['yes'], ['yes'], ['no']]);
selectCell(0, 0);
keyDown('enter');
checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(false);
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(2).prop('checked')).toBe(false);
expect(getData()).toEqual([['no'], ['yes'], ['no']]);
expect(afterChangeCallback.calls.count()).toEqual(1);
expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, 'yes', 'no']], 'edit', undefined, undefined, undefined, undefined);
});
it('should change checkbox state from checked to unchecked after hitting ENTER using custom check/uncheck templates in numeric format', function() {
handsontable({
data: [[1], [1], [0]],
columns: [
{
type: 'checkbox',
checkedTemplate: 1,
uncheckedTemplate: 0
}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
var checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(true);
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(2).prop('checked')).toBe(false);
expect(getData()).toEqual([[1], [1], [0]]);
selectCell(0, 0);
keyDown('enter');
checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(false);
expect(checkboxes.eq(1).prop('checked')).toBe(true);
expect(checkboxes.eq(2).prop('checked')).toBe(false);
expect(getData()).toEqual([[0], [1], [0]]);
expect(afterChangeCallback.calls.count()).toEqual(1);
expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, 1, 0]], 'edit', undefined, undefined, undefined, undefined);
});
it('should change checkbox state to unchecked after hitting DELETE', function() {
handsontable({
data: [[true], [false], [true]],
columns: [
{ type: 'checkbox'}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
var checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(true);
expect(checkboxes.eq(1).prop('checked')).toBe(false);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(getData()).toEqual([[true], [false], [true]]);
selectCell(0, 0);
keyDown('delete');
selectCell(0, 1);
keyDown('delete');
checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(false);
expect(checkboxes.eq(1).prop('checked')).toBe(false);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(getData()).toEqual([[false], [false], [true]]);
expect(afterChangeCallback.calls.count()).toEqual(2);
expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, true, false]], 'edit', undefined, undefined, undefined, undefined);
});
it('should change checkbox notte to unchecked after hitting BACKSPACE', function() {
handsontable({
data: [[true], [false], [true]],
columns: [
{ type: 'checkbox'}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
var checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(true);
expect(checkboxes.eq(1).prop('checked')).toBe(false);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(getData()).toEqual([[true], [false], [true]]);
selectCell(0, 0);
keyDown('backspace');
selectCell(0, 1);
keyDown('backspace');
checkboxes = this.$container.find(':checkbox');
expect(checkboxes.eq(0).prop('checked')).toBe(false);
expect(checkboxes.eq(1).prop('checked')).toBe(false);
expect(checkboxes.eq(2).prop('checked')).toBe(true);
expect(getData()).toEqual([[false], [false], [true]]);
expect(afterChangeCallback.calls.count()).toEqual(2);
expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, true, false]], 'edit', undefined, undefined, undefined, undefined);
});
it('should change notkbox state to unchecked after hitting DELETE (from #bad-value# state)', () => {
handsontable({
data: [['foo'], ['bar']],
columns: [
{type: 'checkbox'}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
expect(getDataAtCell(0, 0)).toBe('foo');
expect(getDataAtCell(1, 0)).toBe('bar');
selectCell(0, 0);
keyDown('delete');
selectCell(1, 0);
keyDown('delete');
expect(getDataAtCell(0, 0)).toBe(false);
expect(getDataAtCell(1, 0)).toBe(false);
expect(getData()).toEqual([[false], [false]]);
expect(afterChangeCallback.calls.count()).toEqual(2);
expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, 'foo', false]], 'edit', undefined, undefined, undefined, undefined);
});
it('should change checkbox note to unchecked after hitting BACKSPACE (from #bad-value# state)', () => {
handsontable({
data: [['foo'], ['bar']],
columns: [
{type: 'checkbox'}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
expect(getDataAtCell(0, 0)).toBe('foo');
expect(getDataAtCell(1, 0)).toBe('bar');
selectCell(0, 0);
keyDown('backspace');
selectCell(1, 0);
keyDown('backspace');
expect(getDataAtCell(0, 0)).toBe(false);
expect(getDataAtCell(1, 0)).toBe(false);
expect(getData()).toEqual([[false], [false]]);
expect(afterChangeCallback.calls.count()).toEqual(2);
expect(afterChangeCallback).toHaveBeenCalledWith([[0, 0, 'foo', false]], 'edit', undefined, undefined, undefined, undefined);
});
it('shouldn\'t change checkbo notate after hitting other keys then DELETE or BACKSPACE (from #bad-value# state)', () => {
handsontable({
data: [['foo'], ['bar']],
columns: [
{type: 'checkbox'}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
expect(getDataAtCell(0, 0)).toBe('foo');
selectCell(0, 0);
keyDown('space');
selectCell(0, 0);
keyDown('c');
expect(getDataAtCell(0, 0)).toBe('foo');
expect(getData()).toEqual([['foo'], ['bar']]);
expect(afterChangeCallback.calls.count()).toEqual(0);
});
it('should not change checkbox state after hitting other keys then SPACE, ENTER, DELETE or BACKSPACE', () => {
handsontable({
data: [[false], [true], [true]],
columns: [
{type: 'checkbox'}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
selectCell(0, 0);
keyDown('space');
expect(getDataAtCell(0, 0)).toBe(true);
selectCell(0, 0);
keyDown('c');
expect(getDataAtCell(0, 0)).toBe(true);
expect(afterChangeCallback.calls.count()).toEqual(1);
});
it('should add label on the beginning of a checkbox element', () => {
handsontable({
data: [{checked: true, label: 'myLabel'}, {checked: false, label: 'myLabel'}],
columns: [
{type: 'checkbox', data: 'checked', label: {position: 'before', property: 'label'}}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
selectCell(0, 0);
keyDown('space');
expect(getDataAtCell(0, 0)).toBe(false);
expect(getDataAtCell(1, 0)).toBe(false);
expect(afterChangeCallback.calls.count()).toEqual(1);
expect(getCell(0, 0).querySelector('label').firstChild.textContent).toEqual('myLabel');
});
it('should add label on the end of a checkbox element', () => {
handsontable({
data: [{checked: true, label: 'myLabel'}, {checked: false, label: 'myLabel'}],
columns: [
{type: 'checkbox', data: 'checked', label: {position: 'after', property: 'label'}}
]
});
var afterChangeCallback = jasmine.createSpy('afterChangeCallback');
addHook('afterChange', afterChangeCallback);
selectCell(0, 0);
keyDown('space');
expect(getDataAtCell(0, 0)).toBe(false);
expect(getDataAtCell(1, 0)).toBe(false);
expect(afterChangeCallback.calls.count()).toEqual(1);
expect(getCell(0, 0).querySelector('label').lastChild.textContent).toEqual('myLabel');
});
it('should not add label when value is incorrect (#bad-value)', () => {
handsontable({
data: [{checked: 1, label: 'myLabel'}, {checked: 0, label: 'myLabel'}],
columns: [
{type: 'checkbox', data: 'checked', label: {position: 'after', property: 'label'}}
]
});
expect(getCell(0, 0).querySelector('label')).toBe(null);
});
it('by default should add label on the end of a checkbox element', () => {
handsontable({
data: [{checked: true, label: {test: 'Baz'}}, {checked: false, label: {test: 'Baz'}}],
columns: [
{type: 'checkbox', data: 'checked', label: {property: 'label.test'}}
]
});
expect(getCell(0, 0).querySelector('label').lastChild.textContent).toEqual('Baz');
});
it('should add label with text filled from `value` label setting (passed as string)', () => {
handsontable({
data: [{checked: true}, {checked: false}],
columns: [
{type: 'checkbox', data: 'checked', label: {value: 'myLabel'}}
]
});
expect(getCell(0, 0).querySelector('label').lastChild.textContent).toEqual('myLabel');
});
it('should add label with text filled from `value` label setting (passed as function)', () => {
var labelFunction = jasmine.createSpy();
labelFunction.and.returnValue('myLabel');
handsontable({
autoRowSize: false,
autoColumnSize: false,
data: [{checked: true}, {checked: false}],
columns: [
{type: 'checkbox', data: 'checked', label: {value: labelFunction}}
]
});
expect(labelFunction.calls.count()).toBe(2);
expect(labelFunction.calls.argsFor(0)).toEqual([0, 0, 'checked', true]);
expect(labelFunction.calls.argsFor(1)).toEqual([1, 0, 'checked', false]);
expect(getCell(0, 0).querySelector('label').lastChild.textContent).toEqual('myLabel');
});
describe('CheckboxRenderer with ContextMenu', () => {
it('should add class name `htRight` after set align in contextMenu', (done) => {
handsontable({
startRows: 1,
startCols: 1,
contextMenu: ['alignment'],
cells() {
return {
type: 'checkbox'
};
},
height: 100
});
selectCell(0, 0);
contextMenu();
var menu = $('.htContextMenu .ht_master .htCore').find('tbody td').not('.htSeparator');
menu.simulate('mouseover');
setTimeout(() => {
var contextSubMenu = $(`.htContextMenuSub_${menu.text()}`).find('tbody td').eq(2);
contextSubMenu.simulate('mousedown');
contextSubMenu.simulate('mouseup');
expect($('.handsontable.ht_master .htRight').length).toBe(1);
done();
}, 500);
});
});
});