diff --git a/.github/workflows/e2e-pr.yml b/.github/workflows/e2e-pr.yml index d90f31c361..b21bf8ce79 100644 --- a/.github/workflows/e2e-pr.yml +++ b/.github/workflows/e2e-pr.yml @@ -30,7 +30,8 @@ jobs: - uses: actions/setup-node@v3 with: node-version: '16' - - run: npx playwright@1.21.1 install + - run: npx playwright@1.23.0 install + - run: npx playwright install chrome-beta - run: npm install - run: npm run test:e2e:full - name: Archive test results diff --git a/.github/workflows/e2e-visual.yml b/.github/workflows/e2e-visual.yml index bd0ec056f5..11c8da3caf 100644 --- a/.github/workflows/e2e-visual.yml +++ b/.github/workflows/e2e-visual.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/setup-node@v3 with: node-version: '16' - - run: npx playwright@1.21.1 install + - run: npx playwright@1.23.0 install - run: npm install - name: Run the e2e visual tests run: npm run test:e2e:visual diff --git a/app.js b/app.js index a1a30ef839..baa951e129 100644 --- a/app.js +++ b/app.js @@ -12,6 +12,7 @@ const express = require('express'); const app = express(); const fs = require('fs'); const request = require('request'); +const __DEV__ = process.env.NODE_ENV === 'development'; // Defaults options.port = options.port || options.p || 8080; @@ -49,14 +50,18 @@ class WatchRunPlugin { } const webpack = require('webpack'); -const webpackConfig = process.env.CI ? require('./webpack.coverage.js') : require('./webpack.dev.js'); -webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin()); -webpackConfig.plugins.push(new WatchRunPlugin()); - -webpackConfig.entry.openmct = [ - 'webpack-hot-middleware/client?reload=true', - webpackConfig.entry.openmct -]; +let webpackConfig; +if (__DEV__) { + webpackConfig = require('./webpack.dev'); + webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin()); + webpackConfig.entry.openmct = [ + 'webpack-hot-middleware/client?reload=true', + webpackConfig.entry.openmct + ]; + webpackConfig.plugins.push(new WatchRunPlugin()); +} else { + webpackConfig = require('./webpack.coverage'); +} const compiler = webpack(webpackConfig); @@ -68,10 +73,12 @@ app.use(require('webpack-dev-middleware')( } )); -app.use(require('webpack-hot-middleware')( - compiler, - {} -)); +if (__DEV__) { + app.use(require('webpack-hot-middleware')( + compiler, + {} + )); +} // Expose index.html for development users. app.get('/', function (req, res) { diff --git a/e2e/playwright-ci.config.js b/e2e/playwright-ci.config.js index 4364d11bd4..a0139f56bf 100644 --- a/e2e/playwright-ci.config.js +++ b/e2e/playwright-ci.config.js @@ -4,6 +4,8 @@ // eslint-disable-next-line no-unused-vars const { devices } = require('@playwright/test'); +const MAX_FAILURES = 5; +const NUM_WORKERS = 2; /** @type {import('@playwright/test').PlaywrightTestConfig} */ const config = { @@ -12,20 +14,20 @@ const config = { testIgnore: '**/*.perf.spec.js', //Ignore performance tests and define in playwright-perfromance.config.js timeout: 60 * 1000, webServer: { - command: 'npm run start', + command: 'cross-env NODE_ENV=test npm run start', url: 'http://localhost:8080/#', timeout: 200 * 1000, - reuseExistingServer: !process.env.CI + reuseExistingServer: false }, - maxFailures: process.env.CI ? 5 : undefined, //Limits failures to 5 to reduce CI Waste - workers: 2, //Limit to 2 for CircleCI Agent + maxFailures: MAX_FAILURES, //Limits failures to 5 to reduce CI Waste + workers: NUM_WORKERS, //Limit to 2 for CircleCI Agent use: { baseURL: 'http://localhost:8080/', headless: true, ignoreHTTPSErrors: true, screenshot: 'only-on-failure', trace: 'on-first-retry', - video: 'on-first-retry' + video: 'off' }, projects: [ { diff --git a/e2e/playwright-local.config.js b/e2e/playwright-local.config.js index 54f59b303e..d79c702b19 100644 --- a/e2e/playwright-local.config.js +++ b/e2e/playwright-local.config.js @@ -12,10 +12,10 @@ const config = { testIgnore: '**/*.perf.spec.js', timeout: 30 * 1000, webServer: { - command: 'npm run start', + command: 'cross-env NODE_ENV=test npm run start', url: 'http://localhost:8080/#', timeout: 120 * 1000, - reuseExistingServer: !process.env.CI + reuseExistingServer: true }, workers: 1, use: { @@ -25,7 +25,7 @@ const config = { ignoreHTTPSErrors: true, screenshot: 'only-on-failure', trace: 'retain-on-failure', - video: 'retain-on-failure' + video: 'off' }, projects: [ { diff --git a/e2e/playwright-performance.config.js b/e2e/playwright-performance.config.js index e9b7e38449..de79304f11 100644 --- a/e2e/playwright-performance.config.js +++ b/e2e/playwright-performance.config.js @@ -2,6 +2,8 @@ // playwright.config.js // @ts-check +const CI = process.env.CI === 'true'; + /** @type {import('@playwright/test').PlaywrightTestConfig} */ const config = { retries: 1, //Only for debugging purposes because trace is enabled only on first retry @@ -9,15 +11,15 @@ const config = { timeout: 60 * 1000, workers: 1, //Only run in serial with 1 worker webServer: { - command: 'npm run start', + command: 'cross-env NODE_ENV=test npm run start', url: 'http://localhost:8080/#', timeout: 200 * 1000, - reuseExistingServer: !process.env.CI + reuseExistingServer: !CI }, use: { browserName: "chromium", baseURL: 'http://localhost:8080/', - headless: Boolean(process.env.CI), //Only if running locally + headless: CI, //Only if running locally ignoreHTTPSErrors: true, screenshot: 'off', trace: 'on-first-retry', diff --git a/e2e/playwright-visual.config.js b/e2e/playwright-visual.config.js index 07758121bd..55570b0493 100644 --- a/e2e/playwright-visual.config.js +++ b/e2e/playwright-visual.config.js @@ -9,7 +9,7 @@ const config = { timeout: 90 * 1000, workers: 1, // visual tests should never run in parallel due to test pollution webServer: { - command: 'npm run start', + command: 'cross-env NODE_ENV=test npm run start', url: 'http://localhost:8080/#', timeout: 200 * 1000, reuseExistingServer: !process.env.CI @@ -21,7 +21,7 @@ const config = { ignoreHTTPSErrors: true, screenshot: 'on', trace: 'off', - video: 'on' + video: 'off' }, reporter: [ ['list'], diff --git a/e2e/tests/branding.e2e.spec.js b/e2e/tests/branding.e2e.spec.js index a37101c8a0..b543abf864 100644 --- a/e2e/tests/branding.e2e.spec.js +++ b/e2e/tests/branding.e2e.spec.js @@ -36,7 +36,7 @@ test.describe('Branding tests', () => { await page.click('.l-shell__app-logo'); // Verify that the NASA Logo Appears - await expect(await page.locator('.c-about__image')).toBeVisible(); + await expect(page.locator('.c-about__image')).toBeVisible(); // Modify the Build information in 'about' Modal const versionInformationLocator = page.locator('ul.t-info.l-info.s-info'); diff --git a/e2e/tests/framework.e2e.spec.js b/e2e/tests/framework.e2e.spec.js new file mode 100644 index 0000000000..b262ddc316 --- /dev/null +++ b/e2e/tests/framework.e2e.spec.js @@ -0,0 +1,55 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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. + *****************************************************************************/ + +/* +This test suite is dedicated to testing our use of the playwright framework as it +relates to how we've extended it (i.e. ./e2e/fixtures.js) and assumptions made in our dev environment +(app.js and ./e2e/webpack-dev-middleware.js) +*/ + +const { test } = require('../fixtures.js'); + +test.describe('fixtures.js tests', () => { + test('Verify that tests fail if console.error is thrown', async ({ page }) => { + test.fail(); + //Go to baseURL + await page.goto('/', { waitUntil: 'networkidle' }); + + //Verify that ../fixtures.js detects console log errors + await Promise.all([ + page.evaluate(() => console.error('This should result in a failure')), + page.waitForEvent('console') // always wait for the event to happen while triggering it! + ]); + + }); + test('Verify that tests pass if console.warn is thrown', async ({ page }) => { + //Go to baseURL + await page.goto('/', { waitUntil: 'networkidle' }); + + //Verify that ../fixtures.js detects console log errors + await Promise.all([ + page.evaluate(() => console.warn('This should result in a pass')), + page.waitForEvent('console') // always wait for the event to happen while triggering it! + ]); + + }); +}); diff --git a/e2e/tests/plugins/condition/condition.e2e.spec.js b/e2e/tests/plugins/condition/condition.e2e.spec.js index 43cd22f591..9662b36926 100644 --- a/e2e/tests/plugins/condition/condition.e2e.spec.js +++ b/e2e/tests/plugins/condition/condition.e2e.spec.js @@ -55,16 +55,13 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => { await context.storageState({ path: './e2e/test-data/recycled_local_storage.json' }); //Set object identifier from url - conditionSetUrl = await page.url(); + conditionSetUrl = page.url(); console.log('conditionSetUrl ' + conditionSetUrl); - getConditionSetIdentifierFromUrl = await conditionSetUrl.split('/').pop().split('?')[0]; + getConditionSetIdentifierFromUrl = conditionSetUrl.split('/').pop().split('?')[0]; console.debug('getConditionSetIdentifierFromUrl ' + getConditionSetIdentifierFromUrl); - await page.close(); - }); - test.afterAll(async ({ browser }) => { - await browser.close(); }); + //Load localStorage for subsequent tests test.use({ storageState: './e2e/test-data/recycled_local_storage.json' }); //Begin suite of tests again localStorage @@ -76,7 +73,7 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => { await expect.soft(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set'); //Assertions on loaded Condition Set in Inspector - await expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy; + expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy(); //Reload Page await Promise.all([ @@ -87,7 +84,7 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => { //Re-verify after reload await expect.soft(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set'); //Assertions on loaded Condition Set in Inspector - await expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy; + expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy(); }); test('condition set object can be modified on @localStorage', async ({ page }) => { @@ -113,18 +110,18 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => { // Verify Inspector properties // Verify Inspector has updated Name property - await expect.soft(page.locator('text=Renamed Condition Set').nth(1)).toBeTruthy(); + expect.soft(page.locator('text=Renamed Condition Set').nth(1)).toBeTruthy(); // Verify Inspector Details has updated Name property - await expect.soft(page.locator('text=Renamed Condition Set').nth(2)).toBeTruthy(); + expect.soft(page.locator('text=Renamed Condition Set').nth(2)).toBeTruthy(); // Verify Tree reflects updated Name proprety // Expand Tree await page.locator('text=Open MCT My Items >> span >> nth=3').click(); // Verify Condition Set Object is renamed in Tree - await expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy(); + expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy(); // Verify Search Tree reflects renamed Name property await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Renamed'); - await expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy(); + expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy(); //Reload Page await Promise.all([ @@ -137,18 +134,18 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => { // Verify Inspector properties // Verify Inspector has updated Name property - await expect.soft(page.locator('text=Renamed Condition Set').nth(1)).toBeTruthy(); + expect.soft(page.locator('text=Renamed Condition Set').nth(1)).toBeTruthy(); // Verify Inspector Details has updated Name property - await expect.soft(page.locator('text=Renamed Condition Set').nth(2)).toBeTruthy(); + expect.soft(page.locator('text=Renamed Condition Set').nth(2)).toBeTruthy(); // Verify Tree reflects updated Name proprety // Expand Tree await page.locator('text=Open MCT My Items >> span >> nth=3').click(); // Verify Condition Set Object is renamed in Tree - await expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy(); + expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy(); // Verify Search Tree reflects renamed Name property await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Renamed'); - await expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy(); + expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy(); }); test('condition set object can be deleted by Search Tree Actions menu on @localStorage', async ({ page }) => { //Navigate to baseURL diff --git a/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js b/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js index 22100fbce4..d4f767be87 100644 --- a/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js +++ b/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js @@ -172,7 +172,8 @@ test.describe('Example Imagery Object', () => { }); - test('Can use the reset button to reset the image', async ({ page }) => { + test('Can use the reset button to reset the image', async ({ page }, testInfo) => { + test.slow(testInfo.project === 'chrome-beta', "This test is slow in chrome-beta"); // wait for zoom animation to finish await page.locator(backgroundImageSelector).hover({trial: true}); @@ -191,16 +192,17 @@ test.describe('Example Imagery Object', () => { expect.soft(zoomedInBoundingBox.height).toBeGreaterThan(initialBoundingBox.height); expect.soft(zoomedInBoundingBox.width).toBeGreaterThan(initialBoundingBox.width); - await zoomResetBtn.click(); // wait for zoom animation to finish - await page.locator(backgroundImageSelector).hover({trial: true}); + // FIXME: The zoom is flakey, sometimes not returning to original dimensions + // https://github.com/nasa/openmct/issues/5491 + await expect.poll(async () => { + await zoomResetBtn.click(); + const boundingBox = await page.locator(backgroundImageSelector).boundingBox(); - const resetBoundingBox = await page.locator(backgroundImageSelector).boundingBox(); - expect.soft(resetBoundingBox.height).toBeLessThan(zoomedInBoundingBox.height); - expect.soft(resetBoundingBox.width).toBeLessThan(zoomedInBoundingBox.width); - - expect.soft(resetBoundingBox.height).toEqual(initialBoundingBox.height); - expect(resetBoundingBox.width).toEqual(initialBoundingBox.width); + return boundingBox; + }, { + timeout: 10 * 1000 + }).toEqual(initialBoundingBox); }); test('Using the zoom features does not pause telemetry', async ({ page }) => { diff --git a/e2e/tests/plugins/notebook/restrictedNotebook.e2e.spec.js b/e2e/tests/plugins/notebook/restrictedNotebook.e2e.spec.js index 37012504a0..18c4653d85 100644 --- a/e2e/tests/plugins/notebook/restrictedNotebook.e2e.spec.js +++ b/e2e/tests/plugins/notebook/restrictedNotebook.e2e.spec.js @@ -35,7 +35,7 @@ test.describe('Restricted Notebook', () => { }); test('Can be renamed @addInit', async ({ page }) => { - await expect.soft(page.locator('.l-browse-bar__object-name')).toContainText(`Unnamed ${CUSTOM_NAME}`); + await expect(page.locator('.l-browse-bar__object-name')).toContainText(`Unnamed ${CUSTOM_NAME}`); }); test('Can be deleted if there are no locked pages @addInit', async ({ page }) => { @@ -52,16 +52,15 @@ test.describe('Restricted Notebook', () => { // Click Remove Text await page.locator('text=Remove').click(); - //Wait until Save Banner is gone + // Click 'OK' on confirmation window and wait for save banner to appear await Promise.all([ page.waitForNavigation(), page.locator('text=OK').click(), page.waitForSelector('.c-message-banner__message') ]); - await page.locator('.c-message-banner__close-button').click(); // has been deleted - expect.soft(await restrictedNotebookTreeObject.count()).toEqual(0); + expect(await restrictedNotebookTreeObject.count()).toEqual(0); }); test('Can be locked if at least one page has one entry @addInit', async ({ page }) => { @@ -69,7 +68,7 @@ test.describe('Restricted Notebook', () => { await enterTextEntry(page); const commitButton = page.locator('button:has-text("Commit Entries")'); - expect.soft(await commitButton.count()).toEqual(1); + expect(await commitButton.count()).toEqual(1); }); }); @@ -81,11 +80,17 @@ test.describe('Restricted Notebook with at least one entry and with the page loc await enterTextEntry(page); await lockPage(page); + // FIXME: Give ample time for the mutation to happen + // https://github.com/nasa/openmct/issues/5409 + // eslint-disable-next-line playwright/no-wait-for-timeout + await page.waitForTimeout(1 * 1000); + // open sidebar await page.locator('button.c-notebook__toggle-nav-button').click(); }); - test('Locked page should now be in a locked state @addInit', async ({ page }) => { + test('Locked page should now be in a locked state @addInit', async ({ page }, testInfo) => { + test.fixme(testInfo.project === 'chrome-beta', "Test is unreliable on chrome-beta"); // main lock message on page const lockMessage = page.locator('text=This page has been committed and cannot be modified or removed'); expect.soft(await lockMessage.count()).toEqual(1); @@ -96,11 +101,9 @@ test.describe('Restricted Notebook with at least one entry and with the page loc // no way to remove a restricted notebook with a locked page await openContextMenuRestrictedNotebook(page); - const menuOptions = page.locator('.c-menu ul'); - await expect.soft(menuOptions).not.toContainText('Remove'); - + await expect(menuOptions).not.toContainText('Remove'); }); test('Can still: add page, rename, add entry, delete unlocked pages @addInit', async ({ page }) => { @@ -139,7 +142,7 @@ test.describe('Restricted Notebook with at least one entry and with the page loc // deleted page, should no longer exist const deletedPageElement = page.locator(`text=${TEST_TEXT_NAME}`); - expect.soft(await deletedPageElement.count()).toEqual(0); + expect(await deletedPageElement.count()).toEqual(0); }); }); @@ -155,7 +158,7 @@ test.describe('Restricted Notebook with a page locked and with an embed @addInit await page.locator('.c-ne__embed__name .c-popup-menu-button').click(); // embed popup menu const embedMenu = page.locator('body >> .c-menu'); - await expect.soft(embedMenu).toContainText('Remove This Embed'); + await expect(embedMenu).toContainText('Remove This Embed'); }); test('Disallows embeds to be deleted if page locked @addInit', async ({ page }) => { @@ -164,7 +167,7 @@ test.describe('Restricted Notebook with a page locked and with an embed @addInit await page.locator('.c-ne__embed__name .c-popup-menu-button').click(); // embed popup menu const embedMenu = page.locator('body >> .c-menu'); - await expect.soft(embedMenu).not.toContainText('Remove This Embed'); + await expect(embedMenu).not.toContainText('Remove This Embed'); }); }); @@ -232,28 +235,18 @@ async function lockPage(page) { await commitButton.click(); //Wait until Lock Banner is visible - await Promise.all([ - page.locator('text=Lock Page').click(), - page.waitForSelector('.c-message-banner__message') - ]); - // Close Lock Banner - await page.locator('.c-message-banner__close-button').click(); - - //artifically wait to avoid mutation delay TODO: https://github.com/nasa/openmct/issues/5409 - // eslint-disable-next-line playwright/no-wait-for-timeout - await page.waitForTimeout(1 * 1000); + await page.locator('text=Lock Page').click(); } /** * @param {import('@playwright/test').Page} page */ async function openContextMenuRestrictedNotebook(page) { - // Click text=Open MCT My Items (This expands the My Items folder to show it's chilren in the tree) - await page.locator('text=Open MCT My Items >> span').nth(3).click(); - - //artifically wait to avoid mutation delay TODO: https://github.com/nasa/openmct/issues/5409 - // eslint-disable-next-line playwright/no-wait-for-timeout - await page.waitForTimeout(1 * 1000); + const myItemsFolder = page.locator('text=Open MCT My Items >> span').nth(3); + const className = await myItemsFolder.getAttribute('class'); + if (!className.includes('c-disclosure-triangle--expanded')) { + await myItemsFolder.click(); + } // Click a:has-text("Unnamed CUSTOM_NAME") await page.locator(`a:has-text("Unnamed ${CUSTOM_NAME}")`).click({ diff --git a/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-panned-chrome-darwin b/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-panned-chrome-darwin index 01850a3bc4..bea4d7c408 100644 Binary files a/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-panned-chrome-darwin and b/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-panned-chrome-darwin differ diff --git a/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-panned-chrome-linux b/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-panned-chrome-linux index 7fb1ec390d..345901fcce 100644 Binary files a/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-panned-chrome-linux and b/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-panned-chrome-linux differ diff --git a/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-prepan-chrome-darwin b/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-prepan-chrome-darwin index 75b1c4d953..fc3db7c140 100644 Binary files a/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-prepan-chrome-darwin and b/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-prepan-chrome-darwin differ diff --git a/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-prepan-chrome-linux b/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-prepan-chrome-linux index 031025d8e0..88e71e7895 100644 Binary files a/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-prepan-chrome-linux and b/e2e/tests/plugins/plot/autoscale.e2e.spec.js-snapshots/autoscale-canvas-prepan-chrome-linux differ diff --git a/e2e/tests/plugins/plot/missingPlotObj.e2e.spec.js b/e2e/tests/plugins/plot/missingPlotObj.e2e.spec.js index e13b786204..a10f990c53 100644 --- a/e2e/tests/plugins/plot/missingPlotObj.e2e.spec.js +++ b/e2e/tests/plugins/plot/missingPlotObj.e2e.spec.js @@ -28,11 +28,12 @@ const { test } = require('../../../fixtures.js'); const { expect } = require('@playwright/test'); test.describe('Handle missing object for plots', () => { - test('Displays empty div for missing stacked plot item', async ({ page }) => { + test('Displays empty div for missing stacked plot item', async ({ page, browserName }) => { + test.fixme(browserName === 'firefox', 'Firefox failing due to console events being missed'); const errorLogs = []; page.on("console", (message) => { - if (message.type() === 'warning') { + if (message.type() === 'warning' && message.text().includes('Missing domain object')) { errorLogs.push(message.text()); } }); @@ -71,7 +72,7 @@ test.describe('Handle missing object for plots', () => { //Check that there is only one stacked item plot with a plot, the missing one will be empty await expect(page.locator(".c-plot--stacked-container:has(.gl-plot)")).toHaveCount(1); //Verify that console.warn is thrown - await expect(errorLogs).toHaveLength(1); + expect(errorLogs).toHaveLength(1); }); }); @@ -94,10 +95,6 @@ async function makeStackedPlot(page) { page.waitForSelector('.c-message-banner__message') ]); - //Wait until Save Banner is gone - await page.locator('.c-message-banner__close-button').click(); - await page.waitForSelector('.c-message-banner__message', { state: 'detached'}); - // save the stacked plot await saveStackedPlot(page); @@ -155,7 +152,4 @@ async function createSineWaveGenerator(page) { //Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') ]); - //Wait until Save Banner is gone - await page.locator('.c-message-banner__close-button').click(); - await page.waitForSelector('.c-message-banner__message', { state: 'detached'}); } diff --git a/e2e/tests/plugins/timer/timer.e2e.spec.js b/e2e/tests/plugins/timer/timer.e2e.spec.js index c910b746f2..3c8a051a90 100644 --- a/e2e/tests/plugins/timer/timer.e2e.spec.js +++ b/e2e/tests/plugins/timer/timer.e2e.spec.js @@ -140,6 +140,7 @@ async function triggerTimer3dotMenuAction(page, action) { * @param {TimerViewAction} action */ async function triggerTimerViewAction(page, action) { + await page.locator('.c-timer').hover({trial: true}); const buttonTitle = buttonTitleFromAction(action); await page.click(`button[title="${buttonTitle}"]`); assertTimerStateAfterAction(page, action); diff --git a/e2e/tests/visual/generateVisualTestData.e2e.spec.js b/e2e/tests/visual/generateVisualTestData.e2e.spec.js index 215c8b92e2..fc67dab723 100644 --- a/e2e/tests/visual/generateVisualTestData.e2e.spec.js +++ b/e2e/tests/visual/generateVisualTestData.e2e.spec.js @@ -52,9 +52,6 @@ test('Generate Visual Test Data @localStorage', async ({ page, context }) => { //Wait for Save Banner to appear1 page.waitForSelector('.c-message-banner__message') ]); - //Wait until Save Banner is gone - await page.locator('.c-message-banner__close-button').click(); - await page.waitForSelector('.c-message-banner__message', { state: 'detached'}); // save (exit edit mode) await page.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button').nth(1).click(); @@ -69,18 +66,12 @@ test('Generate Visual Test Data @localStorage', async ({ page, context }) => { //Add a 5000 ms Delay await page.locator('[aria-label="Loading Delay \\(ms\\)"]').fill('5000'); - // Click on My Items in Tree. Workaround for https://github.com/nasa/openmct/issues/5184 - await page.click('form[name="mctForm"] a:has-text("Overlay Plot")'); - await Promise.all([ page.waitForNavigation(), page.locator('text=OK').click(), //Wait for Save Banner to appear1 page.waitForSelector('.c-message-banner__message') ]); - //Wait until Save Banner is gone - await page.locator('.c-message-banner__close-button').click(); - await page.waitForSelector('.c-message-banner__message', { state: 'detached'}); // focus the overlay plot await page.locator('text=Open MCT My Items >> span').nth(3).click(); diff --git a/package.json b/package.json index 5e11492516..0e00d4fe1c 100644 --- a/package.json +++ b/package.json @@ -88,8 +88,8 @@ "build:coverage": "webpack --config webpack.coverage.js", "build:watch": "webpack --config webpack.dev.js --watch", "info": "npx envinfo --system --browsers --npmPackages --binaries --languages --markdown", - "test": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run", - "test:firefox": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run --browsers=FirefoxHeadless", + "test": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run", + "test:firefox": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run --browsers=FirefoxHeadless", "test:debug": "cross-env NODE_ENV=debug karma start --no-single-run", "test:e2e": "npx playwright test", "test:e2e:ci": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome smoke branding default condition timeConductor clock exampleImagery persistence performance grandsearch notebook/tags", @@ -98,7 +98,7 @@ "test:e2e:visual": "percy exec --config ./e2e/.percy.yml -- npx playwright test --config=e2e/playwright-visual.config.js", "test:e2e:full": "npx playwright test --config=e2e/playwright-ci.config.js", "test:perf": "npx playwright test --config=e2e/playwright-performance.config.js", - "test:watch": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --no-single-run", + "test:watch": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --no-single-run", "jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api", "update-about-dialog-copyright": "perl -pi -e 's/20\\d\\d\\-202\\d/2014\\-2022/gm' ./src/ui/layout/AboutDialog.vue", "update-copyright-date": "npm run update-about-dialog-copyright && grep -lr --null --include=*.{js,scss,vue,ts,sh,html,md,frag} 'Copyright (c) 20' . | xargs -r0 perl -pi -e 's/Copyright\\s\\(c\\)\\s20\\d\\d\\-20\\d\\d/Copyright \\(c\\)\\ 2014\\-2022/gm'", diff --git a/webpack.coverage.js b/webpack.coverage.js index 3d96130a25..cef2c5fe98 100644 --- a/webpack.coverage.js +++ b/webpack.coverage.js @@ -2,10 +2,12 @@ // instrumentation using babel-plugin-istanbul (see babel.coverage.js) const config = require('./webpack.dev'); - const path = require('path'); - const vueLoaderRule = config.module.rules.find(r => r.use === 'vue-loader'); +// eslint-disable-next-line no-undef +const CI = process.env.CI === 'true'; + +config.devtool = CI ? false : undefined; vueLoaderRule.use = { loader: 'vue-loader'