From 92e5cba6d329995f3499ff84d79aaec0ccf723fe Mon Sep 17 00:00:00 2001 From: Jesse Mazzella Date: Mon, 15 Jul 2024 13:28:29 -0700 Subject: [PATCH 1/5] test(visual): skip flaky visual test (#7776) --- .../visual-a11y/components/timeConductor.visual.spec.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/e2e/tests/visual-a11y/components/timeConductor.visual.spec.js b/e2e/tests/visual-a11y/components/timeConductor.visual.spec.js index eef1114e40..bd089bbb6c 100644 --- a/e2e/tests/visual-a11y/components/timeConductor.visual.spec.js +++ b/e2e/tests/visual-a11y/components/timeConductor.visual.spec.js @@ -48,7 +48,13 @@ test.describe('Visual - Time Conductor', () => { // await scanForA11yViolations(page, testInfo.title); // }); - test('Visual - Time Conductor (Fixed time) @clock @snapshot', async ({ page }) => { + /** + * FIXME: This test fails sporadically due to layout shift during initial load. + * The layout shift seems to be caused by loading Open MCT's icons, which are not preloaded + * and load after the initial DOM content has loaded. + * @see https://github.com/nasa/openmct/issues/7775 + */ + test.fixme('Visual - Time Conductor (Fixed time) @clock @snapshot', async ({ page }) => { // Navigate to a specific view that uses the Time Conductor in Fixed Time mode with inspect and browse panes collapsed await page.goto( `./#/browse/mine?tc.mode=fixed&tc.startBound=${MISSION_TIME_FIXED_START}&tc.endBound=${MISSION_TIME_FIXED_END}&tc.timeSystem=utc&view=grid&hideInspector=true&hideTree=true`, From 6983148abab54f141be97b4f54d12cb0151cb507 Mon Sep 17 00:00:00 2001 From: Even Stensberg Date: Tue, 16 Jul 2024 00:09:42 +0200 Subject: [PATCH 2/5] fix(package.json): consistent props (#7768) --- e2e/package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/e2e/package.json b/e2e/package.json index 056e57761f..a891a042df 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -21,6 +21,9 @@ "@axe-core/playwright": "4.8.5", "sinon": "17.0.0" }, - "author": "NASA Ames Research Center", + "author": { + "name": "National Aeronautics and Space Administration", + "url": "https://www.nasa.gov" + }, "license": "Apache-2.0" } \ No newline at end of file From db808b4d54936451ae85c0a07201c41663734fc4 Mon Sep 17 00:00:00 2001 From: Shefali Joshi Date: Tue, 16 Jul 2024 10:57:12 -0700 Subject: [PATCH 3/5] Plots correctly use configuration set on the parent if they can't their own (#7770) * For telemetry that cannot have it's own configuration, ensure that it is correct initialized by the parent. * stacked plot test checks that config properties for immutable telemetry points are applied correctly * add tab navigation to inspector tabs * add accessibility metadata to this component * Update title to be on the correct component. Add expand/collapse logic * clean up test * refactor: better a11y for plot forms, fix "expand by default" test, refactor out `plotActions.js` * a11y: aria label for plotOptionsItem * refactor(a11y): PlotOptionsBrowse structure to have better a11y * fixed tests * address comment * reverted to match previous commit --------- Co-authored-by: Hill, John (ARC-TI)[KBR Wyle Services, LLC] Co-authored-by: Jesse Mazzella Co-authored-by: Jesse Mazzella --- .../plugins/plot/autoscale.e2e.spec.js | 8 +- .../plugins/plot/overlayPlot.e2e.spec.js | 33 +-- .../functional/plugins/plot/plotActions.js | 42 --- .../plugins/plot/plotControls.e2e.spec.js | 8 +- .../plugins/plot/stackedPlot.e2e.spec.js | 147 ++++++---- .../charts/bar/inspector/SeriesOptions.vue | 2 +- .../plot/inspector/PlotOptionsBrowse.vue | 258 +++++++++++------- .../plot/inspector/PlotOptionsEdit.vue | 14 +- .../plot/inspector/PlotOptionsItem.vue | 186 +++++++------ .../plot/inspector/forms/SeriesForm.vue | 40 ++- .../plot/inspector/forms/YAxisForm.vue | 58 ++-- .../plot/stackedPlot/StackedPlotItem.vue | 5 +- src/ui/inspector/InspectorTabs.vue | 2 + 13 files changed, 455 insertions(+), 348 deletions(-) delete mode 100644 e2e/tests/functional/plugins/plot/plotActions.js diff --git a/e2e/tests/functional/plugins/plot/autoscale.e2e.spec.js b/e2e/tests/functional/plugins/plot/autoscale.e2e.spec.js index 9cfbd63cfd..1cd53295c3 100644 --- a/e2e/tests/functional/plugins/plot/autoscale.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/autoscale.e2e.spec.js @@ -26,7 +26,6 @@ Testsuite for plot autoscale. import { createDomainObjectWithDefaults } from '../../../../appActions.js'; import { expect, test } from '../../../../pluginFixtures.js'; -import { setUserDefinedMinAndMax, turnOffAutoscale } from './plotActions.js'; test.use({ viewport: { width: 1280, @@ -62,9 +61,12 @@ test.describe('Autoscale', () => { await page.getByLabel('Edit Object').click(); await page.getByRole('tab', { name: 'Config' }).click(); - await turnOffAutoscale(page); - await setUserDefinedMinAndMax(page, '-2', '2'); + // turn off autoscale + await page.getByRole('checkbox', { name: 'Auto scale' }).uncheck(); + + await page.getByLabel('Y Axis 1 Minimum value').fill('-2'); + await page.getByLabel('Y Axis 1 Maximum value').fill('2'); // save await page.click('button[title="Save"]'); diff --git a/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js b/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js index 114d8beb79..c5a9aa6874 100644 --- a/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js @@ -91,7 +91,7 @@ test.describe('Overlay Plot', () => { // Assert that the legend is collapsed by default await expect(page.getByLabel('Plot Legend Collapsed')).toBeVisible(); await expect(page.getByLabel('Plot Legend Expanded')).toBeHidden(); - await expect(page.getByLabel('Expand by Default')).toHaveText('No'); + await expect(page.getByLabel('Expand by Default')).toHaveText(/No/); expect(await page.getByLabel('Plot Legend Item').count()).toBe(3); @@ -106,7 +106,7 @@ test.describe('Overlay Plot', () => { await expect(page.getByRole('cell', { name: 'Name' })).toBeVisible(); await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeVisible(); await expect(page.getByRole('cell', { name: 'Value' })).toBeVisible(); - await expect(page.getByLabel('Expand by Default')).toHaveText('Yes'); + await expect(page.getByLabel('Expand by Default')).toHaveText(/Yes/); await expect(page.getByLabel('Plot Legend Item')).toHaveCount(3); // Assert that the legend is expanded on page load @@ -116,7 +116,7 @@ test.describe('Overlay Plot', () => { await expect(page.getByRole('cell', { name: 'Name' })).toBeVisible(); await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeVisible(); await expect(page.getByRole('cell', { name: 'Value' })).toBeVisible(); - await expect(page.getByLabel('Expand by Default')).toHaveText('Yes'); + await expect(page.getByLabel('Expand by Default')).toHaveText(/Yes/); await expect(page.getByLabel('Plot Legend Item')).toHaveCount(3); }); @@ -144,15 +144,8 @@ test.describe('Overlay Plot', () => { // Expand the "Sine Wave Generator" plot series options and enable limit lines await page.getByRole('tab', { name: 'Config' }).click(); - await page - .getByRole('list', { name: 'Plot Series Properties' }) - .locator('span') - .first() - .click(); - await page - .getByRole('list', { name: 'Plot Series Properties' }) - .locator('[title="Display limit lines"]~div input') - .check(); + await page.getByLabel('Expand Sine Wave Generator:').click(); + await page.getByLabel('Limit lines').check(); await assertLimitLinesExistAndAreVisible(page); @@ -215,21 +208,13 @@ test.describe('Overlay Plot', () => { // Expand the "Sine Wave Generator" plot series options and enable limit lines await page.getByRole('tab', { name: 'Config' }).click(); - await page - .getByRole('list', { name: 'Plot Series Properties' }) - .locator('span') - .first() - .click(); - await page - .getByRole('list', { name: 'Plot Series Properties' }) - .getByRole('checkbox', { name: 'Limit lines' }) - .check(); + await page.getByLabel('Expand Sine Wave Generator:').click(); + await page.getByLabel('Limit lines').check(); await assertLimitLinesExistAndAreVisible(page); - // Save (exit edit mode) - await page.locator('button[title="Save"]').click(); - await page.locator('li[title="Save and Finish Editing"]').click(); + await page.getByRole('button', { name: 'Save' }).click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); const initialCoords = await assertLimitLinesExistAndAreVisible(page); // Resize the chart container by showing the snapshot pane. diff --git a/e2e/tests/functional/plugins/plot/plotActions.js b/e2e/tests/functional/plugins/plot/plotActions.js deleted file mode 100644 index 14e697f3c6..0000000000 --- a/e2e/tests/functional/plugins/plot/plotActions.js +++ /dev/null @@ -1,42 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2024, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is licensed under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ -/** - * @param {import('@playwright/test').Page} page - */ -async function turnOffAutoscale(page) { - // uncheck autoscale - await page.getByRole('checkbox', { name: 'Auto scale' }).uncheck(); -} - -/** - * @param {import('@playwright/test').Page} page - * @param {string} min - * @param {string} max - */ -async function setUserDefinedMinAndMax(page, min, max) { - // set minimum value - await page.getByRole('spinbutton').first().fill(min); - // set maximum value - await page.getByRole('spinbutton').nth(1).fill(max); -} - -export { setUserDefinedMinAndMax, turnOffAutoscale }; diff --git a/e2e/tests/functional/plugins/plot/plotControls.e2e.spec.js b/e2e/tests/functional/plugins/plot/plotControls.e2e.spec.js index b66e0a8e65..ba614cf90c 100644 --- a/e2e/tests/functional/plugins/plot/plotControls.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/plotControls.e2e.spec.js @@ -33,7 +33,6 @@ import { setStartOffset } from '../../../../appActions.js'; import { expect, test } from '../../../../pluginFixtures.js'; -import { setUserDefinedMinAndMax, turnOffAutoscale } from './plotActions.js'; test.describe('Plot Controls', () => { let overlayPlot; @@ -78,9 +77,12 @@ test.describe('Plot Controls', () => { await page.getByLabel('Edit Object').click(); await page.getByRole('tab', { name: 'Config' }).click(); - await turnOffAutoscale(page); - await setUserDefinedMinAndMax(page, '-1', '1'); + // turn off autoscale + await page.getByRole('checkbox', { name: 'Auto scale' }).uncheck(); + + await page.getByLabel('Y Axis 1 Minimum value').fill('-1'); + await page.getByLabel('Y Axis 1 Maximum value').fill('1'); // save await page.click('button[title="Save"]'); diff --git a/e2e/tests/functional/plugins/plot/stackedPlot.e2e.spec.js b/e2e/tests/functional/plugins/plot/stackedPlot.e2e.spec.js index 3cffb3b28c..aed64e7e8c 100644 --- a/e2e/tests/functional/plugins/plot/stackedPlot.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/stackedPlot.e2e.spec.js @@ -39,19 +39,23 @@ test.describe('Stacked Plot', () => { await page.goto('./', { waitUntil: 'domcontentloaded' }); stackedPlot = await createDomainObjectWithDefaults(page, { - type: 'Stacked Plot' + type: 'Stacked Plot', + name: 'Stacked Plot' }); swgA = await createDomainObjectWithDefaults(page, { type: 'Sine Wave Generator', + name: 'Sine Wave Generator A', parent: stackedPlot.uuid }); swgB = await createDomainObjectWithDefaults(page, { type: 'Sine Wave Generator', + name: 'Sine Wave Generator B', parent: stackedPlot.uuid }); swgC = await createDomainObjectWithDefaults(page, { type: 'Sine Wave Generator', + name: 'Sine Wave Generator C', parent: stackedPlot.uuid }); }); @@ -151,40 +155,80 @@ test.describe('Stacked Plot', () => { await page.getByRole('tab', { name: 'Config' }).click(); // Click on the 1st plot - await page.locator(`[aria-label="Stacked Plot Item ${swgA.name}"] canvas`).nth(1).click(); + await page + .getByLabel('Stacked Plot Item Sine Wave Generator A') + .getByLabel('Plot Canvas') + .click(); // Assert that the inspector shows the Y Axis properties for swgA - await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText( - 'Plot Series' - ); + await expect(page.getByRole('heading', { name: 'Plot Series' })).toBeVisible(); await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); await expect( - page.locator('[aria-label="Plot Series Properties"] .c-object-label') - ).toContainText(swgA.name); + page.getByLabel('Inspector Views').getByText('Sine Wave Generator A', { exact: true }) + ).toBeVisible(); // Click on the 2nd plot - await page.locator(`[aria-label="Stacked Plot Item ${swgB.name}"] canvas`).nth(1).click(); - + await page + .getByLabel('Stacked Plot Item Sine Wave Generator B') + .getByLabel('Plot Canvas') + .click(); // Assert that the inspector shows the Y Axis properties for swgB - await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText( - 'Plot Series' - ); + await expect(page.getByRole('heading', { name: 'Plot Series' })).toBeVisible(); await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); await expect( - page.locator('[aria-label="Plot Series Properties"] .c-object-label') - ).toContainText(swgB.name); + page.getByLabel('Inspector Views').getByText('Sine Wave Generator B', { exact: true }) + ).toBeVisible(); // Click on the 3rd plot - await page.locator(`[aria-label="Stacked Plot Item ${swgC.name}"] canvas`).nth(1).click(); - - // Assert that the inspector shows the Y Axis properties for swgC - await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText( - 'Plot Series' - ); + await page + .getByLabel('Stacked Plot Item Sine Wave Generator C') + .getByLabel('Plot Canvas') + .click(); + // Assert that the inspector shows the Y Axis properties for swgB + await expect(page.getByRole('heading', { name: 'Plot Series' })).toBeVisible(); await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); await expect( - page.locator('[aria-label="Plot Series Properties"] .c-object-label') - ).toContainText(swgC.name); + page.getByLabel('Inspector Views').getByText('Sine Wave Generator C', { exact: true }) + ).toBeVisible(); + + // Go into edit mode + await page.getByLabel('Edit Object').click(); + + await page.getByRole('tab', { name: 'Config' }).click(); + + // Click on the 1st plot + await page.getByLabel('Stacked Plot Item Sine Wave Generator A').click(); + + // Assert that the inspector shows the Y Axis properties for swgA + await expect(page.getByRole('heading', { name: 'Plot Series' })).toBeVisible(); + await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); + await expect( + page.getByLabel('Inspector Views').getByText('Sine Wave Generator A', { exact: true }) + ).toBeVisible(); + + // Click on the 2nd plot + await page.getByLabel('Stacked Plot Item Sine Wave Generator B').click(); + + // Assert that the inspector shows the Y Axis properties for swgB + await expect(page.getByRole('heading', { name: 'Plot Series' })).toBeVisible(); + await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); + await expect( + page.getByLabel('Inspector Views').getByText('Sine Wave Generator B', { exact: true }) + ).toBeVisible(); + + // Click on the 3rd plot + await page.getByLabel('Stacked Plot Item Sine Wave Generator C').click(); + + // Assert that the inspector shows the Y Axis properties for swgC + await expect(page.getByRole('heading', { name: 'Plot Series' })).toBeVisible(); + await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); + await expect( + page.getByLabel('Inspector Views').getByText('Sine Wave Generator C', { exact: true }) + ).toBeVisible(); + }); + + test('Changing properties of an immutable child plot are applied correctly', async ({ page }) => { + await page.goto(stackedPlot.url); // Go into edit mode await page.getByLabel('Edit Object').click(); @@ -192,40 +236,35 @@ test.describe('Stacked Plot', () => { await page.getByRole('tab', { name: 'Config' }).click(); // Click on canvas for the 1st plot - await page.locator(`[aria-label="Stacked Plot Item ${swgA.name}"]`).click(); + await page.getByLabel(`Stacked Plot Item ${swgA.name}`).click(); - // Assert that the inspector shows the Y Axis properties for swgA - await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText( - 'Plot Series' - ); - await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); + // Expand config for the series + await page.getByLabel('Expand Sine Wave Generator').click(); + + // turn off alarm markers + await page.getByLabel('Alarm Markers').uncheck(); + + // save + await page.getByRole('button', { name: 'Save' }).click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); + + // reload page and waitForPlotsToRender + await page.reload(); + await waitForPlotsToRender(page); + + // Click on canvas for the 1st plot + await page.getByLabel(`Stacked Plot Item ${swgA.name}`).click(); + + // Expand config for the series + //TODO Fix this locator + await page.getByLabel('Expand Sine Wave Generator A generator').click(); + + // Assert that alarm markers are still turned off await expect( - page.locator('[aria-label="Plot Series Properties"] .c-object-label') - ).toContainText(swgA.name); - - //Click on canvas for the 2nd plot - await page.locator(`[aria-label="Stacked Plot Item ${swgB.name}"]`).click(); - - // Assert that the inspector shows the Y Axis properties for swgB - await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText( - 'Plot Series' - ); - await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); - await expect( - page.locator('[aria-label="Plot Series Properties"] .c-object-label') - ).toContainText(swgB.name); - - //Click on canvas for the 3rd plot - await page.locator(`[aria-label="Stacked Plot Item ${swgC.name}"]`).click(); - - // Assert that the inspector shows the Y Axis properties for swgC - await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText( - 'Plot Series' - ); - await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); - await expect( - page.locator('[aria-label="Plot Series Properties"] .c-object-label') - ).toContainText(swgC.name); + page + .getByTitle('Display markers visually denoting points in alarm.') + .getByRole('cell', { name: 'Disabled' }) + ).toBeVisible(); }); test('the legend toggles between aggregate and per child', async ({ page }) => { diff --git a/src/plugins/charts/bar/inspector/SeriesOptions.vue b/src/plugins/charts/bar/inspector/SeriesOptions.vue index 06b02d52b8..eae12be23b 100644 --- a/src/plugins/charts/bar/inspector/SeriesOptions.vue +++ b/src/plugins/charts/bar/inspector/SeriesOptions.vue @@ -21,7 +21,7 @@ -->