tabulator-tables
Version:
Interactive table generation JavaScript library
269 lines (228 loc) • 7.48 kB
JavaScript
import Module from '../../../src/js/core/Module.js';
import ColumnCalcs from '../../../src/js/modules/ColumnCalcs/ColumnCalcs.js';
// Override the Module methods that interact with the table to avoid dependency issues
const originalRegisterTableOption = Module.prototype.registerTableOption;
Module.prototype.registerTableOption = function() {};
const originalRegisterColumnOption = Module.prototype.registerColumnOption;
Module.prototype.registerColumnOption = function() {};
// Define test calculation functions
const testCalcs = {
'avg': function(values, data){
var output = 0;
var count = 0;
if(!values.length){
return 0;
}
values.forEach(function(value){
output += Number(value);
count++;
});
return output / count;
},
'max': function(values, data){
var output = null;
values.forEach(function(value){
if(value > output || output === null){
output = value;
}
});
return output;
},
'min': function(values, data){
var output = null;
values.forEach(function(value){
if(value < output || output === null){
output = value;
}
});
return output;
},
'sum': function(values, data){
var output = 0;
values.forEach(function(value){
output += Number(value);
});
return output;
}
};
describe('ColumnCalcs', function(){
beforeAll(function() {
// Ensure calculations are available for tests
ColumnCalcs.calculations = testCalcs;
});
// Test direct functionality without a complete table instance
describe('Functionality tests', function() {
test('initializeColumn sets up calculations correctly', function(){
// Create a mock column
const mockColumn = {
definition: {
topCalc: "avg",
topCalcParams: { test: true },
bottomCalc: "max"
},
modules: {}
};
// Create a mock context with required properties
const mockContext = {
table: {options: {}},
topCalcs: [], // Initialize the required array
botCalcs: [], // Initialize the required array
initializeTopRow: jest.fn(), // Mock the initialization function
initializeBottomRow: jest.fn() // Mock the initialization function
};
// Call the function directly with the mock context
ColumnCalcs.prototype.initializeColumn.call(mockContext, mockColumn);
// Check the results
expect(mockColumn.modules.columnCalcs).toBeDefined();
expect(mockColumn.modules.columnCalcs.topCalc).toBeDefined();
expect(mockColumn.modules.columnCalcs.botCalc).toBeDefined();
expect(typeof mockColumn.modules.columnCalcs.topCalc).toBe('function');
expect(typeof mockColumn.modules.columnCalcs.botCalc).toBe('function');
});
test('initializeColumn warns on invalid calculation', function(){
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
// Create a column with invalid calculation type
const testColumn = {
definition: {
topCalc: "invalid"
},
modules: {}
};
// Create a mock context with required properties
const mockContext = {
table: {options: {}},
topCalcs: [], // Initialize the required array
botCalcs: [], // Initialize the required array
initializeTopRow: jest.fn(), // Mock the initialization function
initializeBottomRow: jest.fn() // Mock the initialization function
};
// Call the function directly
ColumnCalcs.prototype.initializeColumn.call(mockContext, testColumn);
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
test('rowsToData extracts data from rows', function(){
// Create mock rows
const rows = [
{ getData: function() { return {id:1, name:"John", age:20}; } },
{ getData: function() { return {id:2, name:"Jane", age:25}; } }
];
// Mock table options needed for the function
const mockThis = {
table: {
options: {
dataTree: false,
dataTreeChildColumnCalcs: false
},
modules: {}
}
};
const data = ColumnCalcs.prototype.rowsToData.call(mockThis, rows);
expect(data.length).toBe(rows.length);
expect(data[0].id).toBe(1);
expect(data[1].name).toBe("Jane");
});
test('generateRowData creates calculation results', function(){
// Create mock data
const data = [
{age: 20, total: 100},
{age: 25, total: 200},
{age: 30, total: 300},
{age: 35, total: 400}
];
// Create mock columns
const ageColumn = {
modules: {
columnCalcs: {
topCalc: testCalcs.avg,
botCalc: testCalcs.max,
topCalcParams: {},
botCalcParams: {}
}
},
getFieldValue: function(row) { return row.age; },
setFieldValue: function(row, value) { row.age = value; }
};
const totalColumn = {
modules: {
columnCalcs: {
topCalc: testCalcs.sum,
botCalc: testCalcs.sum,
topCalcParams: {},
botCalcParams: {}
}
},
getFieldValue: function(row) { return row.total; },
setFieldValue: function(row, value) { row.total = value; }
};
// Create a mock context object with the needed properties
const mockThis = {
topCalcs: [ageColumn, totalColumn],
botCalcs: [ageColumn, totalColumn],
table: {}
};
// Test top calculations
const topData = ColumnCalcs.prototype.generateRowData.call(mockThis, "top", data);
expect(topData.age).toBe(27.5); // avg of [20,25,30,35]
expect(topData.total).toBe(1000); // sum of [100,200,300,400]
// Test bottom calculations
const botData = ColumnCalcs.prototype.generateRowData.call(mockThis, "bottom", data);
expect(botData.age).toBe(35); // max of [20,25,30,35]
expect(botData.total).toBe(1000); // sum of [100,200,300,400]
});
test('blockCheck manages blocking state', function(){
// Create a mock object with the properties needed by blockCheck
const mockObj = {
blocked: false,
recalcAfterBlock: false
};
// Initially not blocked
expect(ColumnCalcs.prototype.blockCheck.call(mockObj)).toBe(false);
expect(mockObj.recalcAfterBlock).toBe(false);
// Set to blocked
mockObj.blocked = true;
expect(ColumnCalcs.prototype.blockCheck.call(mockObj)).toBe(true);
expect(mockObj.recalcAfterBlock).toBe(true);
// Restore from blocked
mockObj.blocked = false;
expect(ColumnCalcs.prototype.blockCheck.call(mockObj)).toBe(false);
});
test('cellValueChanged triggers recalc for relevant columns', function(){
// Create mock object for 'this' context
const mockThis = {
recalcActiveRows: jest.fn(),
recalcRowGroup: jest.fn(),
table: { options: { groupBy: false } }
};
// Create a cell in a column with calcs
const cell = {
column: {
definition: {
topCalc: "avg",
bottomCalc: "max"
}
},
row: { /* mock row */ }
};
// Test with calc column
ColumnCalcs.prototype.cellValueChanged.call(mockThis, cell);
expect(mockThis.recalcActiveRows).toHaveBeenCalled();
// Reset mock
mockThis.recalcActiveRows.mockReset();
// Create a cell in a column without calcs
const cell2 = {
column: {
definition: { /* no calcs */ }
},
row: { /* mock row */ }
};
ColumnCalcs.prototype.cellValueChanged.call(mockThis, cell2);
expect(mockThis.recalcActiveRows).not.toHaveBeenCalled();
});
});
});
// Restore original Module methods after all tests
afterAll(() => {
Module.prototype.registerTableOption = originalRegisterTableOption;
Module.prototype.registerColumnOption = originalRegisterColumnOption;
});