You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gristlabs_grist-core/test/nbrowser/ImportReferences.ts

213 lines
9.2 KiB

/**
* 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);
}