mirror of
https://github.com/nasa/openmct.git
synced 2024-12-24 07:16:39 +00:00
Mct7367-tests (#7387)
* refactor(ExportAsJSONAction): use private methods * refactor: remove unnecessary webpack alias * refactor: lint * fix: tests for `ExportAsJSONAction` * test: stabilize `InspectorStylesSpec` tests * docs: fix jsdocs * chore: remove dead / redundant code * refactor(LocalStorageObjectProvider): use `getItem()` and `setItem()` * refactor(ExportAsJSONAction): use `Promise.all` where applicable * refactor(MenuAPI): one-liner * feat: add percentage ProgressBar to ExportAsJSONAction * fix(ProgressBar.vue): v-if conditionals * test(fix): update mockLocalStorage * test: fix locators * test: remove unneeded awaits * fix: example imagery urls (moved after NASA wordpress migration) * Revert "refactor(LocalStorageObjectProvider): use `getItem()` and `setItem()`" This reverts commit4f8403adab
. * test(e2e): fix logPlot test * Revert "Revert "refactor(LocalStorageObjectProvider): use `getItem()` and `setItem()`"" This reverts commit0de66401cd
. * test(e2e): remove waitForNavigations * driveby and fixes * aria improvement * getting tests back oline * more tests * add last test * Add a11y * lint * lint * driveby * review comments * driveby rename * fix selectors and break up test suites * add test for snapshot in header * last lint fixes * stable --------- Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov>
This commit is contained in:
parent
43ae3cf655
commit
4cf63062c0
@ -284,7 +284,7 @@ async function navigateToObjectWithFixedTimeBounds(page, url, start, end) {
|
|||||||
*/
|
*/
|
||||||
async function openObjectTreeContextMenu(page, url) {
|
async function openObjectTreeContextMenu(page, url) {
|
||||||
await page.goto(url);
|
await page.goto(url);
|
||||||
await page.click('button[title="Show selected item in tree"]');
|
await page.getByLabel('Show selected item in tree').click();
|
||||||
await page.locator('.is-navigated-object').click({
|
await page.locator('.is-navigated-object').click({
|
||||||
button: 'right'
|
button: 'right'
|
||||||
});
|
});
|
||||||
|
@ -49,7 +49,7 @@ async function dragAndDropEmbed(page, notebookObject) {
|
|||||||
// Navigate to notebook
|
// Navigate to notebook
|
||||||
await page.goto(notebookObject.url);
|
await page.goto(notebookObject.url);
|
||||||
// Expand the tree to reveal the notebook
|
// Expand the tree to reveal the notebook
|
||||||
await page.click('button[title="Show selected item in tree"]');
|
await page.getByLabel('Show selected item in tree').click();
|
||||||
// Drag and drop the SWG into the notebook
|
// Drag and drop the SWG into the notebook
|
||||||
await page.dragAndDrop(`text=${swg.name}`, NOTEBOOK_DROP_AREA);
|
await page.dragAndDrop(`text=${swg.name}`, NOTEBOOK_DROP_AREA);
|
||||||
await commitEntry(page);
|
await commitEntry(page);
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
import {
|
import {
|
||||||
createDomainObjectWithDefaults,
|
createDomainObjectWithDefaults,
|
||||||
createNotification,
|
createNotification,
|
||||||
expandEntireTree
|
expandEntireTree,
|
||||||
|
openObjectTreeContextMenu
|
||||||
} from '../../appActions.js';
|
} from '../../appActions.js';
|
||||||
import { expect, test } from '../../pluginFixtures.js';
|
import { expect, test } from '../../pluginFixtures.js';
|
||||||
|
|
||||||
@ -166,4 +167,13 @@ test.describe('AppActions', () => {
|
|||||||
const locatorTreeCollapsedItems = locatorTree.locator('role=treeitem[expanded=false]');
|
const locatorTreeCollapsedItems = locatorTree.locator('role=treeitem[expanded=false]');
|
||||||
expect(await locatorTreeCollapsedItems.count()).toBe(0);
|
expect(await locatorTreeCollapsedItems.count()).toBe(0);
|
||||||
});
|
});
|
||||||
|
test('openObjectTreeContextMenu', async ({ page }) => {
|
||||||
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
|
const folder = await createDomainObjectWithDefaults(page, {
|
||||||
|
type: 'Folder'
|
||||||
|
});
|
||||||
|
await openObjectTreeContextMenu(page, folder.url);
|
||||||
|
await expect(page.getByLabel('Menu')).toBeVisible();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -24,36 +24,182 @@
|
|||||||
This test suite is dedicated to tests which verify the basic operations surrounding exportAsJSON.
|
This test suite is dedicated to tests which verify the basic operations surrounding exportAsJSON.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// FIXME: Remove this eslint exception once tests are implemented
|
import fs from 'fs/promises';
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
|
import {
|
||||||
|
createDomainObjectWithDefaults,
|
||||||
|
openObjectTreeContextMenu
|
||||||
|
} from '../../../../appActions.js';
|
||||||
import { expect, test } from '../../../../baseFixtures.js';
|
import { expect, test } from '../../../../baseFixtures.js';
|
||||||
|
import { navigateToFaultManagementWithExample } from '../../../../helper/faultUtils.js';
|
||||||
|
|
||||||
test.describe('ExportAsJSON', () => {
|
test.describe('ExportAsJSON', () => {
|
||||||
test.fixme(
|
let folder;
|
||||||
'Create a basic object and verify that it can be exported as JSON from Tree',
|
test.beforeEach(async ({ page }) => {
|
||||||
async ({ page }) => {
|
// Go to baseURL
|
||||||
//Create domain object
|
await page.goto('./');
|
||||||
//Save Domain Object
|
// Perform actions to create the domain object
|
||||||
//Verify that the newly created domain object can be exported as JSON from the Tree
|
folder = await createDomainObjectWithDefaults(page, {
|
||||||
}
|
type: 'Folder',
|
||||||
);
|
name: 'e2e folder'
|
||||||
test.fixme(
|
});
|
||||||
'Create a basic object and verify that it can be exported as JSON from 3 dot menu',
|
});
|
||||||
async ({ page }) => {
|
test('Create a basic object and verify that it can be exported as JSON from Tree', async ({
|
||||||
//Create domain object
|
page
|
||||||
//Save Domain Object
|
}) => {
|
||||||
//Verify that the newly created domain object can be exported as JSON from the 3 dot menu
|
// Navigate to the page
|
||||||
}
|
await page.goto(folder.url);
|
||||||
);
|
|
||||||
test.fixme('Verify that a nested Object can be exported as JSON', async ({ page }) => {
|
// Open context menu and initiate download
|
||||||
// Create 2 objects with hierarchy
|
await openObjectTreeContextMenu(page, folder.url);
|
||||||
// Export as JSON
|
const [download] = await Promise.all([
|
||||||
// Verify Hierarchy
|
page.waitForEvent('download'), // Waits for the download event
|
||||||
|
page.getByLabel('Export as JSON').click() // Triggers the download
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Wait for the download process to complete
|
||||||
|
const path = await download.path();
|
||||||
|
|
||||||
|
// Read the contents of the downloaded file using readFile from fs/promises
|
||||||
|
const fileContents = await fs.readFile(path, 'utf8');
|
||||||
|
const jsonData = JSON.parse(fileContents);
|
||||||
|
|
||||||
|
// Use the function to retrieve the key
|
||||||
|
const key = getFirstKeyFromOpenMctJson(jsonData);
|
||||||
|
|
||||||
|
// Verify the contents of the JSON file
|
||||||
|
expect(jsonData.openmct[key]).toHaveProperty('name', 'e2e folder');
|
||||||
|
expect(jsonData.openmct[key]).toHaveProperty('type', 'folder');
|
||||||
|
});
|
||||||
|
test('Create a basic object and verify that it can be exported as JSON from 3 dot menu', async ({
|
||||||
|
page
|
||||||
|
}) => {
|
||||||
|
// Navigate to the page
|
||||||
|
await page.goto(folder.url);
|
||||||
|
//3 dot menu
|
||||||
|
await page.getByLabel('More actions').click();
|
||||||
|
// Open context menu and initiate download
|
||||||
|
const [download] = await Promise.all([
|
||||||
|
page.waitForEvent('download'), // Waits for the download event
|
||||||
|
page.getByLabel('Export as JSON').click() // Triggers the download
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Read the contents of the downloaded file using readFile from fs/promises
|
||||||
|
const fileContents = await fs.readFile(await download.path(), 'utf8');
|
||||||
|
const jsonData = JSON.parse(fileContents);
|
||||||
|
|
||||||
|
// Use the function to retrieve the key
|
||||||
|
const key = getFirstKeyFromOpenMctJson(jsonData);
|
||||||
|
|
||||||
|
// Verify the contents of the JSON file
|
||||||
|
expect(jsonData.openmct[key]).toHaveProperty('name', 'e2e folder');
|
||||||
|
expect(jsonData.openmct[key]).toHaveProperty('type', 'folder');
|
||||||
|
});
|
||||||
|
test('Verify that a nested Object can be exported as JSON', async ({ page }) => {
|
||||||
|
const timer = await createDomainObjectWithDefaults(page, {
|
||||||
|
type: 'Timer',
|
||||||
|
name: 'timer',
|
||||||
|
parent: folder.uuid
|
||||||
|
});
|
||||||
|
// Navigate to the page
|
||||||
|
await page.goto(timer.url);
|
||||||
|
|
||||||
|
//do this against parent folder.url, NOT timer.url child
|
||||||
|
await openObjectTreeContextMenu(page, folder.url);
|
||||||
|
// Open context menu and initiate download
|
||||||
|
const [download] = await Promise.all([
|
||||||
|
page.waitForEvent('download'), // Waits for the download event
|
||||||
|
page.getByLabel('Export as JSON').click() // Triggers the download
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Read the contents of the downloaded file
|
||||||
|
const fileContents = await fs.readFile(await download.path(), 'utf8');
|
||||||
|
const jsonData = JSON.parse(fileContents);
|
||||||
|
|
||||||
|
// Retrieve the keys for folder and timer
|
||||||
|
const folderKey = getFirstKeyFromOpenMctJson(jsonData);
|
||||||
|
const timerKey = jsonData.openmct[folderKey].composition[0].key;
|
||||||
|
|
||||||
|
// Verify the folder properties
|
||||||
|
expect(jsonData.openmct[folderKey]).toHaveProperty('name', 'e2e folder');
|
||||||
|
expect(jsonData.openmct[folderKey]).toHaveProperty('type', 'folder');
|
||||||
|
|
||||||
|
// Verify the timer properties
|
||||||
|
expect(jsonData.openmct[timerKey]).toHaveProperty('name', 'timer');
|
||||||
|
expect(jsonData.openmct[timerKey]).toHaveProperty('type', 'timer');
|
||||||
|
|
||||||
|
// Verify the composition of the folder includes the timer
|
||||||
|
expect(jsonData.openmct[folderKey].composition).toEqual(
|
||||||
|
expect.arrayContaining([expect.objectContaining({ key: timerKey })])
|
||||||
|
);
|
||||||
});
|
});
|
||||||
test.fixme(
|
|
||||||
'Verify that the ExportAsJSON dropdown does not appear for the item X',
|
|
||||||
async ({ page }) => {
|
|
||||||
// Other than non-persistable objects
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
test.describe('ExportAsJSON Disabled Actions', () => {
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
//Use a Fault Management Object which is not composable
|
||||||
|
await navigateToFaultManagementWithExample(page);
|
||||||
|
});
|
||||||
|
test('Verify that the ExportAsJSON dropdown does not appear for the item X', async ({ page }) => {
|
||||||
|
await page.getByLabel('More actions').click();
|
||||||
|
await expect(await page.getByLabel('Export as JSON')).toHaveCount(0);
|
||||||
|
|
||||||
|
await page.getByRole('treeitem', { name: 'Fault Management' }).click({
|
||||||
|
button: 'right'
|
||||||
|
});
|
||||||
|
await expect(await page.getByLabel('Export as JSON')).toHaveCount(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
test.describe('ExportAsJSON ProgressBar @couchdb', () => {
|
||||||
|
let folder;
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto('./', { waitUntil: 'networkidle' });
|
||||||
|
// Perform actions to create the domain object
|
||||||
|
folder = await createDomainObjectWithDefaults(page, {
|
||||||
|
type: 'Folder'
|
||||||
|
});
|
||||||
|
await createDomainObjectWithDefaults(page, {
|
||||||
|
type: 'Timer',
|
||||||
|
parent: folder.uuid
|
||||||
|
});
|
||||||
|
await createDomainObjectWithDefaults(page, {
|
||||||
|
type: 'Timer',
|
||||||
|
parent: folder.uuid
|
||||||
|
});
|
||||||
|
});
|
||||||
|
test('Verify that the ExportAsJSON action creates a progressbar', async ({ page }) => {
|
||||||
|
// Navigate to the page
|
||||||
|
await page.goto(folder.url);
|
||||||
|
|
||||||
|
//Export My Items to create a large export
|
||||||
|
await page.getByRole('treeitem', { name: 'My Items' }).click({ button: 'right' });
|
||||||
|
// Open context menu and initiate download
|
||||||
|
await Promise.all([
|
||||||
|
page.getByRole('progressbar'), // This is just a check for the progress bar
|
||||||
|
page.getByText(
|
||||||
|
'Do not navigate away from this page or close this browser tab while this message'
|
||||||
|
), // This is the text associated with the download
|
||||||
|
page.waitForEvent('download'), // Waits for the download event
|
||||||
|
page.getByLabel('Export as JSON').click() // Triggers the download
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the first key from the 'openmct' property of the provided JSON object.
|
||||||
|
*
|
||||||
|
* @param {Object} jsonData - The JSON object containing the 'openmct' property.
|
||||||
|
* @returns {string} The first key found in the 'openmct' object.
|
||||||
|
* @throws {Error} If no keys are found in the 'openmct' object.
|
||||||
|
*/
|
||||||
|
function getFirstKeyFromOpenMctJson(jsonData) {
|
||||||
|
if (!jsonData.openmct) {
|
||||||
|
throw new Error("The provided JSON object does not have an 'openmct' property.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const keys = Object.keys(jsonData.openmct);
|
||||||
|
if (keys.length === 0) {
|
||||||
|
throw new Error('No keys found in the openmct object');
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys[0];
|
||||||
|
}
|
||||||
|
@ -36,7 +36,7 @@ test.describe('Testing numeric data with inspector data visualization (i.e., dat
|
|||||||
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Can click on telemetry and see data in inspector', async ({ page, context }) => {
|
test('Can click on telemetry and see data in inspector @2p', async ({ page, context }) => {
|
||||||
const exampleDataVisualizationSource = await createDomainObjectWithDefaults(page, {
|
const exampleDataVisualizationSource = await createDomainObjectWithDefaults(page, {
|
||||||
type: 'Example Data Visualization Source'
|
type: 'Example Data Visualization Source'
|
||||||
});
|
});
|
||||||
|
@ -53,6 +53,9 @@ test.describe('LAD Table Sets', () => {
|
|||||||
|
|
||||||
await page.goto(ladTableSet.url);
|
await page.goto(ladTableSet.url);
|
||||||
|
|
||||||
|
// Wait for the initial value to show after mount
|
||||||
|
await expect(page.getByLabel('lad value').first()).not.toContainText('---');
|
||||||
|
|
||||||
const valueFromFirstSineWave = await page.getByLabel('lad value').first().innerText();
|
const valueFromFirstSineWave = await page.getByLabel('lad value').first().innerText();
|
||||||
const firstSineWaveNumber = parseFloat(valueFromFirstSineWave);
|
const firstSineWaveNumber = parseFloat(valueFromFirstSineWave);
|
||||||
// ensure we have a float value in the cell and it's finite
|
// ensure we have a float value in the cell and it's finite
|
||||||
|
@ -0,0 +1,147 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2024, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This test suite is dedicated to tests which verify the basic operations surrounding Notebooks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import fs from 'fs/promises';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
import { createDomainObjectWithDefaults } from '../../../../appActions.js';
|
||||||
|
import { expect, test } from '../../../../pluginFixtures.js';
|
||||||
|
|
||||||
|
const NOTEBOOK_NAME = 'Notebook';
|
||||||
|
|
||||||
|
test.describe('Snapshot image tests', () => {
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
//Navigate to baseURL
|
||||||
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
|
// Create Notebook
|
||||||
|
await createDomainObjectWithDefaults(page, {
|
||||||
|
type: NOTEBOOK_NAME
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Can drop an image onto a notebook and create a new entry', async ({ page }) => {
|
||||||
|
const imageData = await fs.readFile(
|
||||||
|
fileURLToPath(
|
||||||
|
new URL('../../../../../src/images/favicons/favicon-96x96.png', import.meta.url)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const imageArray = new Uint8Array(imageData);
|
||||||
|
const fileData = Array.from(imageArray);
|
||||||
|
|
||||||
|
const dropTransfer = await page.evaluateHandle((data) => {
|
||||||
|
const dataTransfer = new DataTransfer();
|
||||||
|
const file = new File([new Uint8Array(data)], 'favicon-96x96.png', { type: 'image/png' });
|
||||||
|
dataTransfer.items.add(file);
|
||||||
|
return dataTransfer;
|
||||||
|
}, fileData);
|
||||||
|
|
||||||
|
await page.dispatchEvent('.c-notebook__drag-area', 'drop', { dataTransfer: dropTransfer });
|
||||||
|
await page.locator('.c-ne__save-button > button').click();
|
||||||
|
// be sure that entry was created
|
||||||
|
await expect(page.getByText('favicon-96x96.png')).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByRole('img', { name: 'favicon-96x96.png thumbnail' }).click();
|
||||||
|
// expect large image to be displayed
|
||||||
|
await expect(page.getByRole('dialog').getByText('favicon-96x96.png')).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByLabel('Close').click();
|
||||||
|
|
||||||
|
// drop another image onto the entry
|
||||||
|
await page.dispatchEvent('.c-snapshots', 'drop', { dataTransfer: dropTransfer });
|
||||||
|
|
||||||
|
const secondThumbnail = page.getByRole('img', { name: 'favicon-96x96.png thumbnail' }).nth(1);
|
||||||
|
await secondThumbnail.waitFor({ state: 'attached' });
|
||||||
|
// expect two embedded images now
|
||||||
|
expect(await page.getByRole('img', { name: 'favicon-96x96.png thumbnail' }).count()).toBe(2);
|
||||||
|
|
||||||
|
await page.locator('.c-snapshot.c-ne__embed').first().getByTitle('More actions').click();
|
||||||
|
|
||||||
|
await page.getByRole('menuitem', { name: /Remove This Embed/ }).click();
|
||||||
|
await page.getByRole('button', { name: 'Ok', exact: true }).click();
|
||||||
|
// Ensure that the thumbnail is removed before we assert
|
||||||
|
await secondThumbnail.waitFor({ state: 'detached' });
|
||||||
|
|
||||||
|
// expect one embedded image now as we deleted the other
|
||||||
|
expect(await page.getByRole('img', { name: 'favicon-96x96.png thumbnail' }).count()).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('Snapshot image failure tests', () => {
|
||||||
|
test.use({ failOnConsoleError: false });
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
//Navigate to baseURL
|
||||||
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
|
// Create Notebook
|
||||||
|
await createDomainObjectWithDefaults(page, {
|
||||||
|
type: NOTEBOOK_NAME
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Get an error notification when dropping unknown file onto notebook entry', async ({
|
||||||
|
page
|
||||||
|
}) => {
|
||||||
|
// fill Uint8Array array with some garbage data
|
||||||
|
const garbageData = new Uint8Array(100);
|
||||||
|
const fileData = Array.from(garbageData);
|
||||||
|
|
||||||
|
const dropTransfer = await page.evaluateHandle((data) => {
|
||||||
|
const dataTransfer = new DataTransfer();
|
||||||
|
const file = new File([new Uint8Array(data)], 'someGarbage.foo', { type: 'unknown/garbage' });
|
||||||
|
dataTransfer.items.add(file);
|
||||||
|
return dataTransfer;
|
||||||
|
}, fileData);
|
||||||
|
|
||||||
|
await page.dispatchEvent('.c-notebook__drag-area', 'drop', { dataTransfer: dropTransfer });
|
||||||
|
|
||||||
|
// should have gotten a notification from OpenMCT that we couldn't add it
|
||||||
|
await expect(page.getByText('Unknown object(s) dropped and cannot embed')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Get an error notification when dropping big files onto notebook entry', async ({
|
||||||
|
page
|
||||||
|
}) => {
|
||||||
|
const garbageSize = 15 * 1024 * 1024; // 15 megabytes
|
||||||
|
|
||||||
|
await page.addScriptTag({
|
||||||
|
// make the garbage client side
|
||||||
|
content: `window.bigGarbageData = new Uint8Array(${garbageSize})`
|
||||||
|
});
|
||||||
|
|
||||||
|
const bigDropTransfer = await page.evaluateHandle(() => {
|
||||||
|
const dataTransfer = new DataTransfer();
|
||||||
|
const file = new File([window.bigGarbageData], 'bigBoy.png', { type: 'image/png' });
|
||||||
|
dataTransfer.items.add(file);
|
||||||
|
return dataTransfer;
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.dispatchEvent('.c-notebook__drag-area', 'drop', { dataTransfer: bigDropTransfer });
|
||||||
|
|
||||||
|
// should have gotten a notification from OpenMCT that we couldn't add it as it's too big
|
||||||
|
await expect(page.getByText('unable to embed')).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
@ -24,14 +24,8 @@
|
|||||||
This test suite is dedicated to tests which verify the basic operations surrounding Notebooks.
|
This test suite is dedicated to tests which verify the basic operations surrounding Notebooks.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from 'fs/promises';
|
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
|
|
||||||
import { createDomainObjectWithDefaults } from '../../../../appActions.js';
|
|
||||||
import { expect, test } from '../../../../pluginFixtures.js';
|
import { expect, test } from '../../../../pluginFixtures.js';
|
||||||
|
|
||||||
const NOTEBOOK_NAME = 'Notebook';
|
|
||||||
|
|
||||||
test.describe('Snapshot Menu tests', () => {
|
test.describe('Snapshot Menu tests', () => {
|
||||||
test.fixme(
|
test.fixme(
|
||||||
'When no default notebook is selected, Snapshot Menu dropdown should only have a single option',
|
'When no default notebook is selected, Snapshot Menu dropdown should only have a single option',
|
||||||
@ -91,22 +85,13 @@ test.describe('Snapshot Container tests', () => {
|
|||||||
|
|
||||||
await page.getByLabel('Take a Notebook Snapshot').click();
|
await page.getByLabel('Take a Notebook Snapshot').click();
|
||||||
await page.getByRole('menuitem', { name: 'Save to Notebook Snapshots' }).click();
|
await page.getByRole('menuitem', { name: 'Save to Notebook Snapshots' }).click();
|
||||||
await page.getByRole('button', { name: 'Show' }).click();
|
await page.getByLabel('Show Snapshots').click();
|
||||||
});
|
});
|
||||||
test('A snapshot can be Quick Viewed from Container with 3 dot action menu', async ({ page }) => {
|
test('A snapshot can be Quick Viewed from Container with 3 dot action menu', async ({ page }) => {
|
||||||
await page.locator('.c-snapshot.c-ne__embed').first().getByTitle('More actions').click();
|
await page.locator('.c-snapshot.c-ne__embed').first().getByTitle('More actions').click();
|
||||||
await page.getByRole('menuitem', { name: 'Quick View' }).click();
|
await page.getByRole('menuitem', { name: 'Quick View' }).click();
|
||||||
await expect(page.locator('.c-overlay__outer')).toBeVisible();
|
await expect(page.locator('.c-overlay__outer')).toBeVisible();
|
||||||
});
|
});
|
||||||
test.fixme('5 Snapshots can be added to a container', async ({ page }) => {});
|
|
||||||
test.fixme(
|
|
||||||
'5 Snapshots can be added to a container and Deleted with Delete All action',
|
|
||||||
async ({ page }) => {}
|
|
||||||
);
|
|
||||||
test.fixme(
|
|
||||||
'A snapshot can be Deleted from Container with 3 dot action menu',
|
|
||||||
async ({ page }) => {}
|
|
||||||
);
|
|
||||||
test.fixme(
|
test.fixme(
|
||||||
'A snapshot can be Viewed, Annotated, display deleted, and saved from Container with 3 dot action menu',
|
'A snapshot can be Viewed, Annotated, display deleted, and saved from Container with 3 dot action menu',
|
||||||
async ({ page }) => {
|
async ({ page }) => {
|
||||||
@ -122,7 +107,15 @@ test.describe('Snapshot Container tests', () => {
|
|||||||
//await expect(await page.locator)
|
//await expect(await page.locator)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
test.fixme('5 Snapshots can be added to a container', async ({ page }) => {});
|
||||||
|
test.fixme(
|
||||||
|
'5 Snapshots can be added to a container and Deleted with Delete All action',
|
||||||
|
async ({ page }) => {}
|
||||||
|
);
|
||||||
|
test.fixme(
|
||||||
|
'A snapshot can be Deleted from Container with 3 dot action menu',
|
||||||
|
async ({ page }) => {}
|
||||||
|
);
|
||||||
test.fixme(
|
test.fixme(
|
||||||
'A snapshot can be Navigated To from Container with 3 dot action menu',
|
'A snapshot can be Navigated To from Container with 3 dot action menu',
|
||||||
async ({ page }) => {}
|
async ({ page }) => {}
|
||||||
@ -166,117 +159,3 @@ test.describe('Snapshot Container tests', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('Snapshot image tests', () => {
|
|
||||||
test.beforeEach(async ({ page }) => {
|
|
||||||
//Navigate to baseURL
|
|
||||||
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
|
||||||
|
|
||||||
// Create Notebook
|
|
||||||
await createDomainObjectWithDefaults(page, {
|
|
||||||
type: NOTEBOOK_NAME
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Can drop an image onto a notebook and create a new entry', async ({ page }) => {
|
|
||||||
const imageData = await fs.readFile(
|
|
||||||
fileURLToPath(
|
|
||||||
new URL('../../../../../src/images/favicons/favicon-96x96.png', import.meta.url)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const imageArray = new Uint8Array(imageData);
|
|
||||||
const fileData = Array.from(imageArray);
|
|
||||||
|
|
||||||
const dropTransfer = await page.evaluateHandle((data) => {
|
|
||||||
const dataTransfer = new DataTransfer();
|
|
||||||
const file = new File([new Uint8Array(data)], 'favicon-96x96.png', { type: 'image/png' });
|
|
||||||
dataTransfer.items.add(file);
|
|
||||||
return dataTransfer;
|
|
||||||
}, fileData);
|
|
||||||
|
|
||||||
await page.dispatchEvent('.c-notebook__drag-area', 'drop', { dataTransfer: dropTransfer });
|
|
||||||
await page.locator('.c-ne__save-button > button').click();
|
|
||||||
// be sure that entry was created
|
|
||||||
await expect(page.getByText('favicon-96x96.png')).toBeVisible();
|
|
||||||
|
|
||||||
await page.getByRole('img', { name: 'favicon-96x96.png thumbnail' }).click();
|
|
||||||
// expect large image to be displayed
|
|
||||||
await expect(page.getByRole('dialog').getByText('favicon-96x96.png')).toBeVisible();
|
|
||||||
|
|
||||||
await page.getByLabel('Close').click();
|
|
||||||
|
|
||||||
// drop another image onto the entry
|
|
||||||
await page.dispatchEvent('.c-snapshots', 'drop', { dataTransfer: dropTransfer });
|
|
||||||
|
|
||||||
const secondThumbnail = page.getByRole('img', { name: 'favicon-96x96.png thumbnail' }).nth(1);
|
|
||||||
await secondThumbnail.waitFor({ state: 'attached' });
|
|
||||||
// expect two embedded images now
|
|
||||||
expect(await page.getByRole('img', { name: 'favicon-96x96.png thumbnail' }).count()).toBe(2);
|
|
||||||
|
|
||||||
await page.locator('.c-snapshot.c-ne__embed').first().getByTitle('More actions').click();
|
|
||||||
|
|
||||||
await page.getByRole('menuitem', { name: /Remove This Embed/ }).click();
|
|
||||||
await page.getByRole('button', { name: 'Ok', exact: true }).click();
|
|
||||||
// Ensure that the thumbnail is removed before we assert
|
|
||||||
await secondThumbnail.waitFor({ state: 'detached' });
|
|
||||||
|
|
||||||
// expect one embedded image now as we deleted the other
|
|
||||||
expect(await page.getByRole('img', { name: 'favicon-96x96.png thumbnail' }).count()).toBe(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe('Snapshot image failure tests', () => {
|
|
||||||
test.use({ failOnConsoleError: false });
|
|
||||||
test.beforeEach(async ({ page }) => {
|
|
||||||
//Navigate to baseURL
|
|
||||||
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
|
||||||
|
|
||||||
// Create Notebook
|
|
||||||
await createDomainObjectWithDefaults(page, {
|
|
||||||
type: NOTEBOOK_NAME
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Get an error notification when dropping unknown file onto notebook entry', async ({
|
|
||||||
page
|
|
||||||
}) => {
|
|
||||||
// fill Uint8Array array with some garbage data
|
|
||||||
const garbageData = new Uint8Array(100);
|
|
||||||
const fileData = Array.from(garbageData);
|
|
||||||
|
|
||||||
const dropTransfer = await page.evaluateHandle((data) => {
|
|
||||||
const dataTransfer = new DataTransfer();
|
|
||||||
const file = new File([new Uint8Array(data)], 'someGarbage.foo', { type: 'unknown/garbage' });
|
|
||||||
dataTransfer.items.add(file);
|
|
||||||
return dataTransfer;
|
|
||||||
}, fileData);
|
|
||||||
|
|
||||||
await page.dispatchEvent('.c-notebook__drag-area', 'drop', { dataTransfer: dropTransfer });
|
|
||||||
|
|
||||||
// should have gotten a notification from OpenMCT that we couldn't add it
|
|
||||||
await expect(page.getByText('Unknown object(s) dropped and cannot embed')).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Get an error notification when dropping big files onto notebook entry', async ({
|
|
||||||
page
|
|
||||||
}) => {
|
|
||||||
const garbageSize = 15 * 1024 * 1024; // 15 megabytes
|
|
||||||
|
|
||||||
await page.addScriptTag({
|
|
||||||
// make the garbage client side
|
|
||||||
content: `window.bigGarbageData = new Uint8Array(${garbageSize})`
|
|
||||||
});
|
|
||||||
|
|
||||||
const bigDropTransfer = await page.evaluateHandle(() => {
|
|
||||||
const dataTransfer = new DataTransfer();
|
|
||||||
const file = new File([window.bigGarbageData], 'bigBoy.png', { type: 'image/png' });
|
|
||||||
dataTransfer.items.add(file);
|
|
||||||
return dataTransfer;
|
|
||||||
});
|
|
||||||
|
|
||||||
await page.dispatchEvent('.c-notebook__drag-area', 'drop', { dataTransfer: bigDropTransfer });
|
|
||||||
|
|
||||||
// should have gotten a notification from OpenMCT that we couldn't add it as it's too big
|
|
||||||
await expect(page.getByText('unable to embed')).toBeVisible();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
@ -51,7 +51,7 @@ test.describe('Operator Status', () => {
|
|||||||
// Description should be empty https://github.com/nasa/openmct/issues/6978
|
// Description should be empty https://github.com/nasa/openmct/issues/6978
|
||||||
await expect(page.locator('.c-message__action-text')).toBeHidden();
|
await expect(page.locator('.c-message__action-text')).toBeHidden();
|
||||||
// set role
|
// set role
|
||||||
await page.getByRole('button', { name: 'Select' }).click();
|
await page.getByRole('button', { name: 'Select', exact: true }).click();
|
||||||
// dismiss role confirmation popup
|
// dismiss role confirmation popup
|
||||||
await page.getByRole('button', { name: 'Dismiss' }).click();
|
await page.getByRole('button', { name: 'Dismiss' }).click();
|
||||||
});
|
});
|
||||||
|
@ -34,13 +34,13 @@ test.describe('User Roles', () => {
|
|||||||
// we have multiple available roles, so it should prompt the user
|
// we have multiple available roles, so it should prompt the user
|
||||||
await expect(page.getByText('Select Role')).toBeVisible();
|
await expect(page.getByText('Select Role')).toBeVisible();
|
||||||
await page.getByRole('combobox').selectOption('driver');
|
await page.getByRole('combobox').selectOption('driver');
|
||||||
await page.getByRole('button', { name: 'Select' }).click();
|
await page.getByRole('button', { name: 'Select', exact: true }).click();
|
||||||
await expect(page.getByLabel('User Role')).toContainText('driver');
|
await expect(page.getByLabel('User Role')).toContainText('driver');
|
||||||
|
|
||||||
// attempt changing the role to another valid available role
|
// attempt changing the role to another valid available role
|
||||||
await page.getByRole('button', { name: 'Change Role' }).click();
|
await page.getByRole('button', { name: 'Change Role' }).click();
|
||||||
await page.getByRole('combobox').selectOption('flight');
|
await page.getByRole('combobox').selectOption('flight');
|
||||||
await page.getByRole('button', { name: 'Select' }).click();
|
await page.getByRole('button', { name: 'Select', exact: true }).click();
|
||||||
await expect(page.getByLabel('User Role')).toContainText('flight');
|
await expect(page.getByLabel('User Role')).toContainText('flight');
|
||||||
|
|
||||||
// reload page
|
// reload page
|
||||||
@ -63,7 +63,7 @@ test.describe('User Roles', () => {
|
|||||||
|
|
||||||
// select real role of "driver"
|
// select real role of "driver"
|
||||||
await page.getByRole('combobox').selectOption('driver');
|
await page.getByRole('combobox').selectOption('driver');
|
||||||
await page.getByRole('button', { name: 'Select' }).click();
|
await page.getByRole('button', { name: 'Select', exact: true }).click();
|
||||||
await expect(page.getByLabel('User Role')).toContainText('driver');
|
await expect(page.getByLabel('User Role')).toContainText('driver');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -26,7 +26,7 @@ Tests the branding associated with the default deployment. At least the about mo
|
|||||||
|
|
||||||
import percySnapshot from '@percy/playwright';
|
import percySnapshot from '@percy/playwright';
|
||||||
|
|
||||||
import { scanForA11yViolations, test } from '../../../avpFixtures.js';
|
import { expect, scanForA11yViolations, test } from '../../../avpFixtures.js';
|
||||||
import { VISUAL_URL } from '../../../constants.js';
|
import { VISUAL_URL } from '../../../constants.js';
|
||||||
|
|
||||||
//Declare the scope of the visual test
|
//Declare the scope of the visual test
|
||||||
@ -50,6 +50,17 @@ test.describe('Visual - Header @a11y', () => {
|
|||||||
scope: header
|
scope: header
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('show snapshot button', async ({ page, theme }) => {
|
||||||
|
await page.getByLabel('Take a Notebook Snapshot').click();
|
||||||
|
|
||||||
|
await page.getByRole('menuitem', { name: 'Save to Notebook Snapshots' }).click();
|
||||||
|
|
||||||
|
await percySnapshot(page, `Notebook Snapshot Show button (theme: '${theme}')`, {
|
||||||
|
scope: header
|
||||||
|
});
|
||||||
|
await expect(await page.getByLabel('Show Snapshots')).toBeVisible();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
test.afterEach(async ({ page }, testInfo) => {
|
test.afterEach(async ({ page }, testInfo) => {
|
||||||
await scanForA11yViolations(page, testInfo.title);
|
await scanForA11yViolations(page, testInfo.title);
|
||||||
|
@ -56,8 +56,8 @@
|
|||||||
{{ formatImageAltText }}
|
{{ formatImageAltText }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
role="button"
|
|
||||||
ref="focusedImageWrapper"
|
ref="focusedImageWrapper"
|
||||||
|
role="button"
|
||||||
class="image-wrapper"
|
class="image-wrapper"
|
||||||
aria-label="Image Wrapper"
|
aria-label="Image Wrapper"
|
||||||
:style="{
|
:style="{
|
||||||
@ -74,8 +74,8 @@
|
|||||||
:style="getVisibleLayerStyles(layer)"
|
:style="getVisibleLayerStyles(layer)"
|
||||||
></div>
|
></div>
|
||||||
<img
|
<img
|
||||||
aria-label="Focused Image"
|
|
||||||
ref="focusedImage"
|
ref="focusedImage"
|
||||||
|
aria-label="Focused Image"
|
||||||
class="c-imagery__main-image__image js-imageryView-image"
|
class="c-imagery__main-image__image js-imageryView-image"
|
||||||
:src="imageUrl"
|
:src="imageUrl"
|
||||||
:draggable="!isSelectable"
|
:draggable="!isSelectable"
|
||||||
|
@ -25,6 +25,10 @@
|
|||||||
class="c-progress-bar__bar"
|
class="c-progress-bar__bar"
|
||||||
:class="{ '--indeterminate': !progressPerc }"
|
:class="{ '--indeterminate': !progressPerc }"
|
||||||
:style="styleBarWidth"
|
:style="styleBarWidth"
|
||||||
|
role="progressbar"
|
||||||
|
:aria-valuenow="progressPerc"
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax="100"
|
||||||
></div>
|
></div>
|
||||||
<div v-if="progressText !== ''" class="c-progress-bar__text">
|
<div v-if="progressText !== ''" class="c-progress-bar__text">
|
||||||
<span v-if="progressPerc > 0">{{ progressPerc }}% complete.</span>
|
<span v-if="progressPerc > 0">{{ progressPerc }}% complete.</span>
|
||||||
|
@ -85,11 +85,13 @@
|
|||||||
<template #controls>
|
<template #controls>
|
||||||
<button
|
<button
|
||||||
class="c-icon-button l-shell__reset-tree-button icon-folders-collapse"
|
class="c-icon-button l-shell__reset-tree-button icon-folders-collapse"
|
||||||
|
aria-label="Collapse all tree items"
|
||||||
title="Collapse all tree items"
|
title="Collapse all tree items"
|
||||||
@click="handleTreeReset"
|
@click="handleTreeReset"
|
||||||
></button>
|
></button>
|
||||||
<button
|
<button
|
||||||
class="c-icon-button l-shell__sync-tree-button icon-target"
|
class="c-icon-button l-shell__sync-tree-button icon-target"
|
||||||
|
aria-label="Show selected item in tree"
|
||||||
title="Show selected item in tree"
|
title="Show selected item in tree"
|
||||||
@click="handleSyncTreeNavigation"
|
@click="handleSyncTreeNavigation"
|
||||||
></button>
|
></button>
|
||||||
|
Loading…
Reference in New Issue
Block a user