mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
213 lines
9.2 KiB
TypeScript
213 lines
9.2 KiB
TypeScript
|
/**
|
||
|
* Parsing strings as references when importing into an existing table
|
||
|
*/
|
||
|
import {assert, driver, Key, WebElement} from 'mocha-webdriver';
|
||
|
import * as gu from 'test/nbrowser/gristUtils';
|
||
|
import {openSource as openSourceMenu, waitForColumnMapping} from 'test/nbrowser/importerTestUtils';
|
||
|
import {setupTestSuite} from 'test/nbrowser/testUtils';
|
||
|
|
||
|
describe('ImportReferences', function() {
|
||
|
this.timeout(30000);
|
||
|
const cleanup = setupTestSuite();
|
||
|
|
||
|
before(async function() {
|
||
|
// Log in and import a sample document.
|
||
|
const session = await gu.session().teamSite.user('user1').login();
|
||
|
await session.tempDoc(cleanup, 'ImportReferences.grist');
|
||
|
});
|
||
|
|
||
|
afterEach(() => gu.checkForErrors());
|
||
|
|
||
|
it('should convert strings to references', async function() {
|
||
|
// Import a CSV file containing strings representing references
|
||
|
await gu.importFileDialog('./uploads/name_references.csv');
|
||
|
assert.equal(await driver.findWait('.test-importer-preview', 2000).isPresent(), true);
|
||
|
|
||
|
// Change the destination to the existing table
|
||
|
await driver.findContent('.test-importer-target-existing-table', /Table1/).click();
|
||
|
await gu.waitForServer();
|
||
|
|
||
|
// Finish import, and verify the import succeeded.
|
||
|
await driver.find('.test-modal-confirm').click();
|
||
|
await gu.waitForServer();
|
||
|
|
||
|
// Verify data was imported to Names correctly.
|
||
|
assert.deepEqual(
|
||
|
await gu.getVisibleGridCells({rowNums: [1, 2, 3, 4, 5], cols: [0, 1, 2]}),
|
||
|
[
|
||
|
// Previously existing data in the fixture document
|
||
|
'Alice', '', '',
|
||
|
'Bob', '', '',
|
||
|
|
||
|
// Imported data from the CSV file
|
||
|
// The second column is references which have been successfully parsed from strings
|
||
|
// The third column is a formula equal to the second column to demonstrate the references
|
||
|
'Charlie', 'Alice', 'Table1[1]',
|
||
|
'Dennis', 'Bob', 'Table1[2]',
|
||
|
|
||
|
// 'add new' row
|
||
|
'', '', '',
|
||
|
]
|
||
|
);
|
||
|
|
||
|
// TODO this test relies on the imported data referring to names (Alice,Bob)
|
||
|
// already existing in the table before the import, and not being changed by the import
|
||
|
});
|
||
|
|
||
|
it('should support importing into any reference columns and show preview', async function() {
|
||
|
// Switch to page showing Projects and Tasks.
|
||
|
await gu.getPageItem('Projects').click();
|
||
|
await gu.waitForServer(); // wait for table load
|
||
|
|
||
|
// Load up a CSV file that matches the structure of the Tasks table.
|
||
|
await gu.importFileDialog('./uploads/ImportReferences-Tasks.csv');
|
||
|
|
||
|
// The default import into "New Table" just shows the content of the file.
|
||
|
assert.equal(await driver.findWait('.test-importer-preview', 2000).isPresent(), true);
|
||
|
assert.deepEqual(await gu.getPreviewContents([0, 1, 2, 3, 4, 5, 6], [1, 2, 3, 4], mapper), [
|
||
|
'Foo2', 'Clean', '1000', '1,000', '27 Mar 2023', '', '0',
|
||
|
'Bar2', 'Wash', '3000', '2,000', '', 'Projects[2]', '2',
|
||
|
'Baz2', 'Build2', '', '2', '20 Mar 2023', 'Projects[1]', '1',
|
||
|
'Zoo2', 'Clean', '2000', '4,000', '24 Apr 2023', 'Projects[3]', '3',
|
||
|
]);
|
||
|
|
||
|
await driver.findContent('.test-importer-target-existing-table', /Tasks/).click();
|
||
|
await gu.waitForServer();
|
||
|
|
||
|
// See that preview works, and cells that should be valid are valid.
|
||
|
assert.deepEqual(await gu.getPreviewContents([0, 1, 2, 3, 4], [1, 2, 3, 4], mapper), [
|
||
|
// Label, PName, PIndex, PDate, PRowID
|
||
|
'Foo2', 'Clean', '1,000', '27 Mar 2023', '',
|
||
|
'Bar2', 'Wash', '3,000', '', '!Projects[2]',
|
||
|
'Baz2', '!Build2', '', '!2023-03-20', '!Projects[1]',
|
||
|
'Zoo2', 'Clean', '2,000', '24 Apr 2023', '!Projects[3]',
|
||
|
]);
|
||
|
|
||
|
await driver.find('.test-modal-confirm').click();
|
||
|
await gu.waitForServer();
|
||
|
|
||
|
// Verify data was imported to Tasks correctly.
|
||
|
assert.deepEqual(
|
||
|
await gu.getVisibleGridCells({section: 'TASKS', cols: [0, 1, 2, 3, 4], rowNums: [4, 5, 6, 7, 8, 9], mapper}), [
|
||
|
// Label, PName, PIndex, PDate, PRowID
|
||
|
// Previous data in the fixture, in row 4
|
||
|
'Zoo', 'Clean', '2,000', '27 Mar 2023', 'Projects[3]',
|
||
|
// New rows (values like "!Project[2]" are invalid, which may be fixed in the future).
|
||
|
'Foo2', 'Clean', '1,000', '27 Mar 2023', '',
|
||
|
'Bar2', 'Wash', '3,000', '', '!Projects[2]',
|
||
|
'Baz2', '!Build2', '', '!2023-03-20', '!Projects[1]',
|
||
|
'Zoo2', 'Clean', '2,000', '24 Apr 2023', '!Projects[3]',
|
||
|
// 'Add New' row
|
||
|
'', '', '', '', '',
|
||
|
]);
|
||
|
|
||
|
await gu.undo();
|
||
|
});
|
||
|
|
||
|
it('should support importing numeric columns as lookups or rowIDs', async function() {
|
||
|
// Load up the same CSV file again, with Tasks as the destination.
|
||
|
await gu.importFileDialog('./uploads/ImportReferences-Tasks.csv');
|
||
|
await driver.findContent('.test-importer-target-existing-table', /Tasks/).click();
|
||
|
await gu.waitForServer();
|
||
|
await waitForColumnMapping();
|
||
|
|
||
|
// Check that preview works, and cells are valid.
|
||
|
assert.deepEqual(await gu.getPreviewContents([0, 1, 2, 3, 4], [1, 2, 3, 4], mapper), [
|
||
|
// Label, PName, PIndex, PDate, PRowID
|
||
|
'Foo2', 'Clean', '1,000', '27 Mar 2023', '',
|
||
|
'Bar2', 'Wash', '3,000', '', '!Projects[2]',
|
||
|
'Baz2', '!Build2', '', '!2023-03-20', '!Projects[1]',
|
||
|
'Zoo2', 'Clean', '2,000', '24 Apr 2023', '!Projects[3]',
|
||
|
]);
|
||
|
|
||
|
// Check that dropdown for Label does not include "(as row ID)" entries, but the dropdown for
|
||
|
// PName (a reference column) does.
|
||
|
await openSourceMenu('Label');
|
||
|
assert.equal(await findColumnMenuItem('PIndex').isPresent(), true);
|
||
|
assert.equal(await findColumnMenuItem(/as row ID/).isPresent(), false);
|
||
|
await driver.sendKeys(Key.ESCAPE);
|
||
|
|
||
|
await openSourceMenu('PName');
|
||
|
assert.equal(await findColumnMenuItem('PIndex').isPresent(), true);
|
||
|
assert.equal(await findColumnMenuItem('PIndex (as row ID)').isPresent(), true);
|
||
|
await driver.sendKeys(Key.ESCAPE);
|
||
|
|
||
|
// Change PIndex column from lookup to row ID.
|
||
|
await openSourceMenu('PIndex');
|
||
|
await findColumnMenuItem('PIndex (as row ID)').click();
|
||
|
await gu.waitForServer();
|
||
|
|
||
|
// The values become invalid because there are no such rowIDs.
|
||
|
assert.deepEqual(await gu.getPreviewContents([0, 1, 2, 3, 4], [1, 2, 3, 4], mapper), [
|
||
|
// Label, PName, PIndex, PDate, PRowID
|
||
|
'Foo2', 'Clean', '!1000', '27 Mar 2023', '',
|
||
|
'Bar2', 'Wash', '!3000', '', '!Projects[2]',
|
||
|
'Baz2', '!Build2', '', '!2023-03-20', '!Projects[1]',
|
||
|
'Zoo2', 'Clean', '!2000', '24 Apr 2023', '!Projects[3]',
|
||
|
]);
|
||
|
|
||
|
// Try a lookup using PIndex2. It is differently formatted, one value is invalid, and one is a
|
||
|
// valid row ID (but shouldn't be seen as a rowID for a lookup)
|
||
|
await openSourceMenu('PIndex');
|
||
|
await findColumnMenuItem('PIndex2').click();
|
||
|
await gu.waitForServer();
|
||
|
|
||
|
// Note: two PIndex values are different, and two are invalid.
|
||
|
assert.deepEqual(await gu.getPreviewContents([0, 1, 2, 3, 4], [1, 2, 3, 4], mapper), [
|
||
|
// Label, PName, PIndex, PDate, PRowID
|
||
|
'Foo2', 'Clean', '1,000', '27 Mar 2023', '',
|
||
|
'Bar2', 'Wash', '2,000', '', '!Projects[2]',
|
||
|
'Baz2', '!Build2', '!2.0', '!2023-03-20', '!Projects[1]',
|
||
|
'Zoo2', 'Clean', '!4000.0', '24 Apr 2023', '!Projects[3]',
|
||
|
]);
|
||
|
|
||
|
// Change PRowID column to use "PID (as row ID)". It has 3 valid rowIDs.
|
||
|
await openSourceMenu('PRowID');
|
||
|
await findColumnMenuItem('PID (as row ID)').click();
|
||
|
await gu.waitForServer();
|
||
|
|
||
|
// Note: PRowID values are now valid.
|
||
|
assert.deepEqual(await gu.getPreviewContents([0, 1, 2, 3, 4], [1, 2, 3, 4], mapper), [
|
||
|
// Label, PName, PIndex, PDate, PRowID
|
||
|
'Foo2', 'Clean', '1,000', '27 Mar 2023', '',
|
||
|
'Bar2', 'Wash', '2,000', '', 'Projects[2]',
|
||
|
'Baz2', '!Build2', '!2.0', '!2023-03-20', 'Projects[1]',
|
||
|
'Zoo2', 'Clean', '!4000.0', '24 Apr 2023', 'Projects[3]',
|
||
|
]);
|
||
|
|
||
|
await driver.find('.test-modal-confirm').click();
|
||
|
await gu.waitForServer();
|
||
|
|
||
|
// Verify data was imported to Tasks correctly.
|
||
|
assert.deepEqual(
|
||
|
await gu.getVisibleGridCells({section: 'TASKS', cols: [0, 1, 2, 3, 4], rowNums: [4, 5, 6, 7, 8, 9], mapper}), [
|
||
|
// Label, PName, PIndex, PDate, PRowID
|
||
|
// Previous data in the fixture, in row 4
|
||
|
'Zoo', 'Clean', '2,000', '27 Mar 2023', 'Projects[3]',
|
||
|
// New rows; PRowID values are valid.
|
||
|
'Foo2', 'Clean', '1,000', '27 Mar 2023', '',
|
||
|
'Bar2', 'Wash', '2,000', '', 'Projects[2]',
|
||
|
'Baz2', '!Build2', '!2.0', '!2023-03-20', 'Projects[1]',
|
||
|
'Zoo2', 'Clean', '!4000.0', '24 Apr 2023', 'Projects[3]',
|
||
|
// 'Add New' row
|
||
|
'', '', '', '', '',
|
||
|
]);
|
||
|
|
||
|
await gu.undo();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// mapper for getVisibleGridCells and getPreviewContents to get both text and whether the cell is
|
||
|
// invalid (pink). Invalid cells prefixed with "!".
|
||
|
async function mapper(el: WebElement) {
|
||
|
let text = await el.getText();
|
||
|
if (await el.find(".field_clip").matches(".invalid")) {
|
||
|
text = "!" + text;
|
||
|
}
|
||
|
return text;
|
||
|
}
|
||
|
|
||
|
function findColumnMenuItem(label: RegExp|string) {
|
||
|
return driver.findContent('.test-importer-column-match-menu-item', label);
|
||
|
}
|