Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions src/js/modules/Import/Import.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,32 +239,38 @@ export default class Import extends Module{
structureArrayToColumns(parsedData){
var data = [],
firstRow = this.transformHeader(parsedData[0]),
columns = this.table.getColumns();

allColumns = this.table.getColumns(),
//exclude rowHeader and hidden columns so the column-position-based mapping
//matches what was actually written to the export
//(see https://github.com/tabulator-tables/tabulator/issues/4726)
columns = allColumns.filter(function(column){
return column && !column.isRowHeader && column.visible;
});

//remove first row if it is the column names
if(columns[0] && firstRow[0]){
if(columns[0].getDefinition().title === firstRow[0]){
parsedData.shift();
}
}

//convert row arrays to objects
parsedData.forEach((rowData) => {
var row = {};

rowData = this.transformData(rowData);

rowData.forEach((value, index) => {
var column = columns[index];

if(column){
row[column.getField()] = value;
}
});

data.push(row);
});

return data;
}

Expand Down
93 changes: 88 additions & 5 deletions test/unit/modules/Import.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ describe("Import module", () => {
const mockColumnField = "columnField";
const mockColumn = {
getField: jest.fn().mockReturnValue(mockColumnField),
getDefinition: jest.fn().mockReturnValue({ title: "Column" })
getDefinition: jest.fn().mockReturnValue({ title: "Column" }),
visible: true,
};

// Create mock module manager
Expand Down Expand Up @@ -375,18 +376,100 @@ describe("Import module", () => {
return [{ name: "Imported" }];
});
jest.spyOn(importMod, 'structureData').mockImplementation(data => data);

// Set importFormat
mockTable.options.importFormat = "csv";

// Trigger data load
const result = await importMod.loadData("some csv data");

// Verify functions were called
expect(importMod.lookupImporter).toHaveBeenCalled();
expect(importMod.structureData).toHaveBeenCalledWith([{ name: "Imported" }]);

// Verify result
expect(result).toEqual([{ name: "Imported" }]);
});

// Regression: https://github.com/tabulator-tables/tabulator/issues/4726
// rowHeader must not consume an import column slot.
it("should skip rowHeader column when mapping imported xlsx/array data to columns", () => {
jest.spyOn(importMod, 'transformHeader').mockImplementation(headers => headers);
jest.spyOn(importMod, 'transformData').mockImplementation(data => data);

// columns: [rowHeader, name, rating] - rowHeader must be ignored
const rowHeaderCol = {
getField: jest.fn().mockReturnValue(undefined),
getDefinition: jest.fn().mockReturnValue({ title: "" }),
isRowHeader: true,
visible: true,
};
const nameCol = {
getField: jest.fn().mockReturnValue("name"),
getDefinition: jest.fn().mockReturnValue({ title: "Name" }),
visible: true,
};
const ratingCol = {
getField: jest.fn().mockReturnValue("rating"),
getDefinition: jest.fn().mockReturnValue({ title: "Rating" }),
visible: true,
};

mockTable.getColumns.mockReturnValue([rowHeaderCol, nameCol, ratingCol]);

// Simulate a 2-column export: the rowHeader column is not written
// to the file, so only the two data columns appear in the array data.
const arrayData = [
["AB", 50],
["CD", 55],
];

const result = importMod.structureArrayToColumns(arrayData);

// name should hold the first column ("AB", "CD"), rating the second (50, 55)
expect(result).toEqual([
{ name: "AB", rating: 50 },
{ name: "CD", rating: 55 },
]);
});

// Regression: https://github.com/tabulator-tables/tabulator/issues/4726
// Hidden columns (visible:false) also break the index-based mapping on import.
it("should skip hidden columns when mapping imported xlsx/array data to columns", () => {
jest.spyOn(importMod, 'transformHeader').mockImplementation(headers => headers);
jest.spyOn(importMod, 'transformData').mockImplementation(data => data);

// columns: [name, hiddenProgress, rating]
const nameCol = {
getField: jest.fn().mockReturnValue("name"),
getDefinition: jest.fn().mockReturnValue({ title: "Name" }),
visible: true,
};
const hiddenCol = {
getField: jest.fn().mockReturnValue("progress"),
getDefinition: jest.fn().mockReturnValue({ title: "Progress" }),
visible: false,
};
const ratingCol = {
getField: jest.fn().mockReturnValue("rating"),
getDefinition: jest.fn().mockReturnValue({ title: "Rating" }),
visible: true,
};

mockTable.getColumns.mockReturnValue([nameCol, hiddenCol, ratingCol]);

// Hidden column was excluded on export, so import has only 2 columns
const arrayData = [
["AB", 50],
["CD", 55],
];

const result = importMod.structureArrayToColumns(arrayData);

// hidden column must not absorb index 1; rating should receive it
expect(result).toEqual([
{ name: "AB", rating: 50 },
{ name: "CD", rating: 55 },
]);
});
});