diff options
author | Scott Bell <scott@traclabs.com> | 2022-08-08 23:34:32 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-08 23:34:32 +0300 |
commit | caecdd60a884b801c72ed8f813c99b50ac608d61 (patch) | |
tree | 07c1841737735a85e3ed375d2e3b406ec8878ebb | |
parent | dd4b27ada77a17b01314c9ee39b8716f182092e5 (diff) | |
parent | c6c58af12cea8441911b8df6d053c8a78dfee8df (diff) |
Merge branch 'release/2.0.7' into 5615-infinite-loop-in-some-search-cases5615-infinite-loop-in-some-search-cases
-rw-r--r-- | e2e/appActions.js | 93 | ||||
-rw-r--r-- | e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js | 122 | ||||
-rw-r--r-- | e2e/tests/functional/plugins/lad/lad.e2e.spec.js | 120 | ||||
-rw-r--r-- | e2e/tests/functional/plugins/timeConductor/timeConductor.e2e.spec.js | 86 |
4 files changed, 334 insertions, 87 deletions
diff --git a/e2e/appActions.js b/e2e/appActions.js index d0504ff0b..e4fbf7589 100644 --- a/e2e/appActions.js +++ b/e2e/appActions.js @@ -83,7 +83,7 @@ async function createDomainObjectWithDefaults(page, { type, name, parent = 'mine ]); // Wait until the URL is updated - await page.waitForNavigation('networkidle'); + await page.waitForURL(`**/${parent}/*`); const uuid = await getFocusedObjectUuid(page); const objectUrl = await getHashUrlToDomainObject(page, uuid); @@ -175,10 +175,99 @@ async function _isInEditMode(page, identifier) { return await page.evaluate((objectIdentifier) => window.openmct.objects.isTransactionActive(objectIdentifier), identifier); } +/** + * Set the time conductor mode to either fixed timespan or realtime mode. + * @param {import('@playwright/test').Page} page + * @param {boolean} [isFixedTimespan=true] true for fixed timespan mode, false for realtime mode; default is true + */ +async function setTimeConductorMode(page, isFixedTimespan = true) { + // Click 'mode' button + await page.locator('.c-mode-button').click(); + + // Switch time conductor mode + if (isFixedTimespan) { + await page.locator('data-testid=conductor-modeOption-fixed').click(); + } else { + await page.locator('data-testid=conductor-modeOption-realtime').click(); + } +} + +/** + * Set the time conductor to fixed timespan mode + * @param {import('@playwright/test').Page} page + */ +async function setFixedTimeMode(page) { + await setTimeConductorMode(page, true); +} + +/** + * Set the time conductor to realtime mode + * @param {import('@playwright/test').Page} page + */ +async function setRealTimeMode(page) { + await setTimeConductorMode(page, false); +} + +/** + * @typedef {Object} OffsetValues + * @property {string | undefined} hours + * @property {string | undefined} mins + * @property {string | undefined} secs + */ + +/** + * Set the values (hours, mins, secs) for the TimeConductor offsets when in realtime mode + * @param {import('@playwright/test').Page} page + * @param {OffsetValues} offset + * @param {import('@playwright/test').Locator} offsetButton + */ +async function setTimeConductorOffset(page, {hours, mins, secs}, offsetButton) { + await offsetButton.click(); + + if (hours) { + await page.fill('.pr-time-controls__hrs', hours); + } + + if (mins) { + await page.fill('.pr-time-controls__mins', mins); + } + + if (secs) { + await page.fill('.pr-time-controls__secs', secs); + } + + // Click the check button + await page.locator('.pr-time__buttons .icon-check').click(); +} + +/** + * Set the values (hours, mins, secs) for the start time offset when in realtime mode + * @param {import('@playwright/test').Page} page + * @param {OffsetValues} offset + */ +async function setStartOffset(page, offset) { + const startOffsetButton = page.locator('data-testid=conductor-start-offset-button'); + await setTimeConductorOffset(page, offset, startOffsetButton); +} + +/** + * Set the values (hours, mins, secs) for the end time offset when in realtime mode + * @param {import('@playwright/test').Page} page + * @param {OffsetValues} offset + */ +async function setEndOffset(page, offset) { + const endOffsetButton = page.locator('data-testid=conductor-end-offset-button'); + await setTimeConductorOffset(page, offset, endOffsetButton); +} + // eslint-disable-next-line no-undef module.exports = { createDomainObjectWithDefaults, openObjectTreeContextMenu, getHashUrlToDomainObject, - getFocusedObjectUuid + getFocusedObjectUuid, + setFixedTimeMode, + setRealTimeMode, + setStartOffset, + setEndOffset }; diff --git a/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js b/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js new file mode 100644 index 000000000..83090fc0e --- /dev/null +++ b/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js @@ -0,0 +1,122 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + +const { test, expect } = require('../../../../pluginFixtures'); +const { createDomainObjectWithDefaults, setStartOffset, setFixedTimeMode, setRealTimeMode } = require('../../../../appActions'); + +test.describe('Testing Display Layout @unstable', () => { + let sineWaveObject; + test.beforeEach(async ({ page }) => { + await page.goto('./', { waitUntil: 'networkidle' }); + await setRealTimeMode(page); + + // Create Sine Wave Generator + sineWaveObject = await createDomainObjectWithDefaults(page, { + type: 'Sine Wave Generator', + name: "Test Sine Wave Generator" + }); + }); + test('alpha-numeric widget telemetry value exactly matches latest telemetry value received in real time', async ({ page }) => { + // Create a Display Layout + await createDomainObjectWithDefaults(page, { + type: 'Display Layout', + name: "Test Display Layout" + }); + // Edit Display Layout + await page.locator('[title="Edit"]').click(); + + // Expand the 'My Items' folder in the left tree + await page.locator('.c-tree__item__view-control.c-disclosure-triangle').click(); + // Add the Sine Wave Generator to the Display Layout and save changes + await page.dragAndDrop('text=Test Sine Wave Generator', '.l-layout__grid-holder'); + await page.locator('button[title="Save"]').click(); + await page.locator('text=Save and Finish Editing').click(); + + // Subscribe to the Sine Wave Generator data + // On getting data, check if the value found in the Display Layout is the most recent value + // from the Sine Wave Generator + const getTelemValuePromise = await subscribeToTelemetry(page, sineWaveObject.uuid); + const formattedTelemetryValue = await getTelemValuePromise; + const displayLayoutValuePromise = await page.waitForSelector(`text="${formattedTelemetryValue}"`); + const displayLayoutValue = await displayLayoutValuePromise.textContent(); + const trimmedDisplayValue = displayLayoutValue.trim(); + + await expect(trimmedDisplayValue).toBe(formattedTelemetryValue); + }); + test('alpha-numeric widget telemetry value exactly matches latest telemetry value received in fixed time', async ({ page }) => { + // Create a Display Layout + await createDomainObjectWithDefaults(page, { + type: 'Display Layout', + name: "Test Display Layout" + }); + // Edit Display Layout + await page.locator('[title="Edit"]').click(); + + // Expand the 'My Items' folder in the left tree + await page.locator('.c-tree__item__view-control.c-disclosure-triangle').click(); + // Add the Sine Wave Generator to the Display Layout and save changes + await page.dragAndDrop('text=Test Sine Wave Generator', '.l-layout__grid-holder'); + await page.locator('button[title="Save"]').click(); + await page.locator('text=Save and Finish Editing').click(); + + // Subscribe to the Sine Wave Generator data + const getTelemValuePromise = await subscribeToTelemetry(page, sineWaveObject.uuid); + // Set an offset of 1 minute and then change the time mode to fixed to set a 1 minute historical window + await setStartOffset(page, { mins: '1' }); + await setFixedTimeMode(page); + + // On getting data, check if the value found in the Display Layout is the most recent value + // from the Sine Wave Generator + const formattedTelemetryValue = await getTelemValuePromise; + const displayLayoutValuePromise = await page.waitForSelector(`text="${formattedTelemetryValue}"`); + const displayLayoutValue = await displayLayoutValuePromise.textContent(); + const trimmedDisplayValue = displayLayoutValue.trim(); + + await expect(trimmedDisplayValue).toBe(formattedTelemetryValue); + }); +}); + +/** + * Util for subscribing to a telemetry object by object identifier + * Limitations: Currently only works to return telemetry once to the node scope + * To Do: See if there's a way to await this multiple times to allow for multiple + * values to be returned over time + * @param {import('@playwright/test').Page} page + * @param {string} objectIdentifier identifier for object + * @returns {Promise<string>} the formatted sin telemetry value + */ +async function subscribeToTelemetry(page, objectIdentifier) { + const getTelemValuePromise = new Promise(resolve => page.exposeFunction('getTelemValue', resolve)); + + await page.evaluate(async (telemetryIdentifier) => { + const telemetryObject = await window.openmct.objects.get(telemetryIdentifier); + const metadata = window.openmct.telemetry.getMetadata(telemetryObject); + const formats = await window.openmct.telemetry.getFormatMap(metadata); + window.openmct.telemetry.subscribe(telemetryObject, (obj) => { + const sinVal = obj.sin; + const formattedSinVal = formats.sin.format(sinVal); + window.getTelemValue(formattedSinVal); + }); + }, objectIdentifier); + + return getTelemValuePromise; +} diff --git a/e2e/tests/functional/plugins/lad/lad.e2e.spec.js b/e2e/tests/functional/plugins/lad/lad.e2e.spec.js new file mode 100644 index 000000000..4ec084c1b --- /dev/null +++ b/e2e/tests/functional/plugins/lad/lad.e2e.spec.js @@ -0,0 +1,120 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + +const { test, expect } = require('../../../../pluginFixtures'); +const { createDomainObjectWithDefaults, setStartOffset, setFixedTimeMode, setRealTimeMode } = require('../../../../appActions'); + +test.describe('Testing LAD table @unstable', () => { + let sineWaveObject; + test.beforeEach(async ({ page }) => { + await page.goto('./', { waitUntil: 'networkidle' }); + await setRealTimeMode(page); + + // Create Sine Wave Generator + sineWaveObject = await createDomainObjectWithDefaults(page, { + type: 'Sine Wave Generator', + name: "Test Sine Wave Generator" + }); + }); + test('telemetry value exactly matches latest telemetry value received in real time', async ({ page }) => { + // Create LAD table + await createDomainObjectWithDefaults(page, { + type: 'LAD Table', + name: "Test LAD Table" + }); + // Edit LAD table + await page.locator('[title="Edit"]').click(); + + // Expand the 'My Items' folder in the left tree + await page.locator('.c-tree__item__view-control.c-disclosure-triangle').click(); + // Add the Sine Wave Generator to the LAD table and save changes + await page.dragAndDrop('text=Test Sine Wave Generator', '.c-lad-table-wrapper'); + await page.locator('button[title="Save"]').click(); + await page.locator('text=Save and Finish Editing').click(); + + // Subscribe to the Sine Wave Generator data + // On getting data, check if the value found in the LAD table is the most recent value + // from the Sine Wave Generator + const getTelemValuePromise = await subscribeToTelemetry(page, sineWaveObject.uuid); + const subscribeTelemValue = await getTelemValuePromise; + const ladTableValuePromise = await page.waitForSelector(`text="${subscribeTelemValue}"`); + const ladTableValue = await ladTableValuePromise.textContent(); + + expect(ladTableValue).toBe(subscribeTelemValue); + }); + test('telemetry value exactly matches latest telemetry value received in fixed time', async ({ page }) => { + // Create LAD table + await createDomainObjectWithDefaults(page, { + type: 'LAD Table', + name: "Test LAD Table" + }); + // Edit LAD table + await page.locator('[title="Edit"]').click(); + + // Expand the 'My Items' folder in the left tree + await page.locator('.c-tree__item__view-control.c-disclosure-triangle').click(); + // Add the Sine Wave Generator to the LAD table and save changes + await page.dragAndDrop('text=Test Sine Wave Generator', '.c-lad-table-wrapper'); + await page.locator('button[title="Save"]').click(); + await page.locator('text=Save and Finish Editing').click(); + + // Subscribe to the Sine Wave Generator data + const getTelemValuePromise = await subscribeToTelemetry(page, sineWaveObject.uuid); + // Set an offset of 1 minute and then change the time mode to fixed to set a 1 minute historical window + await setStartOffset(page, { mins: '1' }); + await setFixedTimeMode(page); + + // On getting data, check if the value found in the LAD table is the most recent value + // from the Sine Wave Generator + const subscribeTelemValue = await getTelemValuePromise; + const ladTableValuePromise = await page.waitForSelector(`text="${subscribeTelemValue}"`); + const ladTableValue = await ladTableValuePromise.textContent(); + + expect(ladTableValue).toBe(subscribeTelemValue); + }); +}); + +/** + * Util for subscribing to a telemetry object by object identifier + * Limitations: Currently only works to return telemetry once to the node scope + * To Do: See if there's a way to await this multiple times to allow for multiple + * values to be returned over time + * @param {import('@playwright/test').Page} page + * @param {string} objectIdentifier identifier for object + * @returns {Promise<string>} the formatted sin telemetry value + */ +async function subscribeToTelemetry(page, objectIdentifier) { + const getTelemValuePromise = new Promise(resolve => page.exposeFunction('getTelemValue', resolve)); + + await page.evaluate(async (telemetryIdentifier) => { + const telemetryObject = await window.openmct.objects.get(telemetryIdentifier); + const metadata = window.openmct.telemetry.getMetadata(telemetryObject); + const formats = await window.openmct.telemetry.getFormatMap(metadata); + window.openmct.telemetry.subscribe(telemetryObject, (obj) => { + const sinVal = obj.sin; + const formattedSinVal = formats.sin.format(sinVal); + window.getTelemValue(formattedSinVal); + }); + }, objectIdentifier); + + return getTelemValuePromise; +} diff --git a/e2e/tests/functional/plugins/timeConductor/timeConductor.e2e.spec.js b/e2e/tests/functional/plugins/timeConductor/timeConductor.e2e.spec.js index 8d764526b..59d317170 100644 --- a/e2e/tests/functional/plugins/timeConductor/timeConductor.e2e.spec.js +++ b/e2e/tests/functional/plugins/timeConductor/timeConductor.e2e.spec.js @@ -21,6 +21,7 @@ *****************************************************************************/ const { test, expect } = require('../../../../baseFixtures'); +const { setFixedTimeMode, setRealTimeMode, setStartOffset, setEndOffset } = require('../../../../appActions'); test.describe('Time conductor operations', () => { test('validate start time does not exceeds end time', async ({ page }) => { @@ -147,88 +148,3 @@ test.describe('Time conductor input fields real-time mode', () => { expect(page.url()).toContain(`endDelta=${endDelta}`); }); }); - -/** - * @typedef {Object} OffsetValues - * @property {string | undefined} hours - * @property {string | undefined} mins - * @property {string | undefined} secs - */ - -/** - * Set the values (hours, mins, secs) for the start time offset when in realtime mode - * @param {import('@playwright/test').Page} page - * @param {OffsetValues} offset - */ -async function setStartOffset(page, offset) { - const startOffsetButton = page.locator('data-testid=conductor-start-offset-button'); - await setTimeConductorOffset(page, offset, startOffsetButton); -} - -/** - * Set the values (hours, mins, secs) for the end time offset when in realtime mode - * @param {import('@playwright/test').Page} page - * @param {OffsetValues} offset - */ -async function setEndOffset(page, offset) { - const endOffsetButton = page.locator('data-testid=conductor-end-offset-button'); - await setTimeConductorOffset(page, offset, endOffsetButton); -} - -/** - * Set the time conductor to fixed timespan mode - * @param {import('@playwright/test').Page} page - */ -async function setFixedTimeMode(page) { - await setTimeConductorMode(page, true); -} - -/** - * Set the time conductor to realtime mode - * @param {import('@playwright/test').Page} page - */ -async function setRealTimeMode(page) { - await setTimeConductorMode(page, false); -} - -/** - * Set the values (hours, mins, secs) for the TimeConductor offsets when in realtime mode - * @param {import('@playwright/test').Page} page - * @param {OffsetValues} offset - * @param {import('@playwright/test').Locator} offsetButton - */ -async function setTimeConductorOffset(page, {hours, mins, secs}, offsetButton) { - await offsetButton.click(); - - if (hours) { - await page.fill('.pr-time-controls__hrs', hours); - } - - if (mins) { - await page.fill('.pr-time-controls__mins', mins); - } - - if (secs) { - await page.fill('.pr-time-controls__secs', secs); - } - - // Click the check button - await page.locator('.icon-check').click(); -} - -/** - * Set the time conductor mode to either fixed timespan or realtime mode. - * @param {import('@playwright/test').Page} page - * @param {boolean} [isFixedTimespan=true] true for fixed timespan mode, false for realtime mode; default is true - */ -async function setTimeConductorMode(page, isFixedTimespan = true) { - // Click 'mode' button - await page.locator('.c-mode-button').click(); - - // Switch time conductor mode - if (isFixedTimespan) { - await page.locator('data-testid=conductor-modeOption-fixed').click(); - } else { - await page.locator('data-testid=conductor-modeOption-realtime').click(); - } -} |