mirror of
https://github.com/nasa/openmct.git
synced 2025-01-18 10:46:42 +00:00
Fix stacked plot child selection (#6275)
* Fix selections for different scenarios * Ensure plot selection in stacked plots works when there are no selected or found annotations * Adds e2e test for stacked plot selection and fixes the old e2e test which was testing overlay plots instead. * Fix selection of plots while in Edit mode * Improve tests for stacked plots * refactor: remove unnecessary `await`s * a11y: move aria-label to StackedPlotItem * refactor(e2e): combine like tests, unique object names - Use unique object names in `text=` selectors - Combine like tests to reduce execution time - Use `getByRole` selectors where able * docs(e2e): add comments to test * fix: add class back for unit test selector --------- Co-authored-by: Scott Bell <scott@traclabs.com> Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov>
This commit is contained in:
parent
0f312a88bb
commit
be38c3e654
@ -29,29 +29,39 @@ const { test, expect } = require('../../../../pluginFixtures');
|
|||||||
const { createDomainObjectWithDefaults } = require('../../../../appActions');
|
const { createDomainObjectWithDefaults } = require('../../../../appActions');
|
||||||
|
|
||||||
test.describe('Stacked Plot', () => {
|
test.describe('Stacked Plot', () => {
|
||||||
|
let stackedPlot;
|
||||||
|
let swgA;
|
||||||
|
let swgB;
|
||||||
|
let swgC;
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
//Open a browser, navigate to the main page, and wait until all networkevents to resolve
|
||||||
|
await page.goto('/', { waitUntil: 'networkidle' });
|
||||||
|
stackedPlot = await createDomainObjectWithDefaults(page, {
|
||||||
|
type: "Stacked Plot"
|
||||||
|
});
|
||||||
|
|
||||||
|
swgA = await createDomainObjectWithDefaults(page, {
|
||||||
|
type: "Sine Wave Generator",
|
||||||
|
parent: stackedPlot.uuid
|
||||||
|
});
|
||||||
|
swgB = await createDomainObjectWithDefaults(page, {
|
||||||
|
type: "Sine Wave Generator",
|
||||||
|
parent: stackedPlot.uuid
|
||||||
|
});
|
||||||
|
swgC = await createDomainObjectWithDefaults(page, {
|
||||||
|
type: "Sine Wave Generator",
|
||||||
|
parent: stackedPlot.uuid
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('Using the remove action removes the correct plot', async ({ page }) => {
|
test('Using the remove action removes the correct plot', async ({ page }) => {
|
||||||
await page.goto('/', { waitUntil: 'networkidle' });
|
const swgAElementsPoolItem = page.locator('#inspector-elements-tree').locator('.c-object-label', { hasText: swgA.name });
|
||||||
const overlayPlot = await createDomainObjectWithDefaults(page, {
|
const swgBElementsPoolItem = page.locator('#inspector-elements-tree').locator('.c-object-label', { hasText: swgB.name });
|
||||||
type: "Overlay Plot"
|
const swgCElementsPoolItem = page.locator('#inspector-elements-tree').locator('.c-object-label', { hasText: swgC.name });
|
||||||
});
|
|
||||||
|
await page.goto(stackedPlot.url);
|
||||||
|
|
||||||
await createDomainObjectWithDefaults(page, {
|
|
||||||
type: "Sine Wave Generator",
|
|
||||||
name: 'swg a',
|
|
||||||
parent: overlayPlot.uuid
|
|
||||||
});
|
|
||||||
await createDomainObjectWithDefaults(page, {
|
|
||||||
type: "Sine Wave Generator",
|
|
||||||
name: 'swg b',
|
|
||||||
parent: overlayPlot.uuid
|
|
||||||
});
|
|
||||||
await createDomainObjectWithDefaults(page, {
|
|
||||||
type: "Sine Wave Generator",
|
|
||||||
name: 'swg c',
|
|
||||||
parent: overlayPlot.uuid
|
|
||||||
});
|
|
||||||
await page.goto(overlayPlot.url);
|
|
||||||
await page.click('button[title="Edit"]');
|
await page.click('button[title="Edit"]');
|
||||||
|
|
||||||
// Expand the elements pool vertically
|
// Expand the elements pool vertically
|
||||||
@ -60,20 +70,70 @@ test.describe('Stacked Plot', () => {
|
|||||||
await page.mouse.move(0, 100);
|
await page.mouse.move(0, 100);
|
||||||
await page.mouse.up();
|
await page.mouse.up();
|
||||||
|
|
||||||
await page.locator('.js-elements-pool__tree >> text=swg b').click({ button: 'right' });
|
await swgBElementsPoolItem.click({ button: 'right' });
|
||||||
await page.locator('li[role="menuitem"]:has-text("Remove")').click();
|
await page.getByRole('menuitem').filter({ hasText: /Remove/ }).click();
|
||||||
await page.locator('.js-overlay .js-overlay__button >> text=OK').click();
|
await page.getByRole('button').filter({ hasText: "OK" }).click();
|
||||||
|
|
||||||
// Wait until the number of elements in the elements pool has changed, and then confirm that the correct children were retained
|
await expect(page.locator('#inspector-elements-tree .js-elements-pool__item')).toHaveCount(2);
|
||||||
// await page.waitForFunction(() => {
|
|
||||||
// return Array.from(document.querySelectorAll('.js-elements-pool__tree .js-elements-pool__item')).length === 2;
|
|
||||||
// });
|
|
||||||
// Wait until there are only two items in the elements pool (ie the remove action has completed)
|
|
||||||
await expect(page.locator('.js-elements-pool__tree .js-elements-pool__item')).toHaveCount(2);
|
|
||||||
|
|
||||||
// Confirm that the elements pool contains the items we expect
|
// Confirm that the elements pool contains the items we expect
|
||||||
await expect(page.locator('.js-elements-pool__tree >> text=swg a')).toHaveCount(1);
|
await expect(swgAElementsPoolItem).toHaveCount(1);
|
||||||
await expect(page.locator('.js-elements-pool__tree >> text=swg b')).toHaveCount(0);
|
await expect(swgBElementsPoolItem).toHaveCount(0);
|
||||||
await expect(page.locator('.js-elements-pool__tree >> text=swg c')).toHaveCount(1);
|
await expect(swgCElementsPoolItem).toHaveCount(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Selecting a child plot while in browse and edit modes shows its properties in the inspector', async ({ page }) => {
|
||||||
|
await page.goto(stackedPlot.url);
|
||||||
|
|
||||||
|
// Click on the 1st plot
|
||||||
|
await page.locator(`[aria-label="Stacked Plot Item ${swgA.name}"] canvas`).nth(1).click();
|
||||||
|
|
||||||
|
// Assert that the inspector shows the Y Axis properties for swgA
|
||||||
|
await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText("Plot Series");
|
||||||
|
await expect(page.getByRole('list', { name: "Y Axis Properties" }).locator("h2")).toContainText("Y Axis");
|
||||||
|
await expect(page.locator('[aria-label="Plot Series Properties"] .c-object-label')).toContainText(swgA.name);
|
||||||
|
|
||||||
|
// Click on the 2nd plot
|
||||||
|
await page.locator(`[aria-label="Stacked Plot Item ${swgB.name}"] canvas`).nth(1).click();
|
||||||
|
|
||||||
|
// Assert that the inspector shows the Y Axis properties for swgB
|
||||||
|
await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText("Plot Series");
|
||||||
|
await expect(page.getByRole('list', { name: "Y Axis Properties" }).locator("h2")).toContainText("Y Axis");
|
||||||
|
await expect(page.locator('[aria-label="Plot Series Properties"] .c-object-label')).toContainText(swgB.name);
|
||||||
|
|
||||||
|
// Click on the 3rd plot
|
||||||
|
await page.locator(`[aria-label="Stacked Plot Item ${swgC.name}"] canvas`).nth(1).click();
|
||||||
|
|
||||||
|
// Assert that the inspector shows the Y Axis properties for swgC
|
||||||
|
await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText("Plot Series");
|
||||||
|
await expect(page.getByRole('list', { name: "Y Axis Properties" }).locator("h2")).toContainText("Y Axis");
|
||||||
|
await expect(page.locator('[aria-label="Plot Series Properties"] .c-object-label')).toContainText(swgC.name);
|
||||||
|
|
||||||
|
// Go into edit mode
|
||||||
|
await page.click('button[title="Edit"]');
|
||||||
|
|
||||||
|
// Click on canvas for the 1st plot
|
||||||
|
await page.locator(`[aria-label="Stacked Plot Item ${swgA.name}"]`).click();
|
||||||
|
|
||||||
|
// Assert that the inspector shows the Y Axis properties for swgA
|
||||||
|
await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText("Plot Series");
|
||||||
|
await expect(page.getByRole('list', { name: "Y Axis Properties" }).locator("h2")).toContainText("Y Axis");
|
||||||
|
await expect(page.locator('[aria-label="Plot Series Properties"] .c-object-label')).toContainText(swgA.name);
|
||||||
|
|
||||||
|
//Click on canvas for the 2nd plot
|
||||||
|
await page.locator(`[aria-label="Stacked Plot Item ${swgB.name}"]`).click();
|
||||||
|
|
||||||
|
// Assert that the inspector shows the Y Axis properties for swgB
|
||||||
|
await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText("Plot Series");
|
||||||
|
await expect(page.getByRole('list', { name: "Y Axis Properties" }).locator("h2")).toContainText("Y Axis");
|
||||||
|
await expect(page.locator('[aria-label="Plot Series Properties"] .c-object-label')).toContainText(swgB.name);
|
||||||
|
|
||||||
|
//Click on canvas for the 3rd plot
|
||||||
|
await page.locator(`[aria-label="Stacked Plot Item ${swgC.name}"]`).click();
|
||||||
|
|
||||||
|
// Assert that the inspector shows the Y Axis properties for swgC
|
||||||
|
await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText("Plot Series");
|
||||||
|
await expect(page.getByRole('list', { name: "Y Axis Properties" }).locator("h2")).toContainText("Y Axis");
|
||||||
|
await expect(page.locator('[aria-label="Plot Series Properties"] .c-object-label')).toContainText(swgC.name);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1190,28 +1190,42 @@ export default {
|
|||||||
selectNearbyAnnotations(event) {
|
selectNearbyAnnotations(event) {
|
||||||
// need to stop propagation right away to prevent selecting the plot itself
|
// need to stop propagation right away to prevent selecting the plot itself
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (!this.annotationViewingAndEditingAllowed || this.annotationSelections.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nearbyAnnotations = this.gatherNearbyAnnotations();
|
const nearbyAnnotations = this.gatherNearbyAnnotations();
|
||||||
if (!nearbyAnnotations.length) {
|
|
||||||
const emptySelection = this.createPathSelection();
|
if (this.annotationViewingAndEditingAllowed && this.annotationSelections.length) {
|
||||||
this.openmct.selection.select(emptySelection, true);
|
//no annotations were found, but we are adding some now
|
||||||
// should show plot itself if we didn't find any annotations
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.annotationViewingAndEditingAllowed && nearbyAnnotations.length) {
|
||||||
|
//show annotations if some were found
|
||||||
|
const { targetDomainObjects, targetDetails } = this.prepareExistingAnnotationSelection(nearbyAnnotations);
|
||||||
|
this.selectPlotAnnotations({
|
||||||
|
targetDetails,
|
||||||
|
targetDomainObjects,
|
||||||
|
annotations: nearbyAnnotations
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { targetDomainObjects, targetDetails } = this.prepareExistingAnnotationSelection(nearbyAnnotations);
|
//Fall through to here if either there is no new selection add tags or no existing annotations were retrieved
|
||||||
this.selectPlotAnnotations({
|
this.selectPlot();
|
||||||
targetDetails,
|
},
|
||||||
targetDomainObjects,
|
selectPlot() {
|
||||||
annotations: nearbyAnnotations
|
// should show plot itself if we didn't find any annotations
|
||||||
});
|
const selection = this.createPathSelection();
|
||||||
|
this.openmct.selection.select(selection, true);
|
||||||
},
|
},
|
||||||
createPathSelection() {
|
createPathSelection() {
|
||||||
let selection = [];
|
let selection = [];
|
||||||
|
selection.unshift({
|
||||||
|
element: this.$el,
|
||||||
|
context: {
|
||||||
|
item: this.domainObject
|
||||||
|
}
|
||||||
|
});
|
||||||
this.path.forEach((pathObject, index) => {
|
this.path.forEach((pathObject, index) => {
|
||||||
selection.push({
|
selection.push({
|
||||||
element: this.openmct.layout.$refs.browseObject.$el,
|
element: this.openmct.layout.$refs.browseObject.$el,
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
<ul
|
<ul
|
||||||
v-if="!isStackedPlotObject"
|
v-if="!isStackedPlotObject"
|
||||||
class="c-tree"
|
class="c-tree"
|
||||||
|
aria-label="Plot Series Properties"
|
||||||
>
|
>
|
||||||
<h2 title="Plot series display properties in this object">Plot Series</h2>
|
<h2 title="Plot series display properties in this object">Plot Series</h2>
|
||||||
<plot-options-item
|
<plot-options-item
|
||||||
@ -43,6 +44,7 @@
|
|||||||
v-for="(yAxis, index) in yAxesWithSeries"
|
v-for="(yAxis, index) in yAxesWithSeries"
|
||||||
:key="`yAxis-${index}`"
|
:key="`yAxis-${index}`"
|
||||||
class="l-inspector-part js-yaxis-properties"
|
class="l-inspector-part js-yaxis-properties"
|
||||||
|
:aria-label="yAxesWithSeries.length > 1 ? `Y Axis ${yAxis.id} Properties` : 'Y Axis Properties'"
|
||||||
>
|
>
|
||||||
<h2 title="Y axis settings for this object">Y Axis {{ yAxesWithSeries.length > 1 ? yAxis.id : '' }}</h2>
|
<h2 title="Y axis settings for this object">Y Axis {{ yAxesWithSeries.length > 1 ? yAxis.id : '' }}</h2>
|
||||||
<li class="grid-row">
|
<li class="grid-row">
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
<ul
|
<ul
|
||||||
v-if="!isStackedPlotObject"
|
v-if="!isStackedPlotObject"
|
||||||
class="c-tree"
|
class="c-tree"
|
||||||
|
aria-label="Plot Series Properties"
|
||||||
>
|
>
|
||||||
<h2 title="Display properties for this object">Plot Series</h2>
|
<h2 title="Display properties for this object">Plot Series</h2>
|
||||||
<li
|
<li
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="loaded">
|
<div v-if="loaded">
|
||||||
<ul class="l-inspector-part">
|
<ul
|
||||||
|
class="l-inspector-part"
|
||||||
|
:aria-label="id > 1 ? `Y Axis ${id} Properties` : 'Y Axis Properties'"
|
||||||
|
>
|
||||||
<h2>Y Axis {{ id > 1 ? id : '' }}</h2>
|
<h2>Y Axis {{ id > 1 ? id : '' }}</h2>
|
||||||
<li class="grid-row">
|
<li class="grid-row">
|
||||||
<div
|
<div
|
||||||
|
@ -20,7 +20,9 @@
|
|||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div></div>
|
<div
|
||||||
|
:aria-label="`Stacked Plot Item ${childObject.name}`"
|
||||||
|
></div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
@ -102,13 +104,33 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.updateView();
|
this.updateView();
|
||||||
|
this.isEditing = this.openmct.editor.isEditing();
|
||||||
|
this.openmct.editor.on('isEditing', this.setEditState);
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
this.openmct.editor.off('isEditing', this.setEditState);
|
||||||
|
|
||||||
|
if (this.removeSelectable) {
|
||||||
|
this.removeSelectable();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.component) {
|
if (this.component) {
|
||||||
this.component.$destroy();
|
this.component.$destroy();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
setEditState(isEditing) {
|
||||||
|
this.isEditing = isEditing;
|
||||||
|
|
||||||
|
if (this.isEditing) {
|
||||||
|
this.setSelection();
|
||||||
|
} else {
|
||||||
|
if (this.removeSelectable) {
|
||||||
|
this.removeSelectable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
updateComponentProp(prop, value) {
|
updateComponentProp(prop, value) {
|
||||||
if (this.component) {
|
if (this.component) {
|
||||||
this.component[prop] = value;
|
this.component[prop] = value;
|
||||||
@ -203,6 +225,10 @@ export default {
|
|||||||
@loadingUpdated="loadingUpdated"/>
|
@loadingUpdated="loadingUpdated"/>
|
||||||
</div>`
|
</div>`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.isEditing) {
|
||||||
|
this.setSelection();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onLockHighlightPointUpdated() {
|
onLockHighlightPointUpdated() {
|
||||||
this.$emit('lockHighlightPoint', ...arguments);
|
this.$emit('lockHighlightPoint', ...arguments);
|
||||||
@ -226,6 +252,17 @@ export default {
|
|||||||
this.status = status;
|
this.status = status;
|
||||||
this.updateComponentProp('status', status);
|
this.updateComponentProp('status', status);
|
||||||
},
|
},
|
||||||
|
setSelection() {
|
||||||
|
let childContext = {};
|
||||||
|
childContext.item = this.childObject;
|
||||||
|
this.context = childContext;
|
||||||
|
if (this.removeSelectable) {
|
||||||
|
this.removeSelectable();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeSelectable = this.openmct.selection.selectable(
|
||||||
|
this.$el, this.context);
|
||||||
|
},
|
||||||
getProps() {
|
getProps() {
|
||||||
return {
|
return {
|
||||||
limitLineLabels: this.showLimitLineLabels,
|
limitLineLabels: this.showLimitLineLabels,
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div></div>
|
<div aria-label="Inspector Views"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
Loading…
Reference in New Issue
Block a user