Skip to content

Commit

Permalink
[Telemetry Tables] Make sure tables auto scroll correctly on first lo…
Browse files Browse the repository at this point in the history
…ad (#7720)

* run scroll method to scroll to top after initial load of historical data

* clarifying comment

* added e2e test to make sure tables auto scroll on mount

* adding descriptive comments

* adding in ascending check as well

* added new appAction for navigating to/in realtime, using it in table scroll test

* lint

---------

Co-authored-by: David Tsay <3614296+davetsay@users.noreply.github.com>
  • Loading branch information
jvigliotta and davetsay committed May 9, 2024
1 parent 977792f commit 810d580
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 4 deletions.
12 changes: 12 additions & 0 deletions e2e/appActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,17 @@ async function navigateToObjectWithFixedTimeBounds(page, url, start, end) {
);
}

/**
* Navigates directly to a given object url, in real-time mode.
* @param {import('@playwright/test').Page} page
* @param {string} url The url to the domainObject
*/
async function navigateToObjectWithRealTime(page, url, start = '1800000', end = '30000') {
await page.goto(
`${url}?tc.mode=local&tc.startDelta=${start}&tc.endDelta=${end}&tc.timeSystem=utc`
);
}

/**
* Open the given `domainObject`'s context menu from the object tree.
* Expands the path to the object and scrolls to it if necessary.
Expand Down Expand Up @@ -656,6 +667,7 @@ export {
getFocusedObjectUuid,
getHashUrlToDomainObject,
navigateToObjectWithFixedTimeBounds,
navigateToObjectWithRealTime,
openObjectTreeContextMenu,
renameObjectFromContextMenu,
setEndOffset,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@

import {
createDomainObjectWithDefaults,
setTimeConductorBounds,
setTimeConductorMode
navigateToObjectWithRealTime,
setTimeConductorBounds
} from '../../../../appActions.js';
import { expect, test } from '../../../../pluginFixtures.js';

Expand All @@ -39,12 +39,52 @@ test.describe('Telemetry Table', () => {
type: 'Sine Wave Generator',
parent: table.uuid
});
await page.goto(table.url);
await setTimeConductorMode(page, false);
await navigateToObjectWithRealTime(page, table.url);
const rows = page.getByLabel('table content').getByLabel('Table Row');
await expect(rows).toHaveCount(50);
});

test('on load, auto scrolls to top for descending, and to bottom for ascending', async ({
page
}) => {
const sineWaveGenerator = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator',
parent: table.uuid
});

// verify in telemetry table object view
await navigateToObjectWithRealTime(page, table.url);

expect(await getScrollPosition(page)).toBe(0);

// verify in telemetry table view
await page.goto(sineWaveGenerator.url);
await page.getByLabel('Open the View Switcher Menu').click();
await page.getByText('Telemetry Table', { exact: true }).click();

expect(await getScrollPosition(page)).toBe(0);

// navigate back to table
await page.goto(table.url);

// go into edit mode
await page.getByLabel('Edit Object').click();

// change sort direction
await page.locator('thead div').filter({ hasText: 'Time' }).click();

// save view
await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();

// navigate away and back
await page.goto(sineWaveGenerator.url);
await page.goto(table.url);

// verify scroll position
expect(await getScrollPosition(page, false)).toBeLessThan(1);
});

test('unpauses and filters data when paused by button and user changes bounds', async ({
page
}) => {
Expand Down Expand Up @@ -183,3 +223,42 @@ test.describe('Telemetry Table', () => {
await page.click('button[title="Pause"]');
});
});

async function getScrollPosition(page, top = true) {
const tableBody = page.locator('.c-table__body-w');

// Wait for the scrollbar to appear
await tableBody.evaluate((node) => {
return new Promise((resolve) => {
function checkScroll() {
if (node.scrollHeight > node.clientHeight) {
resolve();
} else {
setTimeout(checkScroll, 100);
}
}
checkScroll();
});
});

// make sure there are rows
const rows = page.getByLabel('table content').getByLabel('Table Row');
await rows.first().waitFor();

// Using this to allow for rows to come and go, so we can truly test the scroll position
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout(1000);

const { scrollTop, clientHeight, scrollHeight } = await tableBody.evaluate((node) => ({
scrollTop: node.scrollTop,
clientHeight: node.clientHeight,
scrollHeight: node.scrollHeight
}));

// eslint-disable-next-line playwright/no-conditional-in-test
if (top) {
return scrollTop;
} else {
return Math.abs(scrollHeight - (scrollTop + clientHeight));
}
}
3 changes: 3 additions & 0 deletions src/plugins/telemetryTable/components/TableComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,9 @@ export default {
this.table.initialize();
this.rescaleToContainer();
// Scroll to the top of the table after loading
this.addToAfterLoadActions(this.scroll);
},
beforeUnmount() {
this.table.off('object-added', this.addObject);
Expand Down

0 comments on commit 810d580

Please sign in to comment.