@quantlab/handsontable
Version:
Spreadsheet-like data grid editor that provides copy/paste functionality compatible with Excel/Google Docs
1,809 lines (1,469 loc) • 80.1 kB
JavaScript
describe('AutocompleteEditor', () => {
var id = 'testContainer';
var choices = ['yellow', 'red', 'orange', 'green', 'blue', 'gray', 'black', 'white', 'purple', 'lime', 'olive', 'cyan'];
var hot;
beforeEach(function() {
this.$container = $(`<div id="${id}" style="width: 300px; height: 200px; overflow: auto"></div>`).appendTo('body');
});
afterEach(function() {
if (hot) {
hot = null;
}
if (this.$container) {
destroy();
this.$container.remove();
}
});
describe('open editor', () => {
it('should display editor (after hitting ENTER)', () => {
handsontable({
columns: [
{
editor: 'autocomplete',
source: choices
}
]
});
selectCell(0, 0);
var editor = $('.autocompleteEditor');
expect(editor.is(':visible')).toBe(false);
keyDownUp('enter');
expect(editor.is(':visible')).toBe(true);
});
it('should display editor (after hitting F2)', () => {
handsontable({
columns: [
{
editor: 'autocomplete',
source: choices
}
]
});
selectCell(0, 0);
var editor = $('.autocompleteEditor');
expect(editor.is(':visible')).toBe(false);
keyDownUp('f2');
expect(editor.is(':visible')).toBe(true);
});
it('should display editor (after doubleclicking)', () => {
handsontable({
columns: [
{
editor: 'autocomplete',
source: choices
}
]
});
selectCell(0, 0);
var editor = $('.autocompleteEditor');
expect(editor.is(':visible')).toBe(false);
mouseDoubleClick($(getCell(0, 0)));
expect(editor.is(':visible')).toBe(true);
});
// see https://github.com/handsontable/handsontable/issues/3380
it('should not throw error while selecting the next cell by hitting enter key', () => {
var spy = jasmine.createSpyObj('error', ['test']);
var prevError = window.onerror;
window.onerror = function(messageOrEvent, source, lineno, colno, error) {
spy.test();
};
handsontable({
columns: [{
editor: 'autocomplete',
source: choices
}]
});
selectCell(0, 0);
keyDownUp('enter');
keyDownUp('enter');
keyDownUp('enter');
expect(spy.test.calls.count()).toBe(0);
window.onerror = prevError;
});
});
describe('choices', () => {
it('should display given choices (array)', (done) => {
handsontable({
columns: [
{
editor: 'autocomplete',
source: choices
}
]
});
selectCell(0, 0);
var editor = $('.autocompleteEditor');
keyDownUp('enter');
setTimeout(() => {
expect(editor.find('tbody td:eq(0)').text()).toEqual(choices[0]);
expect(editor.find('tbody td:eq(1)').text()).toEqual(choices[1]);
expect(editor.find('tbody td:eq(2)').text()).toEqual(choices[2]);
expect(editor.find('tbody td:eq(3)').text()).toEqual(choices[3]);
expect(editor.find('tbody td:eq(4)').text()).toEqual(choices[4]);
done();
}, 100);
});
it('should call source function with context set as cellProperties', (done) => {
var source = jasmine.createSpy('source');
var context;
source.and.callFake(function(query, process) {
process(choices);
context = this;
});
var hot = handsontable({
columns: [
{
editor: 'autocomplete',
source
}
]
});
selectCell(0, 0);
source.calls.reset();
keyDownUp('enter');
setTimeout(() => {
expect(context.instance).toBe(hot);
expect(context.row).toBe(0);
expect(context.col).toBe(0);
done();
}, 200);
});
it('should display given choices (sync function)', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
var editor = $('.autocompleteEditor');
syncSources.calls.reset();
keyDownUp('enter');
setTimeout(() => {
expect(editor.find('tbody td:eq(0)').text()).toEqual(choices[0]);
expect(editor.find('tbody td:eq(1)').text()).toEqual(choices[1]);
expect(editor.find('tbody td:eq(2)').text()).toEqual(choices[2]);
expect(editor.find('tbody td:eq(3)').text()).toEqual(choices[3]);
expect(editor.find('tbody td:eq(4)').text()).toEqual(choices[4]);
done();
}, 200);
});
it('should display given choices (async function)', (done) => {
var asyncSources = jasmine.createSpy('asyncSources');
asyncSources.and.callFake((process) => {
process(choices);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source(query, process) {
setTimeout(() => {
asyncSources(process);
}, 0);
}
}
]
});
selectCell(0, 0);
var editor = $('.autocompleteEditor');
keyDownUp('enter');
setTimeout(() => {
expect(asyncSources.calls.count()).toEqual(1);
expect(editor.find('tbody td:eq(0)').text()).toEqual(choices[0]);
expect(editor.find('tbody td:eq(1)').text()).toEqual(choices[1]);
expect(editor.find('tbody td:eq(2)').text()).toEqual(choices[2]);
expect(editor.find('tbody td:eq(3)').text()).toEqual(choices[3]);
expect(editor.find('tbody td:eq(4)').text()).toEqual(choices[4]);
done();
}, 200);
});
it('should NOT update choices list, after cursor leaves and enters the list (#1330)', (done) => {
spyOn(Handsontable.editors.AutocompleteEditor.prototype, 'updateChoicesList').and.callThrough();
var updateChoicesList = Handsontable.editors.AutocompleteEditor.prototype.updateChoicesList;
var hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: choices
}
]
});
selectCell(0, 0);
var editor = hot.getActiveEditor();
keyDownUp('enter');
setTimeout(() => {
updateChoicesList.calls.reset();
$(editor.htContainer).find('.htCore tr:eq(0) td:eq(0)').mouseenter();
$(editor.htContainer).find('.htCore tr:eq(0) td:eq(0)').mouseleave();
$(editor.htContainer).find('.htCore tr:eq(0) td:eq(0)').mouseenter();
}, 200);
setTimeout(() => {
expect(updateChoicesList).not.toHaveBeenCalled();
done();
}, 300);
});
it('should update choices list exactly once after a key is pressed (#1330)', (done) => {
spyOn(Handsontable.editors.AutocompleteEditor.prototype, 'updateChoicesList').and.callThrough();
var updateChoicesList = Handsontable.editors.AutocompleteEditor.prototype.updateChoicesList;
var hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: choices
}
]
});
selectCell(0, 0);
var editor = hot.getActiveEditor();
updateChoicesList.calls.reset();
keyDownUp('enter');
setTimeout(() => {
updateChoicesList.calls.reset();
editor.TEXTAREA.value = 'red';
$(editor.TEXTAREA).simulate('keydown', {
keyCode: 'd'.charCodeAt(0)
});
}, 200);
setTimeout(() => {
expect(updateChoicesList.calls.count()).toEqual(1);
done();
}, 100);
});
it('should not initialize the dropdown with unneeded scrollbars (scrollbar causing a scrollbar issue)', (done) => {
spyOn(Handsontable.editors.AutocompleteEditor.prototype, 'updateChoicesList').and.callThrough();
var updateChoicesList = Handsontable.editors.AutocompleteEditor.prototype.updateChoicesList;
var hot = handsontable({
data: [
[
'blue'
],
[],
[],
[]
],
columns: [
{
editor: 'autocomplete',
source: choices
}
]
});
selectCell(0, 0);
var editor = hot.getActiveEditor();
updateChoicesList.calls.reset();
keyDownUp('enter');
setTimeout(() => {
expect(editor.htContainer.scrollWidth).toEqual(editor.htContainer.clientWidth);
done();
}, 200);
});
it('autocomplete list should have textarea dimensions', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices);
});
handsontable({
colWidths: [200],
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
var editor = $('.handsontableInputHolder');
syncSources.calls.reset();
keyDownUp('enter');
setTimeout(() => {
// -2 for transparent borders
expect(editor.find('.autocompleteEditor .htCore td').width()).toEqual(editor.find('.handsontableInput').width() - 2);
expect(editor.find('.autocompleteEditor .htCore td').width()).toBeGreaterThan(187);
done();
}, 200);
});
it('autocomplete list should have the suggestion table dimensions, when trimDropdown option is set to false', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(['long text', 'even longer text', 'extremely long text in the suggestion list', 'short text', 'text', 'another', 'yellow', 'black']);
});
var hot = handsontable({
colWidths: [200],
columns: [
{
editor: 'autocomplete',
source: syncSources
}
],
trimDropdown: false,
});
selectCell(0, 0);
var editor = $('.handsontableInputHolder');
syncSources.calls.reset();
keyDownUp('enter');
setTimeout(() => {
expect(editor.find('.autocompleteEditor .htCore td').eq(0).width()).toBeGreaterThan(editor.find('.handsontableInput').width());
done();
}, 200);
});
it('autocomplete textarea should have cell dimensions (after render)', (done) => {
var data = [
['a', 'b'],
['c', 'd']
];
hot = handsontable({
data,
minRows: 4,
minCols: 4,
minSpareRows: 4,
minSpareCols: 4,
cells() {
return {
type: Handsontable.AutocompleteCell
};
}
});
selectCell(1, 1);
keyDownUp('enter');
data[1][1] = 'dddddddddddddddddddd';
render();
setTimeout(() => {
var $td = spec().$container.find('.htCore tbody tr:eq(1) td:eq(1)');
expect(autocompleteEditor().width()).toEqual($td.width());
done();
}, 10);
});
it('should invoke beginEditing only once after dobleclicking on a cell (#1011)', () => {
var hot = handsontable({
columns: [
{},
{},
{
type: 'autocomplete',
source: choices
}
]
});
selectCell(0, 2);
spyOn(hot.getActiveEditor(), 'beginEditing');
expect(hot.getActiveEditor().beginEditing.calls.count()).toBe(0);
mouseDoubleClick(getCell(0, 2));
expect(hot.getActiveEditor().beginEditing.calls.count()).toBe(1);
mouseDoubleClick(getCell(1, 2));
expect(hot.getActiveEditor().beginEditing.calls.count()).toBe(2);
mouseDoubleClick(getCell(2, 2));
expect(hot.getActiveEditor().beginEditing.calls.count()).toBe(3);
});
it('should not display all the choices from a long source list and not leave any unused space in the dropdown (YouTrack: #HOT-32)', (done) => {
var hot = handsontable({
columns: [
{
type: 'autocomplete',
source: [
'Acura', 'Audi', 'BMW', 'Buick', 'Cadillac', 'Chevrolet', 'Chrysler', 'Citroen', 'Dodge', 'Eagle', 'Ferrari',
'Ford', 'General Motors', 'GMC', 'Honda', 'Hummer', 'Hyundai', 'Infiniti', 'Isuzu', 'Jaguar', 'Jeep', 'Kia',
'Lamborghini', 'Land Rover', 'Lexus', 'Lincoln', 'Lotus', 'Mazda', 'Mercedes-Benz', 'Mercury', 'Mitsubishi',
'Nissan', 'Oldsmobile', 'Peugeot', 'Pontiac', 'Porsche', 'Regal', 'Renault', 'Saab', 'Saturn', 'Seat', 'Skoda',
'Subaru', 'Suzuki', 'Toyota', 'Volkswagen', 'Volvo']
}
]
});
selectCell(0, 0);
keyDownUp('enter');
var $autocomplete = autocomplete();
var $autocompleteHolder = $autocomplete.find('.ht_master .wtHolder').first();
setTimeout(() => {
expect($autocomplete.find('td').first().text()).toEqual('Acura');
$autocompleteHolder.scrollTop($autocompleteHolder[0].scrollHeight);
}, 100);
setTimeout(() => {
expect($autocomplete.find('td').last().text()).toEqual('Volvo');
done();
}, 200);
});
it('should display the choices, regardless if they\'re declared as string or numeric', (done) => {
handsontable({
columns: [
{
editor: 'autocomplete',
source: ['1', '2', 3, '4', 5, 6]
}
]
});
selectCell(0, 0);
var editor = $('.autocompleteEditor');
keyDownUp('enter');
setTimeout(() => {
expect(editor.find('tbody td:eq(0)').text()).toEqual('1');
expect(editor.find('tbody td:eq(1)').text()).toEqual('2');
expect(editor.find('tbody td:eq(2)').text()).toEqual('3');
expect(editor.find('tbody td:eq(3)').text()).toEqual('4');
expect(editor.find('tbody td:eq(4)').text()).toEqual('5');
expect(editor.find('tbody td:eq(5)').text()).toEqual('6');
done();
}, 100);
});
it('should display the choices, regardless if they\'re declared as string or numeric, when data is present', (done) => {
handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 1),
columns: [
{
editor: 'autocomplete',
source: ['1', '2', 3, '4', 5, 6]
}
]
});
selectCell(0, 0);
keyDownUp('backspace');
var editor = $('.autocompleteEditor');
keyDownUp('enter');
setTimeout(() => {
expect(editor.find('tbody td:eq(0)').text()).toEqual('1');
expect(editor.find('tbody td:eq(1)').text()).toEqual('2');
expect(editor.find('tbody td:eq(2)').text()).toEqual('3');
expect(editor.find('tbody td:eq(3)').text()).toEqual('4');
expect(editor.find('tbody td:eq(4)').text()).toEqual('5');
expect(editor.find('tbody td:eq(5)').text()).toEqual('6');
done();
}, 100);
});
it('should display the dropdown above the editor, when there is not enough space below the cell AND there is more space above the cell', (done) => {
var hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(30, 30),
columns: [
{
editor: 'autocomplete',
source: choices
}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}
],
width: 400,
height: 400
});
setDataAtCell(29, 0, '');
selectCell(29, 0);
mouseDoubleClick($(getCell(29, 0)));
setTimeout(() => {
var autocompleteEditor = $('.autocompleteEditor');
expect(autocompleteEditor.css('position')).toEqual('absolute');
expect(autocompleteEditor.css('top')).toEqual(`${(-1) * autocompleteEditor.height()}px`);
done();
}, 200);
});
it('should flip the dropdown upwards when there is no more room left below the cell after filtering the choice list', (done) => {
var hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(30, 30),
columns: [
{
editor: 'autocomplete',
source: choices
}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}
],
width: 400,
height: 400
});
setDataAtCell(26, 0, 'b');
selectCell(26, 0);
hot.view.wt.wtTable.holder.scrollTop = 999;
mouseDoubleClick($(getCell(26, 0)));
var autocompleteEditor = $('.autocompleteEditor');
setTimeout(() => {
expect(autocompleteEditor.css('position')).toEqual('relative');
autocompleteEditor.siblings('textarea').first().val('');
keyDownUp('backspace');
}, 20);
setTimeout(() => {
expect(autocompleteEditor.css('position')).toEqual('absolute');
expect(autocompleteEditor.css('top')).toEqual(`${(-1) * autocompleteEditor.height()}px`);
done();
}, 100);
});
});
describe('closing editor', () => {
it('should destroy editor when value change with mouse click on suggestion', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
keyDownUp('enter');
setTimeout(() => {
autocomplete().find('tbody td:eq(3)').simulate('mousedown');
expect(getDataAtCell(0, 0)).toEqual('green');
done();
}, 200);
});
it('should not change value type from `numeric` to `string` after mouse click suggestion - ' +
'test no. 1 #4143', (done) => {
handsontable({
columns: [
{
editor: 'autocomplete',
source: [1, 2, 3, 4, 5, 11, 14]
}
]
});
selectCell(0, 0);
keyDownUp('enter');
setTimeout(() => {
autocomplete().find('tbody td:eq(0)').simulate('mousedown');
expect(typeof getDataAtCell(0, 0)).toEqual('number');
done();
}, 200);
});
it('should not change value type from `numeric` to `string` after mouse click on suggestion - ' +
'test no. 2 #4143', (done) => {
const syncSources = jasmine.createSpy('syncSources');
const source = [1, 2, 3, 4, 5, 11, 14];
syncSources.and.callFake((query, process) => {
process(source);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
keyDownUp('enter');
setTimeout(() => {
autocomplete().find('tbody td:eq(0)').simulate('mousedown');
expect(typeof getDataAtCell(0, 0)).toEqual('number');
done();
}, 200);
});
it('should call `afterChange` hook with proper value types - test no. 1 #4143', (done) => {
let changesInside;
let sourceInside;
const afterChange = (changes, source) => {
if (source !== 'loadData') {
changesInside = changes;
sourceInside = source;
}
};
handsontable({
columns: [
{
editor: 'autocomplete',
source: [1, 2, 3, 4, 5, 11, 14]
}
],
afterChange
});
selectCell(0, 0);
keyDownUp('enter');
setTimeout(() => {
autocomplete().find('tbody td:eq(1)').simulate('mousedown');
expect(changesInside[0]).toEqual([0, 0, null, 2]);
done();
}, 200);
});
it('should call `afterChange` hook with proper value types - test no. 2 #4143', (done) => {
let changesInside;
let sourceInside;
const afterChange = (changes, source) => {
if (source !== 'loadData') {
changesInside = changes;
sourceInside = source;
}
};
const syncSources = jasmine.createSpy('syncSources');
const source = [1, 2, 3, 4, 5, 11, 14];
syncSources.and.callFake((query, process) => {
process(source);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
],
afterChange
});
selectCell(0, 0);
keyDownUp('enter');
setTimeout(() => {
autocomplete().find('tbody td:eq(1)').simulate('mousedown');
expect(changesInside[0]).toEqual([0, 0, null, 2]);
done();
}, 200);
});
it('should not change value type from `numeric` to `string` when written down value from set of suggestions #4143', (done) => {
const syncSources = jasmine.createSpy('syncSources');
const source = [1, 2, 3, 4, 5, 11, 14];
syncSources.and.callFake((query, process) => {
process(source);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
keyDownUp('enter');
keyDownUp('backspace');
document.activeElement.value = '1';
$(document.activeElement).simulate('keyup');
setTimeout(() => {
keyDownUp('enter');
expect(getDataAtCell(0, 0)).toEqual(1);
done();
}, 200);
});
it('should destroy editor when value change with Enter on suggestion', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
keyDownUp('enter');
setTimeout(() => {
keyDownUp('arrow_down');
keyDownUp('arrow_down');
keyDownUp('arrow_down');
keyDownUp('arrow_down');
keyDownUp('enter');
expect(getDataAtCell(0, 0)).toEqual('green');
done();
}, 200);
});
it('should destroy editor when pressed Enter then Esc', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
keyDownUp('enter');
setTimeout(() => {
expect(autocompleteEditor().is(':visible')).toBe(true);
keyDownUp('esc');
expect(autocompleteEditor().is(':visible')).toBe(false);
done();
}, 200);
});
it('should destroy editor when mouse double clicked then Esc', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
mouseDoubleClick(getCell(0, 0));
setTimeout(() => {
expect(autocompleteEditor().is(':visible')).toBe(true);
keyDownUp('esc');
expect(autocompleteEditor().is(':visible')).toBe(false);
done();
}, 200);
});
it('cancel editing (Esc) should restore the previous value', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
setDataAtCell(0, 0, 'black');
selectCell(0, 0);
keyDownUp('enter');
setTimeout(() => {
autocomplete().siblings('.handsontableInput').val('ye');
keyDownUp(69); // e
keyDownUp('esc');
expect(getDataAtCell(0, 0)).toEqual('black');
done();
}, 200);
});
it('should destroy editor when clicked outside the table', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
mouseDoubleClick(getCell(0, 0));
setTimeout(() => {
expect(autocompleteEditor().is(':visible')).toBe(true);
$('body').simulate('mousedown');
expect(autocompleteEditor().is(':visible')).toBe(false);
done();
}, 200);
});
it('should show fillHandle element again after close editor', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.plan = function(query, process) {
process(choices.filter((choice) => choice.indexOf(query) != -1));
};
var hot = handsontable({
columns: [
{
type: 'autocomplete',
source: syncSources,
strict: false
},
{}
]
});
selectCell(1, 0);
keyDownUp('x'); // Trigger quick edit mode
keyDownUp('enter');
setTimeout(() => {
expect($('#testContainer.handsontable > .handsontable .wtBorder.current.corner:visible').length).toEqual(1);
done();
}, 200);
});
});
describe('non strict mode', () => {
it('should allow any value in non strict mode (close editor with ENTER)', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
keyDownUp('enter');
setTimeout(() => {
var editor = $('.handsontableInput');
editor.val('foo');
keyDownUp('enter');
expect(getDataAtCell(0, 0)).toEqual('foo');
done();
}, 200);
});
it('should allow any value in non strict mode (close editor by clicking on table)', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
keyDownUp('enter');
setTimeout(() => {
var editor = $('.handsontableInput');
editor.val('foo');
spec().$container.find('tbody tr:eq(1) td:eq(0)').simulate('mousedown');
expect(getDataAtCell(0, 0)).toEqual('foo');
done();
}, 200);
});
it('should save the value from textarea after hitting ENTER', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices.filter((choice) => choice.indexOf(query) != -1));
});
hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
var editorInput = $('.handsontableInput');
expect(getDataAtCell(0, 0)).toBeNull();
keyDownUp('enter');
setTimeout(() => {
syncSources.calls.reset();
editorInput.val('b');
keyDownUp('b'.charCodeAt(0));
}, 200);
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
expect(innerHot.getData()).toEqual([
['blue'],
['black']
]);
var selected = innerHot.getSelected();
expect(selected).toBeUndefined();
keyDownUp('enter');
expect(getDataAtCell(0, 0)).toEqual('b');
done();
}, 400);
});
});
describe('strict mode', () => {
it('strict mode should NOT use value if it DOES NOT match the list (sync reponse is empty)', (done) => {
var onAfterValidate = jasmine.createSpy('onAfterValidate');
var onAfterChange = jasmine.createSpy('onAfterChange');
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process([]); // hardcoded empty result
});
handsontable({
data: [
['one', 'two'],
['three', 'four']
],
columns: [
{
type: 'autocomplete',
source: syncSources,
allowInvalid: false,
strict: true
},
{}
],
afterValidate: onAfterValidate,
afterChange: onAfterChange
});
setDataAtCell(0, 0, 'unexistent');
setTimeout(() => {
expect(getData()).toEqual([
['one', 'two'],
['three', 'four']
]);
expect(syncSources.calls.count()).toEqual(1);
expect(onAfterValidate.calls.count()).toEqual(1);
expect(onAfterChange.calls.count()).toEqual(1); // 1 for loadData (it is not called after failed edit)
done();
}, 200);
});
it('strict mode should use value if it DOES match the list (sync reponse is not empty)', (done) => {
var onAfterValidate = jasmine.createSpy('onAfterValidate');
var onAfterChange = jasmine.createSpy('onAfterChange');
var syncSources = jasmine.createSpy('asyncSources');
syncSources.and.callFake((query, process) => {
process(choices); // hardcoded empty result
});
handsontable({
data: [
['one', 'two'],
['three', 'four']
],
columns: [
{
type: 'autocomplete',
source: syncSources,
allowInvalid: false,
strict: true
},
{}
],
afterValidate: onAfterValidate,
afterChange: onAfterChange
});
setDataAtCell(0, 0, 'yellow');
setTimeout(() => {
expect(getData()).toEqual([
['yellow', 'two'],
['three', 'four']
]);
expect(syncSources.calls.count()).toEqual(1);
expect(onAfterValidate.calls.count()).toEqual(1);
expect(onAfterChange.calls.count()).toEqual(2); // 1 for loadData and 1 for setDataAtCell
done();
}, 200);
});
it('strict mode should NOT use value if it DOES NOT match the list (async reponse is empty)', (done) => {
var onAfterValidate = jasmine.createSpy('onAfterValidate');
var onAfterChange = jasmine.createSpy('onAfterChange');
var asyncSources = jasmine.createSpy('asyncSources');
asyncSources.and.callFake((query, process) => {
setTimeout(() => {
process([]); // hardcoded empty result
});
});
handsontable({
data: [
['one', 'two'],
['three', 'four']
],
columns: [
{
type: 'autocomplete',
source: asyncSources,
allowInvalid: false,
strict: true
},
{}
],
afterValidate: onAfterValidate,
afterChange: onAfterChange
});
setDataAtCell(0, 0, 'unexistent');
setTimeout(() => {
expect(getData()).toEqual([
['one', 'two'],
['three', 'four']
]);
expect(asyncSources.calls.count()).toEqual(1);
expect(onAfterValidate.calls.count()).toEqual(1);
expect(onAfterChange.calls.count()).toEqual(1); // 1 for loadData (it is not called after failed edit)
done();
}, 200);
});
it('strict mode should use value if it DOES match the list (async reponse is not empty)', (done) => {
var onAfterValidate = jasmine.createSpy('onAfterValidate');
var onAfterChange = jasmine.createSpy('onAfterChange');
var asyncSources = jasmine.createSpy('asyncSources');
asyncSources.and.callFake((query, process) => {
setTimeout(() => {
process(choices); // hardcoded empty result
});
});
handsontable({
data: [
['one', 'two'],
['three', 'four']
],
columns: [
{
type: 'autocomplete',
source: asyncSources,
allowInvalid: false,
strict: true
},
{}
],
afterValidate: onAfterValidate,
afterChange: onAfterChange
});
setDataAtCell(0, 0, 'yellow');
setTimeout(() => {
expect(getData()).toEqual([
['yellow', 'two'],
['three', 'four']
]);
expect(asyncSources.calls.count()).toEqual(1);
expect(onAfterValidate.calls.count()).toEqual(1);
expect(onAfterChange.calls.count()).toEqual(2); // 1 for loadData and 1 for setDataAtCell
done();
}, 200);
});
it('strict mode mark value as invalid if it DOES NOT match the list (sync reponse is empty)', (done) => {
var onAfterValidate = jasmine.createSpy('onAfterValidate');
var onAfterChange = jasmine.createSpy('onAfterChange');
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process([]); // hardcoded empty result
});
handsontable({
data: [
['one', 'two'],
['three', 'four']
],
columns: [
{
type: 'autocomplete',
source: syncSources,
allowInvalid: true,
strict: true
},
{}
],
afterValidate: onAfterValidate,
afterChange: onAfterChange
});
expect(getCellMeta(0, 0).valid).not.toBe(false);
expect($(getCell(0, 0)).hasClass('htInvalid')).toBe(false);
setDataAtCell(0, 0, 'unexistent');
setTimeout(() => {
expect(getData()).toEqual([
['unexistent', 'two'],
['three', 'four']
]);
expect(getCellMeta(0, 0).valid).toBe(false);
expect($(getCell(0, 0)).hasClass('htInvalid')).toBe(true);
done();
}, 200);
});
it('should select the best matching option after hitting ENTER', (done) => {
var onAfterValidate = jasmine.createSpy('onAfterValidate');
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices.filter((choice) => choice.indexOf(query) != -1));
});
hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources,
strict: true
}
],
afterValidate: onAfterValidate
});
selectCell(0, 0);
var editorInput = $('.handsontableInput');
expect(getDataAtCell(0, 0)).toBeNull();
keyDownUp('enter');
setTimeout(() => {
syncSources.calls.reset();
editorInput.val('b');
keyDownUp('b'.charCodeAt(0));
}, 200);
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
expect(innerHot.getData()).toEqual([
['blue'],
['black']
]);
var selected = innerHot.getSelected();
var selectedData = innerHot.getDataAtCell(selected[0], selected[1]);
expect(selectedData).toEqual('blue');
onAfterValidate.calls.reset();
keyDownUp('enter');
}, 400);
setTimeout(() => {
expect(getDataAtCell(0, 0)).toEqual('blue');
done();
}, 600);
});
it('should select the best matching option after hitting TAB', (done) => {
var onAfterValidate = jasmine.createSpy('onAfterValidate');
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices.filter((choice) => choice.indexOf(query) != -1));
});
hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources,
strict: true
}
],
afterValidate: onAfterValidate
});
selectCell(0, 0);
var editorInput = $('.handsontableInput');
expect(getDataAtCell(0, 0)).toBeNull();
keyDownUp('enter');
setTimeout(() => {
syncSources.calls.reset();
editorInput.val('b');
keyDownUp('b'.charCodeAt(0));
}, 200);
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
expect(innerHot.getData()).toEqual([
['blue'],
['black']
]);
var selected = innerHot.getSelected();
var selectedData = innerHot.getDataAtCell(selected[0], selected[1]);
expect(selectedData).toEqual('blue');
onAfterValidate.calls.reset();
keyDownUp('tab');
}, 400);
setTimeout(() => {
expect(getDataAtCell(0, 0)).toEqual('blue');
done();
}, 600);
});
it('should mark list item corresponding to current cell value as selected', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(['red', 'dark-yellow', 'yellow', 'light-yellow', 'black']);
});
handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources,
strict: true
}
],
data: [
['yellow'],
['red'],
['blue']
]
});
selectCell(0, 0);
keyDownUp('enter');
setTimeout(() => {
expect(autocomplete().find('.current').text()).toEqual(getDataAtCell(0, 0));
done();
}, 200);
});
});
describe('filtering', () => {
it('typing in textarea should filter the lookup list', (done) => {
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices.filter((choice) => choice.indexOf(query) != -1));
});
hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources
}
]
});
selectCell(0, 0);
var editorInput = $('.handsontableInput');
expect(getDataAtCell(0, 0)).toBeNull();
keyDownUp('enter');
setTimeout(() => {
syncSources.calls.reset();
editorInput.val('e');
keyDownUp(69); // e
}, 200);
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
expect(innerHot.getData()).toEqual([
['red'],
['yellow'],
['green'],
['blue'],
['lime'],
['white'],
['olive'],
['orange'],
['purple']
]);
syncSources.calls.reset();
editorInput.val('ed');
keyDownUp(68); // d
}, 400);
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
expect(innerHot.getData()).toEqual([
['red']
]);
done();
}, 600);
});
it('default filtering should be case insensitive', (done) => {
hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: choices
}
]
});
selectCell(0, 0);
var editorInput = $('.handsontableInput');
expect(getDataAtCell(0, 0)).toBeNull();
keyDownUp('enter');
editorInput.val('e');
keyDownUp(69); // e
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
expect(innerHot.getData()).toEqual([
['red'],
['yellow'],
['green'],
['blue'],
['lime'],
['white'],
['olive'],
['orange'],
['purple']
]);
editorInput.val('e');
keyDownUp(69); // E (same as 'e')
}, 50);
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
expect(innerHot.getData()).toEqual([
['red'],
['yellow'],
['green'],
['blue'],
['lime'],
['white'],
['olive'],
['orange'],
['purple']
]);
done();
}, 100);
});
it('default filtering should be case sensitive when filteringCaseSensitive is false', (done) => {
hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: choices,
filteringCaseSensitive: true
}
]
});
selectCell(0, 0);
var editorInput = $('.handsontableInput');
expect(getDataAtCell(0, 0)).toBeNull();
keyDownUp('enter');
editorInput.val('e');
keyDownUp(69); // e
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
expect(innerHot.getData()).toEqual([
['red'],
['yellow'],
['green'],
['blue'],
['lime'],
['white'],
['olive'],
['orange'],
['purple']
]);
editorInput.val('E');
keyDownUp(69); // E (same as 'e')
}, 50);
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
expect(innerHot.getData()).toEqual([]);
expect(innerHot.getSourceData()).toEqual([]);
done();
}, 200);
});
it('typing in textarea should NOT filter the lookup list when filtering is disabled', (done) => {
hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: choices,
filter: false
}
]
});
selectCell(0, 0);
var editorInput = $('.handsontableInput');
expect(getDataAtCell(0, 0)).toBeNull();
keyDownUp('enter');
setTimeout(() => {
editorInput.val('e');
keyDownUp('e'.charCodeAt(0)); // e
}, 20);
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
expect(innerHot.getData()).toEqual(Handsontable.helper.pivot([choices]));
editorInput.val('ed');
keyDownUp('d'.charCodeAt(0)); // d
}, 40);
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
expect(innerHot.getData()).toEqual(Handsontable.helper.pivot([choices]));
done();
}, 60);
});
it('typing in textarea should highlight the matching phrase', (done) => {
var choices = ['Male', 'Female'];
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices.filter((choice) => choice.search(new RegExp(query, 'i')) != -1));
});
hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources,
filter: false
}
]
});
selectCell(0, 0);
var editorInput = $('.handsontableInput');
expect(getDataAtCell(0, 0)).toBeNull();
keyDownUp('enter');
setTimeout(() => {
syncSources.calls.reset();
editorInput.val('Male');
keyDownUp(69); // e
}, 200);
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
var autocompleteList = $(innerHot.rootElement);
expect(autocompleteList.find('td:eq(0)').html()).toMatch(/<(strong|STRONG)>Male<\/(strong|STRONG)>/); // IE8 makes the tag names UPPERCASE
expect(autocompleteList.find('td:eq(1)').html()).toMatch(/Fe<(strong|STRONG)>male<\/(strong|STRONG)>/);
done();
}, 400);
});
it('text in textarea should not be interpreted as regexp', (done) => {
spyOn(Handsontable.editors.AutocompleteEditor.prototype, 'queryChoices').and.callThrough();
var queryChoices = Handsontable.editors.AutocompleteEditor.prototype.queryChoices;
hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: choices
}
]
});
selectCell(0, 0);
var editorInput = $('.handsontableInput');
expect(getDataAtCell(0, 0)).toBeNull();
keyDownUp('enter');
setTimeout(() => {
queryChoices.calls.reset();
editorInput.val('yellow|red');
keyDownUp('d'.charCodeAt(0));
}, 200);
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
expect(innerHot.getData().length).toEqual(0);
done();
}, 400);
});
it('text in textarea should not be interpreted as regexp when highlighting the matching phrase', (done) => {
var choices = ['Male', 'Female'];
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices.filter((choice) => choice.search(new RegExp(query, 'i')) != -1));
});
hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources,
filter: false
}
]
});
selectCell(0, 0);
var editorInput = $('.handsontableInput');
expect(getDataAtCell(0, 0)).toBeNull();
keyDownUp('enter');
setTimeout(() => {
syncSources.calls.reset();
editorInput.val('M|F');
keyDownUp('F'.charCodeAt(0));
}, 200);
setTimeout(() => {
var ac = hot.getActiveEditor();
var innerHot = ac.htEditor;
var autocompleteList = $(innerHot.rootElement);
expect(autocompleteList.find('td:eq(0)').html()).toEqual('Male');
expect(autocompleteList.find('td:eq(1)').html()).toEqual('Female');
done();
}, 400);
});
it('should allow any value if filter === false and allowInvalid === true', (done) => {
spyOn(Handsontable.editors.AutocompleteEditor.prototype, 'queryChoices').and.callThrough();
var queryChoices = Handsontable.editors.AutocompleteEditor.prototype.queryChoices;
handsontable({
columns: [
{
editor: 'autocomplete',
source: choices,
filter: false,
strict: true,
allowInvalid: true
}
]
});
selectCell(0, 0);
var editorInput = $('.handsontableInput');
expect(getDataAtCell(0, 0)).toBeNull();
keyDownUp('enter');
setTimeout(() => {
queryChoices.calls.reset();
editorInput.val('foobar');
keyDownUp(82); // r
}, 200);
setTimeout(() => {
keyDownUp(Handsontable.helper.KEY_CODES.ENTER);
expect(getDataAtCell(0, 0)).toEqual('foobar');
done();
}, 400);
});
it('typing in textarea should highlight best choice, if strict === true', (done) => {
var choices = ['Male', 'Female'];
var syncSources = jasmine.createSpy('syncSources');
syncSources.and.callFake((query, process) => {
process(choices.filter((choice) => choice.search(new RegExp(query, 'i')) != -1));
});
var hot = handsontable({
columns: [
{
editor: 'autocomplete',
source: syncSources,
filter: false,
strict: true
}
]
});
selectCell(0, 0);
var editorInput = $('.handsontableInput');
expect(getDataAtCell(0, 0)).toBeNull();
keyDownUp('enter');
setTimeout(() =>