mirror of
https://github.com/nasa/openmct.git
synced 2025-02-14 14:42:35 +00:00
* Bump d3-selection from 1.3.2 to 3.0.0 Bumps [d3-selection](https://github.com/d3/d3-selection) from 1.3.2 to 3.0.0. - [Release notes](https://github.com/d3/d3-selection/releases) - [Commits](https://github.com/d3/d3-selection/compare/v1.3.2...v3.0.0) --- updated-dependencies: - dependency-name: d3-selection dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Remove snapshot * Fix imagery filter slider drag in flexible layouts (#5326) (#5350) * Dont' mutate a stacked plot unless its user initiated (#5357) * Port grid icons and imagery test to release 2.0.5 from master (#5360) * Port grid icons to release 2.0.5 from master * Port imagery test to release/2.0.5 * Restrict timestrip composition to time based plots, plans and imagery (#5161) * Restrict timestrip composition to time based plots, plans and imagery * Adds unit tests for timeline composition policy * Addresses review comments Improves tests * Reuse test objects Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov> * Include objectStyles reference to conditionSetIdentifier in imports (#5354) * Include objectStyles reference to conditionSetIdentifier in imports * Add tests for export * Refactored some code and removed console log * Remove workarounds for chrome 'scrollTop' issue (#5375) * Fix naming of method (#5368) * Imagery View does not discard old images when they fall out of bounds (#5351) * change to using telemetry collection * fix tests * added more unit tests * Cherrypicked commits (#5390) Co-authored-by: unlikelyzero <jchill2@gmail.com> * [Timer] Update 3dot menu actions appropriately (#5387) * Call `removeAllListeners()` after emit * Manually show/hide actions if within a view * remove sneaky `console.log()` * Add Timer e2e test * Add to comments * Avoid hard waits in Timer e2e test - Assert against timer view state instead of menu options * Let's also test actions from the Timer view * 5391 Add preview and drag support to Grand Search (#5394) * add preview and drag actions * added unit test, simplified remove action * do not hide search results in preview mode when clicking outside search results * add semantic aria labels to enable e2e tests * readd preview * add e2e test * remove commented out url * add percy snapshot and add search to ci * make percy stuff work * linting * fix percy again * move percy snapshots to a visual test * added separate visual test and changed test to fixtures * fix fixtures path * addressing review comments * 5361 tags not persisting locally (#5408) * fixed typo * remove unneeded lookup * fix tags adding and deleting * more reliable way to remove tags * break tests up for parallel execution * fixed notebook tagging test * enable e2e tests * made schedule index comment more clear and fix uppercase/lowercase issue * address e2e changes * add unit test to bump coverage * fix typo * need to check on annotation creation if provider exists or not * added fixtures * undo silly couchdb commit * Plot progress bar fix for 2.0.5 (#5386) * Add .bind(this) to stopLoading() in loadMoreData() * Replace load spinner with progress bar for plots * Add loading delay prop to swg * fix linting errors * match load order * Update accessibility * Add Math.max to timeout to handle negative inputs * Moved math.max to load delay variable * Add loading fix for stacked plots * Move loadingUpdate func into plot item for update * Merge conflict resolve * Check if delay is 0 and send, put post in a func * Put obj directly to model, removed computed prop * Lint fix * Fix template where legend was not displayed * Remove commented out template * Fixed failing test Co-authored-by: unlikelyzero <jchill2@gmail.com> * Make plans non editable. (#5377) * Make plans non editable. * Add unit test for fix * [CouchDB] Better determination of indicator status (#5415) * Add unknown state, remove maintenance state * Handle all CouchDB status codes - Set unknown status if we receive an unhandled code * Include status code in error messages * SharedWorker can send unknown status * Add test for unknown status * Gauge fixes for Firefox and units display (#5369) * Closes #5323, #5325. Parent branch is release/2.0.5. - Significant work refactoring SVG markup and CSS for dial gauge; - Fixed missing `v-if` to control display of units for #5325; - Fixed bad `.length` test for limit properties; * Closes #5323, #5325 - Add 'value out of range' indicator * Closes #5323, #5325 - More accurate element naming; - Fix cross-browser problems with current value display in dial gauge; - Refinements to "out of range" indicator approach; - Fixed size of "Amplitude" input in Sine Wave Generator; * Closes #5323, #5325 - Styles and stubbed in code to support needle meter type; * Closes #5323, #5325 - Stubbed in markup and CSS for needle-style meter; * Closes #5323, #5325 - Fixed missing `js-*` classes that were failing npm run test; * Closes #5323, #5325 - Fix to not display meter value bar unless a data value is expected; * Addressing PR comments - Renamed method for clarity; - Added null value check in method `valueExpected`; * [Static Root] Return leafValue if null/undefined/false (#5416) * Return leafValue if null/undefined/false * Added a null to the test json * Show a better default poll question (#5425) * 5361 Tags not persisting when several notebook entries are created at once (#5428) * add end to end test to catch multiple entry errors * click expansion triangle instead * fix race condition between annotation creation and mutation * make sure notebook tags run in e2e * address PR comments * Handle missing objects gracefully (#5399) * Handle missing object errors for display layouts * Handle missing object errors for Overlay Plots * Add check for this.config * Add try/catch statement & check if obj is missing * Changed console.error to console.warn * Lint fix * Fix for this.metadata.value is undefined * Add e2e test * Update comment text * Add reload check and @private, verify console.warn * Redid assignment and metadata check * Fix typo * Changed assignment and metadata check * Redid checks for isMissing(object) * Lint fix * Backmerge e2e code coverage changes and fixes into release/2.0.5 (#5431) * [Telemetry Collections] Respect "Latest" Strategy Option (#5421) * Respect latest strategy in Telemetry Collections to limit potential memory growth. * fix sourcemaps (#5373) Co-authored-by: John Hill <john.c.hill@nasa.gov> * Debounce status summary (#5448) Co-authored-by: John Hill <john.c.hill@nasa.gov> * No gauge (#5451) * Installed gauge plugin by default * Make gauge part of standard install in e2e suite and add restrictednotebook Co-authored-by: Andrew Henry <akhenry@gmail.com> * [CouchDB] Always subscribe to the CouchDB changes feed (#5434) * Add unknown state, remove maintenance state * Handle all CouchDB status codes - Set unknown status if we receive an unhandled code * Include status code in error messages * SharedWorker can send unknown status * Add test for unknown status * Always subscribe to CouchDB changes feed - Always subscribe to the CouchDB changes feed, even if there are no observable objects, since we are also checking the status of CouchDB via this feed. * Update indicator status if not using SharedWorker * Start listening to changes feed on first request * fix test * adjust test to hopefully avoid race condition * lint Co-authored-by: John Hill <john.c.hill@nasa.gov> Co-authored-by: Andrew Henry <akhenry@gmail.com> Co-authored-by: Scott Bell <scott@traclabs.com> * Fix for Fault Management Visual Bugs (#5376) * Closes #5365 * General visual improvements Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com> Co-authored-by: Andrew Henry <akhenry@gmail.com> * fix pathing (#5452) Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com> * [Static Root] Static Root Plugin not loading (#5455) * Log if hitting falsy leafValue * Add some logging * Remove logs and specify null/undefined Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com> * Allow endpoints with a single enum metadata value in Bar/Line graphs (#5443) * If there is only 1 metadata value, set yKey to none. Also, fix bug for determining the name of a metadata value * Update tests for enum metadata values Co-authored-by: John Hill <john.c.hill@nasa.gov> Co-authored-by: Andrew Henry <akhenry@gmail.com> * [Remote Clock] Wait for first tick and recalculate historical request bounds (#5433) * Updated to ES6 class * added request intercept functionality to telemetry api, added a request interceptor for remote clock * add remoteClock e2e test stub Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov> Co-authored-by: Andrew Henry <akhenry@gmail.com> * Fix for missing object for LADTableSet (#5458) * Handle missing object errors for display layouts Co-authored-by: Andrew Henry <akhenry@gmail.com> * removing the call for default import now that TelemetryAPI is an ES6 class (#5461) * [Remote Clock] Fix requestInterceptor typo (#5462) * Fix typo in telemetry request interceptor Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov> Co-authored-by: Andrew Henry <akhenry@gmail.com> * Lock model (#5457) * Lock event Model to prevent reactification * de-reactify all the things * Make API properties writable to allow test mocks to override them * Fix merge conflict * Added plot interceptor for missing series config (#5422) Co-authored-by: Andrew Henry <akhenry@gmail.com> Co-authored-by: Shefali Joshi <simplyrender@gmail.com> * Remove performance marks (#5465) * Remove performance marks * Retain performance mark in view large. It doesn't happen very often and it's needed for an automated performance test * Use timeKey for time comparison (#5471) * Fix couchdb no response (#5474) * Update the creation date only when the document is created for the first time * If there is no response from a bulk get, couch db has issues * Check the response - if it's null, don't apply interceptors * Fix shelved alarms (#5479) * Fix the logic around shelved alarms * Remove application router listener * Release 2.0.5 UI and Gauge fixes (#5470) * Various UI fixes - Tweak to Gauge properties form for clarity and usability. - Fix Gauge 'dial' type not obeying "Show units" property setting, closes #5325. - Tweaks to Operator Status UI label and layout for clarity. - Changed name and description of Graph object for clarity and consistency. - Fixed CSS classing that was coloring Export menu items text incorrectly. - Fixed icon-to-text vertical alignment in `.c-object-label`. - Fix for broken layout in imagery local controls (brightness, layers, magnification). Co-authored-by: Andrew Henry <akhenry@gmail.com> * Stacked plot interceptor rename (#5468) * Rename stacked plot interceptor and move to folder Co-authored-by: Andrew Henry <akhenry@gmail.com> * Clear data when time bounds are changed (#5482) * Clear data when time bounds are changed Also react to clear data action Ensure that the yKey is set to 'none' if there is no range with array Values * Refactor trace updates to a method * get rid of root (#5483) * Do not pass onPartialResponse option on to upstream telemetry (#5486) * Fix all of the e2e tests (#5477) * Fix timer test * be explicit about the warnings text * add full suite to CI to enable CircleCI Checks * add back in devtool=false for CI env so firefox tests run * add framework suite * Don't install webpack HMR in CI * Fix playwright version installs * exclude HMR if running tests in any environment - use NODE_ENV=TEST to exclude webpack HMR - deparameterize some of the playwright configs * use lower-case 'test' * timer hover fix * conditionally skip for firefox due to missing console events * increase timeouts to give time for mutation * no need to close save banner * remove devtool setting * revert * update snapshots * disable video to save some resources * use one worker * more timeouts :) * Remove `browser.close()` and `page.close()` as it was breaking other tests * Remove unnecessary awaits and fix func call syntax * Fix image reset test * fix restrictedNotebook tests * revert playwright-ci.config settings * increase timeout for polling imagery test * remove unnecessary waits * disable notebook lock test for chrome-beta as its unreliable - remove some unnecessary 'wait for save banner' logic - remove unused await - mark imagery test as slow in chrome-beta * LINT!! *shakes fist* * don't run full e2e suite per commit * disable video in all configs * add flakey zoom comment * exclude webpack HMR in non-development modes Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov> Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com> * lint fix Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Joshi <simplyrender@gmail.com> Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com> Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov> Co-authored-by: Andrew Henry <akhenry@gmail.com> Co-authored-by: Scott Bell <scott@traclabs.com> Co-authored-by: unlikelyzero <jchill2@gmail.com> Co-authored-by: Alize Nguyen <alizenguyen@gmail.com> Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com> Co-authored-by: Khalid Adil <khalidadil29@gmail.com> Co-authored-by: rukmini-bose <48999852+rukmini-bose@users.noreply.github.com> Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov>
780 lines
34 KiB
JavaScript
780 lines
34 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 { test } = require('../../../fixtures.js');
|
|
const { expect } = require('@playwright/test');
|
|
|
|
const backgroundImageSelector = '.c-imagery__main-image__background-image';
|
|
|
|
//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' });
|
|
|
|
//Click the Create button
|
|
await page.click('button:has-text("Create")');
|
|
|
|
// 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')
|
|
]);
|
|
// Close Banner
|
|
await page.locator('.c-message-banner__close-button').click();
|
|
|
|
//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});
|
|
});
|
|
|
|
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
|
|
const panHotkey = process.platform === 'linux' ? ['Control', 'Alt'] : ['Alt'];
|
|
|
|
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 expectedAltText = process.platform === 'linux' ? 'Ctrl+Alt drag to pan' : 'Alt drag to pan';
|
|
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', async ({ page }) => {
|
|
await page.locator(backgroundImageSelector).hover({trial: true});
|
|
const zoomInBtn = page.locator('.t-btn-zoom-in').nth(0);
|
|
const zoomOutBtn = page.locator('.t-btn-zoom-out').nth(0);
|
|
const initialBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
|
|
await zoomInBtn.click();
|
|
await zoomInBtn.click();
|
|
// wait for zoom animation to finish
|
|
await page.locator(backgroundImageSelector).hover({trial: true});
|
|
const zoomedInBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
expect(zoomedInBoundingBox.height).toBeGreaterThan(initialBoundingBox.height);
|
|
expect(zoomedInBoundingBox.width).toBeGreaterThan(initialBoundingBox.width);
|
|
|
|
await zoomOutBtn.click();
|
|
// wait for zoom animation to finish
|
|
await page.locator(backgroundImageSelector).hover({trial: true});
|
|
const zoomedOutBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
expect(zoomedOutBoundingBox.height).toBeLessThan(zoomedInBoundingBox.height);
|
|
expect(zoomedOutBoundingBox.width).toBeLessThan(zoomedInBoundingBox.width);
|
|
|
|
});
|
|
|
|
test('Can use the reset button to reset the image', async ({ page }, testInfo) => {
|
|
test.slow(testInfo.project === 'chrome-beta', "This test is slow in chrome-beta");
|
|
// wait for zoom animation to finish
|
|
await page.locator(backgroundImageSelector).hover({trial: true});
|
|
|
|
const zoomInBtn = page.locator('.t-btn-zoom-in').nth(0);
|
|
const zoomResetBtn = page.locator('.t-btn-zoom-reset').nth(0);
|
|
const initialBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
|
|
await zoomInBtn.click();
|
|
// wait for zoom animation to finish
|
|
await page.locator(backgroundImageSelector).hover({trial: true});
|
|
await zoomInBtn.click();
|
|
// wait for zoom animation to finish
|
|
await page.locator(backgroundImageSelector).hover({trial: true});
|
|
|
|
const zoomedInBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
expect.soft(zoomedInBoundingBox.height).toBeGreaterThan(initialBoundingBox.height);
|
|
expect.soft(zoomedInBoundingBox.width).toBeGreaterThan(initialBoundingBox.width);
|
|
|
|
// wait for zoom animation to finish
|
|
// FIXME: The zoom is flakey, sometimes not returning to original dimensions
|
|
// https://github.com/nasa/openmct/issues/5491
|
|
await expect.poll(async () => {
|
|
await zoomResetBtn.click();
|
|
const boundingBox = await page.locator(backgroundImageSelector).boundingBox();
|
|
|
|
return boundingBox;
|
|
}, {
|
|
timeout: 10 * 1000
|
|
}).toEqual(initialBoundingBox);
|
|
});
|
|
|
|
test('Using the zoom features does not pause telemetry', async ({ page }) => {
|
|
const pausePlayButton = page.locator('.c-button.pause-play');
|
|
// wait for zoom animation to finish
|
|
await page.locator(backgroundImageSelector).hover({trial: true});
|
|
|
|
// open the time conductor drop down
|
|
await page.locator('button:has-text("Fixed Timespan")').click();
|
|
// Click local clock
|
|
await page.locator('[data-testid="conductor-modeOption-realtime"]').click();
|
|
|
|
await expect.soft(pausePlayButton).not.toHaveClass(/is-paused/);
|
|
const zoomInBtn = page.locator('.t-btn-zoom-in').nth(0);
|
|
await zoomInBtn.click();
|
|
// wait for zoom animation to finish
|
|
await page.locator(backgroundImageSelector).hover({trial: true});
|
|
|
|
return 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', 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/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 expectedAltText = process.platform === 'linux' ? 'Ctrl+Alt drag to pan' : 'Alt drag to pan';
|
|
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', 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'
|
|
});
|
|
|
|
// 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 Flexable layout
|
|
await expect(page.locator('.js-form-title')).toHaveText('Create a New Flexible Layout');
|
|
|
|
await page.locator('form[name="mctForm"] >> text=My Items').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 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]').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');
|
|
});
|
|
|
|
/**
|
|
* @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 panHotkey = process.platform === 'linux' ? ['Control', 'Alt'] : ['Alt'];
|
|
const expectedAltText = process.platform === 'linux' ? 'Ctrl+Alt drag to pan' : 'Alt drag to pan';
|
|
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);
|
|
}
|
|
|