Compare commits

...

12 Commits

Author SHA1 Message Date
John Hill
349be42275 add draggable true to tree items 2024-03-13 16:16:56 -07:00
John Hill
6edb3b2dc4 Update plot aria 2024-03-13 16:16:43 -07:00
John Hill
444c9ff33e update notebook snapshot drop area 2024-03-13 16:16:20 -07:00
John Hill
b7b7bc2d41 update gauge component 2024-03-13 16:16:06 -07:00
John Hill
6e1272dfe9 start to factor out bad locators 2024-03-13 16:15:34 -07:00
John Hill
d8df0e15e8 driveby 2024-03-13 16:15:17 -07:00
John Hill
a393bfb87a update component tests to match linting rules 2024-03-12 11:24:45 -07:00
John Hill
8933baf103 change ruleset 2024-03-12 11:24:14 -07:00
John Hill
82326dc658 update package 2024-03-12 11:24:02 -07:00
John Hill
df2d9ab133 Merge branch 'master' of https://github.com/nasa/openmct into eslint_update 2024-03-11 18:44:06 -07:00
John Hill
2897ca65b3 first pass of lint fixes 2024-02-26 08:59:20 -08:00
John Hill
0590b50d59 update eslint package 2024-02-26 04:28:24 -08:00
26 changed files with 179 additions and 149 deletions

View File

@@ -4,7 +4,8 @@ module.exports = {
browser: true, browser: true,
es6: true, es6: true,
jasmine: true, jasmine: true,
amd: true amd: true,
node: true
}, },
globals: { globals: {
_: 'readonly' _: 'readonly'
@@ -150,6 +151,7 @@ module.exports = {
'error', 'error',
{ {
cases: { cases: {
camelCase: true,
pascalCase: true pascalCase: true
}, },
ignore: ['^.*\\.js$'] ignore: ['^.*\\.js$']

View File

@@ -1,14 +1,20 @@
/* eslint-disable no-undef */ /* eslint-disable no-undef */
module.exports = { module.exports = {
extends: ['plugin:playwright/playwright-test'], extends: ['plugin:playwright/recommended'],
rules: { rules: {
'playwright/max-nested-describe': ['error', { max: 1 }] 'playwright/max-nested-describe': ['error', { max: 1 }]
}, },
overrides: [ overrides: [
{ {
files: ['tests/visual/*.spec.js'], files: ['**/*.visual.spec.js'],
rules: { rules: {
'playwright/no-wait-for-timeout': 'off' 'playwright/expect-expect': 'off'
}
},
{
files: ['**/*.perf.spec.js'],
rules: {
'playwright/expect-expect': 'off'
} }
} }
] ]

View File

@@ -383,7 +383,7 @@ By adhering to this principle, we can create tests that are both robust and refl
1. Avoid creating locator aliases. This likely means that you're compensating for a bad locator. Improve the application instead. 1. Avoid creating locator aliases. This likely means that you're compensating for a bad locator. Improve the application instead.
1. Leverage `await page.goto('./', { waitUntil: 'domcontentloaded' });` instead of `{ waitUntil: 'networkidle' }`. Tests run against deployments with websockets often have issues with the networkidle detection. 1. Leverage `await page.goto('./', { waitUntil: 'domcontentloaded' });` instead of `{ waitUntil: 'networkidle' }`. Tests run against deployments with websockets often have issues with the networkidle detection.
#### How to make tests faster and more resilient #### How to make tests faster and more resilient to application changes
1. Avoid app interaction when possible. The best way of doing this is to navigate directly by URL: 1. Avoid app interaction when possible. The best way of doing this is to navigate directly by URL:
```js ```js
@@ -398,6 +398,16 @@ By adhering to this principle, we can create tests that are both robust and refl
- Initial navigation should _almost_ always use the `{ waitUntil: 'domcontentloaded' }` option. - Initial navigation should _almost_ always use the `{ waitUntil: 'domcontentloaded' }` option.
1. Avoid repeated setup to test a single assertion. Write longer tests with multiple soft assertions. 1. Avoid repeated setup to test a single assertion. Write longer tests with multiple soft assertions.
This ensures that your changes will be picked up with large refactors. This ensures that your changes will be picked up with large refactors.
1. Use [user-facing locators](https://playwright.dev/docs/best-practices#use-locators) (Now a eslint rule!)
```js
page.getByRole('button', { name: 'Create' } )
```
Instead of
```js
page.locator('.c-create-button')
```
Note: `page.locator()` can be used in performance tests as xk6-browser does not yet support the new `page.getBy` pattern and css lookups can be [1.5x faster](https://serpapi.com/blog/css-selectors-faster-than-getbyrole-playwright/)
##### Utilizing LocalStorage ##### Utilizing LocalStorage
1. In order to save test runtime in the case of tests that require a decent amount of initial setup (such as in the case of testing complex displays), you may use [Playwright's `storageState` feature](https://playwright.dev/docs/api/class-browsercontext#browser-context-storage-state) to generate and load localStorage states. 1. In order to save test runtime in the case of tests that require a decent amount of initial setup (such as in the case of testing complex displays), you may use [Playwright's `storageState` feature](https://playwright.dev/docs/api/class-browsercontext#browser-context-storage-state) to generate and load localStorage states.

View File

@@ -41,7 +41,7 @@ test.describe('CouchDB Status Indicator with mocked responses @couchdb', () => {
//Go to baseURL //Go to baseURL
await page.goto('./#/browse/mine?hideTree=true&hideInspector=true', { await page.goto('./#/browse/mine?hideTree=true&hideInspector=true', {
waitUntil: 'networkidle' waitUntil: 'domcontentloaded'
}); });
await expect(page.locator('div:has-text("CouchDB is connected")').nth(3)).toBeVisible(); await expect(page.locator('div:has-text("CouchDB is connected")').nth(3)).toBeVisible();
}); });
@@ -56,7 +56,7 @@ test.describe('CouchDB Status Indicator with mocked responses @couchdb', () => {
//Go to baseURL //Go to baseURL
await page.goto('./#/browse/mine?hideTree=true&hideInspector=true', { await page.goto('./#/browse/mine?hideTree=true&hideInspector=true', {
waitUntil: 'networkidle' waitUntil: 'domcontentloaded'
}); });
await expect(page.locator('div:has-text("CouchDB is offline")').nth(3)).toBeVisible(); await expect(page.locator('div:has-text("CouchDB is offline")').nth(3)).toBeVisible();
}); });
@@ -71,7 +71,7 @@ test.describe('CouchDB Status Indicator with mocked responses @couchdb', () => {
//Go to baseURL //Go to baseURL
await page.goto('./#/browse/mine?hideTree=true&hideInspector=true', { await page.goto('./#/browse/mine?hideTree=true&hideInspector=true', {
waitUntil: 'networkidle' waitUntil: 'domcontentloaded'
}); });
await expect(page.locator('div:has-text("CouchDB connectivity unknown")').nth(3)).toBeVisible(); await expect(page.locator('div:has-text("CouchDB connectivity unknown")').nth(3)).toBeVisible();
}); });

View File

@@ -188,8 +188,8 @@ test.describe('Persistence operations @couchdb', () => {
// Both pages: Go to baseURL // Both pages: Go to baseURL
await Promise.all([ await Promise.all([
page.goto('./', { waitUntil: 'networkidle' }), page.goto('./', { waitUntil: 'domcontentloaded' }),
page2.goto('./', { waitUntil: 'networkidle' }) page2.goto('./', { waitUntil: 'domcontentloaded' })
]); ]);
//Slow down the test a bit //Slow down the test a bit

View File

@@ -76,7 +76,7 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage @2p', () =>
description: 'https://github.com/nasa/openmct/issues/7421' description: 'https://github.com/nasa/openmct/issues/7421'
}); });
//Navigate to baseURL with injected localStorage //Navigate to baseURL with injected localStorage
await page.goto(conditionSetUrl, { waitUntil: 'networkidle' }); await page.goto(conditionSetUrl, { waitUntil: 'domcontentloaded' });
//Assertions on loaded Condition Set in main view. This is a stateful transition step after page.goto() //Assertions on loaded Condition Set in main view. This is a stateful transition step after page.goto()
await expect await expect
@@ -87,7 +87,7 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage @2p', () =>
expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy(); expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy();
//Reload Page //Reload Page
await Promise.all([page.reload(), page.waitForLoadState('networkidle')]); await Promise.all([page.reload(), page.waitForLoadState('domcontentloaded')]);
//Re-verify after reload //Re-verify after reload
await expect await expect
@@ -100,7 +100,7 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage @2p', () =>
test('condition set object can be modified on @localStorage', async ({ page, openmctConfig }) => { test('condition set object can be modified on @localStorage', async ({ page, openmctConfig }) => {
const { myItemsFolderName } = openmctConfig; const { myItemsFolderName } = openmctConfig;
await page.goto(conditionSetUrl, { waitUntil: 'networkidle' }); await page.goto(conditionSetUrl, { waitUntil: 'domcontentloaded' });
//Assertions on loaded Condition Set in main view. This is a stateful transition step after page.goto() //Assertions on loaded Condition Set in main view. This is a stateful transition step after page.goto()
await expect await expect
@@ -151,7 +151,7 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage @2p', () =>
expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy(); expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy();
//Reload Page //Reload Page
await Promise.all([page.reload(), page.waitForLoadState('networkidle')]); await Promise.all([page.reload(), page.waitForLoadState('domcontentloaded')]);
//Verify Main section reflects updated Name Property //Verify Main section reflects updated Name Property
await expect await expect
@@ -213,7 +213,7 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage @2p', () =>
//Feature? //Feature?
//Domain Object is still available by direct URL after delete //Domain Object is still available by direct URL after delete
await page.goto(conditionSetUrl, { waitUntil: 'networkidle' }); await page.goto(conditionSetUrl, { waitUntil: 'domcontentloaded' });
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set'); await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set');
}); });
}); });

View File

@@ -519,7 +519,7 @@ test.describe('Display Layout', () => {
await page.reload(); await page.reload();
// wait for annotations requests to be batched and requested // wait for annotations requests to be batched and requested
await page.waitForLoadState('networkidle'); await page.waitForLoadState('domcontentloaded');
// Network requests for the composite telemetry with multiple items should be: // Network requests for the composite telemetry with multiple items should be:
// 1. a single batched request for annotations // 1. a single batched request for annotations
expect(networkRequests.length).toBe(1); expect(networkRequests.length).toBe(1);
@@ -531,7 +531,7 @@ test.describe('Display Layout', () => {
await page.reload(); await page.reload();
// wait for annotations to not load (if we have any, we've got a problem) // wait for annotations to not load (if we have any, we've got a problem)
await page.waitForLoadState('networkidle'); await page.waitForLoadState('domcontentloaded');
// In real time mode, we don't fetch annotations at all // In real time mode, we don't fetch annotations at all
expect(networkRequests.length).toBe(0); expect(networkRequests.length).toBe(0);

View File

@@ -531,7 +531,7 @@ test.describe('Example Imagery in Flexible layout', () => {
// Click text=OK // Click text=OK
await Promise.all([ await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle' }), page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.click('button:has-text("OK")'), page.click('button:has-text("OK")'),
//Wait for Save Banner to appear //Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message') page.waitForSelector('.c-message-banner__message')
@@ -575,7 +575,7 @@ test.describe('Example Imagery in Tabs View', () => {
// Click text=OK // Click text=OK
await Promise.all([ await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle' }), page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.click('button:has-text("OK")'), page.click('button:has-text("OK")'),
//Wait for Save Banner to appear //Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message') page.waitForSelector('.c-message-banner__message')
@@ -1023,7 +1023,7 @@ async function createImageryView(page) {
// Click text=OK // Click text=OK
await Promise.all([ await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle' }), page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.click('button:has-text("OK")'), page.click('button:has-text("OK")'),
//Wait for Save Banner to appear //Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message') page.waitForSelector('.c-message-banner__message')

View File

@@ -152,7 +152,7 @@ test.describe('ExportAsJSON Disabled Actions', () => {
test.describe('ExportAsJSON ProgressBar @couchdb', () => { test.describe('ExportAsJSON ProgressBar @couchdb', () => {
let folder; let folder;
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto('./', { waitUntil: 'networkidle' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
// Perform actions to create the domain object // Perform actions to create the domain object
folder = await createDomainObjectWithDefaults(page, { folder = await createDomainObjectWithDefaults(page, {
type: 'Folder' type: 'Folder'

View File

@@ -37,7 +37,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
// Create Notebook // Create Notebook
testNotebook = await createDomainObjectWithDefaults(page, { type: 'Notebook' }); testNotebook = await createDomainObjectWithDefaults(page, { type: 'Notebook' });
await page.goto(testNotebook.url, { waitUntil: 'networkidle' }); await page.goto(testNotebook.url, { waitUntil: 'domcontentloaded' });
}); });
test('Inspect Notebook Entry Network Requests', async ({ page }) => { test('Inspect Notebook Entry Network Requests', async ({ page }) => {
@@ -58,7 +58,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
page.click('[aria-label="Add Page"]') page.click('[aria-label="Add Page"]')
]); ]);
// Ensures that there are no other network requests // Ensures that there are no other network requests
await page.waitForLoadState('networkidle'); await page.waitForLoadState('domcontentloaded');
// Assert that only two requests are made // Assert that only two requests are made
// Network Requests are: // Network Requests are:
@@ -77,7 +77,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
// 2) The shared worker event from 👆 POST request // 2) The shared worker event from 👆 POST request
notebookElementsRequests = []; notebookElementsRequests = [];
await nbUtils.enterTextEntry(page, 'First Entry'); await nbUtils.enterTextEntry(page, 'First Entry');
await page.waitForLoadState('networkidle'); await page.waitForLoadState('domcontentloaded');
expect(notebookElementsRequests.length).toBeLessThanOrEqual(2); expect(notebookElementsRequests.length).toBeLessThanOrEqual(2);
// Add some tags // Add some tags
@@ -141,7 +141,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
// 4) The shared worker event from 👆 POST request // 4) The shared worker event from 👆 POST request
notebookElementsRequests = []; notebookElementsRequests = [];
await nbUtils.enterTextEntry(page, 'Fourth Entry'); await nbUtils.enterTextEntry(page, 'Fourth Entry');
page.waitForLoadState('networkidle'); page.waitForLoadState('domcontentloaded');
expect(filterNonFetchRequests(notebookElementsRequests).length).toBeLessThanOrEqual(4); expect(filterNonFetchRequests(notebookElementsRequests).length).toBeLessThanOrEqual(4);
@@ -153,7 +153,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
// 4) The shared worker event from 👆 POST request // 4) The shared worker event from 👆 POST request
notebookElementsRequests = []; notebookElementsRequests = [];
await nbUtils.enterTextEntry(page, 'Fifth Entry'); await nbUtils.enterTextEntry(page, 'Fifth Entry');
page.waitForLoadState('networkidle'); page.waitForLoadState('domcontentloaded');
expect(filterNonFetchRequests(notebookElementsRequests).length).toBeLessThanOrEqual(4); expect(filterNonFetchRequests(notebookElementsRequests).length).toBeLessThanOrEqual(4);
@@ -164,7 +164,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
// 4) The shared worker event from 👆 POST request // 4) The shared worker event from 👆 POST request
notebookElementsRequests = []; notebookElementsRequests = [];
await nbUtils.enterTextEntry(page, 'Sixth Entry'); await nbUtils.enterTextEntry(page, 'Sixth Entry');
page.waitForLoadState('networkidle'); page.waitForLoadState('domcontentloaded');
expect(filterNonFetchRequests(notebookElementsRequests).length).toBeLessThanOrEqual(4); expect(filterNonFetchRequests(notebookElementsRequests).length).toBeLessThanOrEqual(4);
}); });
@@ -227,7 +227,7 @@ async function addTagAndAwaitNetwork(page, tagName) {
page.locator(`[aria-label="Autocomplete Options"] >> text=${tagName}`).click(), page.locator(`[aria-label="Autocomplete Options"] >> text=${tagName}`).click(),
expect(page.locator(`[aria-label="Tag"]:has-text("${tagName}")`)).toBeVisible() expect(page.locator(`[aria-label="Tag"]:has-text("${tagName}")`)).toBeVisible()
]); ]);
await page.waitForLoadState('networkidle'); await page.waitForLoadState('domcontentloaded');
} }
/** /**
@@ -246,5 +246,5 @@ async function removeTagAndAwaitNetwork(page, tagName) {
) )
]); ]);
await expect(page.locator(`[aria-label="Tag"]:has-text("${tagName}")`)).toBeHidden(); await expect(page.locator(`[aria-label="Tag"]:has-text("${tagName}")`)).toBeHidden();
await page.waitForLoadState('networkidle'); await page.waitForLoadState('domcontentloaded');
} }

View File

@@ -59,7 +59,7 @@ test.describe('Handle missing object for plots', () => {
await page.evaluate(`window.localStorage.setItem('mct', '${JSON.stringify(parsedData)}')`); await page.evaluate(`window.localStorage.setItem('mct', '${JSON.stringify(parsedData)}')`);
//Reloads page and clicks on stacked plot //Reloads page and clicks on stacked plot
await Promise.all([page.reload(), page.waitForLoadState('networkidle')]); await Promise.all([page.reload(), page.waitForLoadState('domcontentloaded')]);
//Verify Main section is there on load //Verify Main section is there on load
await expect await expect
@@ -92,7 +92,7 @@ async function makeStackedPlot(page, myItemsFolderName) {
await page.locator('li[role="menuitem"]:has-text("Stacked Plot")').click(); await page.locator('li[role="menuitem"]:has-text("Stacked Plot")').click();
await Promise.all([ await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle' }), page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.locator('button:has-text("OK")').click(), page.locator('button:has-text("OK")').click(),
//Wait for Save Banner to appear //Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message') page.waitForSelector('.c-message-banner__message')
@@ -153,7 +153,7 @@ async function createSineWaveGenerator(page) {
await page.locator('li[role="menuitem"]:has-text("Sine Wave Generator")').click(); await page.locator('li[role="menuitem"]:has-text("Sine Wave Generator")').click();
await Promise.all([ await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle' }), page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.locator('button:has-text("OK")').click(), page.locator('button:has-text("OK")').click(),
//Wait for Save Banner to appear //Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message') page.waitForSelector('.c-message-banner__message')

View File

@@ -30,7 +30,7 @@ import { expect, test } from '../../baseFixtures.js';
test.describe('Renaming objects', () => { test.describe('Renaming objects', () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
// Go to baseURL // Go to baseURL
await page.goto('./', { waitUntil: 'networkidle' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
}); });
test('When renaming objects, the browse bar and various components all update', async ({ test('When renaming objects, the browse bar and various components all update', async ({

View File

@@ -48,7 +48,7 @@ test.describe('Verify tooltips', () => {
const swg2Path = 'My Items / Folder Foo / Folder Bar / SWG 2'; const swg2Path = 'My Items / Folder Foo / Folder Bar / SWG 2';
const swg3Path = 'My Items / Folder Foo / Folder Bar / Folder Baz / SWG 3'; const swg3Path = 'My Items / Folder Foo / Folder Bar / Folder Baz / SWG 3';
test.beforeEach(async ({ page, openmctConfig }) => { test.beforeEach(async ({ page }) => {
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
folder1 = await createDomainObjectWithDefaults(page, { folder1 = await createDomainObjectWithDefaults(page, {
@@ -89,7 +89,7 @@ test.describe('Verify tooltips', () => {
await expandEntireTree(page); await expandEntireTree(page);
}); });
test('display correct paths for LAD tables', async ({ page, openmctConfig }) => { test('display correct paths for LAD tables', async ({ page }) => {
// Create LAD table // Create LAD table
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'LAD Table', type: 'LAD Table',
@@ -102,21 +102,25 @@ test.describe('Verify tooltips', () => {
await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.c-lad-table-wrapper'); await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.c-lad-table-wrapper');
await page.dragAndDrop(`text=${sineWaveObject2.name}`, '.c-lad-table-wrapper'); await page.dragAndDrop(`text=${sineWaveObject2.name}`, '.c-lad-table-wrapper');
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-lad-table-wrapper'); await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-lad-table-wrapper');
await page.locator('button[title="Save"]').click(); await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
await page.keyboard.down('Control'); await page.keyboard.down('Control');
async function getToolTip(object) { //I'm not sure why this is necessary to hover over Create
await page.locator('.c-create-button').hover(); await page.getByRole('button', { name: 'Create' }).hover();
await page.getByRole('cell', { name: object.name }).hover(); await page.getByRole('cell', { name: sineWaveObject1.name }).hover();
let tooltipText = await page.locator('.c-tooltip').textContent(); await expect(page.getByRole('tooltip')).toHaveText(sineWaveObject1.path);
return tooltipText.replace('\n', '').trim();
}
expect(await getToolTip(sineWaveObject1)).toBe(sineWaveObject1.path); //I'm not sure why this is necessary to hover over Create
expect(await getToolTip(sineWaveObject2)).toBe(sineWaveObject2.path); await page.getByRole('button', { name: 'Create' }).hover();
expect(await getToolTip(sineWaveObject3)).toBe(sineWaveObject3.path); await page.getByRole('cell', { name: sineWaveObject2.name }).hover();
await expect(page.getByRole('tooltip')).toHaveText(sineWaveObject2.path);
//I'm not sure why this is necessary to hover over Create
await page.getByRole('button', { name: 'Create' }).hover();
await page.getByRole('cell', { name: sineWaveObject3.name }).hover();
await expect(page.getByRole('tooltip')).toHaveText(sineWaveObject3.path);
}); });
test('display correct paths for expanded and collapsed plot legend items', async ({ page }) => { test('display correct paths for expanded and collapsed plot legend items', async ({ page }) => {
@@ -132,26 +136,26 @@ test.describe('Verify tooltips', () => {
await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.gl-plot'); await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.gl-plot');
await page.dragAndDrop(`text=${sineWaveObject2.name}`, '.gl-plot'); await page.dragAndDrop(`text=${sineWaveObject2.name}`, '.gl-plot');
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.gl-plot'); await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.gl-plot');
await page.locator('button[title="Save"]').click(); await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
await page.keyboard.down('Control'); await page.keyboard.down('Control');
async function getCollapsedLegendToolTip(object) { async function getCollapsedLegendToolTip(object) {
await page.locator('.c-create-button').hover(); await page.getByRole('button', { name: 'create' }).hover();
await page await page
.locator('.plot-series-name', { has: page.locator(`text="${object.name} Hz"`) }) .locator('.plot-series-name', { has: page.locator(`text="${object.name} Hz"`) })
.hover(); .hover();
let tooltipText = await page.locator('.c-tooltip').textContent(); let tooltipText = await page.locator('.c-tooltip').innerText();
return tooltipText.replace('\n', '').trim(); return tooltipText.replace('\n', '').trim();
} }
async function getExpandedLegendToolTip(object) { async function getExpandedLegendToolTip(object) {
await page.locator('.c-create-button').hover(); await page.getByRole('button', { name: 'create' }).hover();
await page await page
.locator('.plot-series-name', { has: page.locator(`text="${object.name}"`) }) .locator('.plot-series-name', { has: page.locator(`text="${object.name}"`) })
.hover(); .hover();
let tooltipText = await page.locator('.c-tooltip').textContent(); let tooltipText = await page.locator('.c-tooltip').innerText();
return tooltipText.replace('\n', '').trim(); return tooltipText.replace('\n', '').trim();
} }
@@ -181,7 +185,7 @@ test.describe('Verify tooltips', () => {
has: page.locator(`text="${object.name}"`) has: page.locator(`text="${object.name}"`)
}) })
.hover(); .hover();
const tooltipText = await page.locator('.c-tooltip').textContent(); const tooltipText = await page.locator('.c-tooltip').innerText();
await page.keyboard.up('Control'); await page.keyboard.up('Control');
return tooltipText.replace('\n', '').trim(); return tooltipText.replace('\n', '').trim();
} }
@@ -199,7 +203,7 @@ test.describe('Verify tooltips', () => {
// Edit Overlay Plot // Edit Overlay Plot
await page.getByLabel('Edit Object').click(); await page.getByLabel('Edit Object').click();
await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.gl-plot'); await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.gl-plot');
await page.locator('button[title="Save"]').click(); await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
// Create Stacked Plot // Create Stacked Plot
@@ -210,7 +214,7 @@ test.describe('Verify tooltips', () => {
// Edit Stacked Plot // Edit Stacked Plot
await page.getByLabel('Edit Object').click(); await page.getByLabel('Edit Object').click();
await page.dragAndDrop(`text=${sineWaveObject2.name}`, '.c-plot--stacked.holder'); await page.dragAndDrop(`text=${sineWaveObject2.name}`, '.c-plot--stacked.holder');
await page.locator('button[title="Save"]').click(); await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
// Create Display Layout // Create Display Layout
@@ -230,13 +234,13 @@ test.describe('Verify tooltips', () => {
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.l-layout__grid-holder', { await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.l-layout__grid-holder', {
targetPosition: { x: 500, y: 200 } targetPosition: { x: 500, y: 200 }
}); });
await page.locator('button[title="Save"]').click(); await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
await page.keyboard.down('Control'); await page.keyboard.down('Control');
await page.getByText('Test Overlay Plot').nth(2).hover(); await page.getByText('Test Overlay Plot').nth(2).hover();
let tooltipText = await page.locator('.c-tooltip').textContent(); let tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe('My Items / Test Overlay Plot'); expect(tooltipText).toBe('My Items / Test Overlay Plot');
@@ -244,17 +248,17 @@ test.describe('Verify tooltips', () => {
await page.locator('.c-plot-legend__view-control >> nth=0').click(); await page.locator('.c-plot-legend__view-control >> nth=0').click();
await page.keyboard.down('Control'); await page.keyboard.down('Control');
await page.locator('.plot-wrapper-expanded-legend .plot-series-name').first().hover(); await page.locator('.plot-wrapper-expanded-legend .plot-series-name').first().hover();
tooltipText = await page.locator('.c-tooltip').textContent(); tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject1.path); expect(tooltipText).toBe(sineWaveObject1.path);
await page.getByText('Test Stacked Plot').nth(2).hover(); await page.getByText('Test Stacked Plot').nth(2).hover();
tooltipText = await page.locator('.c-tooltip').textContent(); tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe('My Items / Test Stacked Plot'); expect(tooltipText).toBe('My Items / Test Stacked Plot');
await page.getByText('SWG 3').nth(2).hover(); await page.getByText('SWG 3').nth(2).hover();
tooltipText = await page.locator('.c-tooltip').textContent(); tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(sineWaveObject3.path).toBe(tooltipText); expect(sineWaveObject3.path).toBe(tooltipText);
}); });
@@ -268,19 +272,15 @@ test.describe('Verify tooltips', () => {
await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.c-fl__container >> nth=0'); await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.c-fl__container >> nth=0');
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-fl__container >> nth=1'); await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-fl__container >> nth=1');
await page.locator('button[title="Save"]').click(); await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
await page.keyboard.down('Control'); await page.keyboard.down('Control');
await page.getByText('SWG 1').nth(2).hover(); await page.getByText('SWG 1').nth(2).hover();
let tooltipText = await page.locator('.c-tooltip').textContent(); await expect(page.getByRole('tooltip')).toHaveText(sineWaveObject1.path);
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject1.path);
await page.getByText('SWG 3').nth(2).hover(); await page.getByText('SWG 3').nth(2).hover();
tooltipText = await page.locator('.c-tooltip').textContent(); await expect(page.getByRole('tooltip')).toHaveText(sineWaveObject3.path);
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path);
}); });
test('display correct paths when hovering over tab view labels', async ({ page }) => { test('display correct paths when hovering over tab view labels', async ({ page }) => {
@@ -292,32 +292,25 @@ test.describe('Verify tooltips', () => {
await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.c-tabs-view__tabs-holder'); await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.c-tabs-view__tabs-holder');
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-tabs-view__tabs-holder'); await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-tabs-view__tabs-holder');
await page.locator('button[title="Save"]').click(); await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
await page.keyboard.down('Control'); await page.keyboard.down('Control');
await page.getByText('SWG 1').nth(2).hover(); await page.getByText('SWG 1').nth(2).hover();
let tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim(); await expect(page.getByRole('tooltip')).toHaveText(sineWaveObject1.path);
expect(tooltipText).toBe(sineWaveObject1.path);
await page.getByText('SWG 3').nth(2).hover(); await page.getByText('SWG 3').nth(2).hover();
tooltipText = await page.locator('.c-tooltip').textContent(); await expect(page.getByRole('tooltip')).toHaveText(sineWaveObject3.path);
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path);
}); });
test('display correct paths when hovering tree items', async ({ page }) => { test('display correct paths when hovering tree items', async ({ page }) => {
await page.keyboard.down('Control'); await page.keyboard.down('Control');
await page.getByText('SWG 1').nth(0).hover(); await page.getByText('SWG 1').nth(0).hover();
let tooltipText = await page.locator('.c-tooltip').textContent(); await expect(page.getByRole('tooltip')).toHaveText(sineWaveObject1.path);
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject1.path);
await page.getByText('SWG 3').nth(0).hover(); await page.getByText('SWG 3').nth(0).hover();
tooltipText = await page.locator('.c-tooltip').textContent(); await expect(page.getByRole('tooltip')).toHaveText(sineWaveObject3.path);
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path);
}); });
test('display correct paths when hovering search items', async ({ page }) => { test('display correct paths when hovering search items', async ({ page }) => {
@@ -326,9 +319,7 @@ test.describe('Verify tooltips', () => {
await page.keyboard.down('Control'); await page.keyboard.down('Control');
await page.locator('.c-gsearch-result__title').hover(); await page.locator('.c-gsearch-result__title').hover();
let tooltipText = await page.locator('.c-tooltip').textContent(); await expect(page.getByRole('tooltip')).toHaveText(sineWaveObject3.path);
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path);
}); });
test('display path for source telemetry when hovering over gauge', async ({ page }) => { test('display path for source telemetry when hovering over gauge', async ({ page }) => {
@@ -338,11 +329,8 @@ test.describe('Verify tooltips', () => {
}); });
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-gauge__wrapper'); await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-gauge__wrapper');
await page.keyboard.down('Control'); await page.keyboard.down('Control');
// eslint-disable-next-line playwright/no-force-option await page.getByRole('meter', { name: 'Test Gauge' }).hover({ position: { x: 0, y: 0 } });
await page.locator('.c-gauge.c-dial').hover({ position: { x: 0, y: 0 }, force: true }); await expect(page.getByRole('tooltip')).toHaveText(sineWaveObject3.path);
let tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path);
}); });
test('display tooltip path for notebook embeds', async ({ page }) => { test('display tooltip path for notebook embeds', async ({ page }) => {
@@ -354,7 +342,7 @@ test.describe('Verify tooltips', () => {
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-notebook__drag-area'); await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-notebook__drag-area');
await page.keyboard.down('Control'); await page.keyboard.down('Control');
await page.locator('.c-ne__embed').hover(); await page.locator('.c-ne__embed').hover();
let tooltipText = await page.locator('.c-tooltip').textContent(); let tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path); expect(tooltipText).toBe(sineWaveObject3.path);
}); });
@@ -381,17 +369,17 @@ test.describe('Verify tooltips', () => {
await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.c-telemetry-table'); await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.c-telemetry-table');
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-telemetry-table'); await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-telemetry-table');
await page.locator('button[title="Save"]').click(); await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
await page.keyboard.down('Control'); await page.keyboard.down('Control');
await page.locator('.noselect > [title="SWG 3"]').first().hover(); await page.locator('.noselect > [title="SWG 3"]').first().hover();
let tooltipText = await page.locator('.c-tooltip').textContent(); let tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path); expect(tooltipText).toBe(sineWaveObject3.path);
await page.locator('.noselect > [title="SWG 1"]').first().hover(); await page.locator('.noselect > [title="SWG 1"]').first().hover();
tooltipText = await page.locator('.c-tooltip').textContent(); tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject1.path); expect(tooltipText).toBe(sineWaveObject1.path);
}); });
@@ -410,17 +398,17 @@ test.describe('Verify tooltips', () => {
await page.keyboard.down('Control'); await page.keyboard.down('Control');
await page.getByLabel('Recent Objects').getByText(sineWaveObject3.name).hover(); await page.getByLabel('Recent Objects').getByText(sineWaveObject3.name).hover();
let tooltipText = await page.locator('.c-tooltip').textContent(); let tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path); expect(tooltipText).toBe(sineWaveObject3.path);
await page.getByLabel('Recent Objects').getByText(sineWaveObject2.name).hover(); await page.getByLabel('Recent Objects').getByText(sineWaveObject2.name).hover();
tooltipText = await page.locator('.c-tooltip').textContent(); tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject2.path); expect(tooltipText).toBe(sineWaveObject2.path);
await page.getByLabel('Recent Objects').getByText(sineWaveObject1.name).hover(); await page.getByLabel('Recent Objects').getByText(sineWaveObject1.name).hover();
tooltipText = await page.locator('.c-tooltip').textContent(); tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject1.path); expect(tooltipText).toBe(sineWaveObject1.path);
}); });
@@ -445,22 +433,22 @@ test.describe('Verify tooltips', () => {
`text=${sineWaveObject3.name}`, `text=${sineWaveObject3.name}`,
'.c-object-view.is-object-type-time-strip' '.c-object-view.is-object-type-time-strip'
); );
await page.locator('button[title="Save"]').click(); await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
await page.keyboard.down('Control'); await page.keyboard.down('Control');
await page.getByText(sineWaveObject1.name).nth(2).hover(); await page.getByText(sineWaveObject1.name).nth(2).hover();
let tooltipText = await page.locator('.c-tooltip').textContent(); let tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject1.path); expect(tooltipText).toBe(sineWaveObject1.path);
await page.getByText(sineWaveObject2.name).nth(2).hover(); await page.getByText(sineWaveObject2.name).nth(2).hover();
tooltipText = await page.locator('.c-tooltip').textContent(); tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject2.path); expect(tooltipText).toBe(sineWaveObject2.path);
await page.getByText(sineWaveObject3.name).nth(2).hover(); await page.getByText(sineWaveObject3.name).nth(2).hover();
tooltipText = await page.locator('.c-tooltip').textContent(); tooltipText = await page.locator('.c-tooltip').innerText();
tooltipText = tooltipText.replace('\n', '').trim(); tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path); expect(tooltipText).toBe(sineWaveObject3.path);
}); });

View File

@@ -48,7 +48,9 @@ test.describe('Main Tree', () => {
}); });
await expandTreePaneItemByName(page, folder.name); await expandTreePaneItemByName(page, folder.name);
await assertTreeItemIsVisible(page, clock.name); await expect(
page.getByRole('tree', { name: 'Main Tree' }).getByRole('treeitem', { name: clock.name })
).toBeVisible();
}); });
test('Creating a child object on one tab and expanding its parent on the other shows the correct composition @2p', async ({ test('Creating a child object on one tab and expanding its parent on the other shows the correct composition @2p', async ({
@@ -65,8 +67,8 @@ test.describe('Main Tree', () => {
// Both pages: Go to baseURL // Both pages: Go to baseURL
await Promise.all([ await Promise.all([
page.goto('./', { waitUntil: 'networkidle' }), page.goto('./', { waitUntil: 'domcontentloaded' }),
page2.goto('./', { waitUntil: 'networkidle' }) page2.goto('./', { waitUntil: 'domcontentloaded' })
]); ]);
const page1Folder = await createDomainObjectWithDefaults(page, { const page1Folder = await createDomainObjectWithDefaults(page, {
@@ -74,7 +76,11 @@ test.describe('Main Tree', () => {
}); });
await expandTreePaneItemByName(page2, myItemsFolderName); await expandTreePaneItemByName(page2, myItemsFolderName);
await assertTreeItemIsVisible(page2, page1Folder.name); await expect(
page2
.getByRole('tree', { name: 'Main Tree' })
.getByRole('treeitem', { name: page1Folder.name })
).toBeVisible();
}); });
test('Creating a child object on one tab and expanding its parent on the other shows the correct composition @couchdb @2p', async ({ test('Creating a child object on one tab and expanding its parent on the other shows the correct composition @couchdb @2p', async ({
@@ -91,8 +97,8 @@ test.describe('Main Tree', () => {
// Both pages: Go to baseURL // Both pages: Go to baseURL
await Promise.all([ await Promise.all([
page.goto('./', { waitUntil: 'networkidle' }), page.goto('./', { waitUntil: 'domcontentloaded' }),
page2.goto('./', { waitUntil: 'networkidle' }) page2.goto('./', { waitUntil: 'domcontentloaded' })
]); ]);
const page1Folder = await createDomainObjectWithDefaults(page, { const page1Folder = await createDomainObjectWithDefaults(page, {
@@ -100,9 +106,13 @@ test.describe('Main Tree', () => {
}); });
await expandTreePaneItemByName(page2, myItemsFolderName); await expandTreePaneItemByName(page2, myItemsFolderName);
await assertTreeItemIsVisible(page2, page1Folder.name); await expect(
page2
.getByRole('tree', { name: 'Main Tree' })
.getByRole('treeitem', { name: page1Folder.name })
).toBeVisible();
}); });
// eslint-disable-next-line playwright/expect-expect
test('Renaming an object reorders the tree @unstable', async ({ page, openmctConfig }) => { test('Renaming an object reorders the tree @unstable', async ({ page, openmctConfig }) => {
const { myItemsFolderName } = openmctConfig; const { myItemsFolderName } = openmctConfig;
@@ -221,17 +231,6 @@ async function getAndAssertTreeItems(page, expected) {
expect(allTexts).toEqual(expected); expect(allTexts).toEqual(expected);
} }
async function assertTreeItemIsVisible(page, name) {
const mainTree = page.getByRole('tree', {
name: 'Main Tree'
});
const treeItem = mainTree.getByRole('treeitem', {
name
});
await expect(treeItem).toBeVisible();
}
/** /**
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
* @param {string} name * @param {string} name

View File

@@ -82,14 +82,14 @@ test.describe('Smoke tests for @mobile', () => {
await page.getByTitle('Collapse Browse Pane').click(); await page.getByTitle('Collapse Browse Pane').click();
await expect(page.getByRole('main').getByText('Parent Display Layout')).toBeVisible(); await expect(page.getByRole('main').getByText('Parent Display Layout')).toBeVisible();
//Verify both objects are in view //Verify both objects are in view
await expect(await page.getByLabel('Child Layout 1 Layout')).toBeVisible(); await expect(page.getByLabel('Child Layout 1 Layout')).toBeVisible();
await expect(await page.getByLabel('Child Layout 2 Layout')).toBeVisible(); await expect(page.getByLabel('Child Layout 2 Layout')).toBeVisible();
//Remove First Object to bring up confirmation dialog //Remove First Object to bring up confirmation dialog
await page.getByLabel('View menu items').nth(1).click(); await page.getByLabel('View menu items').nth(1).click();
await page.getByLabel('Remove').click(); await page.getByLabel('Remove').click();
await page.getByRole('button', { name: 'OK' }).click(); await page.getByRole('button', { name: 'OK' }).click();
//Verify that the object is removed //Verify that the object is removed
await expect(await page.getByLabel('Child Layout 1 Layout')).toBeVisible(); await expect(page.getByLabel('Child Layout 1 Layout')).toBeVisible();
expect(await page.getByLabel('Child Layout 2 Layout').count()).toBe(0); expect(await page.getByLabel('Child Layout 2 Layout').count()).toBe(0);
}); });
}); });

View File

@@ -39,7 +39,7 @@ const filePath = 'e2e/test-data/PerformanceDisplayLayout.json';
test.describe('Performance tests', () => { test.describe('Performance tests', () => {
test.beforeEach(async ({ page, browser }, testInfo) => { test.beforeEach(async ({ page, browser }, testInfo) => {
// Go to baseURL // Go to baseURL
await page.goto('./', { waitUntil: 'networkidle' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
// Click a:has-text("My Items") // Click a:has-text("My Items")
await page.locator('a:has-text("My Items")').click({ await page.locator('a:has-text("My Items")').click({
@@ -129,12 +129,12 @@ test.describe('Performance tests', () => {
]); ]);
//Time to Example Imagery Frame loads within Display Layout //Time to Example Imagery Frame loads within Display Layout
await page.waitForSelector('.c-imagery__main-image__bg', { state: 'visible' }); await page.locator('.c-imagery__main-image__bg').waitFor({ state: 'visible' });
//Time to Example Imagery object loads //Time to Example Imagery object loads
await page.waitForSelector('.c-imagery__main-image__background-image', { state: 'visible' }); await page.locator('.c-imagery__main-image__background-image').waitFor({ state: 'visible' });
//Get background-image url from background-image css prop //Get background-image url from background-image css prop
const backgroundImage = await page.locator('.c-imagery__main-image__background-image'); const backgroundImage = page.locator('.c-imagery__main-image__background-image');
let backgroundImageUrl = await backgroundImage.evaluate((el) => { let backgroundImageUrl = await backgroundImage.evaluate((el) => {
return window return window
.getComputedStyle(el) .getComputedStyle(el)
@@ -156,15 +156,15 @@ test.describe('Performance tests', () => {
await page.evaluate(() => window.performance.mark('viewLarge.start.test')); //This is a mark only to compare evaluate timing await page.evaluate(() => window.performance.mark('viewLarge.start.test')); //This is a mark only to compare evaluate timing
//Time to Imagery Rendered in Large Frame //Time to Imagery Rendered in Large Frame
await page.waitForSelector('.c-imagery__main-image__bg', { state: 'visible' }); await page.locator('.c-imagery__main-image__bg').waitFor({ state: 'visible' });
await page.evaluate(() => window.performance.mark('background-image-frame')); await page.evaluate(() => window.performance.mark('background-image-frame'));
//Time to Example Imagery object loads //Time to Example Imagery object loads
await page.waitForSelector('.c-imagery__main-image__background-image', { state: 'visible' }); await page.locator('.c-imagery__main-image__background-image').waitFor({ state: 'visible' });
await page.evaluate(() => window.performance.mark('background-image-visible')); await page.evaluate(() => window.performance.mark('background-image-visible'));
// Get Current number of images in thumbstrip // Get Current number of images in thumbstrip
await page.waitForSelector('.c-imagery__thumb'); await page.locator('.c-imagery__thumb').waitFor({ state: 'visible' });
const thumbCount = await page.locator('.c-imagery__thumb').count(); const thumbCount = await page.locator('.c-imagery__thumb').count();
console.log('number of thumbs rendered ' + thumbCount); console.log('number of thumbs rendered ' + thumbCount);
await page.locator('.c-imagery__thumb').last().click(); await page.locator('.c-imagery__thumb').last().click();

View File

@@ -38,7 +38,7 @@ const notebookFilePath = 'e2e/test-data/PerformanceNotebook.json';
test.describe('Performance tests', () => { test.describe('Performance tests', () => {
test.beforeEach(async ({ page, browser }, testInfo) => { test.beforeEach(async ({ page, browser }, testInfo) => {
// Go to baseURL // Go to baseURL
await page.goto('./', { waitUntil: 'networkidle' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
// Click a:has-text("My Items") // Click a:has-text("My Items")
await page.locator('a:has-text("My Items")').click({ await page.locator('a:has-text("My Items")').click({
@@ -110,20 +110,19 @@ test.describe('Performance tests', () => {
await page.evaluate(() => window.performance.mark('search-entered')); await page.evaluate(() => window.performance.mark('search-entered'));
//Search Result Appears and is clicked //Search Result Appears and is clicked
await Promise.all([ await Promise.all([
page.waitForNavigation(),
page.locator('a:has-text("Performance Notebook")').first().click(), page.locator('a:has-text("Performance Notebook")').first().click(),
page.evaluate(() => window.performance.mark('click-search-result')) page.evaluate(() => window.performance.mark('click-search-result'))
]); ]);
await page.waitForSelector('.c-tree__item c-tree-and-search__loading loading', { await page
state: 'hidden' .locator('.c-tree__item c-tree-and-search__loading loading')
}); .waitFor({ state: 'hidden' });
await page.evaluate(() => window.performance.mark('search-spinner-gone')); await page.evaluate(() => window.performance.mark('search-spinner-gone'));
await page.waitForSelector('.l-browse-bar__object-name', { state: 'visible' }); await page.locator('.l-browse-bar__object-name').waitFor({ state: 'visible' });
await page.evaluate(() => window.performance.mark('object-title-appears')); await page.evaluate(() => window.performance.mark('object-title-appears'));
await page.waitForSelector('.c-notebook__entry >> nth=0', { state: 'visible' }); await page.locator('.c-notebook__entry >> nth=0').waitFor({ state: 'visible' });
await page.evaluate(() => window.performance.mark('notebook-entry-appears')); await page.evaluate(() => window.performance.mark('notebook-entry-appears'));
// Click Add new Notebook Entry // Click Add new Notebook Entry
@@ -139,9 +138,9 @@ test.describe('Performance tests', () => {
await page.evaluate(() => window.performance.mark('notebook-search-start')); await page.evaluate(() => window.performance.mark('notebook-search-start'));
await page.locator('.c-notebook__search >> input').fill('Existing Entry'); await page.locator('.c-notebook__search >> input').fill('Existing Entry');
await page.evaluate(() => window.performance.mark('notebook-search-filled')); await page.evaluate(() => window.performance.mark('notebook-search-filled'));
await page.waitForSelector('text=Search Results (3)', { state: 'visible' }); await page.locator('text=Search Results (3)').waitFor({ state: 'visible' });
await page.evaluate(() => window.performance.mark('notebook-search-processed')); await page.evaluate(() => window.performance.mark('notebook-search-processed'));
await page.waitForSelector('.c-notebook__entry >> nth=2', { state: 'visible' }); await page.locator('.c-notebook__entry >> nth=2').waitFor({ state: 'visible' });
await page.evaluate(() => window.performance.mark('notebook-search-processed')); await page.evaluate(() => window.performance.mark('notebook-search-processed'));
//Clear Search //Clear Search
@@ -154,7 +153,7 @@ test.describe('Performance tests', () => {
await page.locator('div.c-ne__time-and-content').last().hover(); await page.locator('div.c-ne__time-and-content').last().hover();
await page.locator('button[title="Delete this entry"]').last().click(); await page.locator('button[title="Delete this entry"]').last().click();
await page.locator('button:has-text("Ok")').click(); await page.locator('button:has-text("Ok")').click();
await page.waitForSelector('.c-notebook__entry >> nth=3', { state: 'detached' }); await page.locator('.c-notebook__entry >> nth=3').waitFor({ state: 'detached' });
await page.evaluate(() => window.performance.mark('new-notebook-entry-deleted')); await page.evaluate(() => window.performance.mark('new-notebook-entry-deleted'));
//await client.send('HeapProfiler.enable'); //await client.send('HeapProfiler.enable');

View File

@@ -228,9 +228,7 @@ test.describe('Navigation memory leak is not detected in', () => {
expect(result).toBe(true); expect(result).toBe(true);
}); });
test('display layout with plots of swgs, alphanumerics, and condition sets, ', async ({ test('display layout with plots of swgs, alphanumerics, and condition sets', async ({ page }) => {
page
}) => {
const result = await navigateToObjectAndDetectMemoryLeak( const result = await navigateToObjectAndDetectMemoryLeak(
page, page,
'display-layout-simple-telemetry' 'display-layout-simple-telemetry'

View File

@@ -78,7 +78,7 @@ test.describe('Tabs View', () => {
await page.getByLabel(`${sineWaveGenerator.name} tab`, { exact: true }).click(); await page.getByLabel(`${sineWaveGenerator.name} tab`, { exact: true }).click();
// ensure sine wave generator visible // ensure sine wave generator visible
expect(await page.locator('.c-plot').isVisible()).toBe(true); await expect(page.locator('.c-plot')).toBeVisible();
// now select notebook and clear animation calls // now select notebook and clear animation calls
await page.getByLabel(`${notebook.name} tab`, { exact: true }).click(); await page.getByLabel(`${notebook.name} tab`, { exact: true }).click();

View File

@@ -84,7 +84,7 @@ test.describe('Plot Tagging Performance', () => {
await setRealTimeMode(page); await setRealTimeMode(page);
// Search for Science // Search for Science
await page.getByRole('searchbox', { name: 'Search Input' }); await page.getByRole('searchbox', { name: 'Search Input' }).click();
await page.getByRole('searchbox', { name: 'Search Input' }).fill('sc'); await page.getByRole('searchbox', { name: 'Search Input' }).fill('sc');
// click on the search result // click on the search result

View File

@@ -34,7 +34,7 @@
"eslint-config-prettier": "9.1.0", "eslint-config-prettier": "9.1.0",
"eslint-plugin-compat": "4.2.0", "eslint-plugin-compat": "4.2.0",
"eslint-plugin-no-unsanitized": "4.0.2", "eslint-plugin-no-unsanitized": "4.0.2",
"eslint-plugin-playwright": "0.12.0", "eslint-plugin-playwright": "1.5.2",
"eslint-plugin-prettier": "5.1.3", "eslint-plugin-prettier": "5.1.3",
"eslint-plugin-simple-import-sort": "10.0.0", "eslint-plugin-simple-import-sort": "10.0.0",
"eslint-plugin-unicorn": "49.0.0", "eslint-plugin-unicorn": "49.0.0",

View File

@@ -20,7 +20,13 @@ this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<template> <template>
<div ref="tooltip-wrapper" class="c-menu c-tooltip-wrapper" :style="toolTipLocationStyle"> <div
ref="tooltip-wrapper"
class="c-menu c-tooltip-wrapper"
:style="toolTipLocationStyle"
role="tooltip"
aria-live="polite"
>
<div class="c-tooltip"> <div class="c-tooltip">
{{ toolTipText }} {{ toolTipText }}
</div> </div>

View File

@@ -24,8 +24,13 @@
ref="gaugeWrapper" ref="gaugeWrapper"
class="c-gauge__wrapper js-gauge-wrapper" class="c-gauge__wrapper js-gauge-wrapper"
:class="gaugeClasses" :class="gaugeClasses"
:aria-label="gaugeTitle"
:title="gaugeTitle" :title="gaugeTitle"
:aria-label="`${domainObject.name}`"
role="meter"
:aria-valuemin="rangeLow"
:aria-valuemax="rangeHigh"
:aria-valuenow="curVal"
:aria-valuetext="`Current value: ${curVal}`"
> >
<template v-if="typeDial"> <template v-if="typeDial">
<svg <svg

View File

@@ -98,12 +98,14 @@
v-if="selectedPage && !selectedPage.isLocked" v-if="selectedPage && !selectedPage.isLocked"
:aria-disabled="activeTransaction" :aria-disabled="activeTransaction"
class="c-notebook__drag-area icon-plus" class="c-notebook__drag-area icon-plus"
aria-dropeffect="link"
aria-labelledby="newEntryLabel"
@click="newEntry(null, $event)" @click="newEntry(null, $event)"
@dragover="dragOver" @dragover="dragOver"
@drop.capture="dropCapture" @drop.capture="dropCapture"
@drop="dropOnEntry($event)" @drop="dropOnEntry($event)"
> >
<span class="c-notebook__drag-area__label"> <span id="newEntryLabel" class="c-notebook__drag-area__label">
To start a new entry, click here or drag and drop any object To start a new entry, click here or drag and drop any object
</span> </span>
</div> </div>
@@ -150,9 +152,10 @@
<button <button
class="c-button commit-button icon-lock" class="c-button commit-button icon-lock"
title="Commit entries and lock this page from further changes" title="Commit entries and lock this page from further changes"
aria-labelledby="commitEntriesLabel"
@click="lockPage()" @click="lockPage()"
> >
<span class="c-button__label">Commit Entries</span> <span id="commitEntriesLabel" class="c-button__label">Commit Entries</span>
</button> </button>
</div> </div>
</div> </div>

View File

@@ -94,9 +94,15 @@
<button <button
class="c-button icon-minus" class="c-button icon-minus"
title="Zoom out" title="Zoom out"
aria-label="Zoom out"
@click="zoom('out', 0.2)" @click="zoom('out', 0.2)"
></button> ></button>
<button class="c-button icon-plus" title="Zoom in" @click="zoom('in', 0.2)"></button> <button
class="c-button icon-plus"
title="Zoom in"
aria-label="Zoom in"
@click="zoom('in', 0.2)"
></button>
</div> </div>
<div <div
v-if="plotHistory.length && !options.compact" v-if="plotHistory.length && !options.compact"
@@ -104,12 +110,14 @@
> >
<button <button
class="c-button icon-arrow-left" class="c-button icon-arrow-left"
title="Restore previous pan/zoom" title="Restore previous pan and zoom"
aria-label="Restore previous pan and zoom"
@click="back()" @click="back()"
></button> ></button>
<button <button
class="c-button icon-reset" class="c-button icon-reset"
title="Reset pan/zoom" title="Reset pan and zoom"
aria-label="Reset pan and zoom"
@click="resumeRealtimeData()" @click="resumeRealtimeData()"
></button> ></button>
</div> </div>
@@ -121,12 +129,14 @@
v-if="!isFrozen" v-if="!isFrozen"
class="c-button icon-pause" class="c-button icon-pause"
title="Pause incoming real-time data" title="Pause incoming real-time data"
aria-label="Pause incoming real-time data"
@click="pause()" @click="pause()"
></button> ></button>
<button <button
v-if="isFrozen" v-if="isFrozen"
class="c-button icon-arrow-right pause-play is-paused" class="c-button icon-arrow-right pause-play is-paused"
title="Resume displaying real-time data" title="Resume displaying real-time data"
aria-label="Resume displaying real-time data"
@click="resumeRealtimeData()" @click="resumeRealtimeData()"
></button> ></button>
</div> </div>
@@ -134,6 +144,7 @@
<button <button
class="c-button icon-clock" class="c-button icon-clock"
title="Synchronize Time Conductor" title="Synchronize Time Conductor"
aria-label="Synchronize Time Conductor"
@click="showSynchronizeDialog()" @click="showSynchronizeDialog()"
></button> ></button>
</div> </div>
@@ -142,12 +153,14 @@
class="c-button icon-crosshair" class="c-button icon-crosshair"
:class="{ 'is-active': cursorGuide }" :class="{ 'is-active': cursorGuide }"
title="Toggle cursor guides" title="Toggle cursor guides"
aria-label="Toggle cursor guides"
@click="toggleCursorGuide" @click="toggleCursorGuide"
></button> ></button>
<button <button
class="c-button" class="c-button"
:class="{ 'icon-grid-on': gridLines, 'icon-grid-off': !gridLines }" :class="{ 'icon-grid-on': gridLines, 'icon-grid-off': !gridLines }"
title="Toggle grid lines" title="Toggle grid lines"
aria-label="Toggle grid lines"
@click="toggleGridLines" @click="toggleGridLines"
></button> ></button>
</div> </div>

View File

@@ -85,6 +85,7 @@
v-for="(treeItem, index) in visibleItems" v-for="(treeItem, index) in visibleItems"
:key="`${treeItem.navigationPath}-${index}-${treeItem.object.name}`" :key="`${treeItem.navigationPath}-${index}-${treeItem.object.name}`"
:node="treeItem" :node="treeItem"
draggable="true"
:is-selector-tree="isSelectorTree" :is-selector-tree="isSelectorTree"
:selected-item="selectedItem" :selected-item="selectedItem"
:active-search="activeSearch" :active-search="activeSearch"