diff --git a/e2e/tests/functional/staleness.e2e.spec.js b/e2e/tests/functional/staleness.e2e.spec.js new file mode 100644 index 0000000000..0b2a00a536 --- /dev/null +++ b/e2e/tests/functional/staleness.e2e.spec.js @@ -0,0 +1,64 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2023, 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. + *****************************************************************************/ + +import { createDomainObjectWithDefaults, navigateToObjectWithRealTime } from '../../appActions.js'; +import { expect, test } from '../../pluginFixtures.js'; + +test.describe('Staleness', () => { + test.beforeEach(async ({ page }) => { + await page.goto('./', { waitUntil: 'domcontentloaded' }); + }); + + test('Does not show staleness after navigating from a stale object', async ({ page }) => { + const objectViewSelector = '.c-object-view'; + const isStaleClass = 'is-stale'; + const staleSWG = await createDomainObjectWithDefaults(page, { + type: 'Sine Wave Generator', + name: 'SWG' + }); + + // edit properties and enable staleness updates + await page.getByLabel('More actions').click(); + await page.getByLabel('Edit properties...').click(); + await page.getByLabel('Provide Staleness Updates', { exact: true }).click(); + await page.getByLabel('Save').click(); + + const folder = await createDomainObjectWithDefaults(page, { + type: 'Folder', + name: 'Folder 1' + }); + + // Navigate to the stale object + await navigateToObjectWithRealTime(page, staleSWG.url); + + // Assert that staleness is shown + await expect(page.locator(`${objectViewSelector} .${isStaleClass}`)).toBeAttached({ + timeout: 30 * 1000 // Give 30 seconds for the staleness to be updated + }); + + // Immediately navigate to the folder + await page.goto(folder.url); + + // Verify that staleness is not shown + await expect(page.locator(`${objectViewSelector} .${isStaleClass}`)).not.toBeAttached(); + }); +}); diff --git a/example/generator/SinewaveStalenessProvider.js b/example/generator/SinewaveStalenessProvider.js index 27f6ce96d4..06783dada3 100644 --- a/example/generator/SinewaveStalenessProvider.js +++ b/example/generator/SinewaveStalenessProvider.js @@ -26,7 +26,6 @@ export default class SinewaveLimitProvider extends EventEmitter { #openmct; #observingStaleness; #watchingTheClock; - #isRealTime; constructor(openmct) { super(); @@ -34,7 +33,6 @@ export default class SinewaveLimitProvider extends EventEmitter { this.#openmct = openmct; this.#observingStaleness = {}; this.#watchingTheClock = false; - this.#isRealTime = undefined; } supportsStaleness(domainObject) { @@ -61,10 +59,7 @@ export default class SinewaveLimitProvider extends EventEmitter { subscribeToStaleness(domainObject, callback) { const id = this.#getObjectKeyString(domainObject); - if (this.#isRealTime === undefined) { - this.#updateRealTime(this.#openmct.time.getMode()); - } - + this.#realTimeCheck(); this.#handleClockUpdate(); if (this.#observerExists(id)) { @@ -92,17 +87,15 @@ export default class SinewaveLimitProvider extends EventEmitter { if (observers && !this.#watchingTheClock) { this.#watchingTheClock = true; - this.#openmct.time.on('modeChanged', this.#updateRealTime, this); + this.#openmct.time.on('modeChanged', this.#realTimeCheck, this); } else if (!observers && this.#watchingTheClock) { this.#watchingTheClock = false; - this.#openmct.time.off('modeChanged', this.#updateRealTime, this); + this.#openmct.time.off('modeChanged', this.#realTimeCheck, this); } } - #updateRealTime(mode) { - this.#isRealTime = mode !== 'fixed'; - - if (!this.#isRealTime) { + #realTimeCheck() { + if (!this.#openmct.time.isRealTime()) { Object.keys(this.#observingStaleness).forEach((id) => { this.#updateStaleness(id, false); }); @@ -140,7 +133,7 @@ export default class SinewaveLimitProvider extends EventEmitter { } #providingStaleness(domainObject) { - return domainObject.telemetry?.staleness === true && this.#isRealTime; + return domainObject.telemetry?.staleness === true && this.#openmct.time.isRealTime(); } #getObjectKeyString(object) { diff --git a/src/ui/components/ObjectView.vue b/src/ui/components/ObjectView.vue index 6c5c1c9aa3..ceabdf16df 100644 --- a/src/ui/components/ObjectView.vue +++ b/src/ui/components/ObjectView.vue @@ -352,6 +352,10 @@ export default { show(object, viewKey, immediatelySelect, currentObjectPath) { this.updateStyle(); + if (this.domainObject) { + this.triggerUnsubscribeFromStaleness(this.domainObject); + } + if (this.removeSelectable) { this.removeSelectable(); delete this.removeSelectable;