507 lines
16 KiB
JavaScript
507 lines
16 KiB
JavaScript
define([
|
|
'intern!tdd',
|
|
'intern/chai!assert',
|
|
'dgrid/OnDemandList',
|
|
'dgrid/OnDemandGrid',
|
|
'dgrid/Keyboard',
|
|
'dgrid/ColumnSet',
|
|
'dojo/_base/declare',
|
|
'dojo/dom-construct',
|
|
'dojo/on',
|
|
'dojo/query',
|
|
'dstore/Memory',
|
|
'dgrid/test/data/createSyncStore',
|
|
'dgrid/test/data/genericData'
|
|
], function (test, assert, OnDemandList, OnDemandGrid, Keyboard, ColumnSet,
|
|
declare, domConstruct, on, query, Memory, createSyncStore, genericData) {
|
|
var handles = [],
|
|
columns = {
|
|
col1: 'Column 1',
|
|
col3: 'Column 3',
|
|
col5: 'Column 5'
|
|
},
|
|
testStore = createSyncStore({ data: genericData }),
|
|
item = testStore.getSync(1),
|
|
grid,
|
|
columnSet = [
|
|
[
|
|
[
|
|
{ label: 'Column 1', field: 'col1' },
|
|
{ label: 'Column 2', field: 'col2', sortable: false }
|
|
],
|
|
[
|
|
{ label: 'Column 3', field: 'col3', colSpan: 2 }
|
|
]
|
|
],
|
|
[
|
|
[
|
|
{ label: 'Column 1', field: 'col1', rowSpan: 2 },
|
|
{ label: 'Column 4', field: 'col4' }
|
|
],
|
|
[
|
|
{ label: 'Column 5', field: 'col5' }
|
|
]
|
|
]
|
|
];
|
|
|
|
// Common functions run after each test and suite
|
|
|
|
function afterEach() {
|
|
grid.domNode.style.display = '';
|
|
|
|
for (var i = handles.length; i--;) {
|
|
handles[i].remove && handles[i].remove();
|
|
}
|
|
handles = [];
|
|
}
|
|
|
|
function after() {
|
|
// Destroy list or grid
|
|
grid.destroy();
|
|
// Restore item that was removed for focus retention test
|
|
testStore.put(item);
|
|
}
|
|
|
|
// Common test functions for grid w/ cellNavigation: false and list
|
|
|
|
function testRowFocus() {
|
|
var rowId;
|
|
// listen for a dgrid-cellfocusin event
|
|
handles.push(on(document.body, 'dgrid-cellfocusin', function (e) {
|
|
assert.ok(e.row, 'dgrid-cellfocusin event got a non-null row value');
|
|
rowId = e.row.id;
|
|
}));
|
|
// trigger a focus with no argument, which should focus the first row
|
|
grid.focus();
|
|
assert.strictEqual(document.activeElement, query('.dgrid-row', grid.contentNode)[0],
|
|
'focus() targeted the first row');
|
|
assert.strictEqual(rowId, 0,
|
|
'dgrid-cellfocusin event triggered on first row on focus() call');
|
|
}
|
|
|
|
function testRowFocusArgs() {
|
|
var rowId, target;
|
|
// listen for a dgrid-cellfocusin event
|
|
handles.push(on(document.body, 'dgrid-cellfocusin', function (e) {
|
|
assert.ok(e.row, 'dgrid-cellfocusin event got a non-null row value');
|
|
rowId = e.row.id;
|
|
}));
|
|
// trigger a body focus with the second row as the target
|
|
target = query('.dgrid-row', grid.contentNode)[1];
|
|
grid.focus(target);
|
|
// make sure we got the right row
|
|
assert.strictEqual(document.activeElement, target,
|
|
'focus(...) targeted the expected row');
|
|
assert.strictEqual(rowId, 1,
|
|
'dgrid-cellfocusin event triggered on expected row');
|
|
}
|
|
|
|
function testRowBlur() {
|
|
var blurredRow,
|
|
targets = query('.dgrid-row', grid.contentNode);
|
|
|
|
// call one focus event, followed by a subsequent focus event,
|
|
// thus triggering a dgrid-cellfocusout event
|
|
grid.focus(targets[0]);
|
|
|
|
// listen for a dgrid-cellfocusout event
|
|
handles.push(on(document.body, 'dgrid-cellfocusout', function (e) {
|
|
blurredRow = e.row;
|
|
assert.ok(blurredRow, 'dgrid-cellfocusout event got a non-null row value');
|
|
}));
|
|
|
|
grid.focus(targets[1]);
|
|
// make sure our handler was called
|
|
assert.strictEqual(blurredRow && blurredRow.id, 0,
|
|
'dgrid-cellfocusout event triggered on expected row');
|
|
}
|
|
|
|
function testRowUpdate() {
|
|
var element, elementId;
|
|
// Focus a row based on a store ID, then issue an update and make sure
|
|
// the same id is still focused
|
|
grid.focus(1);
|
|
|
|
element = document.activeElement;
|
|
assert.ok(element && element.className && element.className.indexOf('dgrid-row') > -1,
|
|
'focus(id) call focused a row');
|
|
|
|
elementId = element.id;
|
|
grid.collection.put(item);
|
|
assert.notStrictEqual(element, document.activeElement,
|
|
'A different DOM element is focused after updating the item');
|
|
assert.strictEqual(elementId, document.activeElement.id,
|
|
'The item\'s new row is focused after updating the item');
|
|
}
|
|
|
|
function testRowRemove() {
|
|
var dfd = this.async(1000),
|
|
element,
|
|
nextElement;
|
|
|
|
// Focus a row based on a store ID, then remove the item and
|
|
// make sure the corresponding cell is eventually focused
|
|
grid.focus(1);
|
|
|
|
element = document.activeElement;
|
|
assert.ok(element && element.className && element.className.indexOf('dgrid-row') > -1,
|
|
'focus(id) call focused a row');
|
|
|
|
nextElement = element.nextSibling;
|
|
grid.collection.remove(1);
|
|
|
|
// The logic responsible for moving to the next row runs on next turn,
|
|
// since it operates as a fallback that is run only if a replacement
|
|
// is not immediately inserted. Therefore we need to execute our
|
|
// assertions on the next turn as well.
|
|
setTimeout(dfd.callback(function () {
|
|
assert.strictEqual(nextElement, document.activeElement,
|
|
'The next row is focused after removing the item');
|
|
}), 0);
|
|
|
|
return dfd;
|
|
}
|
|
|
|
function registerRowTests(name) {
|
|
test.afterEach(afterEach);
|
|
test.after(after);
|
|
|
|
test.test(name + '.focus + no args', testRowFocus);
|
|
test.test(name + '.focus + args', testRowFocusArgs);
|
|
test.test('dgrid-cellfocusout event', testRowBlur);
|
|
test.test(name + '.focus + item update', testRowUpdate);
|
|
test.test(name + '.focus + item removal', testRowRemove);
|
|
}
|
|
|
|
test.suite('Keyboard (Grid + cellNavigation:true)', function () {
|
|
test.before(function () {
|
|
grid = new (declare([OnDemandGrid, Keyboard]))({
|
|
columns: columns,
|
|
sort: 'id',
|
|
collection: testStore
|
|
});
|
|
document.body.appendChild(grid.domNode);
|
|
grid.startup();
|
|
});
|
|
|
|
test.afterEach(afterEach);
|
|
test.after(after);
|
|
|
|
test.test('grid.focus + no args', function () {
|
|
var colId;
|
|
// listen for a dgrid-cellfocusin event
|
|
handles.push(on(document.body, 'dgrid-cellfocusin', function (e) {
|
|
assert.ok(e.cell, 'dgrid-cellfocusin event got a non-null cell value');
|
|
colId = e.cell.column.id;
|
|
}));
|
|
// trigger a focus with no argument, which should focus the first cell
|
|
grid.focus();
|
|
assert.strictEqual(document.activeElement, query('.dgrid-cell', grid.contentNode)[0],
|
|
'focus() targeted the first cell');
|
|
assert.strictEqual(colId, 'col1',
|
|
'dgrid-cellfocusin event triggered on first cell on focus() call');
|
|
});
|
|
|
|
test.test('grid.focusHeader + no args', function () {
|
|
var colId;
|
|
// listen for a dgrid-cellfocusin event (header triggers same event)
|
|
handles.push(on(document.body, 'dgrid-cellfocusin', function (e) {
|
|
assert.ok(e.cell, 'dgrid-cellfocusin event got a non-null cell value');
|
|
assert.ok(!e.row, 'dgrid-cellfocusin event for header got a falsy row value');
|
|
colId = e.cell.column.id;
|
|
}));
|
|
// trigger a header focus with no argument, which should focus the first cell
|
|
grid.focusHeader();
|
|
assert.strictEqual(document.activeElement, query('.dgrid-cell', grid.headerNode)[0],
|
|
'focus() targeted the first header cell');
|
|
assert.strictEqual(colId, 'col1',
|
|
'dgrid-cellfocusin event triggered on first cell on focusHeader() call');
|
|
});
|
|
|
|
test.test('grid.focus + args', function () {
|
|
var focusedCell, target;
|
|
// listen for a dgrid-cellfocusin event
|
|
handles.push(on(document.body, 'dgrid-cellfocusin', function (e) {
|
|
assert.ok(e.cell, 'dgrid-cellfocusin event got a non-null cell value');
|
|
focusedCell = e.cell;
|
|
}));
|
|
// trigger a body focus with the second cell as the target
|
|
target = query('.dgrid-cell', grid.contentNode)[1];
|
|
grid.focus(target);
|
|
assert.strictEqual(document.activeElement, target,
|
|
'focus(...) targeted the expected cell');
|
|
assert.ok(focusedCell, 'dgrid-cellfocusin event fired');
|
|
assert.strictEqual(focusedCell.row.id, 0,
|
|
'dgrid-cellfocusin event triggered on expected row');
|
|
assert.strictEqual(focusedCell.column.id, 'col3',
|
|
'dgrid-cellfocusin event triggered on second cell on focus(...) call');
|
|
});
|
|
|
|
test.test('grid.focusHeader + args', function () {
|
|
var colId, target;
|
|
// listen for a dgrid-cellfocusin event (header triggers same event)
|
|
handles.push(on(document.body, 'dgrid-cellfocusin', function (e) {
|
|
assert.ok(e.cell, 'dgrid-cellfocusin event got a non-null cell value');
|
|
assert.ok(!e.row, 'dgrid-cellfocusin event for header got a falsy row value');
|
|
colId = e.cell.column.id;
|
|
}));
|
|
// trigger a focus on the first header cell
|
|
target = query('.dgrid-cell', grid.headerNode)[1];
|
|
grid.focus(target);
|
|
assert.strictEqual(document.activeElement, target,
|
|
'focusHeader(...) targeted the expected cell');
|
|
assert.strictEqual(colId, 'col3', 'dgrid-cellfocusin event triggered on expected header cell');
|
|
});
|
|
|
|
test.test('dgrid-cellfocusout event', function () {
|
|
var blurredCell,
|
|
blurredElementRowId,
|
|
targets = query('.dgrid-cell', grid.contentNode);
|
|
|
|
// call one focus event, followed by a subsequent focus event,
|
|
// thus triggering a dgrid-cellfocusout event
|
|
grid.focus(targets[0]);
|
|
|
|
// listen for a dgrid-cellfocusout event
|
|
handles.push(on(document.body, 'dgrid-cellfocusout', function (e) {
|
|
blurredElementRowId = grid.row(e.target).id;
|
|
blurredCell = e.cell;
|
|
assert.ok(blurredCell, 'dgrid-cellfocusout event got a non-null cell value');
|
|
}));
|
|
|
|
// Focus first cell in next row and make sure handler was called
|
|
grid.focus(targets[3]);
|
|
assert.ok(blurredCell, 'dgrid-cellfocusout event fired');
|
|
assert.strictEqual(blurredElementRowId, 0,
|
|
'dgrid-cellfocusout event fired from expected element');
|
|
assert.strictEqual(blurredCell.row.id, 0,
|
|
'dgrid-cellfocusout event.cell contains expected row');
|
|
assert.strictEqual(blurredCell.column.id, 'col1',
|
|
'dgrid-cellfocusout event.cell contains expected column');
|
|
});
|
|
|
|
test.test('grid.focus - no args, empty store', function () {
|
|
grid.set('collection', new Memory({ data: [] }));
|
|
assert.doesNotThrow(function () {
|
|
grid.focus();
|
|
}, null, 'grid.focus() on empty grid should not throw error');
|
|
assert.strictEqual(document.activeElement, grid.contentNode,
|
|
'grid.contentNode should be focused after grid.focus() on empty grid');
|
|
});
|
|
});
|
|
|
|
test.suite('Keyboard (Grid + cellNavigation:true + ColumnSet)', function () {
|
|
test.before(function () {
|
|
grid = new (declare([OnDemandGrid, ColumnSet, Keyboard]))({
|
|
columnSets: columnSet,
|
|
sort: 'id',
|
|
collection: testStore
|
|
});
|
|
document.body.appendChild(grid.domNode);
|
|
grid.startup();
|
|
});
|
|
|
|
test.afterEach(afterEach);
|
|
test.after(after);
|
|
|
|
test.test('grid.focusHeader + ColumnSet', function () {
|
|
var colSetId;
|
|
|
|
handles.push(on(document.body, 'dgrid-cellfocusin', function (e) {
|
|
assert.isTrue('cell' in e, 'dgrid-cellfocusin event has a cell property');
|
|
assert.isFalse('row' in e, 'dgrid-cellfocusin event does not have a row property');
|
|
colSetId = e.cell.column.id;
|
|
}));
|
|
|
|
grid.focus(); // first focus the content body
|
|
grid.focusHeader();
|
|
assert.strictEqual(document.activeElement, query('.dgrid-cell', grid.headerNode)[0],
|
|
'focusHeader() targeted the first header cell');
|
|
assert.strictEqual(colSetId, '0-0-0',
|
|
'dgrid-cellfocusin event triggered on first cell on focusHeader() call');
|
|
});
|
|
});
|
|
|
|
test.suite('Keyboard focus preservation', function () {
|
|
test.before(function () {
|
|
grid = new (declare([OnDemandGrid, Keyboard]))({
|
|
columns: columns,
|
|
sort: 'id',
|
|
collection: testStore
|
|
});
|
|
document.body.appendChild(grid.domNode);
|
|
grid.startup();
|
|
});
|
|
|
|
test.afterEach(afterEach);
|
|
test.after(after);
|
|
|
|
test.test('grid.focus + item update', function () {
|
|
var element;
|
|
// Focus a row based on a store ID + column ID,
|
|
// then issue an update and make sure the same id is still focused
|
|
grid.focus(grid.cell(1, 'col1'));
|
|
|
|
element = document.activeElement;
|
|
assert.ok(element && element.className && element.className.indexOf('dgrid-cell') > -1,
|
|
'focus(id) call focused a cell');
|
|
|
|
grid.collection.put(item);
|
|
assert.notStrictEqual(element, document.activeElement,
|
|
'A different DOM element is focused after updating the item');
|
|
assert.strictEqual(grid.cell(1, 'col1').element, document.activeElement,
|
|
'The item\'s new cell is focused after updating the item');
|
|
});
|
|
|
|
test.test('grid.focus + item update on hidden grid', function () {
|
|
var element;
|
|
// Focus a row based on a store ID + column ID,
|
|
// then issue an update and make sure the same id is still focused
|
|
grid.focus(grid.cell(1, 'col1'));
|
|
|
|
element = document.activeElement;
|
|
assert.ok(element && element.className && element.className.indexOf('dgrid-cell') > -1,
|
|
'focus(id) call focused a cell');
|
|
|
|
// Hide the grid
|
|
grid.domNode.style.display = 'none';
|
|
|
|
// Modify the item in the store
|
|
grid.collection.put(item);
|
|
assert.notStrictEqual(element, document.activeElement,
|
|
'A different or no DOM element is focused after updating the item');
|
|
});
|
|
|
|
test.test('grid.focus + item removal', function () {
|
|
var dfd = this.async(1000),
|
|
element,
|
|
nextElement;
|
|
|
|
// Focus a cell based on a store ID, then remove the item and
|
|
// make sure the corresponding cell is eventually focused
|
|
grid.focus(grid.cell(1, 'col1'));
|
|
|
|
element = document.activeElement;
|
|
assert.ok(element && element.className && element.className.indexOf('dgrid-cell') > -1,
|
|
'focus(id) call focused a cell');
|
|
|
|
nextElement = grid.cell(2, 'col1').element;
|
|
grid.collection.remove(1);
|
|
|
|
// The logic responsible for moving to the next row runs on next turn,
|
|
// since it operates as a fallback that is run only if a replacement
|
|
// is not immediately inserted. Therefore we need to execute our
|
|
// assertions on the next turn as well.
|
|
setTimeout(dfd.callback(function () {
|
|
assert.strictEqual(nextElement, document.activeElement,
|
|
'The next row is focused after removing the item');
|
|
}), 0);
|
|
|
|
return dfd;
|
|
});
|
|
});
|
|
|
|
test.suite('Keyboard focused node preservation after blur', function () {
|
|
var button;
|
|
|
|
test.before(function () {
|
|
grid = new (declare([OnDemandGrid, Keyboard]))({
|
|
columns: columns,
|
|
sort: 'id',
|
|
collection: testStore
|
|
});
|
|
document.body.appendChild(grid.domNode);
|
|
grid.startup();
|
|
|
|
// Add a button as a target to move focus out of grid
|
|
button = domConstruct.create('button', null, document.body);
|
|
});
|
|
|
|
test.afterEach(afterEach);
|
|
test.after(function () {
|
|
after();
|
|
domConstruct.destroy(button);
|
|
});
|
|
|
|
test.test('grid.focus + item update', function () {
|
|
var element;
|
|
grid.focus(grid.cell(1, 'col1'));
|
|
|
|
element = document.activeElement;
|
|
assert.ok(element && element.className && element.className.indexOf('dgrid-cell') > -1,
|
|
'focus(id) call focused a cell');
|
|
|
|
// Focus the button we added to move focus out of the grid
|
|
button.focus();
|
|
|
|
grid.collection.put(item);
|
|
grid.focus();
|
|
assert.notStrictEqual(element, document.activeElement,
|
|
'A different DOM element is focused after updating the item');
|
|
assert.strictEqual(grid.cell(1, 'col1').element, document.activeElement,
|
|
'The item\'s new cell is focused after updating the item');
|
|
});
|
|
|
|
test.test('grid.focus + item removal', function () {
|
|
var dfd = this.async(1000),
|
|
element,
|
|
nextElement;
|
|
|
|
grid.focus(grid.cell(1, 'col1'));
|
|
|
|
element = document.activeElement;
|
|
assert.ok(element && element.className && element.className.indexOf('dgrid-cell') > -1,
|
|
'focus(id) call focused a cell');
|
|
|
|
// Focus the button we added to move focus out of the grid
|
|
button.focus();
|
|
|
|
nextElement = grid.cell(2, 'col1').element;
|
|
grid.collection.remove(1);
|
|
|
|
setTimeout(dfd.callback(function () {
|
|
assert.doesNotThrow(function () {
|
|
grid.focus();
|
|
}, null, 'focus() after blur and item removal should not throw error');
|
|
assert.strictEqual(nextElement, document.activeElement,
|
|
'The next row is focused after calling focus()');
|
|
}), 0);
|
|
|
|
return dfd;
|
|
});
|
|
});
|
|
|
|
test.suite('Keyboard (Grid + cellNavigation:false)', function () {
|
|
test.before(function () {
|
|
grid = new (declare([OnDemandGrid, Keyboard]))({
|
|
cellNavigation: false,
|
|
columns: columns,
|
|
sort: 'id',
|
|
collection: testStore
|
|
});
|
|
document.body.appendChild(grid.domNode);
|
|
grid.startup();
|
|
});
|
|
|
|
registerRowTests('grid');
|
|
});
|
|
|
|
test.suite('Keyboard (List)', function () {
|
|
test.before(function () {
|
|
grid = new (declare([OnDemandList, Keyboard]))({
|
|
sort: 'id',
|
|
collection: testStore,
|
|
renderRow: function (item) {
|
|
var div = document.createElement('div');
|
|
div.appendChild(document.createTextNode(item.col5));
|
|
return div;
|
|
}
|
|
});
|
|
document.body.appendChild(grid.domNode);
|
|
grid.startup();
|
|
});
|
|
|
|
registerRowTests('list');
|
|
});
|
|
});
|