import {assert, driver, Key, WebElement} from 'mocha-webdriver'; import * as gu from 'test/nbrowser/gristUtils'; import {setupTestSuite} from 'test/nbrowser/testUtils'; interface CellPosition { /** 0-based column index. */ col: number; /** 0-based row index. */ row: number; } interface SelectionSummary { dimensions: string; count: number | null; sum: string | null; } describe('SelectionSummary', function () { this.timeout(20000); const cleanup = setupTestSuite(); gu.bigScreen(); before(async function() { const session = await gu.session().personalSite.login(); await session.tempDoc(cleanup, 'SelectionSummary.grist'); }); async function assertSelectionSummary(summary: SelectionSummary | null) { if (!summary) { assert.isFalse(await driver.find('.test-selection-summary-dimensions').isPresent()); assert.isFalse(await driver.find('.test-selection-summary-count').isPresent()); assert.isFalse(await driver.find('.test-selection-summary-sum').isPresent()); return; } const {dimensions, count, sum} = summary; await gu.waitToPass(async () => assert.equal( await driver.find('.test-selection-summary-dimensions').getText(), dimensions ), 500); if (count === null) { assert.isFalse(await driver.find('.test-selection-summary-count').isPresent()); } else { await gu.waitToPass(async () => assert.equal( await driver.find('.test-selection-summary-count').getText(), `COUNT ${count}` ), 500); } if (sum === null) { assert.isFalse(await driver.find('.test-selection-summary-sum').isPresent()); } else { await gu.waitToPass(async () => assert.equal( await driver.find('.test-selection-summary-sum').getText(), `SUM ${sum}` ), 500); } } function shiftClick(el: WebElement) { return driver.withActions((actions) => actions.keyDown(Key.SHIFT).click(el).keyUp(Key.SHIFT)); } async function selectAndAssert(start: CellPosition, end: CellPosition, summary: SelectionSummary | null) { const {col: startCol, row: startRow} = start; await gu.getCell(startCol, startRow + 1).click(); const {col: endCol, row: endRow} = end; await shiftClick(await gu.getCell(endCol, endRow + 1)); await assertSelectionSummary(summary); } it('does not display anything if only a single cell is selected', async function () { for (const [col, row] of [[0, 1], [2, 3]]) { await gu.getCell(col, row).click(); await assertSelectionSummary(null); } }); it('displays sum if the selection contains numbers', async function () { await selectAndAssert({col: 0, row: 0}, {col: 0, row: 6}, { dimensions: '7⨯1', count: null, sum: '$135,692,590', }); await selectAndAssert({col: 0, row: 3}, {col: 0, row: 6}, { dimensions: '4⨯1', count: null, sum: '$135,679,011', }); await selectAndAssert({col: 4, row: 0}, {col: 4, row: 6}, { dimensions: '7⨯1', count: null, sum: '135692590', }); await selectAndAssert({col: 0, row: 0}, {col: 4, row: 6}, { dimensions: '7⨯5', count: null, sum: '$271,385,168.02', }); }); it('uses formatter of the first (leftmost) numeric column', async function () { // Column 0 is U.S. currency, while column 1 is just a plain decimal number. await selectAndAssert({col: 0, row: 0}, {col: 1, row: 6}, { dimensions: '7⨯2', count: null, sum: '$135,692,578.02', }); await selectAndAssert({col: 1, row: 0}, {col: 1, row: 6}, { dimensions: '7⨯1', count: null, sum: '-11.98', }); // The entire selection (spanning 6 columns) uses the formatter of column 0. await selectAndAssert({col: 0, row: 0}, {col: 5, row: 6}, { dimensions: '7⨯6', count: null, sum: '$271,385,156.04', }); }); it("displays count if the selection doesn't contain numbers", async function () { await selectAndAssert({col: 2, row: 0}, {col: 2, row: 6}, { dimensions: '7⨯1', count: 5, sum: null, }); await selectAndAssert({col: 2, row: 3}, {col: 2, row: 6}, { dimensions: '4⨯1', count: 2, sum: null, }); // Scroll horizontally to the end of the table. await gu.sendKeys(Key.END); await selectAndAssert({col: 7, row: 0}, {col: 10, row: 4}, { dimensions: '5⨯4', count: 7, sum: null, }); await selectAndAssert({col: 10, row: 0}, {col: 12, row: 6}, { dimensions: '7⨯3', count: 5, sum: null, }); }); it('does not count false values', async function () { // False values in boolean columns should not be included in count await selectAndAssert({col: 2, row: 0}, {col: 3, row: 5}, { dimensions: '6⨯2', count: 9, sum: null, }); }); it('uses the show column of reference columns for computations', async function () { // Column 6 is a Reference column pointing to column 0. await gu.sendKeys(Key.HOME); await selectAndAssert({col: 6, row: 0}, {col: 6, row: 6}, { dimensions: '7⨯1', count: null, sum: '-$123,456', }); // Column 7 is a Reference List column pointing to column 0. At this time, it // only displays counts (but flattening sums also seems like intuitive behavior). await gu.sendKeys(Key.END); await selectAndAssert({col: 7, row: 0}, {col: 7, row: 6}, { dimensions: '7⨯1', count: 2, sum: null, }); }); it('updates whenever the selection changes', async function () { // Scroll horizontally to the beginning of the table. await gu.sendKeys(Key.HOME); // Select a region of the table. await selectAndAssert({col: 0, row: 2}, {col: 0, row: 6}, { dimensions: '5⨯1', count: null, sum: '$135,691,356', }); // Without de-selecting, use keyboard shortcuts to grow the selection to the right. await gu.sendKeys(Key.chord(Key.SHIFT, Key.ARROW_RIGHT)); // Check that the selection summary was updated. await assertSelectionSummary({ dimensions: '5⨯2', count: null, sum: '$135,691,368.5', }); }); it('displays correct sum when all rows/columns are selected', async function () { await driver.find(".gridview_data_corner_overlay").click(); await assertSelectionSummary({ dimensions: '7⨯14', count: null, sum: '$271,261,700.04', }); }); describe('on narrow screens', function() { gu.narrowScreen(); it('is not visible', async function() { await assertSelectionSummary(null); await selectAndAssert({col: 0, row: 0}, {col: 0, row: 6}, null); }); }); });