control-freak-ide/server/nodejs/tests/mixins/Tree.js
plastic-hub-dev-node-saturn 538369cff7 latest
2021-05-12 18:35:18 +02:00

487 lines
12 KiB
JavaScript

define([
'intern!tdd',
'intern/chai!assert',
'dgrid/OnDemandGrid',
'dgrid/Editor',
'dgrid/Tree',
'dgrid/util/has-css3',
'dgrid/util/misc',
'dojo/_base/declare',
'dojo/_base/lang',
'dojo/aspect',
'dojo/Deferred',
'dojo/dom-class',
'dojo/dom-construct',
'dojo/dom-style',
'dojo/on',
'dojo/query',
'dgrid/test/data/createHierarchicalStore',
'../addCss!'
], function (test, assert, OnDemandGrid, Editor, Tree, has, miscUtil, declare, lang, aspect, Deferred,
domClass, domConstruct, domStyle, on, query, createHierarchicalStore) {
var grid,
testDelay = 15,
hasTransitionEnd = has('transitionend');
function createGrid(options) {
var data = [],
store,
treeColumnOptions,
i,
k,
GridConstructor;
for (i = 0; i < 5; i++) {
var parentId = '' + i;
data.push({
id: parentId,
value: 'Root ' + i
});
for (k = 0; k < 100; k++) {
data.push({
id: i + ':' + k,
parent: parentId,
value: 'Child ' + k,
hasChildren: false
});
}
}
store = createHierarchicalStore({
data: data
});
treeColumnOptions = lang.mixin({
renderExpando: true,
label: 'id',
field: 'id'
}, options && options.treeColumnOptions);
if (options && options.useEditor) {
GridConstructor = declare([OnDemandGrid, Editor, Tree]);
if (!treeColumnOptions.editor) {
treeColumnOptions.editor = 'text';
}
}
else {
GridConstructor = declare([OnDemandGrid, Tree]);
}
grid = new GridConstructor(lang.mixin({
sort: 'id',
collection: store,
columns: [
treeColumnOptions,
{ label: 'value', field: 'value'}
]
}, options && options.gridOptions));
document.body.appendChild(grid.domNode);
grid.startup();
}
function destroyGrid() {
grid.destroy();
grid = null;
}
function testRowExists(dataItemId, exists) {
// Tests existence of a row for a given item ID;
// if `exists` is false, tests for nonexistence instead
exists = exists !== false;
assert[exists ? 'isNotNull' : 'isNull'](document.getElementById(grid.id + '-row-' + dataItemId),
'A row for ' + dataItemId + ' should ' + (exists ? '' : 'not ') + 'exist in the grid.');
}
function wait(delay) {
// Returns a promise resolving after the given number of ms (or testDelay by default)
var dfd = new Deferred();
setTimeout(function () {
dfd.resolve();
}, delay || testDelay);
return dfd.promise;
}
// Define a function returning a promise resolving once children are expanded.
// On browsers which support CSS3 transitions, this occurs when transitionend fires;
// otherwise it occurs immediately.
var expand = hasTransitionEnd ? function (id) {
var dfd = new Deferred();
on.once(grid, hasTransitionEnd, function () {
dfd.resolve();
});
grid.expand(id);
return dfd.promise;
} : function (id) {
var dfd = new Deferred();
grid.expand(id);
dfd.resolve();
return dfd.promise;
};
function scrollToEnd() {
var dfd = new Deferred(),
handle;
handle = on.once(grid.bodyNode, 'scroll', miscUtil.debounce(function () {
dfd.resolve();
}));
grid.scrollTo({ y: grid.bodyNode.scrollHeight });
return dfd.promise;
}
test.suite('Tree', function () {
test.suite('large family expansion', function () {
test.beforeEach(function () {
createGrid();
// Firefox in particular seems to skip transitions sometimes
// if we don't wait a bit after creating and placing the grid
return wait();
});
test.afterEach(destroyGrid);
test.test('expand first row', function () {
return expand(0)
.then(function () {
testRowExists('0:0');
testRowExists('0:99', false);
});
});
test.test('expand first row + scroll to bottom', function () {
return expand(0)
.then(scrollToEnd)
.then(function () {
testRowExists('0:0');
testRowExists('0:99');
});
});
test.test('expand last row', function () {
return expand(4).then(function () {
testRowExists('4:0');
testRowExists('4:99', false);
});
});
test.test('expand last row + scroll to bottom', function () {
return expand(4)
.then(scrollToEnd)
.then(function () {
testRowExists('4:0');
testRowExists('4:99');
});
});
test.test('expand first and last rows + scroll to bottom', function () {
return expand(0)
.then(scrollToEnd)
.then(function () {
return expand(4);
})
.then(scrollToEnd)
.then(function () {
testRowExists('4:0');
testRowExists('4:99');
});
});
test.test('expand hidden', function () {
var dfd = this.async(1000);
grid.domNode.style.display = 'none';
grid.expand(0);
grid.domNode.style.display = 'block';
// Since the grid is not displayed the expansion will occur without a transitionend event
// However, DOM updates from the expand will not complete within the current stack frame
setTimeout(dfd.callback(function () {
var connected = grid.row(0).element.connected;
assert.isTrue(connected && connected.offsetHeight > 0,
'Node should be expanded with non-zero height');
}), 0);
});
// Test goal: ensure the expando icon is displayed consistent with the results of the store's
// "mayHaveChildren" method.
// Notes:
// * The store created in "createGrid" has a "mayHaveChildren" that returns true for nodes with no parentId
// * The expando icon (.dgrid-expando-icon) is always rendered, it is not visible if it lacks the class
// ".ui-icon"
test.test('mayHaveChildren', function () {
var rowObject;
var expandoNode;
var i;
var j;
for (i = 0; i < 5; i++) {
rowObject = grid.row(i);
expandoNode = query('.dgrid-expando-icon.ui-icon', rowObject.element)[0];
assert.isDefined(expandoNode, 'Parent node should have an expando icon; node id = ' + i);
grid.expand(i, true, true);
for (j = 0; j < 2; j++) {
rowObject = grid.row(i + ':' + j);
expandoNode = query('.dgrid-expando-icon.ui-icon', rowObject.element)[0];
assert.isUndefined(expandoNode,
'Child node should not have an expando icon; node id = ' + i + ':' + j);
}
grid.expand(i, false, true);
}
});
// Test goal: ensure that rows are correctly expanded/collapsed on grid render in accordance with the
// grid's "shouldExpand" method
test.test('shouldExpand', function () {
var shouldExpand;
var i;
grid.shouldExpand = function (rowObject) {
var shouldExpand = false;
if (rowObject.data.parent === undefined) {
shouldExpand = rowObject.id % 2 === 0;
}
return shouldExpand;
};
grid.refresh();
for (i = 0; i < 5; i++) {
shouldExpand = i % 2 === 0;
if (shouldExpand) {
assert.isTrue(grid._expanded[i], 'Row ' + i + ' should be expanded');
}
else {
assert.isUndefined(grid._expanded[i], 'Row ' + i + ' should not be expanded');
}
}
});
// Test goal: ensure that a custom "renderExpando" column method produces the expected DOM structure
test.test('renderExpando', function () {
var columns;
var rowObject;
var expandoNode;
var i;
columns = grid.get('columns');
columns[0].renderExpando = function () {
// * Adds the "test-expando" class
// * Floats the expando at the opposite end of the cell
var node = grid._defaultRenderExpando.apply(this, arguments);
domClass.add(node, 'test-expando');
domStyle.set(node, 'float', 'right');
return node;
};
grid.set('columns', columns);
for (i = 0; i < 5; i++) {
rowObject = grid.row(i);
expandoNode = query('.dgrid-expando-icon.ui-icon', rowObject.element)[0];
assert.isDefined(expandoNode, 'Row ' + i + ' should have an expando icon');
assert.include(expandoNode.className, 'test-expando',
'Row ' + i + '\'s expando icon should have the class "test-expando"');
}
});
// Test goal: ensure the expando node is still rendered when the column has a custom "renderCell" method
test.test('renderCell', function () {
var rowObject;
var expandoNode;
var i;
grid.destroy();
createGrid({
treeColumnOptions: {
renderCell: function (object, value) {
var div = domConstruct.create('div', { className: 'testRenderCell' });
div.appendChild(document.createTextNode(value));
return div;
}
}
});
for (i = 0; i < 5; i++) {
rowObject = grid.row(i);
expandoNode = query('.dgrid-expando-icon.ui-icon', rowObject.element)[0];
assert.isDefined(expandoNode, 'Row ' + i + ' should have an expando node');
}
grid.destroy();
createGrid({
treeColumnOptions: {
renderCell: function (rowObject, cellValue, cellNode) {
domClass.add(cellNode, 'testRenderCell');
cellNode.appendChild(document.createTextNode(cellValue));
}
}
});
for (i = 0; i < 5; i++) {
rowObject = grid.row(i);
expandoNode = query('.dgrid-expando-icon.ui-icon', rowObject.element)[0];
assert.isDefined(expandoNode, 'Row ' + i + ' should have an expando node');
}
});
// Test goal: ensure the expando node is still rendered with the editor plugin
// Note: ordering is important: tree(editor()), not editor(tree())
test.test('renderCell with editor', function () {
var rowObject;
var expandoNode;
var inputNode;
var i;
grid.destroy();
createGrid({
useEditor: true
});
for (i = 0; i < 5; i++) {
rowObject = grid.row(i);
expandoNode = query('.dgrid-expando-icon.ui-icon', rowObject.element)[0];
assert.isDefined(expandoNode, 'Row ' + i + ' should have an expando node');
inputNode = query('.dgrid-input', rowObject.element)[0];
assert.isDefined(inputNode, 'Row ' + i + ' should have an input node');
}
});
});
test.suite('large family expansion without sort', function () {
test.beforeEach(function () {
createGrid({ gridOptions: { sort: null } });
return wait();
});
test.afterEach(destroyGrid);
test.test('expand first row', function () {
return expand(0)
.then(function () {
testRowExists('0:0');
var row = grid.row('0:0').element;
assert.strictEqual(row.previousSibling.className, 'dgrid-preload',
'Item 0:0 should be the first item even with no sort order specified');
});
});
});
test.suite('Tree + Trackable', function () {
test.beforeEach(createGrid);
test.afterEach(destroyGrid);
test.test('child modification', function () {
return expand(0).then(function () {
testRowExists('0:0');
assert.doesNotThrow(function () {
grid.collection.put({
id: '0:0',
value: 'Modified',
parent: '0'
});
}, null, 'Modification of child should not throw error');
});
});
});
test.suite('Tree + Trackable + shouldTrackCollection: false', function () {
var handles = [];
test.beforeEach(function () {
createGrid({
gridOptions: {
shouldTrackCollection: false
}
});
});
test.afterEach(function () {
for (var i = handles.length; i--;) {
handles[i].remove();
}
handles = [];
destroyGrid();
});
test.test('child add', function () {
return expand(0).then(function () {
testRowExists('0:0');
grid.collection.add({
id: '0:0.5',
value: 'New',
parent: '0'
});
testRowExists('0:0.5', false);
});
});
test.test('child put', function () {
return expand(0).then(function () {
var calls = 0;
handles.push(aspect.before(grid, 'removeRow', function () {
calls++;
}));
handles.push(aspect.before(grid, 'insertRow', function () {
calls++;
}));
testRowExists('0:0');
grid.collection.put({
id: '0:0',
value: 'Modified',
parent: '0'
});
assert.strictEqual(calls, 0, 'insertRow and removeRow should never be called');
});
});
test.test('child remove', function () {
return expand(0).then(function () {
testRowExists('0:0');
grid.collection.remove('0:0');
testRowExists('0:0');
});
});
});
test.suite('treeIndentWidth', function () {
var treeIndentWidth = 20;
test.beforeEach(function () {
createGrid({
gridOptions: { treeIndentWidth: treeIndentWidth }
});
return wait();
});
test.afterEach(destroyGrid);
test.test('treeIndentWidth override', function () {
return expand(0).then(function () {
var row = grid.row('0:0');
assert.ok(row, 'Expected child row exists');
query('.dgrid-expando-icon', row.element).forEach(function (element) {
assert.strictEqual(element.style.marginLeft, treeIndentWidth + 'px');
});
});
});
});
});
});