From a914e4f1f750e2f40f1588ee081e78624d58bfe2 Mon Sep 17 00:00:00 2001 From: David Tsay <3614296+davetsay@users.noreply.github.com> Date: Thu, 16 Nov 2023 10:31:35 -0800 Subject: [PATCH] Only show marquee for selected item (#7180) * only show marquee for selected item * Revert "only show marquee for selected item" This reverts commit d17af210c2d8fcb332abcd239bdcec82d2ae03c0. * revert change made in #6767 * create framework for displayLayout visual test * WIP create display layout for test * only show marquee for selected * fix selection of object in nested layout * fix grid and code cleanup * add child layouts side by side * code cleanup * externalize setup for reuse in multiple tests * write marquee and grid tests * fix object in layout locator * fix nested layout selector * add aria label to layouts * fix layout locator * add jsdoc for test setup function * make test more efficient * cleanup and linting * update locator * update locators --------- Co-authored-by: John Hill --- e2e/appActions.js | 12 +- .../functional/moveAndLinkObjects.e2e.spec.js | 2 +- e2e/tests/functional/notification.e2e.spec.js | 3 +- .../conditionSet/conditionSet.e2e.spec.js | 2 +- .../displayLayout/displayLayout.e2e.spec.js | 14 +- .../flexibleLayout/flexibleLayout.e2e.spec.js | 8 +- .../plugins/gauge/gauge.e2e.spec.js | 2 +- .../functional/plugins/lad/lad.e2e.spec.js | 10 +- .../plugins/plot/autoscale.e2e.spec.js | 2 +- .../plugins/plot/logPlot.e2e.spec.js | 2 +- .../plugins/plot/overlayPlot.e2e.spec.js | 4 +- .../plugins/plot/scatterPlot.e2e.spec.js | 2 +- .../plugins/plot/stackedPlot.e2e.spec.js | 4 +- e2e/tests/functional/search.e2e.spec.js | 4 +- e2e/tests/functional/tooltips.e2e.spec.js | 18 +- e2e/tests/visual/displayLayout.visual.spec.js | 156 ++++++++++++++++++ .../components/DisplayLayout.vue | 1 + .../components/display-layout.scss | 52 +++--- .../components/edit-marquee.scss | 1 + 19 files changed, 229 insertions(+), 70 deletions(-) create mode 100644 e2e/tests/visual/displayLayout.visual.spec.js diff --git a/e2e/appActions.js b/e2e/appActions.js index 24380ceae4..f2940208c5 100644 --- a/e2e/appActions.js +++ b/e2e/appActions.js @@ -81,7 +81,7 @@ async function createDomainObjectWithDefaults( await page.goto(`${parentUrl}`); //Click the Create button - await page.click('button:has-text("Create")'); + await page.getByRole('button', { name: 'Create' }).click(); // Click the object specified by 'type' await page.click(`li[role='menuitem']:text("${type}")`); @@ -108,7 +108,7 @@ async function createDomainObjectWithDefaults( // Click OK button and wait for Navigate event await Promise.all([ page.waitForLoadState(), - page.click('[aria-label="Save"]'), + await page.getByRole('button', { name: 'Save' }).click(), // Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); @@ -120,8 +120,8 @@ async function createDomainObjectWithDefaults( if (await _isInEditMode(page, uuid)) { // 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(); } return { @@ -182,7 +182,7 @@ async function createPlanFromJSON(page, { name, json, parent = 'mine' }) { await page.goto(`${parentUrl}`); // Click the Create button - await page.click('button:has-text("Create")'); + await page.getByRole('button', { name: 'Create' }).click(); // Click 'Plan' menu option await page.click(`li:text("Plan")`); @@ -231,7 +231,7 @@ async function createExampleTelemetryObject(page, parent = 'mine') { await page.goto(`${parentUrl}`); - await page.locator('button:has-text("Create")').click(); + await page.getByRole('button', { name: 'Create' }).click(); await page.locator('li:has-text("Sine Wave Generator")').click(); diff --git a/e2e/tests/functional/moveAndLinkObjects.e2e.spec.js b/e2e/tests/functional/moveAndLinkObjects.e2e.spec.js index 4e8d27e281..b7a067bd47 100644 --- a/e2e/tests/functional/moveAndLinkObjects.e2e.spec.js +++ b/e2e/tests/functional/moveAndLinkObjects.e2e.spec.js @@ -149,7 +149,7 @@ test.describe('Move & link item tests', () => { // Finish editing and save Telemetry Table await page.locator('.c-button--menu.c-button--major.icon-save').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Create New Folder Basic Domain Object let folder = 'Test Folder'; diff --git a/e2e/tests/functional/notification.e2e.spec.js b/e2e/tests/functional/notification.e2e.spec.js index 040fbc666d..bb8c3c3196 100644 --- a/e2e/tests/functional/notification.e2e.spec.js +++ b/e2e/tests/functional/notification.e2e.spec.js @@ -109,8 +109,7 @@ test.describe('Notification Overlay', () => { // Click on the "Save" button await page.click('button[title="Save"]'); - // Click on the "Save and Finish Editing" option - await page.click('li[title="Save and Finish Editing"]'); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Verify that Notification List is NOT open expect(await page.locator('div[role="dialog"]').isVisible()).toBe(false); diff --git a/e2e/tests/functional/plugins/conditionSet/conditionSet.e2e.spec.js b/e2e/tests/functional/plugins/conditionSet/conditionSet.e2e.spec.js index 8111599a47..5217d71a0d 100644 --- a/e2e/tests/functional/plugins/conditionSet/conditionSet.e2e.spec.js +++ b/e2e/tests/functional/plugins/conditionSet/conditionSet.e2e.spec.js @@ -122,7 +122,7 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => { .nth(1) .click(); // Click Save and Finish Editing Option - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); //Verify Main section reflects updated Name Property await expect diff --git a/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js b/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js index 2911b7bb9e..5c58a37fc3 100644 --- a/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js +++ b/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js @@ -148,7 +148,7 @@ test.describe('Display Layout', () => { const layoutGridHolder = page.locator('.l-layout__grid-holder'); await sineWaveGeneratorTreeItem.dragTo(layoutGridHolder); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Subscribe to the Sine Wave Generator data // On getting data, check if the value found in the Display Layout is the most recent value @@ -186,7 +186,7 @@ test.describe('Display Layout', () => { const layoutGridHolder = page.locator('.l-layout__grid-holder'); await sineWaveGeneratorTreeItem.dragTo(layoutGridHolder); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Subscribe to the Sine Wave Generator data const getTelemValuePromise = await subscribeToTelemetry(page, sineWaveObject.uuid); @@ -228,7 +228,7 @@ test.describe('Display Layout', () => { const layoutGridHolder = page.locator('.l-layout__grid-holder'); await sineWaveGeneratorTreeItem.dragTo(layoutGridHolder); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); expect.soft(await page.locator('.l-layout .l-layout__frame').count()).toEqual(1); @@ -270,7 +270,7 @@ test.describe('Display Layout', () => { const layoutGridHolder = page.locator('.l-layout__grid-holder'); await sineWaveGeneratorTreeItem.dragTo(layoutGridHolder); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); expect.soft(await page.locator('.l-layout .l-layout__frame').count()).toEqual(1); @@ -326,7 +326,7 @@ test.describe('Display Layout', () => { await page.locator('div[title="Resize object width"] > input').fill('70'); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); const startDate = '2021-12-30 01:01:00.000Z'; const endDate = '2021-12-30 01:11:00.000Z'; @@ -388,7 +388,7 @@ test.describe('Display Layout', () => { await page.getByText('Overlay Plot').click(); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Time to inspect some network traffic let networkRequests = []; @@ -460,7 +460,7 @@ async function removeLayoutObject(page, layoutObject) { * @param {'Box' | 'Ellipse' | 'Line' | 'Text' | 'Image'} layoutObject */ async function addLayoutObject(page, layoutName, layoutObject) { - await page.getByLabel(`${layoutName} Layout Grid`).click(); + await page.getByLabel(`${layoutName} Layout`, { exact: true }).click(); await page.getByText('Add Drawing Object').click(); await page .getByRole('menuitem', { diff --git a/e2e/tests/functional/plugins/flexibleLayout/flexibleLayout.e2e.spec.js b/e2e/tests/functional/plugins/flexibleLayout/flexibleLayout.e2e.spec.js index 534eb8b8ad..def82aa9d3 100644 --- a/e2e/tests/functional/plugins/flexibleLayout/flexibleLayout.e2e.spec.js +++ b/e2e/tests/functional/plugins/flexibleLayout/flexibleLayout.e2e.spec.js @@ -88,7 +88,7 @@ test.describe('Flexible Layout', () => { await expect(dragWrapper).toHaveAttribute('draggable', 'true'); // Save Flexible Layout await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Check that panes are not draggable while Flexible Layout is in Browse mode dragWrapper = page.locator('.c-fl-container__frames-holder .c-fl-frame__drag-wrapper').first(); await expect(dragWrapper).toHaveAttribute('draggable', 'false'); @@ -174,7 +174,7 @@ test.describe('Flexible Layout', () => { // Add the Sine Wave Generator to the Flexible Layout and save changes await sineWaveGeneratorTreeItem.dragTo(page.locator('.c-fl__container.is-empty').first()); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); expect.soft(await page.locator('.c-fl-container__frame').count()).toEqual(1); @@ -205,7 +205,7 @@ test.describe('Flexible Layout', () => { // Add the Sine Wave Generator to the Flexible Layout and save changes await sineWaveGeneratorTreeItem.dragTo(page.locator('.c-fl__container.is-empty').first()); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); expect.soft(await page.locator('.c-fl-container__frame').count()).toEqual(1); @@ -246,7 +246,7 @@ test.describe('Flexible Layout', () => { await exampleImageryTreeItem.dragTo(page.locator('.c-fl__container.is-empty').first()); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // flip on independent time conductor await setIndependentTimeConductorBounds( diff --git a/e2e/tests/functional/plugins/gauge/gauge.e2e.spec.js b/e2e/tests/functional/plugins/gauge/gauge.e2e.spec.js index bfc4464d50..ace4253d12 100644 --- a/e2e/tests/functional/plugins/gauge/gauge.e2e.spec.js +++ b/e2e/tests/functional/plugins/gauge/gauge.e2e.spec.js @@ -53,7 +53,7 @@ test.describe('Gauge', () => { await editButtonLocator.click(); await expect.soft(page.locator(`#inspector-elements-tree >> text=${swg1.name}`)).toBeVisible(); await saveButtonLocator.click(); - await page.locator('li[title="Save and Finish Editing"]').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Create another sine wave generator within the gauge const swg2 = await createDomainObjectWithDefaults(page, { diff --git a/e2e/tests/functional/plugins/lad/lad.e2e.spec.js b/e2e/tests/functional/plugins/lad/lad.e2e.spec.js index efc61f6c69..d959d06641 100644 --- a/e2e/tests/functional/plugins/lad/lad.e2e.spec.js +++ b/e2e/tests/functional/plugins/lad/lad.e2e.spec.js @@ -101,7 +101,7 @@ test.describe('Testing LAD table configuration', () => { // save and reload and verify they columns are still hidden await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.reload(); await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeHidden(); await expect(page.getByRole('cell', { name: 'Units' })).toBeHidden(); @@ -129,7 +129,7 @@ test.describe('Testing LAD table configuration', () => { // save and reload and make sure timestamp is still visible await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.reload(); await expect(page.getByRole('cell', { name: 'Units' })).toBeHidden(); await expect(page.getByRole('cell', { name: 'Type' })).toBeHidden(); @@ -159,7 +159,7 @@ test.describe('Testing LAD table configuration', () => { // save and reload and make sure all columns are still visible await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.reload(); await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeVisible(); await expect(page.getByRole('cell', { name: 'Units' })).toBeVisible(); @@ -265,7 +265,7 @@ test.describe('Testing LAD table @unstable', () => { // Add the Sine Wave Generator to the LAD table and save changes await page.dragAndDrop('text=Test Sine Wave Generator', '.c-lad-table-wrapper'); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Subscribe to the Sine Wave Generator data // On getting data, check if the value found in the LAD table is the most recent value @@ -293,7 +293,7 @@ test.describe('Testing LAD table @unstable', () => { // Add the Sine Wave Generator to the LAD table and save changes await page.dragAndDrop('text=Test Sine Wave Generator', '.c-lad-table-wrapper'); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Subscribe to the Sine Wave Generator data const getTelemValuePromise = await subscribeToTelemetry(page, sineWaveObject.uuid); diff --git a/e2e/tests/functional/plugins/plot/autoscale.e2e.spec.js b/e2e/tests/functional/plugins/plot/autoscale.e2e.spec.js index aa58c6ca0b..74a1d67c9a 100644 --- a/e2e/tests/functional/plugins/plot/autoscale.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/autoscale.e2e.spec.js @@ -68,7 +68,7 @@ test.describe('Autoscale', () => { // save await page.click('button[title="Save"]'); await Promise.all([ - page.locator('li[title = "Save and Finish Editing"]').click(), + page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(), //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); diff --git a/e2e/tests/functional/plugins/plot/logPlot.e2e.spec.js b/e2e/tests/functional/plugins/plot/logPlot.e2e.spec.js index c41b488aba..cdf39ae89a 100644 --- a/e2e/tests/functional/plugins/plot/logPlot.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/logPlot.e2e.spec.js @@ -214,7 +214,7 @@ async function saveOverlayPlot(page) { .click(); await Promise.all([ - page.locator('text=Save and Finish Editing').click(), + page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(), //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); diff --git a/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js b/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js index 136a61310e..b7dcbd357b 100644 --- a/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js @@ -105,7 +105,7 @@ test.describe('Overlay Plot', () => { // Save (exit edit mode) await page.locator('button[title="Save"]').click(); - await page.locator('li[title="Save and Finish Editing"]').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await assertLimitLinesExistAndAreVisible(page); @@ -127,7 +127,7 @@ test.describe('Overlay Plot', () => { // Save (exit edit mode) await page.locator('button[title="Save"]').click(); - await page.locator('li[title="Save and Finish Editing"]').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await assertLimitLinesExistAndAreVisible(page); diff --git a/e2e/tests/functional/plugins/plot/scatterPlot.e2e.spec.js b/e2e/tests/functional/plugins/plot/scatterPlot.e2e.spec.js index be151af77c..e6efe1e863 100644 --- a/e2e/tests/functional/plugins/plot/scatterPlot.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/scatterPlot.e2e.spec.js @@ -57,7 +57,7 @@ test.describe('Scatter Plot', () => { await page.getByRole('tab', { name: 'Elements' }).click(); await expect.soft(page.locator(`#inspector-elements-tree >> text=${swg1.name}`)).toBeVisible(); await saveButton.click(); - await page.locator('li[title="Save and Finish Editing"]').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Create another sine wave generator within the scatter plot const swg2 = await createDomainObjectWithDefaults(page, { diff --git a/e2e/tests/functional/plugins/plot/stackedPlot.e2e.spec.js b/e2e/tests/functional/plugins/plot/stackedPlot.e2e.spec.js index 1c0d462bc8..83bc77f62c 100644 --- a/e2e/tests/functional/plugins/plot/stackedPlot.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/stackedPlot.e2e.spec.js @@ -135,7 +135,7 @@ test.describe('Stacked Plot', () => { // Save (exit edit mode) await page.locator('button[title="Save"]').click(); - await page.locator('li[title="Save and Finish Editing"]').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // assert plot order persists after save - [swgB, swgC, swgA] await expect(stackedPlotItem1).toHaveAttribute('aria-label', `Stacked Plot Item ${swgB.name}`); @@ -243,7 +243,7 @@ test.describe('Stacked Plot', () => { // Save (exit edit mode) await page.locator('button[title="Save"]').click(); - await page.locator('li[title="Save and Finish Editing"]').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await assertAggregateLegendIsVisible(page); diff --git a/e2e/tests/functional/search.e2e.spec.js b/e2e/tests/functional/search.e2e.spec.js index 3802dff50f..34b47d791e 100644 --- a/e2e/tests/functional/search.e2e.spec.js +++ b/e2e/tests/functional/search.e2e.spec.js @@ -88,8 +88,8 @@ test.describe('Grand Search', () => { .locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button') .nth(1) .click(); - // Click text=Save and Finish Editing - await page.locator('text=Save and Finish Editing').click(); + + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Click [aria-label="OpenMCT Search"] [aria-label="Search Input"] await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').click(); // Fill [aria-label="OpenMCT Search"] [aria-label="Search Input"] diff --git a/e2e/tests/functional/tooltips.e2e.spec.js b/e2e/tests/functional/tooltips.e2e.spec.js index 14f4476234..39165f7df5 100644 --- a/e2e/tests/functional/tooltips.e2e.spec.js +++ b/e2e/tests/functional/tooltips.e2e.spec.js @@ -103,7 +103,7 @@ test.describe('Verify tooltips', () => { await page.dragAndDrop(`text=${sineWaveObject2.name}`, '.c-lad-table-wrapper'); await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-lad-table-wrapper'); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.keyboard.down('Control'); @@ -133,7 +133,7 @@ test.describe('Verify tooltips', () => { await page.dragAndDrop(`text=${sineWaveObject2.name}`, '.gl-plot'); await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.gl-plot'); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.keyboard.down('Control'); @@ -200,7 +200,7 @@ test.describe('Verify tooltips', () => { await page.locator('[title="Edit"]').click(); await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.gl-plot'); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Create Stacked Plot await createDomainObjectWithDefaults(page, { @@ -211,7 +211,7 @@ test.describe('Verify tooltips', () => { await page.locator('[title="Edit"]').click(); await page.dragAndDrop(`text=${sineWaveObject2.name}`, '.c-plot--stacked.holder'); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); // Create Display Layout await createDomainObjectWithDefaults(page, { @@ -231,7 +231,7 @@ test.describe('Verify tooltips', () => { targetPosition: { x: 500, y: 200 } }); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.keyboard.down('Control'); @@ -269,7 +269,7 @@ test.describe('Verify tooltips', () => { await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-fl__container >> nth=1'); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.keyboard.down('Control'); await page.getByText('SWG 1').nth(2).hover(); @@ -293,7 +293,7 @@ test.describe('Verify tooltips', () => { await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-tabs-view__tabs-holder'); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.keyboard.down('Control'); await page.getByText('SWG 1').nth(2).hover(); @@ -378,7 +378,7 @@ test.describe('Verify tooltips', () => { await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-telemetry-table'); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.keyboard.down('Control'); await page.locator('.noselect > [title="SWG 3"]').first().hover(); @@ -442,7 +442,7 @@ test.describe('Verify tooltips', () => { '.c-object-view.is-object-type-time-strip' ); await page.locator('button[title="Save"]').click(); - await page.locator('text=Save and Finish Editing').click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); await page.keyboard.down('Control'); await page.getByText(sineWaveObject1.name).nth(2).hover(); diff --git a/e2e/tests/visual/displayLayout.visual.spec.js b/e2e/tests/visual/displayLayout.visual.spec.js new file mode 100644 index 0000000000..0130356806 --- /dev/null +++ b/e2e/tests/visual/displayLayout.visual.spec.js @@ -0,0 +1,156 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2023, 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. + *****************************************************************************/ + +/** + * Defines playwright locators that can be used in tests. + * @typedef {Object} LayoutLocators + * @property {Object} LayoutLocator + */ + +const { test } = require('../../pluginFixtures'); +const { createDomainObjectWithDefaults } = require('../../appActions'); +const VISUAL_URL = require('../../constants').VISUAL_URL; +const percySnapshot = require('@percy/playwright'); +const snapshotScope = '.l-shell__pane-main .l-pane__contents'; + +test.describe('Visual - Display Layout', () => { + test('Resize Marquee surrounds selection', async ({ page, theme }) => { + const baseline = await setupBaseline(page); + const { child1LayoutLocator, child1LayoutObjectLocator } = baseline; + + await percySnapshot(page, `Resize nested layout selected (theme: '${theme}')`, { + scope: snapshotScope + }); + + await child1LayoutLocator.click(); + await percySnapshot(page, `Resize new nested layout selected (theme: '${theme}')`, { + scope: snapshotScope + }); + + await child1LayoutObjectLocator.click(); + await percySnapshot(page, `Resize Object in nested layout selected (theme: '${theme}')`, { + scope: snapshotScope + }); + }); + + test('Parent layout of selection displays grid', async ({ page, theme }) => { + const baseline = await setupBaseline(page); + const { parentLayoutLocator, child1LayoutObjectLocator } = baseline; + + await percySnapshot(page, `Parent nested layout selected (theme: '${theme}')`, { + scope: snapshotScope + }); + + await parentLayoutLocator.click(); + await percySnapshot(page, `Parent outer layout selected (theme: '${theme}')`, { + scope: snapshotScope + }); + + await child1LayoutObjectLocator.click(); + await percySnapshot(page, `Parent Object in nested layout selected (theme: '${theme}')`, { + scope: snapshotScope + }); + }); +}); + +/** + * Sets up a complex layout with nested layouts and provides the playwright locators + * @param {import('@playwright/test').Page} page + * @returns {LayoutLocators} locators of baseline complex display to be used in tests + */ +async function setupBaseline(page) { + // Load Open MCT visual test baseline + await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' }); + // Open Tree + await page.getByRole('button', { name: 'Browse' }).click(); + + const treePane = page.getByRole('tree', { + name: 'Main Tree' + }); + + const objectViewLocator = page.locator('.c-object-view'); + const parentLayoutLocator = objectViewLocator.first(); + const child1LayoutLocator = parentLayoutLocator.locator(objectViewLocator).first(); + const child1LayoutObjectLocator = child1LayoutLocator.locator('.l-layout__frame'); + const parentLayout = await createDomainObjectWithDefaults(page, { + type: 'Display Layout', + name: 'Parent Layout' + }); + const child1Layout = await createDomainObjectWithDefaults(page, { + type: 'Display Layout', + name: 'Child 1 Layout' + }); + const child2Layout = await createDomainObjectWithDefaults(page, { + type: 'Display Layout', + name: 'Child 2 Layout' + }); + const swg1 = await createDomainObjectWithDefaults(page, { + type: 'Sine Wave Generator', + name: 'SWG 1' + }); + const swg2 = await createDomainObjectWithDefaults(page, { + type: 'Sine Wave Generator', + name: 'SWG 2' + }); + const child1LayoutTreeItem = treePane.getByRole('treeitem', { + name: new RegExp(child1Layout.name) + }); + const child2LayoutTreeItem = treePane.getByRole('treeitem', { + name: new RegExp(child2Layout.name) + }); + const swg1TreeItem = treePane.getByRole('treeitem', { + name: new RegExp(swg1.name) + }); + const swg2TreeItem = treePane.getByRole('treeitem', { + name: new RegExp(swg2.name) + }); + + // Expand folder containing created objects + await page.goto(parentLayout.url); + await page.getByTitle('Show selected item in tree').click(); + + // Add swg1 to child1Layout + await page.goto(child1Layout.url); + await page.getByRole('button', { name: 'Edit' }).click(); + await swg1TreeItem.dragTo(parentLayoutLocator, { targetPosition: { x: 0, y: 0 } }); + await page.getByRole('button', { name: 'Save' }).click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); + + // Add swg1 to child1Layout + await page.goto(child2Layout.url); + await page.getByRole('button', { name: 'Edit' }).click(); + await swg2TreeItem.dragTo(parentLayoutLocator, { targetPosition: { x: 0, y: 0 } }); + await page.getByRole('button', { name: 'Save' }).click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); + + // Add child1Layout and child2Layout to parentLayout + await page.goto(parentLayout.url); + await page.getByRole('button', { name: 'Edit' }).click(); + await child1LayoutTreeItem.dragTo(parentLayoutLocator, { targetPosition: { x: 350, y: 0 } }); + await child2LayoutTreeItem.dragTo(parentLayoutLocator, { targetPosition: { x: 0, y: 0 } }); + + return { + parentLayoutLocator, + child1LayoutLocator, + child1LayoutObjectLocator + }; +} diff --git a/src/plugins/displayLayout/components/DisplayLayout.vue b/src/plugins/displayLayout/components/DisplayLayout.vue index 9f53448a79..892ac645f5 100644 --- a/src/plugins/displayLayout/components/DisplayLayout.vue +++ b/src/plugins/displayLayout/components/DisplayLayout.vue @@ -27,6 +27,7 @@ 'is-multi-selected': selectedLayoutItems.length > 1, 'allow-editing': isEditing }" + :aria-label="`${domainObject.name} Layout`" @dragover="handleDragOver" @click.capture="bypassSelection" @drop="handleDrop" diff --git a/src/plugins/displayLayout/components/display-layout.scss b/src/plugins/displayLayout/components/display-layout.scss index 22426e1af4..07bf6c0018 100644 --- a/src/plugins/displayLayout/components/display-layout.scss +++ b/src/plugins/displayLayout/components/display-layout.scss @@ -1,4 +1,4 @@ -@mixin displayMarquee($c) { +@mixin displayMarquee() { > .c-frame-edit { // All other frames //@include test($c, 0.4); @@ -11,12 +11,29 @@ } } +@mixin displayGrid() { + background: $editUIGridColorBg; + + > [class*='__dimensions'] { + display: block; + } + + > [class*='grid-holder'] { + display: block; + } +} + .l-layout { @include abs(); display: flex; flex-direction: column; overflow: auto; + &__grid-holder, + &__dimensions { + display: none; + } + &__dimensions { $b: 1px dashed $editDimensionsColor; border-right: $b; @@ -45,35 +62,20 @@ .l-shell__main-container { [s-selected], [s-selected-parent] { - // Display grid and allow edit marquee to display in main layout holder when editing + // Display grid in main layout holder when editing > .l-layout { - background: $editUIGridColorBg; - - > [class*='__dimensions'] { - display: block; - } - - > [class*='__grid-holder'] { - display: block; - } + @include displayGrid(); } } } .l-layout__frame { - &[s-selected]:not([multi-select='true']), &[s-selected-parent] { - // Display grid and allow edit marquee to display in nested layouts when editing - > * > * > .l-layout.allow-editing { + // Display grid in nested layouts when editing + > * > * > * > .l-layout.allow-editing { box-shadow: inset $editUIGridColorFg 0 0 2px 1px; - - > [class*='__dimensions'] { - display: block; - } - - > [class*='grid-holder'] { - display: block; - } + + @include displayGrid(); } } } @@ -82,11 +84,11 @@ *[s-selected-parent] { > .l-layout { // When main shell layout is the parent - @include displayMarquee(deeppink); // TEMP + @include displayMarquee(); } - > * > * > * { + > * > * > * > * { // When a sub-layout is the parent - @include displayMarquee(blue); + @include displayMarquee(); } } } diff --git a/src/plugins/displayLayout/components/edit-marquee.scss b/src/plugins/displayLayout/components/edit-marquee.scss index f46a8cab88..00ec1aeba7 100644 --- a/src/plugins/displayLayout/components/edit-marquee.scss +++ b/src/plugins/displayLayout/components/edit-marquee.scss @@ -1,5 +1,6 @@ .c-frame-edit { // In Layouts, this is the editing rect and handles + display: none; // Set to display: block in display-layout.scss pointer-events: none; @include abs(); border: $editMarqueeBorder;