mirror of
https://github.com/nasa/openmct.git
synced 2024-12-18 20:57:53 +00:00
* 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>
This commit is contained in:
parent
e792403788
commit
a8fbabe695
33
e2e/helper/imageryUtils.js
Normal file
33
e2e/helper/imageryUtils.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { createDomainObjectWithDefaults } from '../appActions.js';
|
||||||
|
import { expect } from '../pluginFixtures.js';
|
||||||
|
|
||||||
|
const IMAGE_LOAD_DELAY = 5 * 1000;
|
||||||
|
const FIVE_MINUTES = 1000 * 60 * 5;
|
||||||
|
const THIRTY_SECONDS = 1000 * 30;
|
||||||
|
const MOUSE_WHEEL_DELTA_Y = 120;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('@playwright/test').Page} page
|
||||||
|
*/
|
||||||
|
async function createImageryViewWithShortDelay(page, { name, parent }) {
|
||||||
|
await createDomainObjectWithDefaults(page, {
|
||||||
|
name,
|
||||||
|
type: 'Example Imagery',
|
||||||
|
parent
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery');
|
||||||
|
await page.getByLabel('More actions').click();
|
||||||
|
await page.getByLabel('Edit Properties').click();
|
||||||
|
// Clear and set Image load delay to minimum value
|
||||||
|
await page.locator('input[type="number"]').fill(`${IMAGE_LOAD_DELAY}`);
|
||||||
|
await page.getByLabel('Save').click();
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
createImageryViewWithShortDelay,
|
||||||
|
FIVE_MINUTES,
|
||||||
|
IMAGE_LOAD_DELAY,
|
||||||
|
MOUSE_WHEEL_DELTA_Y,
|
||||||
|
THIRTY_SECONDS
|
||||||
|
};
|
@ -30,16 +30,19 @@ import {
|
|||||||
navigateToObjectWithRealTime,
|
navigateToObjectWithRealTime,
|
||||||
setRealTimeMode
|
setRealTimeMode
|
||||||
} from '../../../../appActions.js';
|
} from '../../../../appActions.js';
|
||||||
import { MISSION_TIME } from '../../../../constants.js';
|
import {
|
||||||
|
createImageryViewWithShortDelay,
|
||||||
|
FIVE_MINUTES,
|
||||||
|
IMAGE_LOAD_DELAY,
|
||||||
|
MOUSE_WHEEL_DELTA_Y,
|
||||||
|
THIRTY_SECONDS
|
||||||
|
} from '../../../../helper/imageryUtils.js';
|
||||||
import { expect, test } from '../../../../pluginFixtures.js';
|
import { expect, test } from '../../../../pluginFixtures.js';
|
||||||
|
|
||||||
const panHotkey = process.platform === 'linux' ? ['Shift', 'Alt'] : ['Alt'];
|
const panHotkey = process.platform === 'linux' ? ['Shift', 'Alt'] : ['Alt'];
|
||||||
const tagHotkey = ['Shift', 'Alt'];
|
const tagHotkey = ['Shift', 'Alt'];
|
||||||
const expectedAltText = process.platform === 'linux' ? 'Shift+Alt drag to pan' : 'Alt drag to pan';
|
const expectedAltText = process.platform === 'linux' ? 'Shift+Alt drag to pan' : 'Alt drag to pan';
|
||||||
const thumbnailUrlParamsRegexp = /\?w=100&h=100/;
|
const thumbnailUrlParamsRegexp = /\?w=100&h=100/;
|
||||||
const IMAGE_LOAD_DELAY = 5 * 1000;
|
|
||||||
const MOUSE_WHEEL_DELTA_Y = 120;
|
|
||||||
const FIVE_MINUTES = 1000 * 60 * 5;
|
|
||||||
const THIRTY_SECONDS = 1000 * 30;
|
|
||||||
|
|
||||||
//The following block of tests verifies the basic functionality of example imagery and serves as a template for Imagery objects embedded in other objects.
|
//The following block of tests verifies the basic functionality of example imagery and serves as a template for Imagery objects embedded in other objects.
|
||||||
test.describe('Example Imagery Object', () => {
|
test.describe('Example Imagery Object', () => {
|
||||||
@ -357,15 +360,10 @@ test.describe('Example Imagery Object', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('Example Imagery in Display Layout @clock', () => {
|
test.describe('Example Imagery in Display Layout', () => {
|
||||||
let displayLayout;
|
let displayLayout;
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
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
|
// Go to baseURL
|
||||||
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
@ -428,12 +426,7 @@ test.describe('Example Imagery in Display Layout @clock', () => {
|
|||||||
await expect.soft(pausePlayButton).toHaveClass(/is-paused/);
|
await expect.soft(pausePlayButton).toHaveClass(/is-paused/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Imagery View operations @clock', async ({ page }) => {
|
test('Imagery View operations', async ({ page }) => {
|
||||||
test.info().annotations.push({
|
|
||||||
type: 'issue',
|
|
||||||
description: 'https://github.com/nasa/openmct/issues/5265'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Edit mode
|
// Edit mode
|
||||||
await page.getByLabel('Edit Object').click();
|
await page.getByLabel('Edit Object').click();
|
||||||
|
|
||||||
@ -526,14 +519,9 @@ test.describe('Example Imagery in Display Layout @clock', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('Example Imagery in Flexible layout @clock', () => {
|
test.describe('Example Imagery in Flexible layout', () => {
|
||||||
let flexibleLayout;
|
let flexibleLayout;
|
||||||
test.beforeEach(async ({ page }) => {
|
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' });
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
flexibleLayout = await createDomainObjectWithDefaults(page, { type: 'Flexible Layout' });
|
flexibleLayout = await createDomainObjectWithDefaults(page, { type: 'Flexible Layout' });
|
||||||
@ -562,7 +550,7 @@ test.describe('Example Imagery in Flexible layout @clock', () => {
|
|||||||
await page.getByRole('button', { name: 'Close' }).click();
|
await page.getByRole('button', { name: 'Close' }).click();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Imagery View operations @clock', async ({ page, browserName }) => {
|
test('Imagery View operations', async ({ page, browserName }) => {
|
||||||
test.fixme(browserName === 'firefox', 'This test needs to be updated to work with firefox');
|
test.fixme(browserName === 'firefox', 'This test needs to be updated to work with firefox');
|
||||||
test.info().annotations.push({
|
test.info().annotations.push({
|
||||||
type: 'issue',
|
type: 'issue',
|
||||||
@ -573,14 +561,10 @@ test.describe('Example Imagery in Flexible layout @clock', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('Example Imagery in Tabs View @clock', () => {
|
test.describe('Example Imagery in Tabs View', () => {
|
||||||
let tabsView;
|
let tabsView;
|
||||||
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();
|
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
tabsView = await createDomainObjectWithDefaults(page, { type: 'Tabs View' });
|
tabsView = await createDomainObjectWithDefaults(page, { type: 'Tabs View' });
|
||||||
@ -607,7 +591,8 @@ test.describe('Example Imagery in Tabs View @clock', () => {
|
|||||||
// Wait for image thumbnail auto-scroll to complete
|
// Wait for image thumbnail auto-scroll to complete
|
||||||
await expect(page.getByLabel('Image Thumbnail from').last()).toBeInViewport();
|
await expect(page.getByLabel('Image Thumbnail from').last()).toBeInViewport();
|
||||||
});
|
});
|
||||||
test('Imagery View operations @clock', async ({ page }) => {
|
|
||||||
|
test('Imagery View operations', async ({ page }) => {
|
||||||
await performImageryViewOperationsAndAssert(page, tabsView);
|
await performImageryViewOperationsAndAssert(page, tabsView);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -668,16 +653,19 @@ test.describe('Example Imagery in Time Strip', () => {
|
|||||||
* 3. Can pan the image using the pan hotkey + mouse drag
|
* 3. Can pan the image using the pan hotkey + mouse drag
|
||||||
* 4. Clicking on the left arrow button pauses imagery and moves to the previous image
|
* 4. Clicking on the left arrow button pauses imagery and moves to the previous image
|
||||||
* 5. Imagery is updated as new images stream in, regardless of pause status
|
* 5. Imagery is updated as new images stream in, regardless of pause status
|
||||||
* 6. Old images are discarded when new images stream in
|
* 6. Old images are discarded when their timestamps fall out of bounds
|
||||||
* 7. Image brightness/contrast can be adjusted by dragging the sliders
|
* 7. Multiple images can be discarded when their timestamps fall out of bounds
|
||||||
|
* 8. Image brightness/contrast can be adjusted by dragging the sliders
|
||||||
* @param {import('@playwright/test').Page} page
|
* @param {import('@playwright/test').Page} page
|
||||||
*/
|
*/
|
||||||
async function performImageryViewOperationsAndAssert(page, layoutObject) {
|
async function performImageryViewOperationsAndAssert(page, layoutObject) {
|
||||||
// Verify that imagery thumbnails use a thumbnail url
|
await test.step('Verify that imagery thumbnails use a thumbnail url', async () => {
|
||||||
const thumbnailImages = page.getByLabel('Image thumbnail from').locator('.c-thumb__image');
|
const thumbnailImages = page.getByLabel('Image thumbnail from').locator('.c-thumb__image');
|
||||||
const mainImage = page.locator('.c-imagery__main-image__image');
|
const mainImage = page.locator('.c-imagery__main-image__image');
|
||||||
await expect(thumbnailImages.first()).toHaveAttribute('src', thumbnailUrlParamsRegexp);
|
await expect(thumbnailImages.first()).toHaveAttribute('src', thumbnailUrlParamsRegexp);
|
||||||
await expect(mainImage).not.toHaveAttribute('src', thumbnailUrlParamsRegexp);
|
await expect(mainImage).not.toHaveAttribute('src', thumbnailUrlParamsRegexp);
|
||||||
|
});
|
||||||
|
|
||||||
// Click previous image button
|
// Click previous image button
|
||||||
const previousImageButton = page.getByLabel('Previous image');
|
const previousImageButton = page.getByLabel('Previous image');
|
||||||
await expect(previousImageButton).toBeVisible();
|
await expect(previousImageButton).toBeVisible();
|
||||||
@ -736,19 +724,6 @@ async function performImageryViewOperationsAndAssert(page, layoutObject) {
|
|||||||
// Unpause imagery
|
// Unpause imagery
|
||||||
await page.locator('.pause-play').click();
|
await page.locator('.pause-play').click();
|
||||||
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
//Get background-image url from background-image css prop
|
|
||||||
await assertBackgroundImageUrlFromBackgroundCss(page);
|
|
||||||
|
|
||||||
// Open the image filter menu
|
// Open the image filter menu
|
||||||
await page.locator('[role=toolbar] button[title="Brightness and contrast"]').click();
|
await page.locator('[role=toolbar] button[title="Brightness and contrast"]').click();
|
||||||
|
|
||||||
@ -815,24 +790,6 @@ async function assertBackgroundImageBrightness(page, expected) {
|
|||||||
expect(actual).toBe(expected);
|
expect(actual).toBe(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import('@playwright/test').Page} page
|
* @param {import('@playwright/test').Page} page
|
||||||
*/
|
*/
|
||||||
@ -918,62 +875,66 @@ async function mouseZoomOnImageAndAssert(page, factor = 2) {
|
|||||||
* @param {import('@playwright/test').Page} page
|
* @param {import('@playwright/test').Page} page
|
||||||
*/
|
*/
|
||||||
async function buttonZoomOnImageAndAssert(page) {
|
async function buttonZoomOnImageAndAssert(page) {
|
||||||
// Lock the zoom and pan so it doesn't reset if a new image comes in
|
await test.step('Can zoom using buttons', async () => {
|
||||||
await page.getByLabel('Focused Image Element').hover({ trial: true });
|
// Lock the zoom and pan so it doesn't reset if a new image comes in
|
||||||
const lockButton = page.getByRole('button', {
|
|
||||||
name: 'Lock current zoom and pan across all images'
|
|
||||||
});
|
|
||||||
if (!(await lockButton.isVisible())) {
|
|
||||||
await page.getByLabel('Focused Image Element').hover({ trial: true });
|
await page.getByLabel('Focused Image Element').hover({ trial: true });
|
||||||
}
|
const lockButton = page.getByRole('button', {
|
||||||
await lockButton.click();
|
name: 'Lock current zoom and pan across all images'
|
||||||
|
});
|
||||||
|
|
||||||
await expect(page.getByLabel('Focused Image Element')).toHaveJSProperty(
|
await lockButton.isVisible();
|
||||||
'style.transform',
|
// if (!(await lockButton.isVisible())) {
|
||||||
'scale(1) translate(0px, 0px)'
|
// await page.getByLabel('Focused Image Element').hover({ trial: true });
|
||||||
);
|
// }
|
||||||
|
await lockButton.click();
|
||||||
|
|
||||||
// Get initial image dimensions
|
await expect(page.getByLabel('Focused Image Element')).toHaveJSProperty(
|
||||||
const initialBoundingBox = await page.getByLabel('Focused Image Element').boundingBox();
|
'style.transform',
|
||||||
|
'scale(1) translate(0px, 0px)'
|
||||||
|
);
|
||||||
|
|
||||||
// Zoom in twice via button
|
// Get initial image dimensions
|
||||||
await zoomIntoImageryByButton(page);
|
const initialBoundingBox = await page.getByLabel('Focused Image Element').boundingBox();
|
||||||
await expect(page.getByLabel('Focused Image Element')).toHaveJSProperty(
|
|
||||||
'style.transform',
|
|
||||||
'scale(2) translate(0px, 0px)'
|
|
||||||
);
|
|
||||||
await zoomIntoImageryByButton(page);
|
|
||||||
await expect(page.getByLabel('Focused Image Element')).toHaveJSProperty(
|
|
||||||
'style.transform',
|
|
||||||
'scale(3) translate(0px, 0px)'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get and assert zoomed in image dimensions
|
// Zoom in twice via button
|
||||||
const zoomedInBoundingBox = await page.getByLabel('Focused Image Element').boundingBox();
|
await zoomIntoImageryByButton(page);
|
||||||
expect(zoomedInBoundingBox.height).toBeGreaterThan(initialBoundingBox.height);
|
await expect(page.getByLabel('Focused Image Element')).toHaveJSProperty(
|
||||||
expect(zoomedInBoundingBox.width).toBeGreaterThan(initialBoundingBox.width);
|
'style.transform',
|
||||||
|
'scale(2) translate(0px, 0px)'
|
||||||
|
);
|
||||||
|
await zoomIntoImageryByButton(page);
|
||||||
|
await expect(page.getByLabel('Focused Image Element')).toHaveJSProperty(
|
||||||
|
'style.transform',
|
||||||
|
'scale(3) translate(0px, 0px)'
|
||||||
|
);
|
||||||
|
|
||||||
// Zoom out once via button
|
// Get and assert zoomed in image dimensions
|
||||||
await zoomOutOfImageryByButton(page);
|
const zoomedInBoundingBox = await page.getByLabel('Focused Image Element').boundingBox();
|
||||||
await expect(page.getByLabel('Focused Image Element')).toHaveJSProperty(
|
expect(zoomedInBoundingBox.height).toBeGreaterThan(initialBoundingBox.height);
|
||||||
'style.transform',
|
expect(zoomedInBoundingBox.width).toBeGreaterThan(initialBoundingBox.width);
|
||||||
'scale(2) translate(0px, 0px)'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get and assert zoomed out image dimensions
|
// Zoom out once via button
|
||||||
const zoomedOutBoundingBox = await page.getByLabel('Focused Image Element').boundingBox();
|
await zoomOutOfImageryByButton(page);
|
||||||
expect(zoomedOutBoundingBox.height).toBeLessThan(zoomedInBoundingBox.height);
|
await expect(page.getByLabel('Focused Image Element')).toHaveJSProperty(
|
||||||
expect(zoomedOutBoundingBox.width).toBeLessThan(zoomedInBoundingBox.width);
|
'style.transform',
|
||||||
|
'scale(2) translate(0px, 0px)'
|
||||||
|
);
|
||||||
|
|
||||||
// Zoom out again via button, assert against the initial image dimensions
|
// Get and assert zoomed out image dimensions
|
||||||
await zoomOutOfImageryByButton(page);
|
const zoomedOutBoundingBox = await page.getByLabel('Focused Image Element').boundingBox();
|
||||||
await expect(page.getByLabel('Focused Image Element')).toHaveJSProperty(
|
expect(zoomedOutBoundingBox.height).toBeLessThan(zoomedInBoundingBox.height);
|
||||||
'style.transform',
|
expect(zoomedOutBoundingBox.width).toBeLessThan(zoomedInBoundingBox.width);
|
||||||
'scale(1) translate(0px, 0px)'
|
|
||||||
);
|
|
||||||
|
|
||||||
const finalBoundingBox = await page.getByLabel('Focused Image Element').boundingBox();
|
// Zoom out again via button, assert against the initial image dimensions
|
||||||
expect(finalBoundingBox).toEqual(initialBoundingBox);
|
await zoomOutOfImageryByButton(page);
|
||||||
|
await expect(page.getByLabel('Focused Image Element')).toHaveJSProperty(
|
||||||
|
'style.transform',
|
||||||
|
'scale(1) translate(0px, 0px)'
|
||||||
|
);
|
||||||
|
|
||||||
|
const finalBoundingBox = await page.getByLabel('Focused Image Element').boundingBox();
|
||||||
|
expect(finalBoundingBox).toEqual(initialBoundingBox);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1035,24 +996,6 @@ async function resetImageryPanAndZoom(page) {
|
|||||||
await expect(page.locator('.c-thumb__viewable-area')).toBeHidden();
|
await expect(page.locator('.c-thumb__viewable-area')).toBeHidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import('@playwright/test').Page} page
|
|
||||||
*/
|
|
||||||
async function createImageryViewWithShortDelay(page, { name, parent }) {
|
|
||||||
await createDomainObjectWithDefaults(page, {
|
|
||||||
name,
|
|
||||||
type: 'Example Imagery',
|
|
||||||
parent
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery');
|
|
||||||
await page.getByLabel('More actions').click();
|
|
||||||
await page.getByLabel('Edit Properties').click();
|
|
||||||
// Clear and set Image load delay to minimum value
|
|
||||||
await page.locator('input[type="number"]').fill(`${IMAGE_LOAD_DELAY}`);
|
|
||||||
await page.getByLabel('Save').click();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import('@playwright/test').Page} page
|
* @param {import('@playwright/test').Page} page
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,489 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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);
|
||||||
|
}
|
@ -116,8 +116,7 @@ export default class TelemetryCollection extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will start the requests for historical and realtime data,
|
* @returns {Array} All bounded telemetry
|
||||||
* as well as setting up initial values and watchers
|
|
||||||
*/
|
*/
|
||||||
getAll() {
|
getAll() {
|
||||||
return this.boundedTelemetry;
|
return this.boundedTelemetry;
|
||||||
|
@ -370,6 +370,7 @@ export default {
|
|||||||
createImageWrapper(index, image, showImagePlaceholders) {
|
createImageWrapper(index, image, showImagePlaceholders) {
|
||||||
const id = `${ID_PREFIX}${image.time}`;
|
const id = `${ID_PREFIX}${image.time}`;
|
||||||
let imageWrapper = document.createElement('div');
|
let imageWrapper = document.createElement('div');
|
||||||
|
imageWrapper.ariaLabel = id;
|
||||||
imageWrapper.classList.add(IMAGE_WRAPPER_CLASS);
|
imageWrapper.classList.add(IMAGE_WRAPPER_CLASS);
|
||||||
imageWrapper.style.left = `${this.xScale(image.time)}px`;
|
imageWrapper.style.left = `${this.xScale(image.time)}px`;
|
||||||
this.setNSAttributesForElement(imageWrapper, {
|
this.setNSAttributesForElement(imageWrapper, {
|
||||||
|
@ -620,7 +620,7 @@ export default {
|
|||||||
if (matchIndex > -1) {
|
if (matchIndex > -1) {
|
||||||
this.setFocusedImage(matchIndex);
|
this.setFocusedImage(matchIndex);
|
||||||
} else {
|
} else {
|
||||||
this.paused();
|
this.paused(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1082,7 +1082,7 @@ export default {
|
|||||||
paused(state) {
|
paused(state) {
|
||||||
this.isPaused = Boolean(state);
|
this.isPaused = Boolean(state);
|
||||||
|
|
||||||
if (!state) {
|
if (!this.isPaused) {
|
||||||
this.previousFocusedImage = null;
|
this.previousFocusedImage = null;
|
||||||
this.setFocusedImage(this.nextImageIndex);
|
this.setFocusedImage(this.nextImageIndex);
|
||||||
this.autoScroll = true;
|
this.autoScroll = true;
|
||||||
|
@ -90,16 +90,17 @@ export default {
|
|||||||
dataCleared() {
|
dataCleared() {
|
||||||
this.imageHistory = [];
|
this.imageHistory = [];
|
||||||
},
|
},
|
||||||
dataRemoved(dataToRemove) {
|
dataRemoved(removed) {
|
||||||
this.imageHistory = this.imageHistory.filter((existingDatum) => {
|
const removedTimestamps = {};
|
||||||
const shouldKeep = dataToRemove.some((datumToRemove) => {
|
removed.forEach((_removed) => {
|
||||||
const existingDatumTimestamp = this.parseTime(existingDatum);
|
const removedTimestamp = this.parseTime(_removed);
|
||||||
const datumToRemoveTimestamp = this.parseTime(datumToRemove);
|
removedTimestamps[removedTimestamp] = true;
|
||||||
|
});
|
||||||
|
|
||||||
return existingDatumTimestamp !== datumToRemoveTimestamp;
|
this.imageHistory = this.imageHistory.filter((image) => {
|
||||||
});
|
const imageTimestamp = this.parseTime(image);
|
||||||
|
|
||||||
return shouldKeep;
|
return !removedTimestamps[imageTimestamp];
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setDataTimeContext() {
|
setDataTimeContext() {
|
||||||
|
@ -99,6 +99,7 @@ export default {
|
|||||||
this.composition.off('remove', this.removeItem);
|
this.composition.off('remove', this.removeItem);
|
||||||
this.composition.off('reorder', this.reorder);
|
this.composition.off('reorder', this.reorder);
|
||||||
this.stopFollowingTimeContext();
|
this.stopFollowingTimeContext();
|
||||||
|
this.handleContentResize.cancel();
|
||||||
this.contentResizeObserver.disconnect();
|
this.contentResizeObserver.disconnect();
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
Loading…
Reference in New Issue
Block a user