mirror of
https://github.com/nasa/openmct.git
synced 2025-01-09 06:22:37 +00:00
a8fbabe695
* more readable * unpause explicitly * fix jsdoc * e2e testing multiple image removal * prettier * fix to remove multiple images from history * move tests that use playwright clock api into own file * fix playwright clock tests * add aria-label to element * prevent straggler debounced function call on unmount * clean up and fix tests * update paths * lint fix * lint fix --------- Co-authored-by: John Hill <john.c.hill@nasa.gov>
490 lines
18 KiB
JavaScript
490 lines
18 KiB
JavaScript
/*****************************************************************************
|
|
* Open MCT, Copyright (c) 2014-2024, 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 how imagery functions over time.
|
|
It only assumes that example imagery is present.
|
|
It uses https://playwright.dev/docs/clock to have control over time
|
|
*/
|
|
|
|
import {
|
|
createDomainObjectWithDefaults,
|
|
navigateToObjectWithRealTime,
|
|
setRealTimeMode,
|
|
setStartOffset
|
|
} from '../../../../appActions.js';
|
|
import { MISSION_TIME } from '../../../../constants.js';
|
|
import {
|
|
createImageryViewWithShortDelay,
|
|
FIVE_MINUTES,
|
|
IMAGE_LOAD_DELAY,
|
|
THIRTY_SECONDS
|
|
} from '../../../../helper/imageryUtils.js';
|
|
import { expect, test } from '../../../../pluginFixtures.js';
|
|
|
|
test.describe('Example Imagery Object with Controlled Clock @clock', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
// We mock the clock so that we don't need to wait for time driven events
|
|
// to verify functionality.
|
|
await page.clock.install({ time: MISSION_TIME });
|
|
await page.clock.resume();
|
|
|
|
//Go to baseURL
|
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
|
|
|
// Create a default 'Example Imagery' object
|
|
// Click the Create button
|
|
await page.getByRole('button', { name: 'Create' }).click();
|
|
|
|
// Click text=Example Imagery
|
|
await page.getByRole('menuitem', { name: 'Example Imagery' }).click();
|
|
|
|
// Clear and set Image load delay to minimum value
|
|
await page.locator('input[type="number"]').clear();
|
|
await page.locator('input[type="number"]').fill(`${IMAGE_LOAD_DELAY}`);
|
|
|
|
await page.getByLabel('Save').click();
|
|
|
|
// Verify that the created object is focused
|
|
await expect(page.locator('.l-browse-bar__object-name')).toContainText(
|
|
'Unnamed Example Imagery'
|
|
);
|
|
await page.getByLabel('Focused Image Element').hover({ trial: true });
|
|
|
|
// set realtime mode
|
|
await setRealTimeMode(page);
|
|
await setStartOffset(page, { startMins: '05' });
|
|
});
|
|
|
|
test('Imagery Time Bounding', async ({ page }) => {
|
|
test.info().annotations.push({
|
|
type: 'issue',
|
|
description: 'https://github.com/nasa/openmct/issues/5265'
|
|
});
|
|
test.info().annotations.push({
|
|
type: 'issue',
|
|
description: 'https://github.com/nasa/openmct/issues/7825'
|
|
});
|
|
|
|
// verify that old images are discarded
|
|
const lastImageInBounds = page.getByLabel('Image thumbnail from').first();
|
|
const lastImageTimestamp = await lastImageInBounds.getAttribute('title');
|
|
expect(lastImageTimestamp).not.toBeNull();
|
|
|
|
// go forward in time to ensure old images are discarded
|
|
await page.clock.fastForward(IMAGE_LOAD_DELAY);
|
|
await page.clock.resume();
|
|
await expect(page.getByLabel(lastImageTimestamp)).toBeHidden();
|
|
|
|
// go way forward in time to ensure multiple images are discarded
|
|
const IMAGES_TO_DISCARD_COUNT = 5;
|
|
|
|
const lastImageToDiscard = page
|
|
.getByLabel('Image thumbnail from')
|
|
.nth(IMAGES_TO_DISCARD_COUNT - 1);
|
|
const lastImageToDiscardTimestamp = await lastImageToDiscard.getAttribute('title');
|
|
expect(lastImageToDiscardTimestamp).not.toBeNull();
|
|
|
|
const imageAfterLastImageToDiscard = page
|
|
.getByLabel('Image thumbnail from')
|
|
.nth(IMAGES_TO_DISCARD_COUNT);
|
|
const imageAfterLastImageToDiscardTimestamp =
|
|
await imageAfterLastImageToDiscard.getAttribute('title');
|
|
expect(imageAfterLastImageToDiscardTimestamp).not.toBeNull();
|
|
|
|
await page.clock.fastForward(IMAGE_LOAD_DELAY * IMAGES_TO_DISCARD_COUNT);
|
|
await page.clock.resume();
|
|
|
|
await expect(page.getByLabel(lastImageToDiscardTimestamp)).toBeHidden();
|
|
await expect(page.getByLabel(imageAfterLastImageToDiscardTimestamp)).toBeVisible();
|
|
});
|
|
|
|
test('Get background-image url from background-image css prop', async ({ page }) => {
|
|
await assertBackgroundImageUrlFromBackgroundCss(page);
|
|
});
|
|
});
|
|
|
|
test.describe('Example Imagery in Display Layout with Controlled Clock @clock', () => {
|
|
let displayLayout;
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
// We mock the clock so that we don't need to wait for time driven events
|
|
// to verify functionality.
|
|
await page.clock.install({ time: MISSION_TIME });
|
|
await page.clock.resume();
|
|
|
|
// Go to baseURL
|
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
|
|
|
displayLayout = await createDomainObjectWithDefaults(page, { type: 'Display Layout' });
|
|
|
|
// Create Example Imagery inside Display Layout
|
|
await createImageryViewWithShortDelay(page, {
|
|
name: 'Unnamed Example Imagery',
|
|
parent: displayLayout.uuid
|
|
});
|
|
|
|
// set realtime mode
|
|
await navigateToObjectWithRealTime(
|
|
page,
|
|
displayLayout.url,
|
|
`${FIVE_MINUTES}`,
|
|
`${THIRTY_SECONDS}`
|
|
);
|
|
});
|
|
|
|
test('Imagery Time Bounding', async ({ page }) => {
|
|
test.info().annotations.push({
|
|
type: 'issue',
|
|
description: 'https://github.com/nasa/openmct/issues/5265'
|
|
});
|
|
test.info().annotations.push({
|
|
type: 'issue',
|
|
description: 'https://github.com/nasa/openmct/issues/7825'
|
|
});
|
|
|
|
// Edit mode
|
|
await page.getByLabel('Edit Object').click();
|
|
|
|
// Click on example imagery to expose toolbar
|
|
await page.locator('.c-so-view__header').click();
|
|
|
|
// Adjust object height
|
|
await page.locator('div[title="Resize object height"] > input').click();
|
|
await page.locator('div[title="Resize object height"] > input').fill('50');
|
|
|
|
// Adjust object width
|
|
await page.locator('div[title="Resize object width"] > input').click();
|
|
await page.locator('div[title="Resize object width"] > input').fill('50');
|
|
|
|
await expect(page.getByLabel('Image Thumbnail from').last()).toBeInViewport();
|
|
|
|
// verify that old images are discarded
|
|
const lastImageInBounds = page.getByLabel('Image thumbnail from').first();
|
|
const lastImageTimestamp = await lastImageInBounds.getAttribute('title');
|
|
expect(lastImageTimestamp).not.toBeNull();
|
|
|
|
// go forward in time to ensure old images are discarded
|
|
await page.clock.fastForward(IMAGE_LOAD_DELAY);
|
|
await page.clock.resume();
|
|
await expect(page.getByLabel(lastImageTimestamp)).toBeHidden();
|
|
|
|
// go way forward in time to ensure multiple images are discarded
|
|
const IMAGES_TO_DISCARD_COUNT = 5;
|
|
|
|
const lastImageToDiscard = page
|
|
.getByLabel('Image thumbnail from')
|
|
.nth(IMAGES_TO_DISCARD_COUNT - 1);
|
|
const lastImageToDiscardTimestamp = await lastImageToDiscard.getAttribute('title');
|
|
expect(lastImageToDiscardTimestamp).not.toBeNull();
|
|
|
|
const imageAfterLastImageToDiscard = page
|
|
.getByLabel('Image thumbnail from')
|
|
.nth(IMAGES_TO_DISCARD_COUNT);
|
|
const imageAfterLastImageToDiscardTimestamp =
|
|
await imageAfterLastImageToDiscard.getAttribute('title');
|
|
expect(imageAfterLastImageToDiscardTimestamp).not.toBeNull();
|
|
|
|
await page.clock.fastForward(IMAGE_LOAD_DELAY * IMAGES_TO_DISCARD_COUNT);
|
|
await page.clock.resume();
|
|
|
|
await expect(page.getByLabel(lastImageToDiscardTimestamp)).toBeHidden();
|
|
await expect(page.getByLabel(imageAfterLastImageToDiscardTimestamp)).toBeVisible();
|
|
});
|
|
|
|
test('Get background-image url from background-image css prop @clock', async ({ page }) => {
|
|
await assertBackgroundImageUrlFromBackgroundCss(page);
|
|
});
|
|
});
|
|
|
|
test.describe('Example Imagery in Flexible layout with Controlled Clock @clock', () => {
|
|
let flexibleLayout;
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
// We mock the clock so that we don't need to wait for time driven events
|
|
// to verify functionality.
|
|
await page.clock.install({ time: MISSION_TIME });
|
|
await page.clock.resume();
|
|
|
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
|
|
|
flexibleLayout = await createDomainObjectWithDefaults(page, { type: 'Flexible Layout' });
|
|
|
|
// Create Example Imagery inside the Flexible Layout
|
|
await createImageryViewWithShortDelay(page, {
|
|
name: 'Unnamed Example Imagery',
|
|
parent: flexibleLayout.uuid
|
|
});
|
|
|
|
// set realtime mode
|
|
await navigateToObjectWithRealTime(
|
|
page,
|
|
flexibleLayout.url,
|
|
`${FIVE_MINUTES}`,
|
|
`${THIRTY_SECONDS}`
|
|
);
|
|
|
|
// Wait for image thumbnail auto-scroll to complete
|
|
await expect(page.getByLabel('Image Thumbnail from').last()).toBeInViewport();
|
|
});
|
|
|
|
test('Imagery Time Bounding @clock', async ({ page, browserName }) => {
|
|
test.fixme(browserName === 'firefox', 'This test needs to be updated to work with firefox');
|
|
test.info().annotations.push({
|
|
type: 'issue',
|
|
description: 'https://github.com/nasa/openmct/issues/5326'
|
|
});
|
|
test.info().annotations.push({
|
|
type: 'issue',
|
|
description: 'https://github.com/nasa/openmct/issues/7825'
|
|
});
|
|
|
|
// verify that old images are discarded
|
|
const lastImageInBounds = page.getByLabel('Image thumbnail from').first();
|
|
const lastImageTimestamp = await lastImageInBounds.getAttribute('title');
|
|
expect(lastImageTimestamp).not.toBeNull();
|
|
|
|
// go forward in time to ensure old images are discarded
|
|
await page.clock.fastForward(IMAGE_LOAD_DELAY);
|
|
await page.clock.resume();
|
|
await expect(page.getByLabel(lastImageTimestamp)).toBeHidden();
|
|
|
|
// go way forward in time to ensure multiple images are discarded
|
|
const IMAGES_TO_DISCARD_COUNT = 5;
|
|
|
|
const lastImageToDiscard = page
|
|
.getByLabel('Image thumbnail from')
|
|
.nth(IMAGES_TO_DISCARD_COUNT - 1);
|
|
const lastImageToDiscardTimestamp = await lastImageToDiscard.getAttribute('title');
|
|
expect(lastImageToDiscardTimestamp).not.toBeNull();
|
|
|
|
const imageAfterLastImageToDiscard = page
|
|
.getByLabel('Image thumbnail from')
|
|
.nth(IMAGES_TO_DISCARD_COUNT);
|
|
const imageAfterLastImageToDiscardTimestamp =
|
|
await imageAfterLastImageToDiscard.getAttribute('title');
|
|
expect(imageAfterLastImageToDiscardTimestamp).not.toBeNull();
|
|
|
|
await page.clock.fastForward(IMAGE_LOAD_DELAY * IMAGES_TO_DISCARD_COUNT);
|
|
await page.clock.resume();
|
|
|
|
await expect(page.getByLabel(lastImageToDiscardTimestamp)).toBeHidden();
|
|
await expect(page.getByLabel(imageAfterLastImageToDiscardTimestamp)).toBeVisible();
|
|
});
|
|
|
|
test('Get background-image url from background-image css prop @clock', async ({ page }) => {
|
|
await assertBackgroundImageUrlFromBackgroundCss(page);
|
|
});
|
|
});
|
|
|
|
test.describe('Example Imagery in Tabs View with Controlled Clock @clock', () => {
|
|
let timeStripObject;
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
// We mock the clock so that we don't need to wait for time driven events
|
|
// to verify functionality.
|
|
await page.clock.install({ time: MISSION_TIME });
|
|
await page.clock.resume();
|
|
|
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
|
|
|
timeStripObject = await createDomainObjectWithDefaults(page, { type: 'Tabs View' });
|
|
await page.goto(timeStripObject.url);
|
|
|
|
/* Create Example Imagery with minimum Image Load Delay */
|
|
// Click the Create button
|
|
await page.getByRole('button', { name: 'Create' }).click();
|
|
|
|
// Click text=Example Imagery
|
|
await page.getByRole('menuitem', { name: 'Example Imagery' }).click();
|
|
|
|
// Clear and set Image load delay to minimum value
|
|
await page.locator('input[type="number"]').clear();
|
|
await page.locator('input[type="number"]').fill(`${IMAGE_LOAD_DELAY}`);
|
|
|
|
await page.getByLabel('Save').click();
|
|
|
|
await expect(page.locator('.l-browse-bar__object-name')).toContainText(
|
|
'Unnamed Example Imagery'
|
|
);
|
|
|
|
// set realtime mode
|
|
await navigateToObjectWithRealTime(
|
|
page,
|
|
timeStripObject.url,
|
|
`${FIVE_MINUTES}`,
|
|
`${THIRTY_SECONDS}`
|
|
);
|
|
|
|
// Wait for image thumbnail auto-scroll to complete
|
|
await expect(page.getByLabel('Image Thumbnail from').last()).toBeInViewport();
|
|
});
|
|
|
|
test('Imagery Time Bounding @clock', async ({ page }) => {
|
|
test.info().annotations.push({
|
|
type: 'issue',
|
|
description: 'https://github.com/nasa/openmct/issues/5265'
|
|
});
|
|
test.info().annotations.push({
|
|
type: 'issue',
|
|
description: 'https://github.com/nasa/openmct/issues/7825'
|
|
});
|
|
|
|
// verify that old images are discarded
|
|
const lastImageInBounds = page.getByLabel('Image thumbnail from').first();
|
|
const lastImageTimestamp = await lastImageInBounds.getAttribute('title');
|
|
expect(lastImageTimestamp).not.toBeNull();
|
|
|
|
// go forward in time to ensure old images are discarded
|
|
await page.clock.fastForward(IMAGE_LOAD_DELAY);
|
|
await page.clock.resume();
|
|
await expect(page.getByLabel(lastImageTimestamp)).toBeHidden();
|
|
|
|
// go way forward in time to ensure multiple images are discarded
|
|
const IMAGES_TO_DISCARD_COUNT = 5;
|
|
|
|
const lastImageToDiscard = page
|
|
.getByLabel('Image thumbnail from')
|
|
.nth(IMAGES_TO_DISCARD_COUNT - 1);
|
|
const lastImageToDiscardTimestamp = await lastImageToDiscard.getAttribute('title');
|
|
expect(lastImageToDiscardTimestamp).not.toBeNull();
|
|
|
|
const imageAfterLastImageToDiscard = page
|
|
.getByLabel('Image thumbnail from')
|
|
.nth(IMAGES_TO_DISCARD_COUNT);
|
|
const imageAfterLastImageToDiscardTimestamp =
|
|
await imageAfterLastImageToDiscard.getAttribute('title');
|
|
expect(imageAfterLastImageToDiscardTimestamp).not.toBeNull();
|
|
|
|
await page.clock.fastForward(IMAGE_LOAD_DELAY * IMAGES_TO_DISCARD_COUNT);
|
|
await page.clock.resume();
|
|
|
|
await expect(page.getByLabel(lastImageToDiscardTimestamp)).toBeHidden();
|
|
await expect(page.getByLabel(imageAfterLastImageToDiscardTimestamp)).toBeVisible();
|
|
});
|
|
|
|
test('Get background-image url from background-image css prop @clock', async ({ page }) => {
|
|
await assertBackgroundImageUrlFromBackgroundCss(page);
|
|
});
|
|
});
|
|
|
|
test.describe('Example Imagery in Time Strip with Controlled Clock @clock', () => {
|
|
let timeStripObject;
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
// We mock the clock so that we don't need to wait for time driven events
|
|
// to verify functionality.
|
|
await page.clock.install({ time: MISSION_TIME });
|
|
await page.clock.resume();
|
|
|
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
|
|
|
timeStripObject = await createDomainObjectWithDefaults(page, { type: 'Time Strip' });
|
|
await page.goto(timeStripObject.url);
|
|
|
|
/* Create Example Imagery with minimum Image Load Delay */
|
|
// Click the Create button
|
|
await page.getByRole('button', { name: 'Create' }).click();
|
|
|
|
// Click text=Example Imagery
|
|
await page.getByRole('menuitem', { name: 'Example Imagery' }).click();
|
|
|
|
// Clear and set Image load delay to minimum value
|
|
await page.locator('input[type="number"]').clear();
|
|
await page.locator('input[type="number"]').fill(`${IMAGE_LOAD_DELAY}`);
|
|
|
|
await page.getByLabel('Save').click();
|
|
|
|
await expect(page.locator('.l-browse-bar__object-name')).toContainText(
|
|
'Unnamed Example Imagery'
|
|
);
|
|
|
|
// set realtime mode
|
|
await navigateToObjectWithRealTime(
|
|
page,
|
|
timeStripObject.url,
|
|
`${FIVE_MINUTES}`,
|
|
`${THIRTY_SECONDS}`
|
|
);
|
|
|
|
// Wait for image thumbnail auto-scroll to complete
|
|
await expect(page.getByLabel('wrapper-').last()).toBeInViewport();
|
|
});
|
|
|
|
test('Imagery Time Bounding @clock', async ({ page }) => {
|
|
test.info().annotations.push({
|
|
type: 'issue',
|
|
description: 'https://github.com/nasa/openmct/issues/5265'
|
|
});
|
|
test.info().annotations.push({
|
|
type: 'issue',
|
|
description: 'https://github.com/nasa/openmct/issues/7825'
|
|
});
|
|
|
|
// verify that old images are discarded
|
|
const lastImageInBounds = page.getByLabel('wrapper-').first();
|
|
const lastImageTimestamp = await lastImageInBounds.getAttribute('aria-label');
|
|
expect(lastImageTimestamp).not.toBeNull();
|
|
|
|
// go forward in time to ensure old images are discarded
|
|
await page.clock.fastForward(IMAGE_LOAD_DELAY);
|
|
await page.clock.resume();
|
|
await expect(page.getByLabel(lastImageTimestamp)).toBeHidden();
|
|
|
|
// go way forward in time to ensure multiple images are discarded
|
|
const IMAGES_TO_DISCARD_COUNT = 5;
|
|
|
|
const lastImageToDiscard = page.getByLabel('wrapper-').nth(IMAGES_TO_DISCARD_COUNT - 1);
|
|
const lastImageToDiscardTimestamp = await lastImageToDiscard.getAttribute('aria-label');
|
|
expect(lastImageToDiscardTimestamp).not.toBeNull();
|
|
|
|
const imageAfterLastImageToDiscard = page.getByLabel('wrapper-').nth(IMAGES_TO_DISCARD_COUNT);
|
|
const imageAfterLastImageToDiscardTimestamp =
|
|
await imageAfterLastImageToDiscard.getAttribute('aria-label');
|
|
expect(imageAfterLastImageToDiscardTimestamp).not.toBeNull();
|
|
|
|
await page.clock.fastForward(IMAGE_LOAD_DELAY * IMAGES_TO_DISCARD_COUNT);
|
|
await page.clock.resume();
|
|
|
|
await expect(page.getByLabel(lastImageToDiscardTimestamp)).toBeHidden();
|
|
await expect(page.getByLabel(imageAfterLastImageToDiscardTimestamp)).toBeVisible();
|
|
});
|
|
});
|
|
|
|
/**
|
|
* @param {import('@playwright/test').Page} page
|
|
*/
|
|
async function assertBackgroundImageUrlFromBackgroundCss(page) {
|
|
const backgroundImage = page.getByLabel('Focused Image Element');
|
|
const backgroundImageUrl = await backgroundImage.evaluate((el) => {
|
|
return window
|
|
.getComputedStyle(el)
|
|
.getPropertyValue('background-image')
|
|
.match(/url\(([^)]+)\)/)[1];
|
|
});
|
|
|
|
// go forward in time to ensure old images are discarded
|
|
await page.clock.fastForward(IMAGE_LOAD_DELAY);
|
|
await page.clock.resume();
|
|
await expect(backgroundImage).not.toHaveJSProperty('background-image', backgroundImageUrl);
|
|
}
|