From 2e1ede1427762b3cd6270247430a0fb033944216 Mon Sep 17 00:00:00 2001 From: John Hill Date: Fri, 29 Jul 2022 17:35:43 -0700 Subject: [PATCH] Add Visual Test for Snow Theme and add visual tests to PR execution (#5570) --- .circleci/config.yml | 28 +++- .github/workflows/e2e-visual.yml | 25 ---- e2e/appActions.js | 2 +- e2e/helper/useSnowTheme.js | 30 +++++ e2e/playwright-ci.config.js | 1 + e2e/playwright-visual.config.js | 33 ++++- e2e/pluginFixtures.js | 30 +++++ e2e/tests/framework/baseFixtures.e2e.spec.js | 4 +- e2e/tests/visual/addInit.visual.spec.js | 24 ++-- .../visual/controlledClock.visual.spec.js | 16 +-- e2e/tests/visual/default.visual.spec.js | 123 +++++------------- e2e/tests/visual/search.visual.spec.js | 81 +++++------- package.json | 4 +- 13 files changed, 195 insertions(+), 206 deletions(-) delete mode 100644 .github/workflows/e2e-visual.yml create mode 100644 e2e/helper/useSnowTheme.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 07687b0c4d..ad7d81143a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,6 +5,7 @@ executors: - image: mcr.microsoft.com/playwright:v1.23.0-focal environment: NODE_ENV: development # Needed to ensure 'dist' folder created and devDependencies installed + PERCY_POSTINSTALL_BROWSER: 'true' # Needed to store the percy browser in cache deps parameters: BUST_CACHE: description: "Set this with the CircleCI UI Trigger Workflow button (boolean = true) to bust the cache!" @@ -64,8 +65,8 @@ commands: suite: type: string steps: - - run: npm run cov:e2e:report - - run: npm run cov:e2e:<>:publish + - run: npm run cov:e2e:report || true + - run: npm run cov:e2e:<>:publish orbs: node: circleci/node@4.9.0 browser-tools: circleci/browser-tools@1.3.0 @@ -153,6 +154,22 @@ jobs: - store_artifacts: path: html-test-results - generate_and_store_version_and_filesystem_artifacts + visual-test: + parameters: + node-version: + type: string + executor: pw-focal-development + steps: + - build_and_install: + node-version: <> + - run: npm run test:e2e:visual + - store_test_results: + path: test-results/results.xml + - store_artifacts: + path: test-results + - store_artifacts: + path: html-test-results + - generate_and_store_version_and_filesystem_artifacts workflows: overall-circleci-commit-status: #These jobs run on every commit jobs: @@ -168,6 +185,9 @@ workflows: suite: stable - perf-test: node-version: lts/gallium + - visual-test: + node-version: lts/gallium + the-nightly: #These jobs do not run on PRs, but against master at night jobs: - unit-test: @@ -185,6 +205,10 @@ workflows: name: e2e-full-nightly node-version: lts/gallium suite: full + - perf-test: + node-version: lts/gallium + - visual-test: + node-version: lts/gallium triggers: - schedule: cron: "0 0 * * *" diff --git a/.github/workflows/e2e-visual.yml b/.github/workflows/e2e-visual.yml deleted file mode 100644 index 11c8da3caf..0000000000 --- a/.github/workflows/e2e-visual.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: "e2e-visual" -on: - workflow_dispatch: - pull_request: - types: - - labeled - - opened - schedule: - - cron: '28 21 * * 1-5' - -jobs: - e2e-visual: - if: ${{ github.event.label.name == 'pr:visual' }} || ${{ github.event.workflow_dispatch }} || ${{ github.event.schedule }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: '16' - - run: npx playwright@1.23.0 install - - run: npm install - - name: Run the e2e visual tests - run: npm run test:e2e:visual - env: - PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }} diff --git a/e2e/appActions.js b/e2e/appActions.js index 0d9963aab3..c119d0c034 100644 --- a/e2e/appActions.js +++ b/e2e/appActions.js @@ -57,7 +57,7 @@ async function createDomainObjectWithDefaults(page, type, name) { // Click OK button and wait for Navigate event await Promise.all([ - page.waitForNavigation(), + page.waitForLoadState(), page.click('[aria-label="Save"]'), // Wait for Save Banner to appear page.waitForSelector('.c-message-banner__message') diff --git a/e2e/helper/useSnowTheme.js b/e2e/helper/useSnowTheme.js new file mode 100644 index 0000000000..5656568686 --- /dev/null +++ b/e2e/helper/useSnowTheme.js @@ -0,0 +1,30 @@ +/***************************************************************************** + * 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 should be used to install the Snow theme for Open MCT. Espresso is the default +// e.g. +// await page.addInitScript({ path: path.join(__dirname, 'useSnowTheme.js') }); + +document.addEventListener('DOMContentLoaded', () => { + const openmct = window.openmct; + openmct.install(openmct.plugins.Snow()); +}); diff --git a/e2e/playwright-ci.config.js b/e2e/playwright-ci.config.js index 7e9bd0b9d8..aeff668823 100644 --- a/e2e/playwright-ci.config.js +++ b/e2e/playwright-ci.config.js @@ -32,6 +32,7 @@ const config = { projects: [ { name: 'chrome', + testMatch: '**/*.e2e.spec.js', // only run e2e tests use: { browserName: 'chromium' } diff --git a/e2e/playwright-visual.config.js b/e2e/playwright-visual.config.js index 55570b0493..417b04cf1d 100644 --- a/e2e/playwright-visual.config.js +++ b/e2e/playwright-visual.config.js @@ -2,12 +2,13 @@ // playwright.config.js // @ts-check -/** @type {import('@playwright/test').PlaywrightTestConfig} */ +/** @type {import('@playwright/test').PlaywrightTestConfig<{ theme: string }>} */ const config = { retries: 0, // visual tests should never retry due to snapshot comparison errors testDir: 'tests/visual', - timeout: 90 * 1000, - workers: 1, // visual tests should never run in parallel due to test pollution + testMatch: '**/*.visual.spec.js', // only run visual tests + timeout: 60 * 1000, + workers: 2, //Limit to 2 for CircleCI Agent webServer: { command: 'cross-env NODE_ENV=test npm run start', url: 'http://localhost:8080/#', @@ -15,17 +16,35 @@ const config = { reuseExistingServer: !process.env.CI }, use: { - browserName: "chromium", baseURL: 'http://localhost:8080/', - headless: true, // this needs to remain headless to avoid visual changes due to GPU + headless: true, // this needs to remain headless to avoid visual changes due to GPU rendering in headed browsers ignoreHTTPSErrors: true, screenshot: 'on', - trace: 'off', + trace: 'on', video: 'off' }, + projects: [ + { + name: 'chrome', + use: { + browserName: 'chromium' + } + }, + { + name: 'chrome-snow-theme', + use: { + browserName: 'chromium', + theme: 'snow' + } + } + ], reporter: [ ['list'], - ['junit', { outputFile: 'test-results/results.xml' }] + ['junit', { outputFile: 'test-results/results.xml' }], + ['html', { + open: 'on-failure', + outputFolder: '../html-test-results' //Must be in different location due to https://github.com/microsoft/playwright/issues/12840 + }] ] }; diff --git a/e2e/pluginFixtures.js b/e2e/pluginFixtures.js index 101cd339ac..a3250054d4 100644 --- a/e2e/pluginFixtures.js +++ b/e2e/pluginFixtures.js @@ -28,6 +28,7 @@ const { test, expect } = require('./baseFixtures'); // const { createDomainObjectWithDefaults } = require('./appActions'); +const path = require('path'); /** * @typedef {Object} ObjectCreateOptions @@ -95,6 +96,23 @@ const { test, expect } = require('./baseFixtures'); */ // const objectCreateOptions = null; +/** + * The default theme for VIPER and Open MCT is the 'espresso' theme. Overriding this value with 'snow' in our playwright config.js + * will override the default theme by injecting the 'snow' theme on launch. + * + * ### Example: + * ```js + * projects: [ + * { + * name: 'chrome-snow-theme', + * use: { + * browserName: 'chromium', + * theme: 'snow' + * ``` + * @type {'snow' | 'espresso'} + */ +const theme = 'espresso'; + /** * The name of the "My Items" folder in the domain object tree. * @@ -105,6 +123,18 @@ const { test, expect } = require('./baseFixtures'); const myItemsFolderName = "My Items"; 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) => { + // 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') }); + } + + await use(page); + }, myItemsFolderName: [myItemsFolderName, { option: true }], // eslint-disable-next-line no-shadow openmctConfig: async ({ myItemsFolderName }, use) => { diff --git a/e2e/tests/framework/baseFixtures.e2e.spec.js b/e2e/tests/framework/baseFixtures.e2e.spec.js index 16b74a8863..86ae7c7d30 100644 --- a/e2e/tests/framework/baseFixtures.e2e.spec.js +++ b/e2e/tests/framework/baseFixtures.e2e.spec.js @@ -29,7 +29,7 @@ relates to how we've extended it (i.e. ./e2e/baseFixtures.js) and assumptions ma const { test } = require('../../baseFixtures.js'); test.describe('baseFixtures tests', () => { - test('Verify that tests fail if console.error is thrown @framework', async ({ page }) => { + test('Verify that tests fail if console.error is thrown', async ({ page }) => { test.fail(); //Go to baseURL await page.goto('./', { waitUntil: 'networkidle' }); @@ -41,7 +41,7 @@ test.describe('baseFixtures tests', () => { ]); }); - test('Verify that tests pass if console.warn is thrown @framework', async ({ page }) => { + test('Verify that tests pass if console.warn is thrown', async ({ page }) => { //Go to baseURL await page.goto('./', { waitUntil: 'networkidle' }); diff --git a/e2e/tests/visual/addInit.visual.spec.js b/e2e/tests/visual/addInit.visual.spec.js index 71e8a34616..5a04c253e2 100644 --- a/e2e/tests/visual/addInit.visual.spec.js +++ b/e2e/tests/visual/addInit.visual.spec.js @@ -32,39 +32,31 @@ Note: Larger testsuite sizes are OK due to the setup time associated with these */ // eslint-disable-next-line no-unused-vars -const { test, expect } = require('../../baseFixtures.js'); +const { test, expect } = require('../../pluginFixtures'); +const { createDomainObjectWithDefaults } = require('../../appActions'); const percySnapshot = require('@percy/playwright'); const path = require('path'); -const VISUAL_GRACE_PERIOD = 5 * 1000; //Lets the application "simmer" before the snapshot is taken - const CUSTOM_NAME = 'CUSTOM_NAME'; test.describe('Visual - addInit', () => { test.use({ clockOptions: { - shouldAdvanceTime: true + now: 0, //Set browser clock to UNIX Epoch + shouldAdvanceTime: false //Don't advance the clock } }); - test('Restricted Notebook is visually correct @addInit', async ({ page }) => { + test('Restricted Notebook is visually correct @addInit @unstable', async ({ page, theme }) => { // eslint-disable-next-line no-undef await page.addInitScript({ path: path.join(__dirname, '../../helper', './addInitRestrictedNotebook.js') }); //Go to baseURL await page.goto('./#/browse/mine?hideTree=true', { waitUntil: 'networkidle' }); - //Click the Create button - await page.click('button:has-text("Create")'); - // Click text=CUSTOM_NAME - await page.click(`text=${CUSTOM_NAME}`); - // Click text=OK - await Promise.all([ - page.waitForNavigation({waitUntil: 'networkidle'}), - page.click('text=OK') - ]); + + await createDomainObjectWithDefaults(page, CUSTOM_NAME); // Take a snapshot of the newly created CUSTOM_NAME notebook - await page.waitForTimeout(VISUAL_GRACE_PERIOD); - await percySnapshot(page, 'Restricted Notebook with CUSTOM_NAME'); + await percySnapshot(page, `Restricted Notebook with CUSTOM_NAME (theme: '${theme}')`); }); }); diff --git a/e2e/tests/visual/controlledClock.visual.spec.js b/e2e/tests/visual/controlledClock.visual.spec.js index f753590c07..c4d6b57679 100644 --- a/e2e/tests/visual/controlledClock.visual.spec.js +++ b/e2e/tests/visual/controlledClock.visual.spec.js @@ -25,27 +25,21 @@ Collection of Visual Tests set to run in a default context. The tests within thi are only meant to run against openmct's app.js started by `npm run start` within the `./e2e/playwright-visual.config.js` file. -These should only use functional expect statements to verify assumptions about the state -in a test and not for functional verification of correctness. Visual tests are not supposed -to "fail" on assertions. Instead, they should be used to detect changes between builds or branches. - -Note: Larger testsuite sizes are OK due to the setup time associated with these tests. */ -const { test, expect } = require('../../baseFixtures.js'); +const { test, expect } = require('../../pluginFixtures'); const percySnapshot = require('@percy/playwright'); -test.describe('Visual - Controlled Clock', () => { +test.describe('Visual - Controlled Clock @localStorage', () => { test.use({ storageState: './e2e/test-data/VisualTestData_storage.json', clockOptions: { now: 0, //Set browser clock to UNIX Epoch - shouldAdvanceTime: false, //Don't advance the clock - toFake: ["setTimeout", "nextTick"] + shouldAdvanceTime: false //Don't advance the clock } }); - test('Overlay Plot Loading Indicator @localstorage', async ({ page }) => { + test('Overlay Plot Loading Indicator @localStorage', async ({ page, theme }) => { // Go to baseURL await page.goto('./#/browse/mine?hideTree=true', { waitUntil: 'networkidle' }); @@ -57,6 +51,6 @@ test.describe('Visual - Controlled Clock', () => { await page.locator('canvas >> nth=1').hover({trial: true}); //Take snapshot of Sine Wave Generator within Overlay Plot - await percySnapshot(page, 'SineWaveInOverlayPlot'); + await percySnapshot(page, `SineWaveInOverlayPlot (theme: '${theme}')`); }); }); diff --git a/e2e/tests/visual/default.visual.spec.js b/e2e/tests/visual/default.visual.spec.js index 747f9fbf18..8b67c9326e 100644 --- a/e2e/tests/visual/default.visual.spec.js +++ b/e2e/tests/visual/default.visual.spec.js @@ -32,85 +32,62 @@ to "fail" on assertions. Instead, they should be used to detect changes between Note: Larger testsuite sizes are OK due to the setup time associated with these tests. */ -const { test, expect } = require('../../baseFixtures.js'); +const { test, expect } = require('../../pluginFixtures'); const percySnapshot = require('@percy/playwright'); -const VISUAL_GRACE_PERIOD = 5 * 1000; //Lets the application "simmer" before the snapshot is taken +const { createDomainObjectWithDefaults } = require('../../appActions'); test.describe('Visual - Default', () => { + test.beforeEach(async ({ page }) => { + //Go to baseURL and Hide Tree + await page.goto('./#/browse/mine?hideTree=true', { waitUntil: 'networkidle' }); + }); test.use({ clockOptions: { - now: 0, - shouldAdvanceTime: true + now: 0, //Set browser clock to UNIX Epoch + shouldAdvanceTime: false //Don't advance the clock } }); - test('Visual - Root and About', async ({ page }) => { - // Go to baseURL - await page.goto('./#/browse/mine?hideTree=true', { waitUntil: 'networkidle' }); - + test('Visual - Root and About', async ({ page, theme }) => { // Verify that Create button is actionable await expect(page.locator('button:has-text("Create")')).toBeEnabled(); // Take a snapshot of the Dashboard - await page.waitForTimeout(VISUAL_GRACE_PERIOD); - await percySnapshot(page, 'Root'); + await percySnapshot(page, `Root (theme: '${theme}')`); // Click About button await page.click('.l-shell__app-logo'); // Modify the Build information in 'about' to be consistent run-over-run - const versionInformationLocator = page.locator('ul.t-info.l-info.s-info'); + const versionInformationLocator = page.locator('ul.t-info.l-info.s-info').first(); await expect(versionInformationLocator).toBeEnabled(); await versionInformationLocator.evaluate(node => node.innerHTML = '
  • Version: visual-snapshot
  • Build Date: Mon Nov 15 2021 08:07:51 GMT-0800 (Pacific Standard Time)
  • Revision: 93049cdbc6c047697ca204893db9603b864b8c9f
  • Branch: master
  • '); // Take a snapshot of the About modal - await page.waitForTimeout(VISUAL_GRACE_PERIOD); - await percySnapshot(page, 'About'); + await percySnapshot(page, `About (theme: '${theme}')`); }); - test('Visual - Default Condition Set', async ({ page }) => { - //Go to baseURL - await page.goto('/', { waitUntil: 'networkidle' }); + test('Visual - Default Condition Set', async ({ page, theme }) => { - //Click the Create button - await page.click('button:has-text("Create")'); - - // Click text=Condition Set - await page.click('text=Condition Set'); - - // Click text=OK - await page.click('text=OK'); + await createDomainObjectWithDefaults(page, 'Condition Set'); // Take a snapshot of the newly created Condition Set object - await page.waitForTimeout(VISUAL_GRACE_PERIOD); - await percySnapshot(page, 'Default Condition Set'); + await percySnapshot(page, `Default Condition Set (theme: '${theme}')`); }); - test.fixme('Visual - Default Condition Widget', async ({ page }) => { + test.fixme('Visual - Default Condition Widget', async ({ page, theme }) => { test.info().annotations.push({ type: 'issue', description: 'https://github.com/nasa/openmct/issues/5349' }); - //Go to baseURL - await page.goto('/', { waitUntil: 'networkidle' }); - //Click the Create button - await page.click('button:has-text("Create")'); - - // Click text=Condition Widget - await page.click('text=Condition Widget'); - - // Click text=OK - await page.click('text=OK'); + await createDomainObjectWithDefaults(page, 'Condition Widget'); // Take a snapshot of the newly created Condition Widget object - await page.waitForTimeout(VISUAL_GRACE_PERIOD); - await percySnapshot(page, 'Default Condition Widget'); + await percySnapshot(page, `Default Condition Widget (theme: '${theme}')`); }); - test('Visual - Time Conductor start time is less than end time', async ({ page }) => { - //Go to baseURL - await page.goto('/', { waitUntil: 'networkidle' }); + test('Visual - Time Conductor start time is less than end time', async ({ page, theme }) => { const year = new Date().getFullYear(); let startDate = 'xxxx-01-01 01:00:00.000Z'; @@ -123,16 +100,14 @@ test.describe('Visual - Default', () => { await page.locator('input[type="text"]').first().fill(startDate.toString()); // verify no error msg - await page.waitForTimeout(VISUAL_GRACE_PERIOD); - await percySnapshot(page, 'Default Time conductor'); + await percySnapshot(page, `Default Time conductor (theme: '${theme}')`); startDate = (year + 1) + startDate.substring(4); await page.locator('input[type="text"]').first().fill(startDate.toString()); await page.locator('input[type="text"]').nth(1).click(); // verify error msg for start time (unable to capture snapshot of popup) - await page.waitForTimeout(VISUAL_GRACE_PERIOD); - await percySnapshot(page, 'Start time error'); + await percySnapshot(page, `Start time error (theme: '${theme}')`); startDate = (year - 1) + startDate.substring(4); await page.locator('input[type="text"]').first().fill(startDate.toString()); @@ -143,79 +118,51 @@ test.describe('Visual - Default', () => { await page.locator('input[type="text"]').first().click(); // verify error msg for end time (unable to capture snapshot of popup) - await page.waitForTimeout(VISUAL_GRACE_PERIOD); - await percySnapshot(page, 'End time error'); + await percySnapshot(page, `End time error (theme: '${theme}')`); }); - test('Visual - Sine Wave Generator Form', async ({ page }) => { - //Go to baseURL - await page.goto('/', { waitUntil: 'networkidle' }); - + test('Visual - Sine Wave Generator Form', async ({ page, theme }) => { //Click the Create button await page.click('button:has-text("Create")'); // Click text=Sine Wave Generator await page.click('text=Sine Wave Generator'); - await page.waitForTimeout(VISUAL_GRACE_PERIOD); - await percySnapshot(page, 'Default Sine Wave Generator Form'); + await percySnapshot(page, `Default Sine Wave Generator Form (theme: '${theme}')`); await page.locator('.field.control.l-input-sm input').first().click(); await page.locator('.field.control.l-input-sm input').first().fill(''); // Validate red x mark - await page.waitForTimeout(VISUAL_GRACE_PERIOD); - await percySnapshot(page, 'removed amplitude property value'); + await percySnapshot(page, `removed amplitude property value (theme: '${theme}')`); }); - test('Visual - Save Successful Banner', async ({ page }) => { - //Go to baseURL - await page.goto('/', { waitUntil: 'networkidle' }); + test('Visual - Save Successful Banner', async ({ page, theme }) => { + await createDomainObjectWithDefaults(page, 'Timer'); - //Click the Create button - await page.click('button:has-text("Create")'); - - //NOTE Something other than example imagery - await page.click('text=Timer'); - - // Click text=OK - await page.click('text=OK'); await page.locator('.c-message-banner__message').hover({ trial: true }); - await percySnapshot(page, 'Banner message shown'); + await percySnapshot(page, `Banner message shown (theme: '${theme}')`); //Wait until Save Banner is gone + await page.locator('.c-message-banner__close-button').click(); await page.waitForSelector('.c-message-banner__message', { state: 'detached'}); - await percySnapshot(page, 'Banner message gone'); + await percySnapshot(page, `Banner message gone (theme: '${theme}')`); }); - test('Visual - Display Layout Icon is correct', async ({ page }) => { - //Go to baseURL - await page.goto('/', { waitUntil: 'networkidle' }); - + test('Visual - Display Layout Icon is correct', async ({ page, theme }) => { //Click the Create button await page.click('button:has-text("Create")'); //Hover on Display Layout option. await page.locator('text=Display Layout').hover(); - await percySnapshot(page, 'Display Layout Create Menu'); + await percySnapshot(page, `Display Layout Create Menu (theme: '${theme}')`); }); - test('Visual - Default Gauge is correct', async ({ page }) => { - - //Go to baseURL - await page.goto('/', { waitUntil: 'networkidle' }); - - //Click the Create button - await page.click('button:has-text("Create")'); - - await page.click('text=Gauge'); - - await page.click('text=OK'); + test('Visual - Default Gauge is correct', async ({ page, theme }) => { + await createDomainObjectWithDefaults(page, 'Gauge'); // Take a snapshot of the newly created Gauge object - await page.waitForTimeout(VISUAL_GRACE_PERIOD); - await percySnapshot(page, 'Default Gauge'); - + await percySnapshot(page, `Default Gauge (theme: '${theme}')`); }); }); diff --git a/e2e/tests/visual/search.visual.spec.js b/e2e/tests/visual/search.visual.spec.js index b181fdb573..1af0e65b55 100644 --- a/e2e/tests/visual/search.visual.spec.js +++ b/e2e/tests/visual/search.visual.spec.js @@ -24,81 +24,58 @@ This test suite is dedicated to tests which verify search functionality. */ -const { test, expect } = require('../../baseFixtures.js'); +const { test, expect } = require('../../pluginFixtures'); +const { createDomainObjectWithDefaults } = require('../../appActions'); + const percySnapshot = require('@percy/playwright'); -/** - * Creates a notebook object and adds an entry. - * @param {import('@playwright/test').Page} page - */ -async function createClockAndDisplayLayout(page) { - //Go to baseURL - await page.goto('./', { waitUntil: 'networkidle' }); - - // Click button:has-text("Create") - await page.locator('button:has-text("Create")').click(); - // Click li:has-text("Notebook") - await page.locator('li:has-text("Clock")').click(); - // Click button:has-text("OK") - await Promise.all([ - page.waitForNavigation(), - page.locator('button:has-text("OK")').click() - ]); - - // Click a:has-text("My Items") - await Promise.all([ - page.waitForNavigation(), - page.locator('a:has-text("My Items") >> 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() - ]); -} - test.describe('Grand Search', () => { - test('Can search for objects, and subsequent search dropdown behaves properly', async ({ page }) => { - await createClockAndDisplayLayout(page); + test.beforeEach(async ({ page, theme }) => { + //Go to baseURL and Hide Tree + await page.goto('./#/browse/mine?hideTree=true', { waitUntil: 'networkidle' }); + }); + test.use({ + clockOptions: { + now: 0, //Set browser clock to UNIX Epoch + shouldAdvanceTime: false //Don't advance the clock + } + }); + //This needs to be rewritten to use a non clock or non display layout object + test('Can search for objects, and subsequent search dropdown behaves properly @unstable', async ({ page, theme }) => { + // await createDomainObjectWithDefaults(page, 'Display Layout'); + // await page.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button').nth(1).click(); + // await page.locator('text=Save and Finish Editing').click(); + const folder1 = 'Folder1'; + await createDomainObjectWithDefaults(page, 'Folder', folder1); // 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"]')).toContainText('Clock'); - await percySnapshot(page, 'Searching for Clocks'); - // Click text=Elements >> nth=0 - await page.locator('text=Elements').first().click(); - await expect(page.locator('[aria-label="Search Result"]')).not.toBeVisible(); + await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill(folder1); + await expect(page.locator('[aria-label="Search Result"]')).toContainText(folder1); + await percySnapshot(page, 'Searching for Folder Object'); - // Click [aria-label="OpenMCT Search"] [aria-label="Search Input"] await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').click(); - // Click [aria-label="Unnamed Clock clock result"] >> text=Unnamed Clock await page.locator('[aria-label="Unnamed Clock clock result"] >> text=Unnamed Clock').click(); await percySnapshot(page, 'Preview for clock should display when editing enabled and search item clicked'); - // Click [aria-label="Close"] await page.locator('[aria-label="Close"]').click(); await percySnapshot(page, 'Search should still be showing after preview closed'); - // 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(); - // Click text=Save and Finish Editing + await page.locator('text=Save and Finish Editing').click(); - // Click [aria-label="OpenMCT Search"] [aria-label="Search Input"] + await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').click(); - // Fill [aria-label="OpenMCT Search"] [aria-label="Search Input"] + await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').fill('Cl'); - // Click text=Unnamed Clock + await Promise.all([ page.waitForNavigation(), page.locator('text=Unnamed Clock').click() ]); - await percySnapshot(page, 'Clicking on search results should navigate to them if not editing'); + await percySnapshot(page, `Clicking on search results should navigate to them if not editing (theme: '${theme}')`); }); }); + diff --git a/package.json b/package.json index f12e56bff8..1164069932 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "devDependencies": { "@babel/eslint-parser": "7.18.2", "@braintree/sanitize-url": "6.0.0", - "@percy/cli": "1.2.1", + "@percy/cli": "1.6.4", "@percy/playwright": "1.0.4", "@playwright/test": "1.23.0", "@types/eventemitter3": "^1.0.0", @@ -94,7 +94,7 @@ "test:e2e:unstable": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome --grep @unstable", "test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js --project=chrome", "test:e2e:updatesnapshots": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome --grep @snapshot --update-snapshots", - "test:e2e:visual": "percy exec --config ./e2e/.percy.yml -- npx playwright test --config=e2e/playwright-visual.config.js", + "test:e2e:visual": "percy exec --config ./e2e/.percy.yml -- npx playwright test --config=e2e/playwright-visual.config.js --grep-invert @unstable", "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_ENV=test NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --no-single-run",