test(contour): contour color change coverage (#6042)

This commit is contained in:
diattamo authored and GitHub committed 2026-06-20 11:11:57 -04:00
1 parent 419366bd25
commit 5955151ba1
5 files changed
+242 -2

No files matched your search

+177
View File
@@ -0,0 +1,177 @@
import {
expect,
test,
visitStudy,
waitForViewportsRendered,
getSvgAttribute,
} from './utils';
const NEW_HEX = '#FF00FF';
const NEW_HEX_CSS_RGB = 'rgb(255, 0, 255)';
const NEW_HEX_CSS_RGBA = 'rgba(255, 0, 255, 1)';
// Default colors baked into the RTSTRUCT in the canonical contour study.
const THRESHOLD_CONTOUR_DEFAULT_HEX = '#00EBEB';
const THRESHOLD_CONTOUR_DEFAULT_CSS_RGBA = 'rgba(0, 235, 235, 1)';
const THRESHOLD_CONTOUR_DEFAULT_CSS_RGB = 'rgb(0, 235, 235)';
const STUDY_UID = '1.2.840.113619.2.290.3.3767434740.226.1600859119.501';
test.beforeEach(async ({ page, leftPanelPageObject, DOMOverlayPageObject }) => {
await visitStudy(page, STUDY_UID, 'segmentation', 2000);
await leftPanelPageObject.loadSeriesByModality('RTSTRUCT');
await waitForViewportsRendered(page);
await expect(DOMOverlayPageObject.viewport.segmentationHydration.locator).toBeVisible();
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
});
test('opens the color edit popup when "Change Color" is clicked', async ({
rightPanelPageObject,
DOMOverlayPageObject,
}) => {
const segment = rightPanelPageObject.contourSegmentationPanel.panel.nthSegment(0);
await segment.actions.openChangeColor();
await expect(DOMOverlayPageObject.dialog.colorPicker.locator).toBeVisible();
await expect(DOMOverlayPageObject.dialog.title).toHaveText('Segment Color');
await expect(DOMOverlayPageObject.dialog.colorPicker.saveButton).toBeVisible();
await expect(DOMOverlayPageObject.dialog.colorPicker.cancelButton).toBeVisible();
await expect(DOMOverlayPageObject.dialog.colorPicker.hexInput).toHaveValue(
THRESHOLD_CONTOUR_DEFAULT_HEX
);
});
test('changes the contour color when the user saves the edits', async ({
viewportPageObject,
rightPanelPageObject,
DOMOverlayPageObject,
}) => {
await rightPanelPageObject.contourSegmentationPanel.segmentsVisibilityToggle.click();
const segment = rightPanelPageObject.contourSegmentationPanel.panel.nthSegment(0);
await segment.toggleVisibility();
await segment.click();
await expect(segment.rowDataColorHex).toHaveCSS('background-color',THRESHOLD_CONTOUR_DEFAULT_CSS_RGB);
const svgStrokeAttributeBeforeColorChange = await getSvgAttribute({
viewportPageObject,
svgInnerElement: 'path',
attributeName: 'stroke',
});
expect(svgStrokeAttributeBeforeColorChange, 'Expected SVG stroke attribute to be original threshold color').toBe(
THRESHOLD_CONTOUR_DEFAULT_CSS_RGBA
);
// change color
await segment.actions.changeColor(NEW_HEX);
await expect(DOMOverlayPageObject.dialog.colorPicker.locator).toBeHidden();
await expect(segment.rowDataColorHex).toHaveCSS('background-color', NEW_HEX_CSS_RGB);
//check svg path stroke attribute is updated with new color
const svgStrokeAttributeAfterColorChange = await getSvgAttribute({
viewportPageObject,
svgInnerElement: 'path',
attributeName: 'stroke',
});
expect(svgStrokeAttributeAfterColorChange, 'Expected SVG stroke attribute to be updated with new color').toBe(
NEW_HEX_CSS_RGBA
);
});
test('does not change the contour color when the user cancels', async ({
rightPanelPageObject,
DOMOverlayPageObject,
viewportPageObject
}) => {
await rightPanelPageObject.contourSegmentationPanel.segmentsVisibilityToggle.click();
const segment = rightPanelPageObject.contourSegmentationPanel.panel.nthSegment(0);
await segment.toggleVisibility();
await segment.click();
await expect(segment.rowDataColorHex).toHaveCSS(
'background-color',
THRESHOLD_CONTOUR_DEFAULT_CSS_RGB
);
const svgStrokeAttributeBeforeColorChange = await getSvgAttribute({
viewportPageObject,
svgInnerElement: 'path',
attributeName: 'stroke',
});
expect(svgStrokeAttributeBeforeColorChange, 'Expected SVG stroke attribute to be original threshold color').toBe(
THRESHOLD_CONTOUR_DEFAULT_CSS_RGBA
);
await segment.actions.cancelChangeColor(NEW_HEX);
await expect(DOMOverlayPageObject.dialog.colorPicker.locator).toBeHidden();
await expect(segment.rowDataColorHex).toHaveCSS('background-color', THRESHOLD_CONTOUR_DEFAULT_CSS_RGB);
//check svg path stroke attribute is updated with new color
const svgStrokeAttributeAfterColorChange = await getSvgAttribute({
viewportPageObject,
svgInnerElement: 'path',
attributeName: 'stroke',
});
expect(svgStrokeAttributeAfterColorChange, 'Expected SVG stroke attribute to remain the original color').toBe(
THRESHOLD_CONTOUR_DEFAULT_CSS_RGBA
);
});
test('duplicated contour will be generated with a new color', async ({
viewportPageObject,
rightPanelPageObject,
}) => {
await rightPanelPageObject.contourSegmentationPanel.segmentsVisibilityToggle.click();
const panel = rightPanelPageObject.contourSegmentationPanel.panel;
const segment0 = panel.nthSegment(0);
await segment0.toggleVisibility();
await segment0.click();
await expect(segment0.rowDataColorHex).toHaveCSS(
'background-color',
THRESHOLD_CONTOUR_DEFAULT_CSS_RGB
);
const svgStrokeAttributeBeforeColorChange = await getSvgAttribute({
viewportPageObject,
svgInnerElement: 'path',
attributeName: 'stroke',
});
expect(svgStrokeAttributeBeforeColorChange, 'Expected SVG stroke attribute to be original threshold color').toBe(
THRESHOLD_CONTOUR_DEFAULT_CSS_RGBA
);
// duplicate the segment
const initialCount = await panel.getSegmentCount();
expect(initialCount, 'Expected to start with 4 segments').toBe(4);
await segment0.actions.duplicate();
await segment0.toggleVisibility(); // toggle original segment 0 visibility off to be able to grab the duplicated segment's path
const duplicateSegment = panel.nthSegment(4);
await duplicateSegment.click();
const duplicatedSegmentSvgStrokeAttribute = await getSvgAttribute({
viewportPageObject,
svgInnerElement: 'path',
attributeName: 'stroke',
});
await expect(duplicateSegment.rowDataColorHex).not.toHaveCSS(
'background-color',
THRESHOLD_CONTOUR_DEFAULT_CSS_RGB
);
expect(duplicatedSegmentSvgStrokeAttribute, 'Expected duplicated segment to have a different stroke color').not.toBe(
THRESHOLD_CONTOUR_DEFAULT_CSS_RGBA
);
});
+33
View File
@@ -60,6 +60,39 @@ export class DOMOverlayPageObject {
return new DicomTagBrowserPageObject(page);
},
get colorPicker() {
const locator = page.getByTestId('color-picker-dialog');
const hexInput = locator.getByLabel('hex');
const saveButton = locator.getByTestId('color-picker-save-btn');
const cancelButton = locator.getByTestId('color-picker-cancel-btn');
return {
locator,
hexInput,
saveButton,
cancelButton,
fillHex: async (hex: string) => {
await hexInput.fill(hex);
await hexInput.press('Enter');
},
save: async () => {
await saveButton.click();
},
cancel: async () => {
await cancelButton.click();
},
fillHexAndSave: async (hex: string) => {
await hexInput.fill(hex);
await hexInput.press('Enter');
await saveButton.click();
},
fillHexAndCancel: async (hex: string) => {
await hexInput.fill(hex);
await hexInput.press('Enter');
await cancelButton.click();
},
};
},
title: page.locator('[role="dialog"] h2'),
};
}
+23
View File
@@ -73,6 +73,26 @@ export class RightPanelPageObject {
await actionsButton.click();
await this.page.getByTestId('Duplicate').click();
},
openChangeColor: async () => {
await actionsButton.click();
await this.page.getByTestId('Change Color').click();
},
changeColor: async (hex: string) => {
await actionsButton.click();
await this.page.getByTestId('Change Color').click();
await this.DOMOverlayPageObject.dialog.colorPicker.fillHexAndSave(hex);
},
// This function assumes the user opens the change color dialog,
// but then cancels out of it instead of saving a new color.
cancelChangeColor: async (hex?: string) => {
await actionsButton.click();
await this.page.getByTestId('Change Color').click();
if (hex) {
await this.DOMOverlayPageObject.dialog.colorPicker.fillHexAndCancel(hex);
} else {
await this.DOMOverlayPageObject.dialog.colorPicker.cancel();
}
},
};
}
@@ -86,6 +106,9 @@ export class RightPanelPageObject {
get title() {
return row.getByTestId('data-row-title');
},
get rowDataColorHex() {
return row.getByTestId('data-row-colorhex');
},
click: async () => {
await row.getByTestId('data-row-title').click();
},