* Imagery thumbnail regression fixes - 5327 (#5591)
* Add an active class to thumbnail to indicate current focused image
* Differentiate bg color between real-time and fixed
* scrollIntoView inline: center
* Added watcher for bounds change to trigger thumbnail scroll
* Resolve merge conflict with requestHistory change to telemetry collection
* Split thumbnail into sub component
* Monitor isFixed value to unpause playback status
Co-authored-by: Khalid Adil <khalidadil29@gmail.com>
* [e2e] Improve appActions (#5592)
* update selectors to use aria labels
* Update appActions
- Create new function `getHashUrlToDomainObject` to get the browse url to a given object given its uuid
- Create new function `getFocusedObjectUuid`... self explanatory :)
- Update `createDomainObjectWIthDefaults` to make use of the new url generation
- Update `createDomainObject...`'s arguments to be more organized, and accept a parent object
- Update some docs, still need to clarify some
* Update appActions e2e tests
- Refactor for organization
- Test our new appActions in one go
* Update existing usages of `createDomainObject...` to match the new API
* fix accidental renamed export
* Fix jsdoc return types
* refactor telemetryTable test to use appActions
* Improve selectors
* Refactor test
* improve selector
* add clock mode appActions
* lint
* Fix jsdoc
* Code review comments
* mark failing visual tests as fixme temporarily
* Update package.json (#5601)
* Fix menu style in Snow theme (#5557)
* Include the plan source map when generating the time list/plan hybrid object (#5604)
* Search should indicate in progress and no results states, filter orphaned results (#5599)
* no matching result implemented
* now filtering annotations that are orphaned
* filter object results without valid paths
* add progress bar
* added e2e tests
* removed extraneous click
* fix typos
* fix unit tests
* lint
* address pr comments
* fix tests
* fix tests, centralize logic to object api, check for root instead
* remove debug statement
* lint
* fix documentation
* lint
* fix doc
* made some optimizations after talking with akhenry
* fix test
* update docs
* fix docs
* Have in-memory search indexer use composition API (#5578)
* need to remove tags and objects on composition removal
* had to separate out emits from load as it was causing memory indexer to loop upon itself
* Add parsing for areIdsEqual util to consistently remove folders (#5589)
* Add parsing util to identifier for ID comparison
* Moved firstIdentifier to top of function
* Lint fix
Co-authored-by: Andrew Henry <akhenry@gmail.com>
* Revert "Have in-memory search indexer use composition API (#5578)" (#5609)
This reverts commit 7cf11e177c.
* [e2e] Tests for Display Layout and LAD Tables and telemetry (#5607)
* Check for circular references in originalPath - 5615 (#5619)
* check for circular references
* add test
* fix test
* address PR comments by making comments better
* fix docs...again
* Update version number
* Prevent cyclic references in link & move actions (#5635)
* do not create circular refs
* add negative validation test
* move to plugin
* add link test too
* fix docs
* refactored per john request
* fix path
* use appAction lib
Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com>
* [Condition Set] Add check for empty string being passed to the makeKeyString util by TelemetryCriterion (#5636) (#5663)
* Check telemetry is defined before using makeKeyString util
* Add optional chaining in the check
* Add e2e test
* Add check for undefined
Co-authored-by: Khalid Adil <khalidadil29@gmail.com>
* [Fault Management] New Example Provider, Unit and e2e tests (#5579)
* added unit tests for fault management plugin
* modified the example fault provider to work out of the box
* updating for new e2e folder structure
* part of the e2e tests
* WIP
* Imagery thumbnail regression fixes - 5327 (#5569)
* Add an active class to thumbnail to indicate current focused image
* Differentiate bg color between real-time and fixed
* scrollIntoView inline: center
* Added watcher for bounds change to trigger thumbnail scroll
* Resolve merge conflict with requestHistory change to telemetry collection
* Split thumbnail into sub component
* Monitor isFixed value to unpause playback status
* updated search to include name, namespace and description added some more e2e tests
* added rest of e2e tests
* fixed my init script, had to disable lint for no-force because it was not working without it, saw online this may be a pw bug
* fix: removing maelstrom theme from application (#5600)
* added some tests for no faults
* visual tests
* added visual tests for fault management
* created utils file for shared functionality between function and visual tests
* updating to 2.0.8
* tryin to remove imagery changes from master
* trying to trigger a refresh
* tryin to refresh
* updated search to include name, namespace and description added some more e2e tests
* added rest of e2e tests
* fix: removing maelstrom theme from application (#5600)
* fixed my init script, had to disable lint for no-force because it was not working without it, saw online this may be a pw bug
* added some tests for no faults
* visual tests
* added visual tests for fault management
* created utils file for shared functionality between function and visual tests
* updating to 2.0.8
* no clue
* still no clue
* removing imports and chaning to requires
* updating utils file to work with require
* fixing paths
* fixing a test I had messed up when adding static exmaple faults
* ONE LAST PATH FIX... hopefully
* typo in files fix
* fix folder typo
* thought I got this one, but apparently not, well I did now! who is laughing now!?
Co-authored-by: Michael Rogers <contact@mhrogers.com>
Co-authored-by: Vitor Henckel <vitor@henckel.com.br>
* Sort tree items locally on rename (#5643)
* fix typo
* Sort the tree items locally on object rename
* Use the navigationPath as a key
- This ensures that objects AND linked objects will be sorted
* add 'tree' and 'treeitem' roles to mct-tree
* WIP tree item reordering test
* Select the first object that matches
* Test that all object links are also reordered
* Get the final uuid before queryParams as notebook sections have uuids
* Make `openObjectTreeContextMenu` more deterministic and update usage
* Add `expandPathToTreeItem` and `expandTreeItemByName` appActions
* add `#tree-pane` id for the tree view
* Add tree visual component test suite and bump percy-cli
* Remove tree appActions
* Better variable name
Co-authored-by: Scott Bell <scott@traclabs.com>
* Mct5549 fix indexer composition error (#5610)
* [Display Layout] Composition and configuration sync (#5669)
LGTM
* [e2e] Stabilize notebook tag tests (#5681)
* Use more deterministic selector
* Hover first to "slow down" e2e actions while in headless mode
* Moves condition set fix into 2.0.8 (#5673)
* Set Focused Image index after a imagery is selected from a timestrip - 5632 (#5664)
* Set focused image when timestamp prop is passed in
* Unused var
* Create timestrip with imagery child
* Add equality check for hovered image and view large image url
* Cleanup
* Time List 5534 for release/2.0.8 (#5678)
* Changes to Time List view. Closes #5534.
- Compacted table row spacing.
- Set all timeframes to display by default when creating a new Time List.
- Removed 'Upload plan' file button from properties.
* Changes to Time List view. Closes #5534.
- Better hint text for editing Timeframe Inspector section.
Co-authored-by: Andrew Henry <akhenry@gmail.com>
* [CI] Enable couchdb e2e testing in open source (#5655)
* Handle couch db not found errors so that interceptors are still invoked. (#5654)
* Fix tests for interceptors
* [e2e] Add test for 'mine' folder initialization
* [e2e] don't fail on expected console errors
Co-authored-by: Andrew Henry <akhenry@gmail.com>
Co-authored-by: Scott Bell <scott@traclabs.com>
Co-authored-by: John Hill <john.c.hill@nasa.gov>
Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov>
* [Docs] Update CouchDB local install documentation (#5692)
* Update local CouchDB install docs to include docker workflow
* reformat to source configuration scripts where possible
* correct couchdb case
Co-authored-by: John Hill <john.c.hill@nasa.gov>
* [Time Conductor] History not working correctly (#5687)
* the check for fixed time vs realtime was not updating, have fixed this
* merging in related changes from master pr #4414
* lint fixes
* Update src/plugins/timeConductor/ConductorHistory.vue
Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com>
* setting time mode directly on load
* fixing issue where realtime history was being wiped on reloads while viewing fixed time
* formatting
* stubbed in some tests
Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com>
* Only index if provider does not support search - mct5690 (#5693)
* only index if provider does not support search
* add some tests
* fix tests
* [e2e] Add search couchdb test for duplicates
* [e2e] Modify existing search test instead
* lint
Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov>
* Don't re-request historical data on ticks (#5701)
Don't rerequest telemetry on ticks.
* Fix duplicate declaration from merge
Co-authored-by: Michael Rogers <contact@mhrogers.com>
Co-authored-by: Khalid Adil <khalidadil29@gmail.com>
Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com>
Co-authored-by: John Hill <john.c.hill@nasa.gov>
Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
Co-authored-by: Scott Bell <scott@traclabs.com>
Co-authored-by: Alize Nguyen <alizenguyen@gmail.com>
Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
Co-authored-by: Vitor Henckel <vitor@henckel.com.br>
Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov>
840 lines
37 KiB
JavaScript
840 lines
37 KiB
JavaScript
/*****************************************************************************
|
|
* 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.
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
This test suite is dedicated to tests which verify the basic operations surrounding imagery,
|
|
but only assume that example imagery is present.
|
|
*/
|
|
/* globals process */
|
|
const { v4: uuid } = require('uuid');
|
|
const { waitForAnimations } = require('../../../../baseFixtures');
|
|
const { test, expect } = require('../../../../pluginFixtures');
|
|
const { createDomainObjectWithDefaults } = require('../../../../appActions');
|
|
const backgroundImageSelector = '.c-imagery__main-image__background-image';
|
|
const panHotkey = process.platform === 'linux' ? ['Control', 'Alt'] : ['Alt'];
|
|
const expectedAltText = process.platform === 'linux' ? 'Ctrl+Alt drag to pan' : '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
|
|
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
|
|
});
|
|
|
|
test('Can use Mouse Wheel to zoom in and out of latest image', async ({ page }) => {
|
|
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();
|
|
|
|
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 }) => {
|
|
test.fixme(browserName === 'firefox', 'This test needs to be updated to work with firefox');
|
|
// 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('Can use alt+drag to move around image once zoomed in', async ({ page }) => {
|
|
const deltaYStep = 100; //equivalent to 1x zoom
|
|
|
|
await page.locator(backgroundImageSelector).hover({trial: true});
|
|
|
|
// zoom in
|
|
await page.mouse.wheel(0, deltaYStep * 2);
|
|
await page.locator(backgroundImageSelector).hover({trial: true});
|
|
const zoomedBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
const imageCenterX = zoomedBoundingBox.x + zoomedBoundingBox.width / 2;
|
|
const imageCenterY = zoomedBoundingBox.y + zoomedBoundingBox.height / 2;
|
|
// move to the right
|
|
|
|
// center the mouse pointer
|
|
await page.mouse.move(imageCenterX, imageCenterY);
|
|
|
|
//Get Diagnostic info about process environment
|
|
console.log('process.platform is ' + process.platform);
|
|
const getUA = await page.evaluate(() => navigator.userAgent);
|
|
console.log('navigator.userAgent ' + getUA);
|
|
// Pan Imagery Hints
|
|
const imageryHintsText = await page.locator('.c-imagery__hints').innerText();
|
|
expect(expectedAltText).toEqual(imageryHintsText);
|
|
|
|
// pan right
|
|
await Promise.all(panHotkey.map(x => page.keyboard.down(x)));
|
|
await page.mouse.down();
|
|
await page.mouse.move(imageCenterX - 200, imageCenterY, 10);
|
|
await page.mouse.up();
|
|
await Promise.all(panHotkey.map(x => page.keyboard.up(x)));
|
|
const afterRightPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
expect(zoomedBoundingBox.x).toBeGreaterThan(afterRightPanBoundingBox.x);
|
|
|
|
// pan left
|
|
await Promise.all(panHotkey.map(x => page.keyboard.down(x)));
|
|
await page.mouse.down();
|
|
await page.mouse.move(imageCenterX, imageCenterY, 10);
|
|
await page.mouse.up();
|
|
await Promise.all(panHotkey.map(x => page.keyboard.up(x)));
|
|
const afterLeftPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
expect(afterRightPanBoundingBox.x).toBeLessThan(afterLeftPanBoundingBox.x);
|
|
|
|
// pan up
|
|
await page.mouse.move(imageCenterX, imageCenterY);
|
|
await Promise.all(panHotkey.map(x => page.keyboard.down(x)));
|
|
await page.mouse.down();
|
|
await page.mouse.move(imageCenterX, imageCenterY + 200, 10);
|
|
await page.mouse.up();
|
|
await Promise.all(panHotkey.map(x => page.keyboard.up(x)));
|
|
const afterUpPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
expect(afterUpPanBoundingBox.y).toBeGreaterThan(afterLeftPanBoundingBox.y);
|
|
|
|
// pan down
|
|
await Promise.all(panHotkey.map(x => page.keyboard.down(x)));
|
|
await page.mouse.down();
|
|
await page.mouse.move(imageCenterX, imageCenterY - 200, 10);
|
|
await page.mouse.up();
|
|
await Promise.all(panHotkey.map(x => page.keyboard.up(x)));
|
|
const afterDownPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
expect(afterDownPanBoundingBox.y).toBeLessThan(afterUpPanBoundingBox.y);
|
|
|
|
});
|
|
|
|
test('Can use + - buttons to zoom on the image @unstable', async ({ 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) => {
|
|
test.slow(testInfo.project === 'chrome-beta', "This test is slow in chrome-beta");
|
|
// 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.soft(zoomedInBoundingBox.height).toBeGreaterThan(initialBoundingBox.height);
|
|
expect.soft(zoomedInBoundingBox.width).toBeGreaterThan(initialBoundingBox.width);
|
|
|
|
// Reset pan and zoom and assert against initial image dimensions
|
|
await resetImageryPanAndZoom(page);
|
|
const finalBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
expect(finalBoundingBox).toEqual(initialBoundingBox);
|
|
});
|
|
|
|
test('Using the zoom features does not pause telemetry', async ({ page }) => {
|
|
const pausePlayButton = page.locator('.c-button.pause-play');
|
|
|
|
// open the time conductor drop down
|
|
await page.locator('.c-mode-button').click();
|
|
|
|
// Click local clock
|
|
await page.locator('[data-testid="conductor-modeOption-realtime"]').click();
|
|
await expect.soft(pausePlayButton).not.toHaveClass(/is-paused/);
|
|
|
|
// Zoom in via button
|
|
await zoomIntoImageryByButton(page);
|
|
await expect(pausePlayButton).not.toHaveClass(/is-paused/);
|
|
});
|
|
|
|
});
|
|
|
|
// 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'
|
|
});
|
|
|
|
// 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 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')
|
|
]);
|
|
|
|
// 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 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();
|
|
|
|
// 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;
|
|
|
|
// 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);
|
|
|
|
// Center the mouse pointer
|
|
await page.mouse.move(imageCenterX, imageCenterY);
|
|
|
|
// 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');
|
|
await nextImageButton.click();
|
|
|
|
// Click time conductor mode button
|
|
await page.locator('.c-mode-button').click();
|
|
|
|
// Select local clock mode
|
|
await page.locator('[data-testid=conductor-modeOption-realtime]').click();
|
|
|
|
// Zoom in on next image
|
|
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 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();
|
|
|
|
// 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 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.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('Clicking on the left arrow should pause the imagery and go to previous image');
|
|
// test.fixme('If the imagery view is in pause mode, images still 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 Flexible layout', () => {
|
|
test('Example Imagery in Flexible layout @unstable', async ({ page, browserName, openmctConfig }) => {
|
|
const { myItemsFolderName } = openmctConfig;
|
|
|
|
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'
|
|
});
|
|
|
|
// 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();
|
|
}
|
|
|
|
/**
|
|
* Drag the brightness slider to max, min, and midpoint and assert the filter values
|
|
* @param {import('@playwright/test').Page} page
|
|
*/
|
|
async function dragBrightnessSliderAndAssertFilterValues(page) {
|
|
const brightnessSlider = 'div.c-image-controls__slider-wrapper.icon-brightness > input';
|
|
const brightnessBoundingBox = await page.locator(brightnessSlider).boundingBox();
|
|
const brightnessMidX = brightnessBoundingBox.x + brightnessBoundingBox.width / 2;
|
|
const brightnessMidY = brightnessBoundingBox.y + brightnessBoundingBox.height / 2;
|
|
|
|
await page.locator(brightnessSlider).hover({trial: true});
|
|
await page.mouse.down();
|
|
await page.mouse.move(brightnessBoundingBox.x + brightnessBoundingBox.width, brightnessMidY);
|
|
await assertBackgroundImageBrightness(page, '500');
|
|
await page.mouse.move(brightnessBoundingBox.x, brightnessMidY);
|
|
await assertBackgroundImageBrightness(page, '0');
|
|
await page.mouse.move(brightnessMidX, brightnessMidY);
|
|
await assertBackgroundImageBrightness(page, '250');
|
|
await page.mouse.up();
|
|
}
|
|
|
|
/**
|
|
* Drag the contrast slider to max, min, and midpoint and assert the filter values
|
|
* @param {import('@playwright/test').Page} page
|
|
*/
|
|
async function dragContrastSliderAndAssertFilterValues(page) {
|
|
const contrastSlider = 'div.c-image-controls__slider-wrapper.icon-contrast > input';
|
|
const contrastBoundingBox = await page.locator(contrastSlider).boundingBox();
|
|
const contrastMidX = contrastBoundingBox.x + contrastBoundingBox.width / 2;
|
|
const contrastMidY = contrastBoundingBox.y + contrastBoundingBox.height / 2;
|
|
|
|
await page.locator(contrastSlider).hover({trial: true});
|
|
await page.mouse.down();
|
|
await page.mouse.move(contrastBoundingBox.x + contrastBoundingBox.width, contrastMidY);
|
|
await assertBackgroundImageContrast(page, '500');
|
|
await page.mouse.move(contrastBoundingBox.x, contrastMidY);
|
|
await assertBackgroundImageContrast(page, '0');
|
|
await page.mouse.move(contrastMidX, contrastMidY);
|
|
await assertBackgroundImageContrast(page, '250');
|
|
await page.mouse.up();
|
|
}
|
|
|
|
/**
|
|
* Gets the filter:brightness value of the current background-image and
|
|
* asserts against an expected value
|
|
* @param {import('@playwright/test').Page} page
|
|
* @param {String} expected The expected brightness value
|
|
*/
|
|
async function assertBackgroundImageBrightness(page, expected) {
|
|
const backgroundImage = page.locator('.c-imagery__main-image__background-image');
|
|
|
|
// Get the brightness filter value (i.e: filter: brightness(500%) => "500")
|
|
const actual = await backgroundImage.evaluate((el) => {
|
|
return el.style.filter.match(/brightness\((\d{1,3})%\)/)[1];
|
|
});
|
|
expect(actual).toBe(expected);
|
|
}
|
|
|
|
/**
|
|
* @param {import('@playwright/test').Page} page
|
|
*/
|
|
async function assertBackgroundImageUrlFromBackgroundCss(page) {
|
|
const backgroundImage = page.locator('.c-imagery__main-image__background-image');
|
|
let backgroundImageUrl = await backgroundImage.evaluate((el) => {
|
|
return window.getComputedStyle(el).getPropertyValue('background-image').match(/url\(([^)]+)\)/)[1];
|
|
});
|
|
let backgroundImageUrl1 = backgroundImageUrl.slice(1, -1); //forgive me, padre
|
|
console.log('backgroundImageUrl1 ' + backgroundImageUrl1);
|
|
|
|
let backgroundImageUrl2;
|
|
await expect.poll(async () => {
|
|
// Verify next image has updated
|
|
let backgroundImageUrlNext = await backgroundImage.evaluate((el) => {
|
|
return window.getComputedStyle(el).getPropertyValue('background-image').match(/url\(([^)]+)\)/)[1];
|
|
});
|
|
backgroundImageUrl2 = backgroundImageUrlNext.slice(1, -1); //forgive me, padre
|
|
|
|
return backgroundImageUrl2;
|
|
}, {
|
|
message: "verify next image has updated",
|
|
timeout: 6 * 1000
|
|
}).not.toBe(backgroundImageUrl1);
|
|
console.log('backgroundImageUrl2 ' + backgroundImageUrl2);
|
|
}
|
|
|
|
/**
|
|
* @param {import('@playwright/test').Page} page
|
|
*/
|
|
async function panZoomAndAssertImageProperties(page) {
|
|
const imageryHintsText = await page.locator('.c-imagery__hints').innerText();
|
|
expect(expectedAltText).toEqual(imageryHintsText);
|
|
const zoomedBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
const imageCenterX = zoomedBoundingBox.x + zoomedBoundingBox.width / 2;
|
|
const imageCenterY = zoomedBoundingBox.y + zoomedBoundingBox.height / 2;
|
|
|
|
// Pan right
|
|
await Promise.all(panHotkey.map(x => page.keyboard.down(x)));
|
|
await page.mouse.down();
|
|
await page.mouse.move(imageCenterX - 200, imageCenterY, 10);
|
|
await page.mouse.up();
|
|
await Promise.all(panHotkey.map(x => page.keyboard.up(x)));
|
|
const afterRightPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
expect(zoomedBoundingBox.x).toBeGreaterThan(afterRightPanBoundingBox.x);
|
|
|
|
// Pan left
|
|
await Promise.all(panHotkey.map(x => page.keyboard.down(x)));
|
|
await page.mouse.down();
|
|
await page.mouse.move(imageCenterX, imageCenterY, 10);
|
|
await page.mouse.up();
|
|
await Promise.all(panHotkey.map(x => page.keyboard.up(x)));
|
|
const afterLeftPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
expect(afterRightPanBoundingBox.x).toBeLessThan(afterLeftPanBoundingBox.x);
|
|
|
|
// Pan up
|
|
await page.mouse.move(imageCenterX, imageCenterY);
|
|
await Promise.all(panHotkey.map(x => page.keyboard.down(x)));
|
|
await page.mouse.down();
|
|
await page.mouse.move(imageCenterX, imageCenterY + 200, 10);
|
|
await page.mouse.up();
|
|
await Promise.all(panHotkey.map(x => page.keyboard.up(x)));
|
|
const afterUpPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
expect(afterUpPanBoundingBox.y).toBeGreaterThanOrEqual(afterLeftPanBoundingBox.y);
|
|
|
|
// Pan down
|
|
await Promise.all(panHotkey.map(x => page.keyboard.down(x)));
|
|
await page.mouse.down();
|
|
await page.mouse.move(imageCenterX, imageCenterY - 200, 10);
|
|
await page.mouse.up();
|
|
await Promise.all(panHotkey.map(x => page.keyboard.up(x)));
|
|
const afterDownPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
expect(afterDownPanBoundingBox.y).toBeLessThanOrEqual(afterUpPanBoundingBox.y);
|
|
}
|
|
|
|
/**
|
|
* @param {import('@playwright/test').Page} page
|
|
*/
|
|
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 * 2);
|
|
const zoomedBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
const imageCenterX = zoomedBoundingBox.x + zoomedBoundingBox.width / 2;
|
|
const imageCenterY = zoomedBoundingBox.y + zoomedBoundingBox.height / 2;
|
|
|
|
// center the mouse pointer
|
|
await page.mouse.move(imageCenterX, imageCenterY);
|
|
|
|
// 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);
|
|
}
|
|
|
|
/**
|
|
* Gets the filter:contrast value of the current background-image and
|
|
* asserts against an expected value
|
|
* @param {import('@playwright/test').Page} page
|
|
* @param {String} expected The expected contrast value
|
|
*/
|
|
async function assertBackgroundImageContrast(page, expected) {
|
|
const backgroundImage = page.locator('.c-imagery__main-image__background-image');
|
|
|
|
// Get the contrast filter value (i.e: filter: contrast(500%) => "500")
|
|
const actual = await backgroundImage.evaluate((el) => {
|
|
return el.style.filter.match(/contrast\((\d{1,3})%\)/)[1];
|
|
});
|
|
expect(actual).toBe(expected);
|
|
}
|
|
|
|
/**
|
|
* Use the '+' button to zoom in. Hovers first if the toolbar is not visible
|
|
* and waits for the zoom animation to finish afterwards.
|
|
* @param {import('@playwright/test').Page} page
|
|
*/
|
|
async function zoomIntoImageryByButton(page) {
|
|
// FIXME: There should only be one set of imagery buttons, but there are two?
|
|
const zoomInBtn = page.locator("[role='toolbar'][aria-label='Image controls'] .t-btn-zoom-in").nth(0);
|
|
const backgroundImage = page.locator(backgroundImageSelector);
|
|
if (!(await zoomInBtn.isVisible())) {
|
|
await backgroundImage.hover({trial: true});
|
|
}
|
|
|
|
await zoomInBtn.click();
|
|
await waitForAnimations(backgroundImage);
|
|
}
|
|
|
|
/**
|
|
* Use the '-' button to zoom out. Hovers first if the toolbar is not visible
|
|
* and waits for the zoom animation to finish afterwards.
|
|
* @param {import('@playwright/test').Page} page
|
|
*/
|
|
async function zoomOutOfImageryByButton(page) {
|
|
// FIXME: There should only be one set of imagery buttons, but there are two?
|
|
const zoomOutBtn = page.locator("[role='toolbar'][aria-label='Image controls'] .t-btn-zoom-out").nth(0);
|
|
const backgroundImage = page.locator(backgroundImageSelector);
|
|
if (!(await zoomOutBtn.isVisible())) {
|
|
await backgroundImage.hover({trial: true});
|
|
}
|
|
|
|
await zoomOutBtn.click();
|
|
await waitForAnimations(backgroundImage);
|
|
}
|
|
|
|
/**
|
|
* Use the reset button to reset image pan and zoom. Hovers first if the toolbar is not visible
|
|
* and waits for the zoom animation to finish afterwards.
|
|
* @param {import('@playwright/test').Page} page
|
|
*/
|
|
async function resetImageryPanAndZoom(page) {
|
|
// FIXME: There should only be one set of imagery buttons, but there are two?
|
|
const panZoomResetBtn = page.locator("[role='toolbar'][aria-label='Image controls'] .t-btn-zoom-reset").nth(0);
|
|
const backgroundImage = page.locator(backgroundImageSelector);
|
|
if (!(await panZoomResetBtn.isVisible())) {
|
|
await backgroundImage.hover({trial: true});
|
|
}
|
|
|
|
await panZoomResetBtn.click();
|
|
await waitForAnimations(backgroundImage);
|
|
}
|