Compare commits
5 Commits
percy-cli-
...
release/2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b85f0dbb80 | ||
|
|
be4450ddae | ||
|
|
b434a3b9df | ||
|
|
6064a0d4fb | ||
|
|
f8b9d9274b |
@@ -2,7 +2,7 @@ version: 2.1
|
||||
executors:
|
||||
pw-focal-development:
|
||||
docker:
|
||||
- image: mcr.microsoft.com/playwright:v1.25.2-focal
|
||||
- image: mcr.microsoft.com/playwright:v1.25.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
|
||||
|
||||
2
.github/workflows/e2e-couchdb.yml
vendored
2
.github/workflows/e2e-couchdb.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
- run: npx playwright@1.25.2 install
|
||||
- run: npx playwright@1.25.0 install
|
||||
- run: npm install
|
||||
- run: sh src/plugins/persistence/couch/replace-localstorage-with-couchdb-indexhtml.sh
|
||||
- run: npm run test:e2e:couchdb
|
||||
|
||||
2
.github/workflows/e2e-pr.yml
vendored
2
.github/workflows/e2e-pr.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
- run: npx playwright@1.25.2 install
|
||||
- run: npx playwright@1.25.0 install
|
||||
- run: npx playwright install chrome-beta
|
||||
- run: npm install
|
||||
- run: npm run test:e2e:full
|
||||
|
||||
@@ -7,9 +7,8 @@ const config = {
|
||||
retries: 0, // visual tests should never retry due to snapshot comparison errors
|
||||
testDir: 'tests/visual',
|
||||
testMatch: '**/*.visual.spec.js', // only run visual tests
|
||||
timeout: 0,
|
||||
workers: 1, //Limit to 2 for CircleCI Agent
|
||||
repeatEach: 10,
|
||||
timeout: 90 * 1000,
|
||||
workers: 1, //Limit to 1 for CircleCI Agent
|
||||
webServer: {
|
||||
command: 'cross-env NODE_ENV=test npm run start',
|
||||
url: 'http://localhost:8080/#',
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*****************************************************************************
|
||||
* 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 } = require('../../../../appActions');
|
||||
|
||||
test.describe('Testing Flexible Layout @unstable', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('./', { waitUntil: 'networkidle' });
|
||||
|
||||
// Create Sine Wave Generator
|
||||
await createDomainObjectWithDefaults(page, {
|
||||
type: 'Sine Wave Generator',
|
||||
name: "Test Sine Wave Generator"
|
||||
});
|
||||
|
||||
// Create Clock Object
|
||||
await createDomainObjectWithDefaults(page, {
|
||||
type: 'Clock',
|
||||
name: "Test Clock"
|
||||
});
|
||||
});
|
||||
test('panes have the appropriate draggable attribute while in Edit and Browse modes', async ({ page }) => {
|
||||
// Create a Flexible Layout
|
||||
await createDomainObjectWithDefaults(page, {
|
||||
type: 'Flexible Layout',
|
||||
name: "Test Flexible Layout"
|
||||
});
|
||||
// Edit Flexible 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').first().click();
|
||||
// Add the Sine Wave Generator and Clock to the Flexible Layout
|
||||
await page.dragAndDrop('text=Test Sine Wave Generator', '.c-fl__container.is-empty');
|
||||
await page.dragAndDrop('text=Test Clock', '.c-fl__container.is-empty');
|
||||
// Check that panes can be dragged while Flexible Layout is in Edit mode
|
||||
let dragWrapper = await page.locator('.c-fl-container__frames-holder .c-fl-frame__drag-wrapper').first();
|
||||
await expect(dragWrapper).toHaveAttribute('draggable', 'true');
|
||||
// Save Flexible Layout
|
||||
await page.locator('button[title="Save"]').click();
|
||||
await page.locator('text=Save and Finish Editing').click();
|
||||
// Check that panes are not draggable while Flexible Layout is in Browse mode
|
||||
dragWrapper = await page.locator('.c-fl-container__frames-holder .c-fl-frame__drag-wrapper').first();
|
||||
await expect(dragWrapper).toHaveAttribute('draggable', 'false');
|
||||
});
|
||||
});
|
||||
@@ -35,24 +35,45 @@ const expectedAltText = process.platform === 'linux' ? 'Ctrl+Alt drag to pan' :
|
||||
|
||||
//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.beforeEach(async ({ page }) => {
|
||||
//Go to baseURL
|
||||
await page.goto('./', { waitUntil: 'networkidle' });
|
||||
|
||||
// Create a default 'Example Imagery' object
|
||||
await createDomainObjectWithDefaults(page, { type: 'Example Imagery' });
|
||||
createDomainObjectWithDefaults(page, { type: 'Example Imagery' });
|
||||
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.locator(backgroundImageSelector).hover({trial: true}),
|
||||
// eslint-disable-next-line playwright/missing-playwright-await
|
||||
expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery')
|
||||
]);
|
||||
|
||||
// Verify that the created object is focused
|
||||
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery');
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
});
|
||||
|
||||
test('Can use Mouse Wheel to zoom in and out of latest image', async ({ page }) => {
|
||||
// Zoom in x2 and assert
|
||||
await mouseZoomOnImageAndAssert(page, 2);
|
||||
const deltaYStep = 100; //equivalent to 1x zoom
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
const originalImageDimensions = await page.locator(backgroundImageSelector).boundingBox();
|
||||
// zoom in
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
await page.mouse.wheel(0, deltaYStep * 2);
|
||||
// wait for zoom animation to finish
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
const imageMouseZoomedIn = await page.locator(backgroundImageSelector).boundingBox();
|
||||
// zoom out
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
await page.mouse.wheel(0, -deltaYStep);
|
||||
// wait for zoom animation to finish
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
const imageMouseZoomedOut = await page.locator(backgroundImageSelector).boundingBox();
|
||||
|
||||
// Zoom out x2 and assert
|
||||
await mouseZoomOnImageAndAssert(page, -2);
|
||||
expect(imageMouseZoomedIn.height).toBeGreaterThan(originalImageDimensions.height);
|
||||
expect(imageMouseZoomedIn.width).toBeGreaterThan(originalImageDimensions.width);
|
||||
expect(imageMouseZoomedOut.height).toBeLessThan(imageMouseZoomedIn.height);
|
||||
expect(imageMouseZoomedOut.width).toBeLessThan(imageMouseZoomedIn.width);
|
||||
});
|
||||
|
||||
test('Can adjust image brightness/contrast by dragging the sliders', async ({ page, browserName }) => {
|
||||
@@ -130,7 +151,30 @@ test.describe('Example Imagery Object', () => {
|
||||
});
|
||||
|
||||
test('Can use + - buttons to zoom on the image @unstable', async ({ page }) => {
|
||||
await buttonZoomOnImageAndAssert(page);
|
||||
// Get initial image dimensions
|
||||
const initialBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
||||
|
||||
// Zoom in twice via button
|
||||
await zoomIntoImageryByButton(page);
|
||||
await zoomIntoImageryByButton(page);
|
||||
|
||||
// Get and assert zoomed in image dimensions
|
||||
const zoomedInBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
||||
expect(zoomedInBoundingBox.height).toBeGreaterThan(initialBoundingBox.height);
|
||||
expect(zoomedInBoundingBox.width).toBeGreaterThan(initialBoundingBox.width);
|
||||
|
||||
// Zoom out once via button
|
||||
await zoomOutOfImageryByButton(page);
|
||||
|
||||
// Get and assert zoomed out image dimensions
|
||||
const zoomedOutBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
||||
expect(zoomedOutBoundingBox.height).toBeLessThan(zoomedInBoundingBox.height);
|
||||
expect(zoomedOutBoundingBox.width).toBeLessThan(zoomedInBoundingBox.width);
|
||||
|
||||
// Zoom out again via button, assert against the initial image dimensions
|
||||
await zoomOutOfImageryByButton(page);
|
||||
const finalBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
||||
expect(finalBoundingBox).toEqual(initialBoundingBox);
|
||||
});
|
||||
|
||||
test('Can use the reset button to reset the image @unstable', async ({ page }, testInfo) => {
|
||||
@@ -167,223 +211,51 @@ test.describe('Example Imagery Object', () => {
|
||||
await zoomIntoImageryByButton(page);
|
||||
await expect(pausePlayButton).not.toHaveClass(/is-paused/);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Example Imagery in Display Layout', () => {
|
||||
let displayLayout;
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Go to baseURL
|
||||
await page.goto('./', { waitUntil: 'networkidle' });
|
||||
|
||||
displayLayout = await createDomainObjectWithDefaults(page, { type: 'Display Layout' });
|
||||
await page.goto(displayLayout.url);
|
||||
|
||||
/* Create Sine Wave Generator with minimum Image Load Delay */
|
||||
// Click the Create button
|
||||
await page.click('button:has-text("Create")');
|
||||
|
||||
// Click text=Example Imagery
|
||||
await page.click('text=Example Imagery');
|
||||
|
||||
// Clear and set Image load delay to minimum value
|
||||
await page.locator('input[type="number"]').fill('');
|
||||
await page.locator('input[type="number"]').fill('5000');
|
||||
|
||||
// Click text=OK
|
||||
await Promise.all([
|
||||
page.waitForNavigation({waitUntil: 'networkidle'}),
|
||||
page.click('text=OK'),
|
||||
//Wait for Save Banner to appear
|
||||
page.waitForSelector('.c-message-banner__message')
|
||||
]);
|
||||
|
||||
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery');
|
||||
|
||||
await page.goto(displayLayout.url);
|
||||
});
|
||||
|
||||
test('Imagery View operations @unstable', async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/nasa/openmct/issues/5265'
|
||||
});
|
||||
|
||||
// Edit mode
|
||||
await page.click('button[title="Edit"]');
|
||||
|
||||
// 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 performImageryViewOperationsAndAssert(page);
|
||||
});
|
||||
|
||||
test('Resizing the layout changes thumbnail visibility and size', async ({ page }) => {
|
||||
const thumbsWrapperLocator = page.locator('.c-imagery__thumbs-wrapper');
|
||||
// Edit mode
|
||||
await page.click('button[title="Edit"]');
|
||||
|
||||
// Click on example imagery to expose toolbar
|
||||
await page.locator('.c-so-view__header').click();
|
||||
|
||||
// expect thumbnails not be visible when first added
|
||||
expect.soft(thumbsWrapperLocator.isHidden()).toBeTruthy();
|
||||
|
||||
// Resize the example imagery vertically to change the thumbnail visibility
|
||||
/*
|
||||
The following arbitrary values are added to observe the separate visual
|
||||
conditions of the thumbnails (hidden, small thumbnails, regular thumbnails).
|
||||
Specifically, height is set to 50px for small thumbs and 100px for regular
|
||||
*/
|
||||
await page.locator('div[title="Resize object height"] > input').click();
|
||||
await page.locator('div[title="Resize object height"] > input').fill('50');
|
||||
|
||||
expect(thumbsWrapperLocator.isVisible()).toBeTruthy();
|
||||
await expect(thumbsWrapperLocator).toHaveClass(/is-small-thumbs/);
|
||||
|
||||
// Resize the example imagery vertically to change the thumbnail visibility
|
||||
await page.locator('div[title="Resize object height"] > input').click();
|
||||
await page.locator('div[title="Resize object height"] > input').fill('100');
|
||||
|
||||
expect(thumbsWrapperLocator.isVisible()).toBeTruthy();
|
||||
await expect(thumbsWrapperLocator).not.toHaveClass(/is-small-thumbs/);
|
||||
test('Uses low fetch priority', async ({ page }) => {
|
||||
const priority = await page.locator('.js-imageryView-image').getAttribute('fetchpriority');
|
||||
await expect(priority).toBe('low');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Example Imagery in Flexible layout', () => {
|
||||
let flexibleLayout;
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('./', { waitUntil: 'networkidle' });
|
||||
|
||||
flexibleLayout = await createDomainObjectWithDefaults(page, { type: 'Flexible Layout' });
|
||||
await page.goto(flexibleLayout.url);
|
||||
|
||||
/* Create Sine Wave Generator with minimum Image Load Delay */
|
||||
// Click the Create button
|
||||
await page.click('button:has-text("Create")');
|
||||
|
||||
// Click text=Example Imagery
|
||||
await page.click('text=Example Imagery');
|
||||
|
||||
// Clear and set Image load delay to minimum value
|
||||
await page.locator('input[type="number"]').fill('');
|
||||
await page.locator('input[type="number"]').fill('5000');
|
||||
|
||||
// Click text=OK
|
||||
await Promise.all([
|
||||
page.waitForNavigation({waitUntil: 'networkidle'}),
|
||||
page.click('text=OK'),
|
||||
//Wait for Save Banner to appear
|
||||
page.waitForSelector('.c-message-banner__message')
|
||||
]);
|
||||
|
||||
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery');
|
||||
|
||||
await page.goto(flexibleLayout.url);
|
||||
// The following test case will cover these scenarios
|
||||
// ('Can use Mouse Wheel to zoom in and out of previous image');
|
||||
// ('Can use alt+drag to move around image once zoomed in');
|
||||
// ('Clicking on the left arrow should pause the imagery and go to previous image');
|
||||
// ('If the imagery view is in pause mode, it should not be updated when new images come in');
|
||||
// ('If the imagery view is not in pause mode, it should be updated when new images come in');
|
||||
test('Example Imagery in Display layout @unstable', async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/nasa/openmct/issues/5265'
|
||||
});
|
||||
test('Imagery View operations @unstable', 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'
|
||||
});
|
||||
|
||||
await performImageryViewOperationsAndAssert(page);
|
||||
});
|
||||
});
|
||||
// Go to baseURL
|
||||
await page.goto('./', { waitUntil: 'networkidle' });
|
||||
|
||||
test.describe('Example Imagery in Tabs View', () => {
|
||||
let tabsView;
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('./', { waitUntil: 'networkidle' });
|
||||
// Click the Create button
|
||||
await page.click('button:has-text("Create")');
|
||||
|
||||
tabsView = await createDomainObjectWithDefaults(page, { type: 'Tabs View' });
|
||||
await page.goto(tabsView.url);
|
||||
// Click text=Example Imagery
|
||||
await page.click('text=Example Imagery');
|
||||
|
||||
/* Create Sine Wave Generator with minimum Image Load Delay */
|
||||
// Click the Create button
|
||||
await page.click('button:has-text("Create")');
|
||||
// Clear and set Image load delay to minimum value
|
||||
await page.locator('input[type="number"]').fill('');
|
||||
await page.locator('input[type="number"]').fill('5000');
|
||||
|
||||
// Click text=Example Imagery
|
||||
await page.click('text=Example Imagery');
|
||||
// Click text=OK
|
||||
await Promise.all([
|
||||
page.waitForNavigation({waitUntil: 'networkidle'}),
|
||||
page.click('text=OK'),
|
||||
//Wait for Save Banner to appear
|
||||
page.waitForSelector('.c-message-banner__message')
|
||||
]);
|
||||
|
||||
// Clear and set Image load delay to minimum value
|
||||
await page.locator('input[type="number"]').fill('');
|
||||
await page.locator('input[type="number"]').fill('5000');
|
||||
// Wait until Save Banner is gone
|
||||
await page.waitForSelector('.c-message-banner__message', { state: 'detached'});
|
||||
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery');
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
|
||||
// Click text=OK
|
||||
await Promise.all([
|
||||
page.waitForNavigation({waitUntil: 'networkidle'}),
|
||||
page.click('text=OK'),
|
||||
//Wait for Save Banner to appear
|
||||
page.waitForSelector('.c-message-banner__message')
|
||||
]);
|
||||
|
||||
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery');
|
||||
|
||||
await page.goto(tabsView.url);
|
||||
});
|
||||
test('Imagery View operations @unstable', async ({ page }) => {
|
||||
await performImageryViewOperationsAndAssert(page);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Example Imagery in Time Strip', () => {
|
||||
let timeStripObject;
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('./', { waitUntil: 'networkidle' });
|
||||
timeStripObject = await createDomainObjectWithDefaults(page, {
|
||||
type: 'Time Strip',
|
||||
name: 'Time Strip'.concat(' ', uuid())
|
||||
});
|
||||
|
||||
await createDomainObjectWithDefaults(page, {
|
||||
type: 'Example Imagery',
|
||||
name: 'Example Imagery'.concat(' ', uuid()),
|
||||
parent: timeStripObject.uuid
|
||||
});
|
||||
// Navigate to timestrip
|
||||
await page.goto(timeStripObject.url);
|
||||
});
|
||||
test('Clicking a thumbnail loads the image in large view', async ({ page, browserName }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/nasa/openmct/issues/5632'
|
||||
});
|
||||
await page.locator('.c-imagery-tsv-container').hover();
|
||||
// get url of the hovered image
|
||||
const hoveredImg = page.locator('.c-imagery-tsv div.c-imagery-tsv__image-wrapper:hover img');
|
||||
const hoveredImgSrc = await hoveredImg.getAttribute('src');
|
||||
expect(hoveredImgSrc).toBeTruthy();
|
||||
await page.locator('.c-imagery-tsv-container').click();
|
||||
// get image of view large container
|
||||
const viewLargeImg = page.locator('img.c-imagery__main-image__image');
|
||||
const viewLargeImgSrc = await viewLargeImg.getAttribute('src');
|
||||
expect(viewLargeImgSrc).toBeTruthy();
|
||||
expect(viewLargeImgSrc).toEqual(hoveredImgSrc);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Perform the common actions and assertions for the Imagery View.
|
||||
* This function verifies the following in order:
|
||||
* 1. Can zoom in/out using the zoom buttons
|
||||
* 2. Can zoom in/out using the mouse wheel
|
||||
* 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
|
||||
* 5. Imagery is updated as new images stream in, regardless of pause status
|
||||
* 6. Old images are discarded when new images stream in
|
||||
* 7. Image brightness/contrast can be adjusted by dragging the sliders
|
||||
* @param {import('@playwright/test').Page} page
|
||||
*/
|
||||
async function performImageryViewOperationsAndAssert(page) {
|
||||
// Click previous image button
|
||||
const previousImageButton = page.locator('.c-nav--prev');
|
||||
await previousImageButton.click();
|
||||
@@ -392,17 +264,27 @@ async function performImageryViewOperationsAndAssert(page) {
|
||||
const selectedImage = page.locator('.selected');
|
||||
await expect(selectedImage).toBeVisible();
|
||||
|
||||
// Use the zoom buttons to zoom in and out
|
||||
await buttonZoomOnImageAndAssert(page);
|
||||
// Zoom in
|
||||
const originalImageDimensions = await page.locator(backgroundImageSelector).boundingBox();
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
const deltaYStep = 100; // equivalent to 1x zoom
|
||||
await page.mouse.wheel(0, deltaYStep * 2);
|
||||
const zoomedBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
||||
const imageCenterX = zoomedBoundingBox.x + zoomedBoundingBox.width / 2;
|
||||
const imageCenterY = zoomedBoundingBox.y + zoomedBoundingBox.height / 2;
|
||||
|
||||
// Use Mouse Wheel to zoom in to previous image
|
||||
await mouseZoomOnImageAndAssert(page, 2);
|
||||
// Wait for zoom animation to finish
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
const imageMouseZoomedIn = await page.locator(backgroundImageSelector).boundingBox();
|
||||
expect(imageMouseZoomedIn.height).toBeGreaterThan(originalImageDimensions.height);
|
||||
expect(imageMouseZoomedIn.width).toBeGreaterThan(originalImageDimensions.width);
|
||||
|
||||
// Use alt+drag to move around image once zoomed in
|
||||
await panZoomAndAssertImageProperties(page);
|
||||
// Center the mouse pointer
|
||||
await page.mouse.move(imageCenterX, imageCenterY);
|
||||
|
||||
// Use Mouse Wheel to zoom out of previous image
|
||||
await mouseZoomOnImageAndAssert(page, -2);
|
||||
// Pan Imagery Hints
|
||||
const imageryHintsText = await page.locator('.c-imagery__hints').innerText();
|
||||
expect(expectedAltText).toEqual(imageryHintsText);
|
||||
|
||||
// Click next image button
|
||||
const nextImageButton = page.locator('.c-nav--next');
|
||||
@@ -415,14 +297,21 @@ async function performImageryViewOperationsAndAssert(page) {
|
||||
await page.locator('[data-testid=conductor-modeOption-realtime]').click();
|
||||
|
||||
// Zoom in on next image
|
||||
await mouseZoomOnImageAndAssert(page, 2);
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
await page.mouse.wheel(0, deltaYStep * 2);
|
||||
|
||||
// Clicking on the left arrow should pause the imagery and go to previous image
|
||||
// Wait for zoom animation to finish
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
const imageNextMouseZoomedIn = await page.locator(backgroundImageSelector).boundingBox();
|
||||
expect(imageNextMouseZoomedIn.height).toBeGreaterThan(originalImageDimensions.height);
|
||||
expect(imageNextMouseZoomedIn.width).toBeGreaterThan(originalImageDimensions.width);
|
||||
|
||||
// Click previous image button
|
||||
await previousImageButton.click();
|
||||
await expect(page.locator('.c-button.pause-play')).toHaveClass(/is-paused/);
|
||||
|
||||
// Verify previous image
|
||||
await expect(selectedImage).toBeVisible();
|
||||
|
||||
// The imagery view should be updated when new images come in
|
||||
const imageCount = await page.locator('.c-imagery__thumb').count();
|
||||
await expect.poll(async () => {
|
||||
const newImageCount = await page.locator('.c-imagery__thumb').count();
|
||||
@@ -430,7 +319,7 @@ async function performImageryViewOperationsAndAssert(page) {
|
||||
return newImageCount;
|
||||
}, {
|
||||
message: "verify that old images are discarded",
|
||||
timeout: 7 * 1000
|
||||
timeout: 6 * 1000
|
||||
}).toBe(imageCount);
|
||||
|
||||
// Verify selected image is still displayed
|
||||
@@ -448,6 +337,283 @@ async function performImageryViewOperationsAndAssert(page) {
|
||||
// Drag the brightness and contrast sliders around and assert filter values
|
||||
await dragBrightnessSliderAndAssertFilterValues(page);
|
||||
await dragContrastSliderAndAssertFilterValues(page);
|
||||
});
|
||||
|
||||
test.describe('Example imagery thumbnails resize in display layouts', () => {
|
||||
test('Resizing the layout changes thumbnail visibility and size', async ({ page }) => {
|
||||
await page.goto('./', { waitUntil: 'networkidle' });
|
||||
|
||||
const thumbsWrapperLocator = page.locator('.c-imagery__thumbs-wrapper');
|
||||
// Click button:has-text("Create")
|
||||
await page.locator('button:has-text("Create")').click();
|
||||
|
||||
// Click li:has-text("Display Layout")
|
||||
await page.locator('li:has-text("Display Layout")').click();
|
||||
const displayLayoutTitleField = page.locator('text=Properties Title Notes Horizontal grid (px) Vertical grid (px) Horizontal size ( >> input[type="text"]');
|
||||
await displayLayoutTitleField.click();
|
||||
|
||||
await displayLayoutTitleField.fill('Thumbnail Display Layout');
|
||||
|
||||
// Click text=OK
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.locator('text=OK').click()
|
||||
]);
|
||||
|
||||
// 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 button:has-text("Create")
|
||||
await page.locator('button:has-text("Create")').click();
|
||||
|
||||
// Click li:has-text("Example Imagery")
|
||||
await page.locator('li:has-text("Example Imagery")').click();
|
||||
|
||||
const imageryTitleField = page.locator('text=Properties Title Notes Images url list (comma separated) Image load delay (milli >> input[type="text"]');
|
||||
// Click text=Properties Title Notes Images url list (comma separated) Image load delay (milli >> input[type="text"]
|
||||
await imageryTitleField.click();
|
||||
|
||||
// Fill text=Properties Title Notes Images url list (comma separated) Image load delay (milli >> input[type="text"]
|
||||
await imageryTitleField.fill('Thumbnail Example Imagery');
|
||||
|
||||
// Click text=OK
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.locator('text=OK').click()
|
||||
]);
|
||||
|
||||
// Click text=Thumbnail Example Imagery Imagery Layout Snapshot >> button >> nth=0
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.locator('text=Thumbnail Example Imagery Imagery Layout Snapshot >> button').first().click()
|
||||
]);
|
||||
|
||||
// Edit mode
|
||||
await page.locator('text=Thumbnail Display Layout Snapshot >> button').nth(3).click();
|
||||
|
||||
// Click on example imagery to expose toolbar
|
||||
await page.locator('text=Thumbnail Example Imagery Snapshot Large View').click();
|
||||
|
||||
// expect thumbnails not be visible when first added
|
||||
expect.soft(thumbsWrapperLocator.isHidden()).toBeTruthy();
|
||||
|
||||
// Resize the example imagery vertically to change the thumbnail visibility
|
||||
/*
|
||||
The following arbitrary values are added to observe the separate visual
|
||||
conditions of the thumbnails (hidden, small thumbnails, regular thumbnails).
|
||||
Specifically, height is set to 50px for small thumbs and 100px for regular
|
||||
*/
|
||||
// Click #mct-input-id-103
|
||||
await page.locator('#mct-input-id-103').click();
|
||||
|
||||
// Fill #mct-input-id-103
|
||||
await page.locator('#mct-input-id-103').fill('50');
|
||||
|
||||
expect(thumbsWrapperLocator.isVisible()).toBeTruthy();
|
||||
await expect(thumbsWrapperLocator).toHaveClass(/is-small-thumbs/);
|
||||
|
||||
// Resize the example imagery vertically to change the thumbnail visibility
|
||||
// Click #mct-input-id-103
|
||||
await page.locator('#mct-input-id-103').click();
|
||||
|
||||
// Fill #mct-input-id-103
|
||||
await page.locator('#mct-input-id-103').fill('100');
|
||||
|
||||
expect(thumbsWrapperLocator.isVisible()).toBeTruthy();
|
||||
await expect(thumbsWrapperLocator).not.toHaveClass(/is-small-thumbs/);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Example Imagery in Flexible layout', () => {
|
||||
test('Example Imagery in Flexible layout @unstable', async ({ page, browserName, openmctConfig }) => {
|
||||
const { myItemsFolderName } = openmctConfig;
|
||||
|
||||
// eslint-disable-next-line playwright/no-skipped-test
|
||||
test.skip(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'
|
||||
});
|
||||
|
||||
// Go to baseURL
|
||||
await page.goto('./', { waitUntil: 'networkidle' });
|
||||
|
||||
// Click the Create button
|
||||
await page.click('button:has-text("Create")');
|
||||
|
||||
// Click text=Example Imagery
|
||||
await page.click('text=Example Imagery');
|
||||
|
||||
// Clear and set Image load delay (milliseconds)
|
||||
await page.click('input[type="number"]', {clickCount: 3});
|
||||
await page.type('input[type="number"]', "20");
|
||||
|
||||
// Click text=OK
|
||||
await Promise.all([
|
||||
page.waitForNavigation({waitUntil: 'networkidle'}),
|
||||
page.click('text=OK'),
|
||||
//Wait for Save Banner to appear
|
||||
page.waitForSelector('.c-message-banner__message')
|
||||
]);
|
||||
// Wait until Save Banner is gone
|
||||
await page.waitForSelector('.c-message-banner__message', { state: 'detached'});
|
||||
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery');
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
|
||||
// Click the Create button
|
||||
await page.click('button:has-text("Create")');
|
||||
|
||||
// Click text=Flexible Layout
|
||||
await page.click('text=Flexible Layout');
|
||||
|
||||
// Assert Flexible layout
|
||||
await expect(page.locator('.js-form-title')).toHaveText('Create a New Flexible Layout');
|
||||
|
||||
await page.locator(`form[name="mctForm"] >> text=${myItemsFolderName}`).click();
|
||||
|
||||
// Click My Items
|
||||
await Promise.all([
|
||||
page.locator('text=OK').click(),
|
||||
page.waitForNavigation({waitUntil: 'networkidle'})
|
||||
]);
|
||||
|
||||
// Click My Items
|
||||
await page.locator('.c-disclosure-triangle').click();
|
||||
|
||||
// Right click example imagery
|
||||
await page.click(('text=Unnamed Example Imagery'), { button: 'right' });
|
||||
|
||||
// Click move
|
||||
await page.locator('.icon-move').click();
|
||||
|
||||
// Click triangle to open sub menu
|
||||
await page.locator('.c-form__section .c-disclosure-triangle').click();
|
||||
|
||||
// Click Flexable Layout
|
||||
await page.click('.c-overlay__outer >> text=Unnamed Flexible Layout');
|
||||
|
||||
// Click text=OK
|
||||
await page.locator('text=OK').click();
|
||||
|
||||
// Save template
|
||||
await saveTemplate(page);
|
||||
|
||||
// Zoom in
|
||||
await mouseZoomIn(page);
|
||||
|
||||
// Center the mouse pointer
|
||||
const zoomedBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
||||
const imageCenterX = zoomedBoundingBox.x + zoomedBoundingBox.width / 2;
|
||||
const imageCenterY = zoomedBoundingBox.y + zoomedBoundingBox.height / 2;
|
||||
await page.mouse.move(imageCenterX, imageCenterY);
|
||||
|
||||
// Pan zoom
|
||||
await panZoomAndAssertImageProperties(page);
|
||||
|
||||
// Click previous image button
|
||||
const previousImageButton = page.locator('.c-nav--prev');
|
||||
await previousImageButton.click();
|
||||
|
||||
// Verify previous image
|
||||
const selectedImage = page.locator('.selected');
|
||||
await expect(selectedImage).toBeVisible();
|
||||
|
||||
// Click time conductor mode button
|
||||
await page.locator('.c-mode-button').click();
|
||||
|
||||
// Select local clock mode
|
||||
await page.locator('[data-testid=conductor-modeOption-realtime]').nth(0).click();
|
||||
|
||||
// Zoom in on next image
|
||||
await mouseZoomIn(page);
|
||||
|
||||
// Click previous image button
|
||||
await previousImageButton.click();
|
||||
|
||||
// Verify previous image
|
||||
await expect(selectedImage).toBeVisible();
|
||||
|
||||
const imageCount = await page.locator('.c-imagery__thumb').count();
|
||||
await expect.poll(async () => {
|
||||
const newImageCount = await page.locator('.c-imagery__thumb').count();
|
||||
|
||||
return newImageCount;
|
||||
}, {
|
||||
message: "verify that old images are discarded",
|
||||
timeout: 6 * 1000
|
||||
}).toBe(imageCount);
|
||||
|
||||
// Verify selected image is still displayed
|
||||
await expect(selectedImage).toBeVisible();
|
||||
|
||||
// Unpause imagery
|
||||
await page.locator('.pause-play').click();
|
||||
|
||||
//Get background-image url from background-image css prop
|
||||
await assertBackgroundImageUrlFromBackgroundCss(page);
|
||||
|
||||
// Open the image filter menu
|
||||
await page.locator('[role=toolbar] button[title="Brightness and contrast"]').click();
|
||||
|
||||
// Drag the brightness and contrast sliders around and assert filter values
|
||||
await dragBrightnessSliderAndAssertFilterValues(page);
|
||||
await dragContrastSliderAndAssertFilterValues(page);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Example Imagery in Tabs view', () => {
|
||||
test.fixme('Can use Mouse Wheel to zoom in and out of previous image');
|
||||
test.fixme('Can use alt+drag to move around image once zoomed in');
|
||||
test.fixme('Can zoom into the latest image and the real-time/fixed-time imagery will pause');
|
||||
test.fixme('Can zoom into a previous image from thumbstrip in real-time or fixed-time');
|
||||
test.fixme('Clicking on the left arrow should pause the imagery and go to previous image');
|
||||
test.fixme('If the imagery view is in pause mode, it should not be updated when new images come in');
|
||||
test.fixme('If the imagery view is not in pause mode, it should be updated when new images come in');
|
||||
});
|
||||
|
||||
test.describe('Example Imagery in Time Strip', () => {
|
||||
test('ensure that clicking a thumbnail loads the image in large view', async ({ page, browserName }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/nasa/openmct/issues/5632'
|
||||
});
|
||||
await page.goto('./', { waitUntil: 'networkidle' });
|
||||
const timeStripObject = await createDomainObjectWithDefaults(page, {
|
||||
type: 'Time Strip',
|
||||
name: 'Time Strip'.concat(' ', uuid())
|
||||
});
|
||||
|
||||
await createDomainObjectWithDefaults(page, {
|
||||
type: 'Example Imagery',
|
||||
name: 'Example Imagery'.concat(' ', uuid()),
|
||||
parent: timeStripObject.uuid
|
||||
});
|
||||
// Navigate to timestrip
|
||||
await page.goto(timeStripObject.url);
|
||||
|
||||
await page.locator('.c-imagery-tsv-container').hover();
|
||||
// get url of the hovered image
|
||||
const hoveredImg = page.locator('.c-imagery-tsv div.c-imagery-tsv__image-wrapper:hover img');
|
||||
const hoveredImgSrc = await hoveredImg.getAttribute('src');
|
||||
expect(hoveredImgSrc).toBeTruthy();
|
||||
await page.locator('.c-imagery-tsv-container').click();
|
||||
// get image of view large container
|
||||
const viewLargeImg = page.locator('img.c-imagery__main-image__image');
|
||||
const viewLargeImgSrc = await viewLargeImg.getAttribute('src');
|
||||
expect(viewLargeImgSrc).toBeTruthy();
|
||||
expect(viewLargeImgSrc).toEqual(hoveredImgSrc);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {import('@playwright/test').Page} page
|
||||
*/
|
||||
async function saveTemplate(page) {
|
||||
await page.locator('.c-button--menu.c-button--major.icon-save').click();
|
||||
await page.locator('text=Save and Finish Editing').click();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -530,7 +696,7 @@ async function assertBackgroundImageUrlFromBackgroundCss(page) {
|
||||
return backgroundImageUrl2;
|
||||
}, {
|
||||
message: "verify next image has updated",
|
||||
timeout: 7 * 1000
|
||||
timeout: 6 * 1000
|
||||
}).not.toBe(backgroundImageUrl1);
|
||||
console.log('backgroundImageUrl2 ' + backgroundImageUrl2);
|
||||
}
|
||||
@@ -584,17 +750,14 @@ async function panZoomAndAssertImageProperties(page) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the mouse wheel to zoom in or out of an image and assert that the image
|
||||
* has successfully zoomed in or out.
|
||||
* @param {import('@playwright/test').Page} page
|
||||
* @param {number} [factor = 2] The zoom factor. Positive for zoom in, negative for zoom out.
|
||||
*/
|
||||
async function mouseZoomOnImageAndAssert(page, factor = 2) {
|
||||
async function mouseZoomIn(page) {
|
||||
// Zoom in
|
||||
const originalImageDimensions = await page.locator(backgroundImageSelector).boundingBox();
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
const deltaYStep = 100; // equivalent to 1x zoom
|
||||
await page.mouse.wheel(0, deltaYStep * factor);
|
||||
await page.mouse.wheel(0, deltaYStep * 2);
|
||||
const zoomedBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
||||
const imageCenterX = zoomedBoundingBox.x + zoomedBoundingBox.width / 2;
|
||||
const imageCenterY = zoomedBoundingBox.y + zoomedBoundingBox.height / 2;
|
||||
@@ -604,47 +767,9 @@ async function mouseZoomOnImageAndAssert(page, factor = 2) {
|
||||
|
||||
// Wait for zoom animation to finish
|
||||
await page.locator(backgroundImageSelector).hover({trial: true});
|
||||
const imageMouseZoomed = await page.locator(backgroundImageSelector).boundingBox();
|
||||
|
||||
if (factor > 0) {
|
||||
expect(imageMouseZoomed.height).toBeGreaterThan(originalImageDimensions.height);
|
||||
expect(imageMouseZoomed.width).toBeGreaterThan(originalImageDimensions.width);
|
||||
} else {
|
||||
expect(imageMouseZoomed.height).toBeLessThan(originalImageDimensions.height);
|
||||
expect(imageMouseZoomed.width).toBeLessThan(originalImageDimensions.width);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zoom in and out of the image using the buttons, and assert that the image has
|
||||
* been successfully zoomed in or out.
|
||||
* @param {import('@playwright/test').Page} page
|
||||
*/
|
||||
async function buttonZoomOnImageAndAssert(page) {
|
||||
// Get initial image dimensions
|
||||
const initialBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
||||
|
||||
// Zoom in twice via button
|
||||
await zoomIntoImageryByButton(page);
|
||||
await zoomIntoImageryByButton(page);
|
||||
|
||||
// Get and assert zoomed in image dimensions
|
||||
const zoomedInBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
||||
expect(zoomedInBoundingBox.height).toBeGreaterThan(initialBoundingBox.height);
|
||||
expect(zoomedInBoundingBox.width).toBeGreaterThan(initialBoundingBox.width);
|
||||
|
||||
// Zoom out once via button
|
||||
await zoomOutOfImageryByButton(page);
|
||||
|
||||
// Get and assert zoomed out image dimensions
|
||||
const zoomedOutBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
||||
expect(zoomedOutBoundingBox.height).toBeLessThan(zoomedInBoundingBox.height);
|
||||
expect(zoomedOutBoundingBox.width).toBeLessThan(zoomedInBoundingBox.width);
|
||||
|
||||
// Zoom out again via button, assert against the initial image dimensions
|
||||
await zoomOutOfImageryByButton(page);
|
||||
const finalBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
||||
expect(finalBoundingBox).toEqual(initialBoundingBox);
|
||||
const imageMouseZoomedIn = await page.locator(backgroundImageSelector).boundingBox();
|
||||
expect(imageMouseZoomedIn.height).toBeGreaterThan(originalImageDimensions.height);
|
||||
expect(imageMouseZoomedIn.width).toBeGreaterThan(originalImageDimensions.width);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "openmct",
|
||||
"version": "2.0.8",
|
||||
"version": "2.1.0",
|
||||
"description": "The Open MCT core platform",
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "7.18.9",
|
||||
"@braintree/sanitize-url": "6.0.0",
|
||||
"@percy/cli": "1.10.2",
|
||||
"@percy/cli": "1.7.2",
|
||||
"@percy/playwright": "1.0.4",
|
||||
"@playwright/test": "1.25.2",
|
||||
"@playwright/test": "1.25.0",
|
||||
"@types/eventemitter3": "^1.0.0",
|
||||
"@types/jasmine": "^4.0.1",
|
||||
"@types/karma": "^6.3.2",
|
||||
@@ -93,7 +93,6 @@
|
||||
"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 --grep-invert @unstable",
|
||||
"test:e2e:visual:debug": "percy exec --config ./e2e/.percy.yml --debug -- npx playwright test --config=e2e/playwright-visual.config.js --grep-invert @unstable",
|
||||
"test:e2e:full": "npx playwright test --config=e2e/playwright-ci.config.js --grep-invert @couchdb",
|
||||
"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",
|
||||
|
||||
@@ -147,7 +147,7 @@ export default {
|
||||
this.mutablePromise.then(() => {
|
||||
this.openmct.objects.destroyMutable(this.domainObject);
|
||||
});
|
||||
} else if (this.domainObject.isMutable) {
|
||||
} else if (this?.domainObject?.isMutable) {
|
||||
this.openmct.objects.destroyMutable(this.domainObject);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -243,7 +243,7 @@ export default {
|
||||
this.mutablePromise.then(() => {
|
||||
this.openmct.objects.destroyMutable(this.domainObject);
|
||||
});
|
||||
} else if (this.domainObject.isMutable) {
|
||||
} else if (this?.domainObject?.isMutable) {
|
||||
this.openmct.objects.destroyMutable(this.domainObject);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -281,6 +281,10 @@ export default {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.isEditing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let containerId = event.dataTransfer.getData('containerid');
|
||||
let container = this.containers.filter((c) => c.id === containerId)[0];
|
||||
let containerPos = this.containers.indexOf(container);
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<div
|
||||
ref="frame"
|
||||
class="c-frame c-fl-frame__drag-wrapper is-selectable u-inspectable is-moveable"
|
||||
draggable="true"
|
||||
:draggable="draggable"
|
||||
@dragstart="initDrag"
|
||||
>
|
||||
<object-frame
|
||||
@@ -93,18 +93,20 @@ export default {
|
||||
computed: {
|
||||
hasFrame() {
|
||||
return !this.frame.noFrame;
|
||||
},
|
||||
draggable() {
|
||||
return this.isEditing;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.frame.domainObjectIdentifier) {
|
||||
let domainObjectPromise;
|
||||
if (this.openmct.objects.supportsMutation(this.frame.domainObjectIdentifier)) {
|
||||
domainObjectPromise = this.openmct.objects.getMutable(this.frame.domainObjectIdentifier);
|
||||
this.domainObjectPromise = this.openmct.objects.getMutable(this.frame.domainObjectIdentifier);
|
||||
} else {
|
||||
domainObjectPromise = this.openmct.objects.get(this.frame.domainObjectIdentifier);
|
||||
this.domainObjectPromise = this.openmct.objects.get(this.frame.domainObjectIdentifier);
|
||||
}
|
||||
|
||||
domainObjectPromise.then((object) => {
|
||||
this.domainObjectPromise.then((object) => {
|
||||
this.setDomainObject(object);
|
||||
});
|
||||
}
|
||||
@@ -112,7 +114,13 @@ export default {
|
||||
this.dragGhost = document.getElementById('js-fl-drag-ghost');
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.domainObject.isMutable) {
|
||||
if (this.domainObjectPromise) {
|
||||
this.domainObjectPromise.then(() => {
|
||||
if (this?.domainObject?.isMutable) {
|
||||
this.openmct.objects.destroyMutable(this.domainObject);
|
||||
}
|
||||
});
|
||||
} else if (this?.domainObject?.isMutable) {
|
||||
this.openmct.objects.destroyMutable(this.domainObject);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<img
|
||||
class="c-thumb__image"
|
||||
:src="image.url"
|
||||
fetchpriority="low"
|
||||
>
|
||||
</a>
|
||||
<div class="c-thumb__timestamp">{{ image.formattedTime }}</div>
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
}"
|
||||
:data-openmct-image-timestamp="time"
|
||||
:data-openmct-object-keystring="keyString"
|
||||
fetchpriority="low"
|
||||
>
|
||||
<div
|
||||
v-if="imageUrl"
|
||||
|
||||
@@ -187,6 +187,7 @@ class CouchObjectProvider {
|
||||
let fetchOptions = {
|
||||
method,
|
||||
body,
|
||||
priority: 'high',
|
||||
signal
|
||||
};
|
||||
|
||||
|
||||
@@ -109,6 +109,12 @@ describe('the plugin', () => {
|
||||
expect(result.identifier.key).toEqual(mockDomainObject.identifier.key);
|
||||
});
|
||||
|
||||
it('prioritizes couch requests above other requests', async () => {
|
||||
await openmct.objects.get(mockDomainObject.identifier);
|
||||
const fetchOptions = fetch.calls.mostRecent().args[1];
|
||||
expect(fetchOptions.priority).toEqual('high');
|
||||
});
|
||||
|
||||
it('creates an object and starts shared worker', async () => {
|
||||
const result = await openmct.objects.save(mockDomainObject);
|
||||
expect(provider.create).toHaveBeenCalled();
|
||||
|
||||
@@ -92,7 +92,7 @@ export default {
|
||||
this.mutablePromise.then(() => {
|
||||
this.openmct.objects.destroyMutable(this.domainObject);
|
||||
});
|
||||
} else if (this.domainObject.isMutable) {
|
||||
} else if (this?.domainObject?.isMutable) {
|
||||
this.openmct.objects.destroyMutable(this.domainObject);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -110,7 +110,9 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.isEditing = this.openmct.editor.isEditing();
|
||||
this.timestamp = Date.now();
|
||||
this.timestamp = this.openmct.time.clock()?.currentValue() || this.openmct.time.bounds()?.start;
|
||||
this.openmct.time.on('clock', this.setViewFromClock);
|
||||
|
||||
this.getPlanDataAndSetConfig(this.domainObject);
|
||||
|
||||
this.unlisten = this.openmct.objects.observe(this.domainObject, 'selectFile', this.planFileUpdated);
|
||||
@@ -118,6 +120,7 @@ export default {
|
||||
this.removeStatusListener = this.openmct.status.observe(this.domainObject.identifier, this.setStatus);
|
||||
this.status = this.openmct.status.get(this.domainObject.identifier);
|
||||
this.unlistenTicker = ticker.listen(this.clearPreviousActivities);
|
||||
this.openmct.time.on('bounds', this.updateTimestamp);
|
||||
this.openmct.editor.on('isEditing', this.setEditState);
|
||||
|
||||
this.deferAutoScroll = _.debounce(this.deferAutoScroll, 500);
|
||||
@@ -128,6 +131,9 @@ export default {
|
||||
this.composition.on('remove', this.removeItem);
|
||||
this.composition.load();
|
||||
}
|
||||
|
||||
this.setViewFromClock(this.openmct.time.clock());
|
||||
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.unlisten) {
|
||||
@@ -147,6 +153,8 @@ export default {
|
||||
}
|
||||
|
||||
this.openmct.editor.off('isEditing', this.setEditState);
|
||||
this.openmct.time.off('bounds', this.updateTimestamp);
|
||||
this.openmct.time.off('clock', this.setViewFromClock);
|
||||
|
||||
this.$el.parentElement.removeEventListener('scroll', this.deferAutoScroll, true);
|
||||
if (this.clearAutoScrollDisabledTimer) {
|
||||
@@ -176,12 +184,32 @@ export default {
|
||||
this.showAll = true;
|
||||
this.listActivities();
|
||||
} else {
|
||||
|
||||
this.filterValue = configuration.filter;
|
||||
this.setSort();
|
||||
this.setViewBounds();
|
||||
this.listActivities();
|
||||
}
|
||||
},
|
||||
updateTimestamp(_bounds, isTick) {
|
||||
if (isTick === true) {
|
||||
this.timestamp = this.openmct.time.clock().currentValue();
|
||||
}
|
||||
},
|
||||
setViewFromClock(newClock) {
|
||||
this.filterValue = this.domainObject.configuration.filter;
|
||||
const isFixedTime = newClock === undefined;
|
||||
if (isFixedTime) {
|
||||
this.hideAll = false;
|
||||
this.showAll = true;
|
||||
// clear invokes listActivities
|
||||
this.clearPreviousActivities(this.openmct.time.bounds()?.start);
|
||||
} else {
|
||||
this.setSort();
|
||||
this.setViewBounds();
|
||||
this.listActivities();
|
||||
}
|
||||
},
|
||||
addItem(domainObject) {
|
||||
this.planObjects = [domainObject];
|
||||
this.resetPlanData();
|
||||
@@ -400,7 +428,7 @@ export default {
|
||||
|
||||
this.firstCurrentActivityIndex = -1;
|
||||
this.currentActivitiesCount = 0;
|
||||
this.$el.parentElement.scrollTo({top: 0});
|
||||
this.$el.parentElement?.scrollTo({top: 0});
|
||||
this.autoScrolled = false;
|
||||
},
|
||||
setScrollTop() {
|
||||
|
||||
@@ -376,7 +376,7 @@ describe('the plugin', function () {
|
||||
|
||||
return Vue.nextTick(() => {
|
||||
const items = element.querySelectorAll(LIST_ITEM_CLASS);
|
||||
expect(items.length).toEqual(1);
|
||||
expect(items.length).toEqual(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user