From 64d4ddd80e233ca172e1691e5f2e6635d95ebc37 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Mon, 8 Jan 2024 20:29:01 +0100 Subject: [PATCH] Set location hash if query parameters or path have changed (#7306) * refactor to es6 class * change URL on path or params change * add test for url * put into edit mode for test * es6 module export * a11y: add `status` role to clock component * a11y: add label to overlay * a11y: update roles for search results * a11y: add `dialog` role and label for PreviewContainer * refactor(e2e): get rid of a bunch of `page.locator()`s * refactor(e2e): spruce up locators * test: fix unit tests * fix tests with new aria labels * fix tests with new aria labels * fix tests with new aria labels --------- Co-authored-by: Jesse Mazzella --- e2e/tests/functional/notification.e2e.spec.js | 17 +- .../flexibleLayout/flexibleLayout.e2e.spec.js | 4 +- .../notebook/notebookWithCouchDB.e2e.spec.js | 12 +- .../plugins/notebook/tags.e2e.spec.js | 62 +++-- e2e/tests/functional/search.e2e.spec.js | 168 ++++++++----- .../visual-a11y/notification.visual.spec.js | 14 +- src/MCT.js | 2 +- .../overlays/components/OverlayComponent.vue | 1 + .../clock/components/ClockComponent.vue | 8 +- .../layout/search/AnnotationSearchResult.vue | 6 +- src/ui/layout/search/GrandSearchSpec.js | 17 +- src/ui/layout/search/ObjectSearchResult.vue | 4 +- .../layout/search/SearchResultsDropDown.vue | 14 +- src/ui/preview/PreviewContainer.vue | 2 +- src/ui/router/ApplicationRouter.js | 17 +- src/ui/router/Browse.js | 234 ++++++++++-------- 16 files changed, 341 insertions(+), 241 deletions(-) diff --git a/e2e/tests/functional/notification.e2e.spec.js b/e2e/tests/functional/notification.e2e.spec.js index a1f295d1bb..f3eda79eed 100644 --- a/e2e/tests/functional/notification.e2e.spec.js +++ b/e2e/tests/functional/notification.e2e.spec.js @@ -91,27 +91,30 @@ test.describe('Notification Overlay', () => { // Create a new Display Layout object await createDomainObjectWithDefaults(page, { type: 'Display Layout' }); + // Dismiss notification banner + await page.getByRole('button', { name: 'Dismiss' }).click(); + // Click on the button "Review 1 Notification" - await page.click('button[aria-label="Review 1 Notification"]'); + await page.getByRole('button', { name: 'Review 1 Notification' }).click(); // Verify that Notification List is open - expect(await page.locator('div[role="dialog"]').isVisible()).toBe(true); + await expect(page.getByRole('dialog', { name: 'Overlay' })).toBeVisible(); // Wait until there is no Notification Banner - await page.waitForSelector('div[role="alert"]', { state: 'detached' }); + await expect(page.getByRole('alert')).not.toBeAttached(); // Click on the "Close" button of the Notification List - await page.click('button[aria-label="Close"]'); + await page.getByRole('button', { name: 'Close' }).click(); // On the Display Layout object, click on the "Edit" button - await page.click('button[title="Edit"]'); + await page.getByRole('button', { name: 'Edit' }).click(); // Click on the "Save" button - await page.click('button[title="Save"]'); + await page.getByRole('button', { name: 'Save' }).click(); 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); + await expect(page.getByRole('dialog', { name: 'Overlay' })).toBeHidden(); }); }); diff --git a/e2e/tests/functional/plugins/flexibleLayout/flexibleLayout.e2e.spec.js b/e2e/tests/functional/plugins/flexibleLayout/flexibleLayout.e2e.spec.js index 378850d7e6..ab8bf6467a 100644 --- a/e2e/tests/functional/plugins/flexibleLayout/flexibleLayout.e2e.spec.js +++ b/e2e/tests/functional/plugins/flexibleLayout/flexibleLayout.e2e.spec.js @@ -290,7 +290,7 @@ test.describe('Flexible Layout Toolbar Actions @localStorage', () => { await page.getByTitle('Add Container').click(); expect(await containerHandles.count()).toEqual(3); await page.getByTitle('Remove Container').click(); - await expect(page.getByRole('dialog')).toHaveText( + await expect(page.getByRole('dialog', { name: 'Overlay' })).toHaveText( 'This action will permanently delete this container from this Flexible Layout. Do you want to continue?' ); await page.getByRole('button', { name: 'OK' }).click(); @@ -300,7 +300,7 @@ test.describe('Flexible Layout Toolbar Actions @localStorage', () => { expect(await page.getByRole('group', { name: 'Frame' }).count()).toEqual(2); await page.getByRole('group', { name: 'Child Layout 1' }).click(); await page.getByTitle('Remove Frame').click(); - await expect(page.getByRole('dialog')).toHaveText( + await expect(page.getByRole('dialog', { name: 'Overlay' })).toHaveText( 'This action will remove this frame from this Flexible Layout. Do you want to continue?' ); await page.getByRole('button', { name: 'OK' }).click(); diff --git a/e2e/tests/functional/plugins/notebook/notebookWithCouchDB.e2e.spec.js b/e2e/tests/functional/plugins/notebook/notebookWithCouchDB.e2e.spec.js index 8ca9a23a01..9ba8de7238 100644 --- a/e2e/tests/functional/plugins/notebook/notebookWithCouchDB.e2e.spec.js +++ b/e2e/tests/functional/plugins/notebook/notebookWithCouchDB.e2e.spec.js @@ -185,16 +185,20 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => { await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); //Partial match for "Science" should only return Science await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Sc'); - await expect(page.locator('[aria-label="Search Result"]').first()).toContainText('Science'); - await expect(page.locator('[aria-label="Search Result"]').first()).not.toContainText('Driving'); - await expect(page.locator('[aria-label="Search Result"]').first()).not.toContainText( + await expect(page.locator('[aria-label="Annotation Search Result"]').first()).toContainText( + 'Science' + ); + await expect(page.locator('[aria-label="Annotation Search Result"]').first()).not.toContainText( + 'Driving' + ); + await expect(page.locator('[aria-label="Annotation Search Result"]').first()).not.toContainText( 'Drilling' ); //Searching for a tag which does not exist should return an empty result await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Xq'); - await expect(page.locator('text=No results found')).toBeVisible(); + await expect(page.getByText('No results found')).toBeVisible(); }); }); diff --git a/e2e/tests/functional/plugins/notebook/tags.e2e.spec.js b/e2e/tests/functional/plugins/notebook/tags.e2e.spec.js index a27d4dfb19..7b4367081c 100644 --- a/e2e/tests/functional/plugins/notebook/tags.e2e.spec.js +++ b/e2e/tests/functional/plugins/notebook/tags.e2e.spec.js @@ -88,43 +88,53 @@ test.describe('Tagging in Notebooks @addInit', () => { await page.locator('[placeholder="Type to select tag"]').click(); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); + await page.getByRole('search').getByLabel('Search Input').click(); await expect(page.locator('button:has-text("Add Tag")')).toBeVisible(); // Test canceling adding a tag after we just click "Add Tag" await page.locator('button:has-text("Add Tag")').click(); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); + await page.getByRole('search').getByLabel('Search Input').click(); await expect(page.locator('button:has-text("Add Tag")')).toBeVisible(); }); test('Can search for tags and preview works properly', async ({ page }) => { await createNotebookEntryAndTags(page); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc'); - await expect(page.locator('[aria-label="Search Result"]')).toContainText('Science'); - await expect(page.locator('[aria-label="Search Result"]')).not.toContainText('Driving'); + await page.getByRole('search').getByLabel('Search Input').click(); + await page.getByRole('search').getByLabel('Search Input').fill('sc'); + await expect(page.getByRole('listitem', { name: 'Annotation Search Result' })).toContainText( + 'Science' + ); + await expect( + page.getByRole('listitem', { name: 'Annotation Search Result' }) + ).not.toContainText('Driving'); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Sc'); - await expect(page.locator('[aria-label="Search Result"]')).toContainText('Science'); - await expect(page.locator('[aria-label="Search Result"]')).not.toContainText('Driving'); + await page.getByRole('search').getByLabel('Search Input').click(); + await page.getByRole('search').getByLabel('Search Input').fill('Sc'); + await expect(page.getByRole('listitem', { name: 'Annotation Search Result' })).toContainText( + 'Science' + ); + await expect( + page.getByRole('listitem', { name: 'Annotation Search Result' }) + ).not.toContainText('Driving'); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Xq'); - await expect(page.locator('text=No results found')).toBeVisible(); + await page.getByRole('search').getByLabel('Search Input').click(); + await page.getByRole('search').getByLabel('Search Input').fill('Xq'); + await expect(page.getByText('No results found')).toBeVisible(); await createDomainObjectWithDefaults(page, { type: 'Display Layout' }); // Go back into edit mode for the display layout - await page.locator('button[title="Edit"]').click(); + await page.getByRole('button', { name: 'Edit' }).click(); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Sc'); - await expect(page.locator('[aria-label="Search Result"]')).toContainText('Science'); + await page.getByRole('search').getByLabel('Search Input').click(); + await page.getByRole('search').getByLabel('Search Input').fill('Sc'); + await expect(page.getByRole('listitem', { name: 'Annotation Search Result' })).toContainText( + 'Science' + ); await page.getByText('Entry 0').click(); await expect(page.locator('.js-preview-window')).toBeVisible(); }); @@ -138,8 +148,10 @@ test.describe('Tagging in Notebooks @addInit', () => { await expect(page.locator('[aria-label="Tags Inspector"]')).toContainText('Science'); await expect(page.locator('[aria-label="Tags Inspector"]')).not.toContainText('Driving'); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc'); - await expect(page.locator('[aria-label="Search Result"]')).not.toContainText('Driving'); + await page.getByRole('search').getByLabel('Search Input').fill('sc'); + await expect( + page.getByRole('listitem', { name: 'Annotation Search Result' }) + ).not.toContainText('Driving'); }); test('Can delete entries without tags', async ({ page }) => { @@ -172,12 +184,12 @@ test.describe('Tagging in Notebooks @addInit', () => { await page.locator('button:has-text("OK")').click(); await page.goto('./', { waitUntil: 'domcontentloaded' }); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Unnamed'); - await expect(page.locator('text=No results found')).toBeVisible(); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sci'); - await expect(page.locator('text=No results found')).toBeVisible(); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('dri'); - await expect(page.locator('text=No results found')).toBeVisible(); + await page.getByRole('search').getByLabel('Search Input').fill('Unnamed'); + await expect(page.getByText('No results found')).toBeVisible(); + await page.getByRole('search').getByLabel('Search Input').fill('sci'); + await expect(page.getByText('No results found')).toBeVisible(); + await page.getByRole('search').getByLabel('Search Input').fill('dri'); + await expect(page.getByText('No results found')).toBeVisible(); }); test('Tags persist across reload', async ({ page }) => { //Go to baseURL diff --git a/e2e/tests/functional/search.e2e.spec.js b/e2e/tests/functional/search.e2e.spec.js index 73af73679f..12e099b013 100644 --- a/e2e/tests/functional/search.e2e.spec.js +++ b/e2e/tests/functional/search.e2e.spec.js @@ -29,12 +29,15 @@ import { createDomainObjectWithDefaults } from '../../appActions.js'; import { expect, test } from '../../pluginFixtures.js'; test.describe('Grand Search', () => { - const searchResultSelector = '.c-gsearch-result__title'; - const searchResultDropDownSelector = '.c-gsearch__results'; + let grandSearchInput; test.beforeEach(async ({ page }) => { + grandSearchInput = page + .getByLabel('OpenMCT Search') + .getByRole('searchbox', { name: 'Search Input' }); + // Go to baseURL - await page.goto('./', { waitUntil: 'networkidle' }); + await page.goto('./', { waitUntil: 'domcontentloaded' }); }); test('Can search for objects, and subsequent search dropdown behaves properly', async ({ @@ -45,103 +48,124 @@ test.describe('Grand Search', () => { const createdObjects = await createObjectsForSearch(page); - // Click [aria-label="OpenMCT Search"] input[type="search"] - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); - // Fill [aria-label="OpenMCT Search"] input[type="search"] - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Cl'); - await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText( + // Go back into edit mode for the display layout + await page.getByRole('button', { name: 'Edit' }).click(); + + await grandSearchInput.click(); + await grandSearchInput.fill('Cl'); + + await expect(page.getByLabel('Object Search Result').first()).toContainText( `Clock A ${myItemsFolderName} Red Folder Blue Folder` ); - await expect(page.locator('[aria-label="Search Result"] >> nth=1')).toContainText( + await expect(page.getByLabel('Object Search Result').nth(1)).toContainText( `Clock B ${myItemsFolderName} Red Folder Blue Folder` ); - await expect(page.locator('[aria-label="Search Result"] >> nth=2')).toContainText( + await expect(page.getByLabel('Object Search Result').nth(2)).toContainText( `Clock C ${myItemsFolderName} Red Folder Blue Folder` ); - await expect(page.locator('[aria-label="Search Result"] >> nth=3')).toContainText( + await expect(page.getByLabel('Object Search Result').nth(3)).toContainText( `Clock D ${myItemsFolderName} Red Folder Blue Folder` ); // Click the Elements pool to dismiss the search menu await page.getByRole('tab', { name: 'Elements' }).click(); - await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden(); + await expect(page.getByLabel('Object Search Result').first()).toBeHidden(); - await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').click(); - await page.locator('[aria-label="Clock A clock result"] >> text=Clock A').click(); - await expect(page.locator('.js-preview-window')).toBeVisible(); + await grandSearchInput.click(); + await page.getByLabel('OpenMCT Search').getByText('Clock A').click(); + await expect(page.getByRole('dialog', { name: 'Preview Container' })).toBeVisible(); - // Click [aria-label="Close"] - await page.locator('[aria-label="Close"]').click(); - await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeVisible(); - await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText( + // Close the Preview window + await page.getByRole('button', { name: 'Close' }).click(); + await expect(page.getByLabel('Object Search Result').first()).toBeVisible(); + await expect(page.getByLabel('Object Search Result').first()).toContainText( `Clock A ${myItemsFolderName} Red Folder Blue Folder` ); - // Click [aria-label="OpenMCT Search"] a >> nth=0 - await page.locator('[aria-label="Search Result"] >> nth=0').click(); - await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden(); + await page.getByLabel('Object Search Result').first().click(); + await expect(page.getByLabel('Object Search Result').first()).toBeHidden(); - // Fill [aria-label="OpenMCT Search"] input[type="search"] - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('foo'); - await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden(); + await grandSearchInput.fill('foo'); + await expect(page.getByLabel('Object Search Result').first()).toBeHidden(); // Click text=Snapshot Save and Finish Editing Save and Continue Editing >> button >> nth=1 - await page - .locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button') - .nth(1) - .click(); + await page.getByRole('button', { name: 'Save' }).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(); + await grandSearchInput.click(); // Fill [aria-label="OpenMCT Search"] [aria-label="Search Input"] - await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').fill('Cl'); + await grandSearchInput.fill('Cl'); await Promise.all([ page.waitForNavigation(), - page.locator('[aria-label="Clock A clock result"] >> text=Clock A').click() + page.getByLabel('OpenMCT Search').getByText('Clock A').click() ]); - await expect(page.locator('.is-object-type-clock')).toBeVisible(); + await expect(page.getByRole('status', { name: 'Clock' })).toBeVisible(); - await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').fill('Disp'); - await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText( + await grandSearchInput.fill('Disp'); + await expect(page.getByLabel('Object Search Result').first()).toContainText( createdObjects.displayLayout.name ); - await expect(page.locator('[aria-label="Search Result"] >> nth=0')).not.toContainText('Folder'); + await expect(page.getByLabel('Object Search Result').first()).not.toContainText('Folder'); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Clock C'); - await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText( + await grandSearchInput.fill('Clock C'); + await expect(page.getByLabel('Object Search Result').first()).toContainText( `Clock C ${myItemsFolderName} Red Folder Blue Folder` ); - await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Cloc'); - await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText( + await grandSearchInput.fill('Cloc'); + await expect(page.getByLabel('Object Search Result').first()).toContainText( `Clock A ${myItemsFolderName} Red Folder Blue Folder` ); - await expect(page.locator('[aria-label="Search Result"] >> nth=1')).toContainText( + await expect(page.getByLabel('Object Search Result').nth(1)).toContainText( `Clock B ${myItemsFolderName} Red Folder Blue Folder` ); - await expect(page.locator('[aria-label="Search Result"] >> nth=2')).toContainText( + await expect(page.getByLabel('Object Search Result').nth(2)).toContainText( `Clock C ${myItemsFolderName} Red Folder Blue Folder` ); - await expect(page.locator('[aria-label="Search Result"] >> nth=3')).toContainText( + await expect(page.getByLabel('Object Search Result').nth(3)).toContainText( `Clock D ${myItemsFolderName} Red Folder Blue Folder` ); + + await grandSearchInput.click(); + await grandSearchInput.fill('Sine'); + }); + + test('Clicking on a search result changes the URL even if the same type is already selected', async ({ + page + }) => { + test.info().annotations.push({ + type: 'issue', + description: 'https://github.com/nasa/openmct/issues/7303' + }); + + const { sineWaveGeneratorAlpha, sineWaveGeneratorBeta } = await createObjectsForSearch(page); + await grandSearchInput.click(); + await grandSearchInput.fill('Sine'); + await waitForSearchCompletion(page); + await page.getByLabel('OpenMCT Search').getByText('Sine Wave Generator Alpha').click(); + const alphaPattern = new RegExp(sineWaveGeneratorAlpha.url.substring(1)); + await expect(page).toHaveURL(alphaPattern); + await grandSearchInput.click(); + await page.getByLabel('OpenMCT Search').getByText('Sine Wave Generator Beta').click(); + const betaPattern = new RegExp(sineWaveGeneratorBeta.url.substring(1)); + await expect(page).toHaveURL(betaPattern); }); test('Validate empty search result', async ({ page }) => { // Invalid search for objects - await page.type('input[type=search]', 'not found'); + await grandSearchInput.fill('not found'); // Wait for search to complete await waitForSearchCompletion(page); // Get the search results - const searchResults = page.locator(searchResultSelector); + const searchResults = page.getByRole('listitem', { name: 'Object Search Result' }); // Verify that no results are found expect(await searchResults.count()).toBe(0); // Verify proper message appears - await expect(page.locator('text=No results found')).toBeVisible(); + await expect(page.getByText('No results found')).toBeVisible(); }); test('Validate single object in search result @couchdb', async ({ page }) => { @@ -153,18 +177,18 @@ test.describe('Grand Search', () => { }); // Full search for object - await page.type('input[type=search]', folderName); + await grandSearchInput.fill(folderName); // Wait for search to complete await waitForSearchCompletion(page); // Get the search results - const searchResults = page.locator(searchResultSelector); + const searchResults = page.getByLabel('Object Search Result'); // Verify that one result is found await expect(searchResults).toBeVisible(); expect(await searchResults.count()).toBe(1); - await expect(searchResults).toHaveText(folderName); + await expect(searchResults).toContainText(folderName); }); test('Search results are debounced @couchdb', async ({ page }) => { @@ -185,7 +209,7 @@ test.describe('Grand Search', () => { }); // Full search for object - await page.type('input[type=search]', 'Clock', { delay: 100 }); + await grandSearchInput.pressSequentially('Clock', { delay: 100 }); // Wait for search to finish await waitForSearchCompletion(page); @@ -194,9 +218,7 @@ test.describe('Grand Search', () => { // 1. batched request for latest telemetry using the bulk API expect(networkRequests.length).toBe(1); - const searchResultDropDown = await page.locator(searchResultDropDownSelector); - - await expect(searchResultDropDown).toContainText('Clock A'); + await expect(page.getByRole('list', { name: 'Object Results' })).toContainText('Clock A'); }); test('Slowly typing after search debounce will abort requests @couchdb', async ({ page }) => { @@ -246,27 +268,40 @@ test.describe('Grand Search', () => { }); // Partial search for objects - await page.type('input[type=search]', 'e928a26e'); + await grandSearchInput.fill('e928a26e'); // Wait for search to finish await waitForSearchCompletion(page); - const searchResultDropDown = page.locator(searchResultDropDownSelector); + const searchResultDropDown = page.getByRole('dialog', { name: 'Search Results' }); // Verify that the search result/s correctly match the search query await expect(searchResultDropDown).toContainText(folderName1); await expect(searchResultDropDown).toContainText(folderName2); // Get the search results - const searchResults = page.locator(searchResultSelector); + const objectSearchResults = page.getByLabel('Object Search Result'); // Verify that two results are found - expect(await searchResults.count()).toBe(2); + expect(await objectSearchResults.count()).toBe(2); }); }); +/** + * Wait for search to complete + * + * @param {import('@playwright/test').Page} page + */ async function waitForSearchCompletion(page) { // Wait loading spinner to disappear - await page.waitForSelector('.search-finished'); + await expect( + page + .getByRole('list', { name: 'Object Results' }) + .or( + page + .getByRole('list', { name: 'Annotation Results' }) + .or(page.getByText('No results found')) + ) + ).toBeVisible(); } /** @@ -306,13 +341,20 @@ async function createObjectsForSearch(page) { parent: blueFolder.uuid }); + const sineWaveGeneratorAlpha = await createDomainObjectWithDefaults(page, { + type: 'Sine Wave Generator', + name: 'Sine Wave Generator Alpha' + }); + + const sineWaveGeneratorBeta = await createDomainObjectWithDefaults(page, { + type: 'Sine Wave Generator', + name: 'Sine Wave Generator Beta' + }); + const displayLayout = await createDomainObjectWithDefaults(page, { type: 'Display Layout' }); - // Go back into edit mode for the display layout - await page.locator('button[title="Edit"]').click(); - return { redFolder, blueFolder, @@ -320,6 +362,8 @@ async function createObjectsForSearch(page) { clockB, clockC, clockD, - displayLayout + displayLayout, + sineWaveGeneratorAlpha, + sineWaveGeneratorBeta }; } diff --git a/e2e/tests/visual-a11y/notification.visual.spec.js b/e2e/tests/visual-a11y/notification.visual.spec.js index 7be4a4e92f..6a5047f084 100644 --- a/e2e/tests/visual-a11y/notification.visual.spec.js +++ b/e2e/tests/visual-a11y/notification.visual.spec.js @@ -45,19 +45,21 @@ test.describe("Visual - Check Notification Info Banner of 'Save successful' @a11 name: 'Default Clock' }); // Click on the div with role="alert" that has "Save successful" text - await page.locator('div[role="alert"]:has-text("Save successful")').click(); + await page.getByRole('alert').filter({ hasText: 'Save successful' }).click(); // Verify there is a div with role="dialog" - expect(await page.locator('div[role="dialog"]').isVisible()).toBe(true); + await expect(page.getByRole('dialog', { name: 'Overlay' })).toBeVisible(); // Verify the div with role="dialog" contains text "Save successful" - expect(await page.locator('div[role="dialog"]').innerText()).toContain('Save successful'); + expect(await page.getByRole('dialog', { name: 'Overlay' }).innerText()).toContain( + 'Save successful' + ); await percySnapshot(page, `Notification banner shows Save successful (theme: '${theme}')`); // Verify there is a button with text "Dismiss" - expect(await page.locator('button:has-text("Dismiss")').isVisible()).toBe(true); + await expect(page.getByText('Dismiss', { exact: true })).toBeVisible(); await percySnapshot(page, `Notification banner shows Dismiss (theme: '${theme}')`); // Click on button with text "Dismiss" - await page.locator('button:has-text("Dismiss")').click(); + await page.getByText('Dismiss', { exact: true }).click(); // Verify there is no div with role="dialog" - expect(await page.locator('div[role="dialog"]').isVisible()).toBe(false); + await expect(page.getByRole('dialog', { name: 'Overlay' })).toBeHidden(); await percySnapshot(page, `Notification banner dismissed (theme: '${theme}')`); }); test.afterEach(async ({ page }, testInfo) => { diff --git a/src/MCT.js b/src/MCT.js index 52e05f312e..35b4390d0b 100644 --- a/src/MCT.js +++ b/src/MCT.js @@ -338,7 +338,7 @@ export class MCT extends EventEmitter { component.$nextTick(() => { this.layout = component; this.app = appLayout; - Browse(this); + this.browseRoutes = new Browse(this); window.addEventListener('beforeunload', this.destroy); this.router.start(); this.emit('start'); diff --git a/src/api/overlays/components/OverlayComponent.vue b/src/api/overlays/components/OverlayComponent.vue index 13b5c6b409..9692bfacf8 100644 --- a/src/api/overlays/components/OverlayComponent.vue +++ b/src/api/overlays/components/OverlayComponent.vue @@ -34,6 +34,7 @@ class="c-overlay__contents js-notebook-snapshot-item-wrapper" tabindex="0" aria-modal="true" + aria-label="Overlay" role="dialog" >
diff --git a/src/plugins/clock/components/ClockComponent.vue b/src/plugins/clock/components/ClockComponent.vue index e3a5ad9049..b2d4558ce3 100644 --- a/src/plugins/clock/components/ClockComponent.vue +++ b/src/plugins/clock/components/ClockComponent.vue @@ -22,7 +22,13 @@