diff --git a/e2e/appActions.js b/e2e/appActions.js index 7b84080bbb..bc1b1a212a 100644 --- a/e2e/appActions.js +++ b/e2e/appActions.js @@ -46,6 +46,7 @@ */ const Buffer = require('buffer').Buffer; +const genUuid = require('uuid').v4; /** * This common function creates a domain object with the default options. It is the preferred way of creating objects @@ -56,6 +57,10 @@ const Buffer = require('buffer').Buffer; * @returns {Promise} An object containing information about the newly created domain object. */ async function createDomainObjectWithDefaults(page, { type, name, parent = 'mine' }) { + if (!name) { + name = `${type}:${genUuid()}`; + } + const parentUrl = await getHashUrlToDomainObject(page, parent); // Navigate to the parent object. This is necessary to create the object @@ -70,11 +75,14 @@ async function createDomainObjectWithDefaults(page, { type, name, parent = 'mine await page.click(`li:text("${type}")`); // Modify the name input field of the domain object to accept 'name' - if (name) { - const nameInput = page.locator('form[name="mctForm"] .first input[type="text"]'); - await nameInput.fill(""); - await nameInput.fill(name); - } + const nameInput = page.locator('form[name="mctForm"] .first input[type="text"]'); + await nameInput.fill(""); + await nameInput.fill(name); + + // Fill the "Notes" section with information about the + // currently running test and its project. + const notesInput = page.locator('form[name="mctForm"] #notes-textarea'); + await notesInput.fill(page.testNotes); // Click OK button and wait for Navigate event await Promise.all([ @@ -96,8 +104,8 @@ async function createDomainObjectWithDefaults(page, { type, name, parent = 'mine } return { - name: name || `Unnamed ${type}`, - uuid: uuid, + name, + uuid, url: objectUrl }; } diff --git a/e2e/helper/notebookUtils.js b/e2e/helper/notebookUtils.js index 5fdd973630..4a26fcd098 100644 --- a/e2e/helper/notebookUtils.js +++ b/e2e/helper/notebookUtils.js @@ -20,6 +20,8 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ +const { createDomainObjectWithDefaults } = require('../appActions'); + const NOTEBOOK_DROP_AREA = '.c-notebook__drag-area'; /** @@ -38,24 +40,17 @@ async function enterTextEntry(page, text) { /** * @param {import('@playwright/test').Page} page */ -async function dragAndDropEmbed(page, myItemsFolderName) { - // Click button:has-text("Create") - await page.locator('button:has-text("Create")').click(); - // Click li:has-text("Sine Wave Generator") - await page.locator('li:has-text("Sine Wave Generator")').click(); - // Click form[name="mctForm"] >> text=My Items - await page.locator(`form[name="mctForm"] >> text=${myItemsFolderName}`).click(); - // Click text=OK - await page.locator('text=OK').click(); - // Click text=Open MCT My Items >> span >> nth=3 - await page.locator(`text=Open MCT ${myItemsFolderName} >> span`).nth(3).click(); - // Click text=Unnamed CUSTOM_NAME - await Promise.all([ - page.waitForNavigation(), - page.locator('text=Unnamed CUSTOM_NAME').click() - ]); - - await page.dragAndDrop('text=UNNAMED SINE WAVE GENERATOR', NOTEBOOK_DROP_AREA); +async function dragAndDropEmbed(page, notebookObject) { + // Create example telemetry object + const swg = await createDomainObjectWithDefaults(page, { + type: "Sine Wave Generator" + }); + // Navigate to notebook + await page.goto(notebookObject.url); + // Expand the tree to reveal the notebook + await page.click('button[title="Show selected item in tree"]'); + // Drag and drop the SWG into the notebook + await page.dragAndDrop(`text=${swg.name}`, NOTEBOOK_DROP_AREA); } // eslint-disable-next-line no-undef diff --git a/e2e/pluginFixtures.js b/e2e/pluginFixtures.js index a3250054d4..90d9a3a25f 100644 --- a/e2e/pluginFixtures.js +++ b/e2e/pluginFixtures.js @@ -126,13 +126,21 @@ exports.test = test.extend({ // This should follow in the Project's configuration. Can be set to 'snow' in playwright config.js theme: [theme, { option: true }], // eslint-disable-next-line no-shadow - page: async ({ page, theme }, use) => { + page: async ({ page, theme }, use, testInfo) => { // eslint-disable-next-line playwright/no-conditional-in-test if (theme === 'snow') { //inject snow theme await page.addInitScript({ path: path.join(__dirname, './helper', './useSnowTheme.js') }); } + // Attach info about the currently running test and its project. + // This will be used by appActions to fill in the created + // domain object's notes. + page.testNotes = [ + `${testInfo.titlePath.join('\n')}`, + `${testInfo.project.name}` + ].join('\n'); + await use(page); }, myItemsFolderName: [myItemsFolderName, { option: true }], @@ -140,22 +148,5 @@ exports.test = test.extend({ openmctConfig: async ({ myItemsFolderName }, use) => { await use({ myItemsFolderName }); } - // objectCreateOptions: [objectCreateOptions, {option: true}], - // eslint-disable-next-line no-shadow - // domainObject: [async ({ page, objectCreateOptions }, use) => { - // // FIXME: This is a false-positive caused by a bug in the eslint-plugin-playwright rule. - // // eslint-disable-next-line playwright/no-conditional-in-test - // if (objectCreateOptions === null) { - // await use(page); - - // return; - // } - - // //Go to baseURL - // await page.goto('./', { waitUntil: 'networkidle' }); - - // const uuid = await getOrCreateDomainObject(page, objectCreateOptions); - // await use({ uuid }); - // }, { auto: true }] }); exports.expect = expect; diff --git a/e2e/tests/framework/appActions.e2e.spec.js b/e2e/tests/framework/appActions.e2e.spec.js index 3a95000ba7..cb8772e274 100644 --- a/e2e/tests/framework/appActions.e2e.spec.js +++ b/e2e/tests/framework/appActions.e2e.spec.js @@ -20,7 +20,7 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -const { test, expect } = require('../../baseFixtures.js'); +const { test, expect } = require('../../pluginFixtures.js'); const { createDomainObjectWithDefaults } = require('../../appActions.js'); test.describe('AppActions', () => { @@ -50,11 +50,11 @@ test.describe('AppActions', () => { }); await page.goto(timer1.url, { waitUntil: 'networkidle' }); - await expect(page.locator('.l-browse-bar__object-name')).toHaveText('Timer Foo'); + await expect(page.locator('.l-browse-bar__object-name')).toHaveText(timer1.name); await page.goto(timer2.url, { waitUntil: 'networkidle' }); - await expect(page.locator('.l-browse-bar__object-name')).toHaveText('Timer Bar'); + await expect(page.locator('.l-browse-bar__object-name')).toHaveText(timer2.name); await page.goto(timer3.url, { waitUntil: 'networkidle' }); - await expect(page.locator('.l-browse-bar__object-name')).toHaveText('Timer Baz'); + await expect(page.locator('.l-browse-bar__object-name')).toHaveText(timer3.name); }); await test.step('Create multiple nested objects in a row', async () => { @@ -74,11 +74,11 @@ test.describe('AppActions', () => { parent: folder2.uuid }); await page.goto(folder1.url, { waitUntil: 'networkidle' }); - await expect(page.locator('.l-browse-bar__object-name')).toHaveText('Folder Foo'); + await expect(page.locator('.l-browse-bar__object-name')).toHaveText(folder1.name); await page.goto(folder2.url, { waitUntil: 'networkidle' }); - await expect(page.locator('.l-browse-bar__object-name')).toHaveText('Folder Bar'); + await expect(page.locator('.l-browse-bar__object-name')).toHaveText(folder2.name); await page.goto(folder3.url, { waitUntil: 'networkidle' }); - await expect(page.locator('.l-browse-bar__object-name')).toHaveText('Folder Baz'); + await expect(page.locator('.l-browse-bar__object-name')).toHaveText(folder3.name); expect(folder1.url).toBe(`${e2eFolder.url}/${folder1.uuid}`); expect(folder2.url).toBe(`${e2eFolder.url}/${folder1.uuid}/${folder2.uuid}`); diff --git a/e2e/tests/framework/exampleTemplate.e2e.spec.js b/e2e/tests/framework/exampleTemplate.e2e.spec.js index 1b8ac44909..d042bebdc5 100644 --- a/e2e/tests/framework/exampleTemplate.e2e.spec.js +++ b/e2e/tests/framework/exampleTemplate.e2e.spec.js @@ -45,7 +45,7 @@ */ // Structure: Some standard Imports. Please update the required pathing. -const { test, expect } = require('../../baseFixtures'); +const { test, expect } = require('../../pluginFixtures'); const { createDomainObjectWithDefaults } = require('../../appActions'); /** @@ -144,5 +144,5 @@ async function renameTimerFrom3DotMenu(page, timerUrl, newNameForTimer) { await page.locator('text=Properties Title Notes >> input[type="text"]').fill(newNameForTimer); // Click Ok button to Save - await page.locator('text=OK').click(); + await page.locator('button:has-text("OK")').click(); } diff --git a/e2e/tests/framework/generateVisualTestData.e2e.spec.js b/e2e/tests/framework/generateVisualTestData.e2e.spec.js index 7cb37719f9..3d304982db 100644 --- a/e2e/tests/framework/generateVisualTestData.e2e.spec.js +++ b/e2e/tests/framework/generateVisualTestData.e2e.spec.js @@ -43,14 +43,14 @@ test('Generate Visual Test Data @localStorage', async ({ page, context }) => { await page.locator('button:has-text("Create")').click(); // add sine wave generator with defaults - await page.locator('li:has-text("Sine Wave Generator")').click(); + await page.locator('li[role="menuitem"]:has-text("Sine Wave Generator")').click(); //Add a 5000 ms Delay await page.locator('[aria-label="Loading Delay \\(ms\\)"]').fill('5000'); await Promise.all([ page.waitForNavigation(), - page.locator('text=OK').click(), + page.locator('button:has-text("OK")').click(), //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); @@ -58,7 +58,7 @@ test('Generate Visual Test Data @localStorage', async ({ page, context }) => { // focus the overlay plot await page.goto(overlayPlot.url); - await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Overlay Plot'); + await expect(page.locator('.l-browse-bar__object-name')).toContainText(overlayPlot.name); //Save localStorage for future test execution await context.storageState({ path: './e2e/test-data/VisualTestData_storage.json' }); }); diff --git a/e2e/tests/functional/couchdb.e2e.spec.js b/e2e/tests/functional/couchdb.e2e.spec.js index b3c2fd918b..9641dbc137 100644 --- a/e2e/tests/functional/couchdb.e2e.spec.js +++ b/e2e/tests/functional/couchdb.e2e.spec.js @@ -25,7 +25,7 @@ * */ -const { test, expect } = require('../../baseFixtures'); +const { test, expect } = require('../../pluginFixtures'); test.describe("CouchDB Status Indicator @couchdb", () => { test.use({ failOnConsoleError: false }); diff --git a/e2e/tests/functional/example/eventGenerator.e2e.spec.js b/e2e/tests/functional/example/eventGenerator.e2e.spec.js index 0db74c480a..2dd7d5061c 100644 --- a/e2e/tests/functional/example/eventGenerator.e2e.spec.js +++ b/e2e/tests/functional/example/eventGenerator.e2e.spec.js @@ -24,7 +24,7 @@ This test suite is dedicated to tests which verify the basic operations surrounding the example event generator. */ -const { test, expect } = require('../../../baseFixtures'); +const { test, expect } = require('../../../pluginFixtures'); const { createDomainObjectWithDefaults } = require('../../../appActions'); test.describe('Example Event Generator CRUD Operations', () => { diff --git a/e2e/tests/functional/example/generator/sineWaveLimitProvider.e2e.spec.js b/e2e/tests/functional/example/generator/sineWaveLimitProvider.e2e.spec.js index 7675406928..ac6f36e3b7 100644 --- a/e2e/tests/functional/example/generator/sineWaveLimitProvider.e2e.spec.js +++ b/e2e/tests/functional/example/generator/sineWaveLimitProvider.e2e.spec.js @@ -96,7 +96,7 @@ test.describe('Sine Wave Generator', () => { //Click text=OK await Promise.all([ page.waitForNavigation(), - page.click('text=OK') + page.click('button:has-text("OK")') ]); // Verify that the Sine Wave Generator is displayed and correct diff --git a/e2e/tests/functional/forms.e2e.spec.js b/e2e/tests/functional/forms.e2e.spec.js index 9da49274ac..b76021be1d 100644 --- a/e2e/tests/functional/forms.e2e.spec.js +++ b/e2e/tests/functional/forms.e2e.spec.js @@ -43,7 +43,7 @@ test.describe('Form Validation Behavior', () => { await page.press('text=Properties Title Notes >> input[type="text"]', 'Tab'); //Required Field Form Validation - await expect(page.locator('text=OK')).toBeDisabled(); + await expect(page.locator('button:has-text("OK")')).toBeDisabled(); await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(/invalid/); //Correct Form Validation for missing title and trigger validation with 'Tab' @@ -52,13 +52,13 @@ test.describe('Form Validation Behavior', () => { await page.press('text=Properties Title Notes >> input[type="text"]', 'Tab'); //Required Field Form Validation is corrected - await expect(page.locator('text=OK')).toBeEnabled(); + await expect(page.locator('button:has-text("OK")')).toBeEnabled(); await expect(page.locator('.c-form-row__state-indicator').first()).not.toHaveClass(/invalid/); //Finish Creating Domain Object await Promise.all([ page.waitForNavigation(), - page.click('text=OK') + page.click('button:has-text("OK")') ]); //Verify that the Domain Object has been created with the corrected title property diff --git a/e2e/tests/functional/moveAndLinkObjects.e2e.spec.js b/e2e/tests/functional/moveAndLinkObjects.e2e.spec.js index 78f20cb65f..6804032673 100644 --- a/e2e/tests/functional/moveAndLinkObjects.e2e.spec.js +++ b/e2e/tests/functional/moveAndLinkObjects.e2e.spec.js @@ -81,7 +81,7 @@ test.describe('Move & link item tests', () => { await page.locator('li.icon-move').click(); await page.locator(`form[name="mctForm"] >> text=${myItemsFolderName}`).click(); - await page.locator('text=OK').click(); + await page.locator('button:has-text("OK")').click(); // Expect that Child Folder is in My Items, the root folder expect(page.locator(`text=${myItemsFolderName} >> nth=0:has(text=Child Folder)`)).toBeTruthy(); @@ -95,11 +95,11 @@ test.describe('Move & link item tests', () => { // Create Telemetry Table let telemetryTable = 'Test Telemetry Table'; await page.locator('button:has-text("Create")').click(); - await page.locator('li:has-text("Telemetry Table")').click(); + await page.locator('li[role="menuitem"]:has-text("Telemetry Table")').click(); await page.locator('text=Properties Title Notes >> input[type="text"]').click(); await page.locator('text=Properties Title Notes >> input[type="text"]').fill(telemetryTable); - await page.locator('text=OK').click(); + await page.locator('button:has-text("OK")').click(); // Finish editing and save Telemetry Table await page.locator('.c-button--menu.c-button--major.icon-save').click(); @@ -108,7 +108,7 @@ test.describe('Move & link item tests', () => { // Create New Folder Basic Domain Object let folder = 'Test Folder'; await page.locator('button:has-text("Create")').click(); - await page.locator('li:has-text("Folder")').click(); + await page.locator('li[role="menuitem"]:has-text("Folder")').click(); await page.locator('text=Properties Title Notes >> input[type="text"]').click(); await page.locator('text=Properties Title Notes >> input[type="text"]').fill(folder); @@ -120,7 +120,7 @@ test.describe('Move & link item tests', () => { // Continue test regardless of assertion and create it in My Items await page.locator(`form[name="mctForm"] >> text=${myItemsFolderName}`).click(); - await page.locator('text=OK').click(); + await page.locator('button:has-text("OK")').click(); // Open My Items await page.locator(`text=Open MCT ${myItemsFolderName} >> span`).nth(3).click(); @@ -196,7 +196,7 @@ test.describe('Move & link item tests', () => { await page.locator('li.icon-link').click(); await page.locator(`form[name="mctForm"] >> text=${myItemsFolderName}`).click(); - await page.locator('text=OK').click(); + await page.locator('button:has-text("OK")').click(); // Expect that Child Folder is in My Items, the root folder expect(page.locator(`text=${myItemsFolderName} >> nth=0:has(text=Child Folder)`)).toBeTruthy(); diff --git a/e2e/tests/functional/plugins/conditionSet/conditionSet.e2e.spec.js b/e2e/tests/functional/plugins/conditionSet/conditionSet.e2e.spec.js index f3f9826aea..0cb927466d 100644 --- a/e2e/tests/functional/plugins/conditionSet/conditionSet.e2e.spec.js +++ b/e2e/tests/functional/plugins/conditionSet/conditionSet.e2e.spec.js @@ -40,11 +40,11 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => { await page.goto('./', { waitUntil: 'networkidle' }); await page.click('button:has-text("Create")'); - await page.locator('li:has-text("Condition Set")').click(); + await page.locator('li[role="menuitem"]:has-text("Condition Set")').click(); await Promise.all([ page.waitForNavigation(), - page.click('text=OK') + page.click('button:has-text("OK")') ]); //Save localStorage for future test execution @@ -163,9 +163,9 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => { // Click hamburger button await page.locator('[title="More options"]').click(); - // Click text=Remove - await page.locator('text=Remove').click(); - await page.locator('text=OK').click(); + // Click 'Remove' and press OK + await page.locator('li[role="menuitem"]:has-text("Remove")').click(); + await page.locator('button:has-text("OK")').click(); //Expect Unnamed Condition Set to be removed in Main View const numberOfConditionSetsAtEnd = await page.locator('a:has-text("Unnamed Condition Set Condition Set")').count(); diff --git a/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js b/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js index 3d6456e2e0..a9c5e56704 100644 --- a/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js +++ b/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js @@ -116,8 +116,8 @@ test.describe('Testing Display Layout @unstable', () => { // Bring up context menu and remove await page.locator('.c-tree__item.is-alias .c-tree__item__name:text("Test Sine Wave Generator")').first().click({ button: 'right' }); - await page.locator('text=Remove').click(); - await page.locator('text=OK').click(); + await page.locator('li[role="menuitem"]:has-text("Remove")').click(); + await page.locator('button:has-text("OK")').click(); // delete @@ -150,7 +150,7 @@ test.describe('Testing Display Layout @unstable', () => { // Bring up context menu and remove await page.locator('.c-tree__item.is-alias .c-tree__item__name:text("Test Sine Wave Generator")').click({ button: 'right' }); await page.locator('text=Remove').click(); - await page.locator('text=OK').click(); + await page.locator('button:has-text("OK")').click(); // navigate back to the display layout to confirm it has been removed await page.locator('.c-tree__item .c-tree__item__name:text("Test Display Layout")').click(); diff --git a/e2e/tests/functional/plugins/imagery/exampleImagery.e2e.spec.js b/e2e/tests/functional/plugins/imagery/exampleImagery.e2e.spec.js index f399daee01..d8ecbf9624 100644 --- a/e2e/tests/functional/plugins/imagery/exampleImagery.e2e.spec.js +++ b/e2e/tests/functional/plugins/imagery/exampleImagery.e2e.spec.js @@ -40,10 +40,10 @@ test.describe('Example Imagery Object', () => { await page.goto('./', { waitUntil: 'networkidle' }); // Create a default 'Example Imagery' object - await createDomainObjectWithDefaults(page, { type: 'Example Imagery' }); + const exampleImagery = await createDomainObjectWithDefaults(page, { type: 'Example Imagery' }); // Verify that the created object is focused - await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery'); + await expect(page.locator('.l-browse-bar__object-name')).toContainText(exampleImagery.name); await page.locator(backgroundImageSelector).hover({trial: true}); }); @@ -188,7 +188,7 @@ test.describe('Example Imagery in Display Layout', () => { await page.click('button:has-text("Create")'); // Click text=Example Imagery - await page.click('text=Example Imagery'); + await page.click('li[role="menuitem"]:has-text("Example Imagery")'); // Clear and set Image load delay to minimum value await page.locator('input[type="number"]').fill(''); @@ -197,7 +197,7 @@ test.describe('Example Imagery in Display Layout', () => { // Click text=OK await Promise.all([ page.waitForNavigation({waitUntil: 'networkidle'}), - page.click('text=OK'), + page.click('button:has-text("OK")'), //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); @@ -275,7 +275,7 @@ test.describe('Example Imagery in Flexible layout', () => { await page.click('button:has-text("Create")'); // Click text=Example Imagery - await page.click('text=Example Imagery'); + await page.click('li[role="menuitem"]:has-text("Example Imagery")'); // Clear and set Image load delay to minimum value await page.locator('input[type="number"]').fill(''); @@ -284,7 +284,7 @@ test.describe('Example Imagery in Flexible layout', () => { // Click text=OK await Promise.all([ page.waitForNavigation({waitUntil: 'networkidle'}), - page.click('text=OK'), + page.click('button:has-text("OK")'), //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); @@ -317,7 +317,7 @@ test.describe('Example Imagery in Tabs View', () => { await page.click('button:has-text("Create")'); // Click text=Example Imagery - await page.click('text=Example Imagery'); + await page.click('li[role="menuitem"]:has-text("Example Imagery")'); // Clear and set Image load delay to minimum value await page.locator('input[type="number"]').fill(''); @@ -326,7 +326,7 @@ test.describe('Example Imagery in Tabs View', () => { // Click text=OK await Promise.all([ page.waitForNavigation({waitUntil: 'networkidle'}), - page.click('text=OK'), + page.click('button:has-text("OK")'), //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); diff --git a/e2e/tests/functional/plugins/notebook/notebook.e2e.spec.js b/e2e/tests/functional/plugins/notebook/notebook.e2e.spec.js index 58e3e0f38d..f44140fe4e 100644 --- a/e2e/tests/functional/plugins/notebook/notebook.e2e.spec.js +++ b/e2e/tests/functional/plugins/notebook/notebook.e2e.spec.js @@ -26,7 +26,7 @@ This test suite is dedicated to tests which verify the basic operations surround // FIXME: Remove this eslint exception once tests are implemented // eslint-disable-next-line no-unused-vars -const { test, expect } = require('../../../../baseFixtures'); +const { test, expect } = require('../../../../pluginFixtures'); const { expandTreePaneItemByName, createDomainObjectWithDefaults } = require('../../../../appActions'); const nbUtils = require('../../../../helper/notebookUtils'); diff --git a/e2e/tests/functional/plugins/notebook/notebookWithCouchDB.e2e.spec.js b/e2e/tests/functional/plugins/notebook/notebookWithCouchDB.e2e.spec.js index 97f5ab3c6c..87a352797d 100644 --- a/e2e/tests/functional/plugins/notebook/notebookWithCouchDB.e2e.spec.js +++ b/e2e/tests/functional/plugins/notebook/notebookWithCouchDB.e2e.spec.js @@ -24,7 +24,7 @@ This test suite is dedicated to tests which verify the basic operations surrounding Notebooks with CouchDB. */ -const { test, expect } = require('../../../../baseFixtures'); +const { test, expect } = require('../../../../pluginFixtures'); const { createDomainObjectWithDefaults } = require('../../../../appActions'); test.describe('Notebook Tests with CouchDB @couchdb', () => { diff --git a/e2e/tests/functional/plugins/notebook/restrictedNotebook.e2e.spec.js b/e2e/tests/functional/plugins/notebook/restrictedNotebook.e2e.spec.js index 8594f58665..6a51238fd2 100644 --- a/e2e/tests/functional/plugins/notebook/restrictedNotebook.e2e.spec.js +++ b/e2e/tests/functional/plugins/notebook/restrictedNotebook.e2e.spec.js @@ -36,27 +36,27 @@ test.describe('Restricted Notebook', () => { }); test('Can be renamed @addInit', async ({ page }) => { - await expect(page.locator('.l-browse-bar__object-name')).toContainText(`Unnamed ${CUSTOM_NAME}`); + await expect(page.locator('.l-browse-bar__object-name')).toContainText(`${notebook.name}`); }); - test('Can be deleted if there are no locked pages @addInit', async ({ page, openmctConfig }) => { + test('Can be deleted if there are no locked pages @addInit', async ({ page }) => { await openObjectTreeContextMenu(page, notebook.url); const menuOptions = page.locator('.c-menu ul'); await expect.soft(menuOptions).toContainText('Remove'); - const restrictedNotebookTreeObject = page.locator(`a:has-text("Unnamed ${CUSTOM_NAME}")`); + const restrictedNotebookTreeObject = page.locator(`a:has-text("${notebook.name}")`); // notebook tree object exists expect.soft(await restrictedNotebookTreeObject.count()).toEqual(1); // Click Remove Text - await page.locator('text=Remove').click(); + await page.locator('li[role="menuitem"]:has-text("Remove")').click(); // Click 'OK' on confirmation window and wait for save banner to appear await Promise.all([ page.waitForNavigation(), - page.locator('text=OK').click(), + page.locator('button:has-text("OK")').click(), page.waitForSelector('.c-message-banner__message') ]); @@ -134,7 +134,7 @@ test.describe('Restricted Notebook with at least one entry and with the page loc // Click text=Ok await Promise.all([ page.waitForNavigation(), - page.locator('text=Ok').click() + page.locator('button:has-text("OK")').click() ]); // deleted page, should no longer exist @@ -145,10 +145,9 @@ test.describe('Restricted Notebook with at least one entry and with the page loc test.describe('Restricted Notebook with a page locked and with an embed @addInit', () => { - test.beforeEach(async ({ page, openmctConfig }) => { - const { myItemsFolderName } = openmctConfig; - await startAndAddRestrictedNotebookObject(page); - await nbUtils.dragAndDropEmbed(page, myItemsFolderName); + test.beforeEach(async ({ page }) => { + const notebook = await startAndAddRestrictedNotebookObject(page); + await nbUtils.dragAndDropEmbed(page, notebook); }); test('Allows embeds to be deleted if page unlocked @addInit', async ({ page }) => { diff --git a/e2e/tests/functional/plugins/notebook/tags.e2e.spec.js b/e2e/tests/functional/plugins/notebook/tags.e2e.spec.js index 792117b3e9..a8a3dd239b 100644 --- a/e2e/tests/functional/plugins/notebook/tags.e2e.spec.js +++ b/e2e/tests/functional/plugins/notebook/tags.e2e.spec.js @@ -36,7 +36,7 @@ async function createNotebookAndEntry(page, iterations = 1) { //Go to baseURL await page.goto('./', { waitUntil: 'networkidle' }); - createDomainObjectWithDefaults(page, { type: 'Notebook' }); + const notebook = createDomainObjectWithDefaults(page, { type: 'Notebook' }); for (let iteration = 0; iteration < iterations; iteration++) { // Create an entry @@ -45,6 +45,8 @@ async function createNotebookAndEntry(page, iterations = 1) { await page.locator(entryLocator).click(); await page.locator(entryLocator).fill(`Entry ${iteration}`); } + + return notebook; } /** @@ -53,7 +55,7 @@ async function createNotebookAndEntry(page, iterations = 1) { * @param {number} [iterations = 1] - the number of entries (and tags) to create */ async function createNotebookEntryAndTags(page, iterations = 1) { - await createNotebookAndEntry(page, iterations); + const notebook = await createNotebookAndEntry(page, iterations); for (let iteration = 0; iteration < iterations; iteration++) { // Hover and click "Add Tag" button @@ -75,6 +77,8 @@ async function createNotebookEntryAndTags(page, iterations = 1) { // Select the "Science" tag await page.locator('[aria-label="Autocomplete Options"] >> text=Science').click(); } + + return notebook; } test.describe('Tagging in Notebooks @addInit', () => { @@ -173,10 +177,10 @@ test.describe('Tagging in Notebooks @addInit', () => { //Go to baseURL await page.goto('./', { waitUntil: 'networkidle' }); - await createDomainObjectWithDefaults(page, { type: 'Clock' }); + const clock = await createDomainObjectWithDefaults(page, { type: 'Clock' }); const ITERATIONS = 4; - await createNotebookEntryAndTags(page, ITERATIONS); + const notebook = await createNotebookEntryAndTags(page, ITERATIONS); for (let iteration = 0; iteration < ITERATIONS; iteration++) { const entryLocator = `[aria-label="Notebook Entry"] >> nth = ${iteration}`; @@ -189,11 +193,11 @@ test.describe('Tagging in Notebooks @addInit', () => { page.goto('./#/browse/mine?hideTree=false'), page.click('.c-disclosure-triangle') ]); - // Click Unnamed Clock - await page.click('text="Unnamed Clock"'); + // Click Clock + await page.click(`text=${clock.name}`); - // Click Unnamed Notebook - await page.click('text="Unnamed Notebook"'); + // Click Notebook + await page.click(`text=${notebook.name}`); for (let iteration = 0; iteration < ITERATIONS; iteration++) { const entryLocator = `[aria-label="Notebook Entry"] >> nth = ${iteration}`; @@ -207,14 +211,13 @@ test.describe('Tagging in Notebooks @addInit', () => { page.waitForLoadState('networkidle') ]); - // Click Unnamed Notebook - await page.click('text="Unnamed Notebook"'); + // Click Notebook + await page.click(`text="${notebook.name}"`); for (let iteration = 0; iteration < ITERATIONS; iteration++) { const entryLocator = `[aria-label="Notebook Entry"] >> nth = ${iteration}`; await expect(page.locator(entryLocator)).toContainText("Science"); await expect(page.locator(entryLocator)).toContainText("Driving"); } - }); }); diff --git a/e2e/tests/functional/plugins/plot/autoscale.e2e.spec.js b/e2e/tests/functional/plugins/plot/autoscale.e2e.spec.js index 81640b95c1..a615254194 100644 --- a/e2e/tests/functional/plugins/plot/autoscale.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/autoscale.e2e.spec.js @@ -110,10 +110,10 @@ async function createSinewaveOverlayPlot(page, myItemsFolderName) { await page.locator('button:has-text("Create")').click(); // add overlay plot with defaults - await page.locator('li:has-text("Overlay Plot")').click(); + await page.locator('li[role="menuitem"]:has-text("Overlay Plot")').click(); await Promise.all([ page.waitForNavigation(), - page.locator('text=OK').click(), + page.locator('button:has-text("OK")').click(), //Wait for Save Banner to appear1 page.waitForSelector('.c-message-banner__message') ]); @@ -129,10 +129,10 @@ async function createSinewaveOverlayPlot(page, myItemsFolderName) { await page.locator('button:has-text("Create")').click(); // add sine wave generator with defaults - await page.locator('li:has-text("Sine Wave Generator")').click(); + await page.locator('li[role="menuitem"]:has-text("Sine Wave Generator")').click(); await Promise.all([ page.waitForNavigation(), - page.locator('text=OK').click(), + page.locator('button:has-text("OK")').click(), //Wait for Save Banner to appear1 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 c76bf82cc9..fa6b43eec1 100644 --- a/e2e/tests/functional/plugins/plot/logPlot.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/logPlot.e2e.spec.js @@ -88,10 +88,10 @@ async function makeOverlayPlot(page, myItemsFolderName) { // create overlay plot await page.locator('button.c-create-button').click(); - await page.locator('li:has-text("Overlay Plot")').click(); + await page.locator('li[role="menuitem"]:has-text("Overlay Plot")').click(); await Promise.all([ page.waitForNavigation({ waitUntil: 'networkidle'}), - page.locator('text=OK').click(), + page.locator('button:has-text("OK")').click(), //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); @@ -106,7 +106,7 @@ async function makeOverlayPlot(page, myItemsFolderName) { // create a sinewave generator await page.locator('button.c-create-button').click(); - await page.locator('li:has-text("Sine Wave Generator")').click(); + await page.locator('li[role="menuitem"]:has-text("Sine Wave Generator")').click(); // set amplitude to 6, offset 4, period 2 @@ -123,7 +123,7 @@ async function makeOverlayPlot(page, myItemsFolderName) { await Promise.all([ page.waitForNavigation({ waitUntil: 'networkidle'}), - page.locator('text=OK').click(), + page.locator('button:has-text("OK")').click(), //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); diff --git a/e2e/tests/functional/plugins/plot/missingPlotObj.e2e.spec.js b/e2e/tests/functional/plugins/plot/missingPlotObj.e2e.spec.js index 0e1eec5c72..a6bdd622e8 100644 --- a/e2e/tests/functional/plugins/plot/missingPlotObj.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/missingPlotObj.e2e.spec.js @@ -88,11 +88,11 @@ async function makeStackedPlot(page, myItemsFolderName) { // create stacked plot await page.locator('button.c-create-button').click(); - await page.locator('li:has-text("Stacked Plot")').click(); + await page.locator('li[role="menuitem"]:has-text("Stacked Plot")').click(); await Promise.all([ page.waitForNavigation({ waitUntil: 'networkidle'}), - page.locator('text=OK').click(), + page.locator('button:has-text("OK")').click(), //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); @@ -146,11 +146,11 @@ async function saveStackedPlot(page) { async function createSineWaveGenerator(page) { //Create sine wave generator await page.locator('button.c-create-button').click(); - await page.locator('li:has-text("Sine Wave Generator")').click(); + await page.locator('li[role="menuitem"]:has-text("Sine Wave Generator")').click(); await Promise.all([ page.waitForNavigation({ waitUntil: 'networkidle'}), - page.locator('text=OK').click(), + page.locator('button:has-text("OK")').click(), //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); diff --git a/e2e/tests/functional/plugins/plot/plotLegendSwatch.e2e.spec.js b/e2e/tests/functional/plugins/plot/plotLegendSwatch.e2e.spec.js index 25a5e348d7..86381f3a85 100644 --- a/e2e/tests/functional/plugins/plot/plotLegendSwatch.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/plotLegendSwatch.e2e.spec.js @@ -68,10 +68,10 @@ async function makeOverlayPlot(page) { // create overlay plot await page.locator('button.c-create-button').click(); - await page.locator('li:has-text("Overlay Plot")').click(); + await page.locator('li[role="menuitem"]:has-text("Overlay Plot")').click(); await Promise.all([ page.waitForNavigation({ waitUntil: 'networkidle'}), - page.locator('text=OK').click(), + page.locator('button:has-text("OK")').click(), //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); @@ -86,13 +86,13 @@ async function makeOverlayPlot(page) { // create a sinewave generator await page.locator('button.c-create-button').click(); - await page.locator('li:has-text("Sine Wave Generator")').click(); + await page.locator('li[role="menuitem"]:has-text("Sine Wave Generator")').click(); // Click OK to make generator await Promise.all([ page.waitForNavigation({ waitUntil: 'networkidle'}), - page.locator('text=OK').click(), + page.locator('button:has-text("OK")').click(), //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); diff --git a/e2e/tests/functional/plugins/plot/plotRendering.e2e.spec.js b/e2e/tests/functional/plugins/plot/plotRendering.e2e.spec.js index 30e8633220..2979a9a3bc 100644 --- a/e2e/tests/functional/plugins/plot/plotRendering.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/plotRendering.e2e.spec.js @@ -25,7 +25,7 @@ * */ -const { test, expect } = require('../../../../baseFixtures'); +const { test, expect } = require('../../../../pluginFixtures'); const { createDomainObjectWithDefaults } = require('../../../../appActions'); test.describe('Plot Integrity Testing @unstable', () => { diff --git a/e2e/tests/functional/plugins/timeConductor/timeConductor.e2e.spec.js b/e2e/tests/functional/plugins/timeConductor/timeConductor.e2e.spec.js index 645c4fc915..14494b5d92 100644 --- a/e2e/tests/functional/plugins/timeConductor/timeConductor.e2e.spec.js +++ b/e2e/tests/functional/plugins/timeConductor/timeConductor.e2e.spec.js @@ -20,7 +20,7 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -const { test, expect } = require('../../../../baseFixtures'); +const { test, expect } = require('../../../../pluginFixtures'); const { setFixedTimeMode, setRealTimeMode, setStartOffset, setEndOffset } = require('../../../../appActions'); test.describe('Time conductor operations', () => { diff --git a/e2e/tests/functional/plugins/timer/timer.e2e.spec.js b/e2e/tests/functional/plugins/timer/timer.e2e.spec.js index 16c6b5defc..9269c0cac2 100644 --- a/e2e/tests/functional/plugins/timer/timer.e2e.spec.js +++ b/e2e/tests/functional/plugins/timer/timer.e2e.spec.js @@ -30,7 +30,7 @@ test.describe('Timer', () => { timer = await createDomainObjectWithDefaults(page, { type: 'timer' }); }); - test('Can perform actions on the Timer', async ({ page, openmctConfig }) => { + test('Can perform actions on the Timer', async ({ page }) => { test.info().annotations.push({ type: 'issue', description: 'https://github.com/nasa/openmct/issues/4313' diff --git a/e2e/tests/functional/search.e2e.spec.js b/e2e/tests/functional/search.e2e.spec.js index a944599691..2aa4116563 100644 --- a/e2e/tests/functional/search.e2e.spec.js +++ b/e2e/tests/functional/search.e2e.spec.js @@ -31,7 +31,7 @@ test.describe('Grand Search', () => { test('Can search for objects, and subsequent search dropdown behaves properly', async ({ page, openmctConfig }) => { const { myItemsFolderName } = openmctConfig; - await createObjectsForSearch(page, myItemsFolderName); + const createdObjects = await createObjectsForSearch(page); // Click [aria-label="OpenMCT Search"] input[type="search"] await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); @@ -41,8 +41,8 @@ test.describe('Grand Search', () => { await expect(page.locator('[aria-label="Search Result"] >> nth=1')).toContainText(`Clock B ${myItemsFolderName} Red Folder Blue Folder`); await expect(page.locator('[aria-label="Search Result"] >> nth=2')).toContainText(`Clock C ${myItemsFolderName} Red Folder Blue Folder`); await expect(page.locator('[aria-label="Search Result"] >> nth=3')).toContainText(`Clock D ${myItemsFolderName} Red Folder Blue Folder`); - // Click text=Elements >> nth=0 - await page.locator('text=Elements').first().click(); + // Click the Elements pool to dismiss the search menu + await page.locator('.l-pane__label:has-text("Elements")').click(); await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden(); await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').click(); @@ -77,7 +77,7 @@ test.describe('Grand Search', () => { await expect(page.locator('.is-object-type-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('Unnamed Display Layout'); + await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(createdObjects.displayLayout.name); await expect(page.locator('[aria-label="Search Result"] >> nth=0')).not.toContainText('Folder'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Clock C'); @@ -185,7 +185,7 @@ async function createFolderObject(page, folderName) { await page.locator('text=Properties Title Notes >> input[type="text"]').fill(folderName); // Create folder object - await page.locator('text=OK').click(); + await page.locator('button:has-text("OK")').click(); } async function waitForSearchCompletion(page) { @@ -197,75 +197,56 @@ async function waitForSearchCompletion(page) { * Creates some domain objects for searching * @param {import('@playwright/test').Page} page */ -async function createObjectsForSearch(page, myItemsFolderName) { +async function createObjectsForSearch(page) { //Go to baseURL await page.goto('./', { waitUntil: 'networkidle' }); - await page.locator('button:has-text("Create")').click(); - await page.locator('li:has-text("Folder") >> nth=1').click(); - await Promise.all([ - page.waitForNavigation(), - await page.locator('text=Properties Title Notes >> input[type="text"]').fill('Red Folder'), - await page.locator(`text=Save In Open MCT ${myItemsFolderName} >> span`).nth(3).click(), - page.locator('button:has-text("OK")').click() - ]); + const redFolder = await createDomainObjectWithDefaults(page, { + type: 'Folder', + name: 'Red Folder' + }); - await page.locator('button:has-text("Create")').click(); - await page.locator('li:has-text("Folder") >> nth=2').click(); - await Promise.all([ - page.waitForNavigation(), - await page.locator('text=Properties Title Notes >> input[type="text"]').fill('Blue Folder'), - await page.locator('form[name="mctForm"] >> text=Red Folder').click(), - page.locator('button:has-text("OK")').click() - ]); + const blueFolder = await createDomainObjectWithDefaults(page, { + type: 'Folder', + name: 'Blue Folder', + parent: redFolder.uuid + }); - await page.locator('button:has-text("Create")').click(); - await page.locator('li[title="A digital clock that uses system time and supports a variety of display formats and timezones."]').click(); - await Promise.all([ - page.waitForNavigation(), - await page.locator('text=Properties Title Notes >> input[type="text"] >> nth=0').fill('Clock A'), - await page.locator('form[name="mctForm"] >> text=Blue Folder').click(), - page.locator('button:has-text("OK")').click() - ]); + const clockA = await createDomainObjectWithDefaults(page, { + type: 'Clock', + name: 'Clock A', + parent: blueFolder.uuid + }); + const clockB = await createDomainObjectWithDefaults(page, { + type: 'Clock', + name: 'Clock B', + parent: blueFolder.uuid + }); + const clockC = await createDomainObjectWithDefaults(page, { + type: 'Clock', + name: 'Clock C', + parent: blueFolder.uuid + }); + const clockD = await createDomainObjectWithDefaults(page, { + type: 'Clock', + name: 'Clock D', + parent: blueFolder.uuid + }); - await page.locator('button:has-text("Create")').click(); - await page.locator('li[title="A digital clock that uses system time and supports a variety of display formats and timezones."]').click(); - await Promise.all([ - page.waitForNavigation(), - await page.locator('text=Properties Title Notes >> input[type="text"] >> nth=0').fill('Clock B'), - await page.locator('form[name="mctForm"] >> text=Blue Folder').click(), - page.locator('button:has-text("OK")').click() - ]); + const displayLayout = await createDomainObjectWithDefaults(page, { + type: 'Display Layout' + }); - await page.locator('button:has-text("Create")').click(); - await page.locator('li[title="A digital clock that uses system time and supports a variety of display formats and timezones."]').click(); - await Promise.all([ - page.waitForNavigation(), - await page.locator('text=Properties Title Notes >> input[type="text"] >> nth=0').fill('Clock C'), - await page.locator('form[name="mctForm"] >> text=Blue Folder').click(), - page.locator('button:has-text("OK")').click() - ]); + // Go back into edit mode for the display layout + await page.locator('button[title="Edit"]').click(); - await page.locator('button:has-text("Create")').click(); - await page.locator('li[title="A digital clock that uses system time and supports a variety of display formats and timezones."]').click(); - await Promise.all([ - page.waitForNavigation(), - await page.locator('text=Properties Title Notes >> input[type="text"] >> nth=0').fill('Clock D'), - await page.locator('form[name="mctForm"] >> text=Blue Folder').click(), - page.locator('button:has-text("OK")').click() - ]); - - await Promise.all([ - page.waitForNavigation(), - page.locator(`a:has-text("${myItemsFolderName}") >> nth=0`).click() - ]); - // Click button:has-text("Create") - await page.locator('button:has-text("Create")').click(); - // Click li:has-text("Notebook") - await page.locator('li:has-text("Display Layout")').click(); - // Click button:has-text("OK") - await Promise.all([ - page.waitForNavigation(), - page.locator('button:has-text("OK")').click() - ]); + return { + redFolder, + blueFolder, + clockA, + clockB, + clockC, + clockD, + displayLayout + }; } diff --git a/e2e/tests/performance/imagery.perf.spec.js b/e2e/tests/performance/imagery.perf.spec.js index 396f249afd..0cbe35bb82 100644 --- a/e2e/tests/performance/imagery.perf.spec.js +++ b/e2e/tests/performance/imagery.perf.spec.js @@ -53,7 +53,7 @@ test.describe('Performance tests', () => { await page.setInputFiles('#fileElem', filePath); // Click text=OK - await page.locator('text=OK').click(); + await page.locator('button:has-text("OK")').click(); await expect(page.locator('a:has-text("Performance Display Layout Display Layout")')).toBeVisible(); diff --git a/src/api/forms/components/controls/TextAreaField.vue b/src/api/forms/components/controls/TextAreaField.vue index 834940b340..25e3c219f1 100644 --- a/src/api/forms/components/controls/TextAreaField.vue +++ b/src/api/forms/components/controls/TextAreaField.vue @@ -27,6 +27,7 @@ :class="model.cssClass" >