tests(Playwright): Full implementation of Page Object Models (POMs) to Playwright tests (#5608)
This commit is contained in:
parent
7b12dcf048
commit
d917e74e68
@ -12,8 +12,14 @@ export function UntrackSeriesModal({ hide, onConfirm, message }) {
|
||||
</div>
|
||||
<FooterAction className="mt-4">
|
||||
<FooterAction.Right>
|
||||
<FooterAction.Secondary onClick={hide}>Cancel</FooterAction.Secondary>
|
||||
<FooterAction.Secondary
|
||||
dataCY="untracked-series-modal-cancel-button"
|
||||
onClick={hide}
|
||||
>
|
||||
Cancel
|
||||
</FooterAction.Secondary>
|
||||
<FooterAction.Primary
|
||||
dataCY="untracked-series-modal-confirm-button"
|
||||
onClick={() => {
|
||||
onConfirm();
|
||||
hide();
|
||||
|
||||
@ -315,6 +315,7 @@ const DataRowComponent = React.forwardRef<HTMLDivElement, DataRowProps>(
|
||||
isSelected || !isVisible ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
|
||||
}`}
|
||||
aria-label={isVisible ? t('Hide') : t('Show')}
|
||||
dataCY="data-row-visibility-toggle"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
onToggleVisibility(e);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Button } from '../Button/Button';
|
||||
import { Button, ButtonProps } from '../Button/Button';
|
||||
import { cn } from '../../lib/utils';
|
||||
|
||||
interface FooterActionProps {
|
||||
@ -7,7 +7,7 @@ interface FooterActionProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
interface ActionProps extends FooterActionProps {
|
||||
interface ActionProps extends ButtonProps {
|
||||
onClick: () => void;
|
||||
className?: string;
|
||||
}
|
||||
@ -60,12 +60,18 @@ FooterAction.Right = ({ children }: FooterActionProps) => {
|
||||
FooterAction.Right.displayName = 'FooterAction.Right';
|
||||
|
||||
// Primary action: Solid button (default)
|
||||
FooterAction.Primary = ({ children, onClick, className = 'min-w-[80px]' }: ActionProps) => {
|
||||
FooterAction.Primary = ({
|
||||
children,
|
||||
onClick,
|
||||
className = 'min-w-[80px]',
|
||||
...rest
|
||||
}: ActionProps) => {
|
||||
return (
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={onClick}
|
||||
className={className}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
@ -74,12 +80,18 @@ FooterAction.Primary = ({ children, onClick, className = 'min-w-[80px]' }: Actio
|
||||
FooterAction.Primary.displayName = 'FooterAction.Primary';
|
||||
|
||||
// Secondary action: Ghost button
|
||||
FooterAction.Secondary = ({ children, onClick, className = 'min-w-[80px]' }: ActionProps) => {
|
||||
FooterAction.Secondary = ({
|
||||
children,
|
||||
onClick,
|
||||
className = 'min-w-[80px]',
|
||||
...rest
|
||||
}: ActionProps) => {
|
||||
return (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={onClick}
|
||||
className={className}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
@ -88,12 +100,13 @@ FooterAction.Secondary = ({ children, onClick, className = 'min-w-[80px]' }: Act
|
||||
FooterAction.Secondary.displayName = 'FooterAction.Secondary';
|
||||
|
||||
// Tertiary action: Ghost button with different styling
|
||||
FooterAction.Auxiliary = ({ children, onClick, className }: ActionProps) => {
|
||||
FooterAction.Auxiliary = ({ children, onClick, className, ...rest }: ActionProps) => {
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={onClick}
|
||||
className={className}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
|
||||
@ -88,7 +88,12 @@ const Thumbnail = ({
|
||||
loadingProgress && loadingProgress < 1 && 'bg-primary/25'
|
||||
)}
|
||||
></div>
|
||||
<div className="text-[11px] font-semibold text-white">{modality}</div>
|
||||
<div
|
||||
className="text-[11px] font-semibold text-white"
|
||||
data-cy="series-modality-label"
|
||||
>
|
||||
{modality}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* top right */}
|
||||
@ -139,7 +144,10 @@ const Thumbnail = ({
|
||||
<Tooltip>
|
||||
<TooltipContent>{description}</TooltipContent>
|
||||
<TooltipTrigger>
|
||||
<div className="min-h-[18px] w-[128px] overflow-hidden text-ellipsis whitespace-nowrap pb-0.5 pl-1 text-left text-[12px] font-normal leading-4 text-white">
|
||||
<div
|
||||
className="min-h-[18px] w-[128px] overflow-hidden text-ellipsis whitespace-nowrap pb-0.5 pl-1 text-left text-[12px] font-normal leading-4 text-white"
|
||||
data-cy="series-description-label"
|
||||
>
|
||||
{description}
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
@ -180,11 +188,19 @@ const Thumbnail = ({
|
||||
></div>
|
||||
<div className="flex h-full w-[calc(100%-12px)] flex-col justify-start">
|
||||
<div className="flex items-center gap-[7px]">
|
||||
<div className="text-[13px] font-semibold text-white">{modality}</div>
|
||||
<div
|
||||
className="text-[13px] font-semibold text-white"
|
||||
data-cy="series-modality-label"
|
||||
>
|
||||
{modality}
|
||||
</div>
|
||||
<Tooltip>
|
||||
<TooltipContent>{description}</TooltipContent>
|
||||
<TooltipTrigger className="w-full overflow-hidden">
|
||||
<div className="max-w-[160px] overflow-hidden overflow-ellipsis whitespace-nowrap text-left text-[13px] font-normal text-white">
|
||||
<div
|
||||
className="max-w-[160px] overflow-hidden overflow-ellipsis whitespace-nowrap text-left text-[13px] font-normal text-white"
|
||||
data-cy="series-description-label"
|
||||
>
|
||||
{description}
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
|
||||
@ -8,6 +8,7 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should display the angle tool', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
@ -17,6 +18,6 @@ test('should display the angle tool', async ({
|
||||
{ x: 450, y: 250 },
|
||||
{ x: 550, y: 300 },
|
||||
]);
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
await checkForScreenshot(page, page, screenShotPaths.angle.angleDisplayedCorrectly);
|
||||
});
|
||||
|
||||
@ -8,10 +8,12 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should display the arrow tool and allow free-form text to be entered', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
mainToolbarPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await page.getByTestId('trackedMeasurements-btn').click();
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
|
||||
await mainToolbarPageObject.measurementTools.arrowAnnotate.click();
|
||||
|
||||
@ -20,10 +22,11 @@ test('should display the arrow tool and allow free-form text to be entered', asy
|
||||
{ x: 344, y: 232 },
|
||||
]);
|
||||
|
||||
await page.getByTestId('dialog-input').fill('Ringo Starr was the drummer for The Beatles');
|
||||
await page.getByTestId('input-dialog-save-button').click();
|
||||
await DOMOverlayPageObject.dialog.input.fillAndSave(
|
||||
'Ringo Starr was the drummer for The Beatles'
|
||||
);
|
||||
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
@ -37,8 +40,7 @@ test('should display the arrow tool and allow free-form text to be entered', asy
|
||||
|
||||
await viewportPageObject.active.doubleClickAt({ x: 164, y: 234 });
|
||||
|
||||
await page.getByTestId('dialog-input').fill('Neil Peart was the drummer for Rush');
|
||||
await page.getByTestId('input-dialog-save-button').click();
|
||||
await DOMOverlayPageObject.dialog.input.fillAndSave('Neil Peart was the drummer for Rush');
|
||||
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
@ -50,11 +52,9 @@ test('should display the arrow tool and allow free-form text to be entered', asy
|
||||
|
||||
// Now edit the label and the text should not change.
|
||||
|
||||
await page.getByTestId('actionsMenuTrigger').click();
|
||||
await page.getByTestId('Rename').click();
|
||||
|
||||
await page.getByTestId('dialog-input').fill('Drummer annotation arrow');
|
||||
await page.getByTestId('input-dialog-save-button').click();
|
||||
await rightPanelPageObject.measurementsPanel.panel
|
||||
.nthMeasurement(0)
|
||||
.actions.rename('Drummer annotation arrow');
|
||||
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should display the bidirectional tool', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
@ -16,7 +17,7 @@ test('should display the bidirectional tool', async ({
|
||||
{ x: 405, y: 277 },
|
||||
{ x: 515, y: 339 },
|
||||
]);
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
await checkForScreenshot(
|
||||
page,
|
||||
page,
|
||||
|
||||
@ -8,6 +8,7 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should display the circle tool', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
@ -16,6 +17,6 @@ test('should display the circle tool', async ({
|
||||
{ x: 480, y: 205 },
|
||||
{ x: 488, y: 247 },
|
||||
]);
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
await checkForScreenshot(page, page, screenShotPaths.circle.circleDisplayedCorrectly);
|
||||
});
|
||||
|
||||
@ -8,6 +8,7 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should display the cobb angle tool', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
@ -18,6 +19,6 @@ test('should display the cobb angle tool', async ({
|
||||
{ x: 527, y: 293 },
|
||||
{ x: 625, y: 291 },
|
||||
]);
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
await checkForScreenshot(page, page, screenShotPaths.cobbangle.cobbangleDisplayedCorrectly);
|
||||
});
|
||||
|
||||
@ -8,6 +8,7 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should the context menu completely on screen and is not clipped for a point near the bottom edge of the screen', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
@ -17,7 +18,7 @@ test('should the context menu completely on screen and is not clipped for a poin
|
||||
{ x: 0.55, y: 0.98 },
|
||||
]);
|
||||
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.contextMenu.preContextMenuNearBottomEdge);
|
||||
|
||||
|
||||
@ -5,17 +5,20 @@ const studyInstanceUID = '1.2.840.113619.2.290.3.3767434740.226.1600859119.501';
|
||||
|
||||
test('should not allow contours to be edited in basic viewer mode', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
const mode = 'viewer';
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
await rightPanelPageObject.toggle();
|
||||
await leftPanelPageObject.loadSeriesByModality('RTSTRUCT');
|
||||
// Wait for the segmentation to be loaded.
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
// Wait for the segmentation to hydrate.
|
||||
await page.waitForTimeout(5000);
|
||||
@ -46,13 +49,16 @@ test('should not allow contours to be edited in basic viewer mode', async ({
|
||||
|
||||
test('should not allow contours to be edited when panelSegmentation.disableEditing is true', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
const mode = 'segmentation';
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
await rightPanelPageObject.toggle();
|
||||
await leftPanelPageObject.loadSeriesByModality('RTSTRUCT');
|
||||
// Wait for the segmentation to be loaded.
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
@ -66,7 +72,7 @@ test('should not allow contours to be edited when panelSegmentation.disableEditi
|
||||
);
|
||||
});
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
// Wait for the segmentation to hydrate.
|
||||
await page.waitForTimeout(5000);
|
||||
@ -97,13 +103,16 @@ test('should not allow contours to be edited when panelSegmentation.disableEditi
|
||||
|
||||
test('should allow contours to be edited when panelSegmentation.disableEditing is false', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
const mode = 'segmentation';
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
await rightPanelPageObject.toggle();
|
||||
await leftPanelPageObject.loadSeriesByModality('RTSTRUCT');
|
||||
// Wait for the segmentation to be loaded.
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
@ -117,7 +126,7 @@ test('should allow contours to be edited when panelSegmentation.disableEditing i
|
||||
);
|
||||
});
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
// Wait for the segmentation to hydrate.
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
@ -1,44 +1,11 @@
|
||||
import { Page } from '@playwright/test';
|
||||
import {
|
||||
checkForScreenshot,
|
||||
getMousePosition,
|
||||
initializeMousePositionTracker,
|
||||
screenShotPaths,
|
||||
test,
|
||||
visitStudy,
|
||||
} from './utils/index.js';
|
||||
|
||||
const rotateCrosshairs = async (page: Page, id: string, lineNumber: number) => {
|
||||
const locator = page.locator(id).locator('line').nth(lineNumber);
|
||||
await locator.click({ force: true });
|
||||
await locator.hover({ force: true });
|
||||
const circleLocator = page.locator(id).locator('circle').nth(1);
|
||||
await circleLocator.hover({ force: true });
|
||||
await page.mouse.down();
|
||||
const position = await getMousePosition(page);
|
||||
await page.mouse.move(position.x, position.y + 100);
|
||||
await page.mouse.up();
|
||||
};
|
||||
|
||||
const increaseSlabThickness = async (page: Page, id: string, lineNumber: number, axis: string) => {
|
||||
const locator = page.locator(id).locator('line').nth(lineNumber);
|
||||
await locator.click({ force: true });
|
||||
await locator.hover({ force: true });
|
||||
const circleLocator = page.locator(id).locator('rect').first();
|
||||
await circleLocator.hover({ force: true });
|
||||
await page.mouse.down();
|
||||
const position = await getMousePosition(page);
|
||||
switch (axis) {
|
||||
case 'x':
|
||||
await page.mouse.move(position.x + 100, position.y);
|
||||
break;
|
||||
case 'y':
|
||||
await page.mouse.move(position.x, position.y + 100);
|
||||
break;
|
||||
}
|
||||
await page.mouse.up();
|
||||
};
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.1706.8374.643249677828306008300337414785';
|
||||
const mode = 'viewer';
|
||||
@ -49,7 +16,7 @@ test.beforeEach(async ({ page }) => {
|
||||
test.describe('Crosshairs Test', async () => {
|
||||
test('should render the crosshairs correctly.', async ({ page, mainToolbarPageObject }) => {
|
||||
await mainToolbarPageObject.layoutSelection.MPR.click();
|
||||
await page.getByTestId('Crosshairs').click();
|
||||
await mainToolbarPageObject.crosshairs.click();
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.crosshairs.crosshairsRendered);
|
||||
});
|
||||
@ -57,13 +24,14 @@ test.describe('Crosshairs Test', async () => {
|
||||
test('should allow the user to rotate the crosshairs', async ({
|
||||
page,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await mainToolbarPageObject.layoutSelection.MPR.click();
|
||||
await page.getByTestId('Crosshairs').click();
|
||||
await mainToolbarPageObject.crosshairs.click();
|
||||
|
||||
await rotateCrosshairs(page, '#svg-layer-mpr-axial', 3);
|
||||
await rotateCrosshairs(page, '#svg-layer-mpr-sagittal', 0);
|
||||
await rotateCrosshairs(page, '#svg-layer-mpr-coronal', 0);
|
||||
await viewportPageObject.crosshairs.axial.rotate();
|
||||
await viewportPageObject.crosshairs.sagittal.rotate();
|
||||
await viewportPageObject.crosshairs.coronal.rotate();
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.crosshairs.crosshairsRotated);
|
||||
});
|
||||
@ -71,13 +39,14 @@ test.describe('Crosshairs Test', async () => {
|
||||
test('should allow the user to adjust the slab thickness', async ({
|
||||
page,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await mainToolbarPageObject.layoutSelection.MPR.click();
|
||||
await page.getByTestId('Crosshairs').click();
|
||||
await mainToolbarPageObject.crosshairs.click();
|
||||
|
||||
await increaseSlabThickness(page, '#svg-layer-mpr-axial', 0, 'x');
|
||||
await increaseSlabThickness(page, '#svg-layer-mpr-sagittal', 2, 'x');
|
||||
await increaseSlabThickness(page, '#svg-layer-mpr-coronal', 0, 'y');
|
||||
await viewportPageObject.crosshairs.axial.increase();
|
||||
await viewportPageObject.crosshairs.sagittal.increase();
|
||||
await viewportPageObject.crosshairs.coronal.increase();
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.crosshairs.crosshairsSlabThickness);
|
||||
});
|
||||
@ -85,15 +54,16 @@ test.describe('Crosshairs Test', async () => {
|
||||
test('should reset the crosshairs to the initial position when reset is clicked', async ({
|
||||
page,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await mainToolbarPageObject.layoutSelection.MPR.click();
|
||||
await page.getByTestId('Crosshairs').click();
|
||||
await mainToolbarPageObject.crosshairs.click();
|
||||
|
||||
await rotateCrosshairs(page, '#svg-layer-mpr-axial', 3);
|
||||
await rotateCrosshairs(page, '#svg-layer-mpr-sagittal', 0);
|
||||
await rotateCrosshairs(page, '#svg-layer-mpr-coronal', 0);
|
||||
await viewportPageObject.crosshairs.axial.rotate();
|
||||
await viewportPageObject.crosshairs.sagittal.rotate();
|
||||
await viewportPageObject.crosshairs.coronal.rotate();
|
||||
|
||||
await page.getByTestId('MoreTools-split-button-primary').click();
|
||||
await mainToolbarPageObject.moreTools.reset.click();
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.crosshairs.crosshairsResetToolbar);
|
||||
});
|
||||
@ -101,15 +71,17 @@ test.describe('Crosshairs Test', async () => {
|
||||
test('should reset the crosshairs when a new displayset is loaded', async ({
|
||||
page,
|
||||
mainToolbarPageObject,
|
||||
leftPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await mainToolbarPageObject.layoutSelection.MPR.click();
|
||||
await page.getByTestId('Crosshairs').click();
|
||||
await mainToolbarPageObject.crosshairs.click();
|
||||
|
||||
await rotateCrosshairs(page, '#svg-layer-mpr-axial', 0);
|
||||
await rotateCrosshairs(page, '#svg-layer-mpr-sagittal', 0);
|
||||
await rotateCrosshairs(page, '#svg-layer-mpr-coronal', 3);
|
||||
await viewportPageObject.crosshairs.axial.rotate();
|
||||
await viewportPageObject.crosshairs.sagittal.rotate();
|
||||
await viewportPageObject.crosshairs.coronal.rotate();
|
||||
|
||||
await page.getByTestId('study-browser-thumbnail').nth(1).dblclick();
|
||||
await leftPanelPageObject.loadSeriesByDescription('Recon 3: LIVER 3 PHASE (AP)');
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.crosshairs.crosshairsNewDisplayset);
|
||||
});
|
||||
|
||||
@ -10,10 +10,9 @@ test('should display added, selected and removed segmentation promptly', async (
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
|
||||
// Add a segmentation overlay and ensure the overlay menu reflects this change.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await page.getByTestId('AddSegmentationDataOverlay-default').click();
|
||||
await page.getByText('SELECT A SEGMENTATION').click();
|
||||
await page.getByTestId('2d-tta_nnU-Net_Segmentation').click();
|
||||
const dataOverlayPageObject = viewportPageObject.getById('default').overlayMenu.dataOverlay;
|
||||
await dataOverlayPageObject.toggle();
|
||||
await dataOverlayPageObject.addSegmentation('2d-tta_nnU-Net_Segmentation');
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
@ -24,7 +23,7 @@ test('should display added, selected and removed segmentation promptly', async (
|
||||
});
|
||||
|
||||
// Hide the overlay menu.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await dataOverlayPageObject.toggle();
|
||||
|
||||
// navigate to the 51st image and ensure the correct overlay is displayed
|
||||
await press({ page, key: 'ArrowDown', nTimes: 50 });
|
||||
@ -37,11 +36,10 @@ test('should display added, selected and removed segmentation promptly', async (
|
||||
});
|
||||
|
||||
// Show the overlay menu.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await dataOverlayPageObject.toggle();
|
||||
|
||||
// Change the segmentation overlay to a different one and ensure the overlay menu reflects this change.
|
||||
await page.getByTestId('overlay-ds-select-value-2D-TTA_NNU-NET_SEGMENTATION').click();
|
||||
await page.getByTestId('Segmentation-SEG').click();
|
||||
await dataOverlayPageObject.changeSegmentation('2d-tta_nnU-Net_Segmentation', 'Segmentation');
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
@ -51,7 +49,7 @@ test('should display added, selected and removed segmentation promptly', async (
|
||||
});
|
||||
|
||||
// Hide the overlay menu.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await dataOverlayPageObject.toggle();
|
||||
|
||||
// navigate to the 51st image and ensure the correct overlay is displayed
|
||||
await press({ page, key: 'ArrowDown', nTimes: 50 });
|
||||
@ -64,11 +62,10 @@ test('should display added, selected and removed segmentation promptly', async (
|
||||
});
|
||||
|
||||
// Show the overlay menu.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await dataOverlayPageObject.toggle();
|
||||
|
||||
// Remove the segmentation overlay and ensure the overlay menu reflects this change.
|
||||
await page.getByTestId('overlay-ds-more-button-SEGMENTATION').click();
|
||||
await page.getByTestId('overlay-ds-remove-button-SEGMENTATION').click();
|
||||
await dataOverlayPageObject.remove('SEGMENTATION');
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
@ -78,7 +75,7 @@ test('should display added, selected and removed segmentation promptly', async (
|
||||
});
|
||||
|
||||
// Hide the overlay menu.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await dataOverlayPageObject.toggle();
|
||||
|
||||
// navigate to the 51st image and ensure no overlay is displayed
|
||||
await press({ page, key: 'ArrowDown', nTimes: 50 });
|
||||
|
||||
@ -8,6 +8,7 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should display the ellipse tool', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
@ -16,6 +17,6 @@ test('should display the ellipse tool', async ({
|
||||
{ x: 446, y: 245 },
|
||||
{ x: 508, y: 281 },
|
||||
]);
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
await checkForScreenshot(page, page, screenShotPaths.ellipse.ellipseDisplayedCorrectly);
|
||||
});
|
||||
|
||||
@ -8,15 +8,16 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should hydrate in MPR correctly', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
mainToolbarPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('trackedMeasurements-btn').click();
|
||||
await rightPanelPageObject.toggle();
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
|
||||
// get the div that has Body 4.0 Lung I and double click it
|
||||
|
||||
await page.locator(':text("S:7")').first().dblclick();
|
||||
await leftPanelPageObject.loadSeriesByDescription('Body 4.0 CE', 1);
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
@ -47,10 +48,9 @@ test('should hydrate in MPR correctly', async ({
|
||||
{ x: 515, y: 339 },
|
||||
]);
|
||||
|
||||
// wait 2 seconds
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
|
||||
// scroll away
|
||||
await checkForScreenshot(page, page, screenShotPaths.jumpToMeasurementMPR.initialDraw);
|
||||
@ -75,34 +75,32 @@ test('should hydrate in MPR correctly', async ({
|
||||
}
|
||||
});
|
||||
|
||||
// wait 5 seconds
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.jumpToMeasurementMPR.scrollAway);
|
||||
|
||||
await page.getByTestId('data-row').first().click();
|
||||
await rightPanelPageObject.measurementsPanel.panel.nthMeasurement(0).click();
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.jumpToMeasurementMPR.jumpToMeasurementStack);
|
||||
|
||||
await mainToolbarPageObject.layoutSelection.MPR.click();
|
||||
|
||||
// wait 5 seconds
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
// jump in viewport again
|
||||
await page.getByTestId('data-row').first().click();
|
||||
await rightPanelPageObject.measurementsPanel.panel.nthMeasurement(0).click();
|
||||
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.jumpToMeasurementMPR.jumpInMPR);
|
||||
|
||||
await page.locator(':text("S:3")').first().dblclick();
|
||||
await leftPanelPageObject.loadSeriesByDescription('Lung 3.0 CE');
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.jumpToMeasurementMPR.changeSeriesInMPR);
|
||||
|
||||
await page.getByTestId('data-row').first().click();
|
||||
await rightPanelPageObject.measurementsPanel.panel.nthMeasurement(0).click();
|
||||
|
||||
await checkForScreenshot(
|
||||
page,
|
||||
|
||||
@ -9,6 +9,9 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should prevent editing of label map segmentations when panelSegmentation.disableEditing is true', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
// disable editing of segmentations via the customization service
|
||||
@ -20,13 +23,13 @@ test('should prevent editing of label map segmentations when panelSegmentation.d
|
||||
}
|
||||
);
|
||||
});
|
||||
await page.getByTestId('panelSegmentationWithToolsLabelMap-btn').click();
|
||||
await rightPanelPageObject.labelMapSegmentationPanel.select();
|
||||
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
await leftPanelPageObject.loadSeriesByModality('SEG');
|
||||
// Wait for the segmentation to be loaded.
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
// Wait for the segmentation to hydrate.
|
||||
await page.waitForTimeout(5000);
|
||||
@ -37,10 +40,10 @@ test('should prevent editing of label map segmentations when panelSegmentation.d
|
||||
await checkForScreenshot(page, page, screenShotPaths.labelMapSegLocking.globalLockedSegPreEdit);
|
||||
|
||||
// Attempt to erase the segmentations.
|
||||
await page.getByTestId('Eraser-btn').click();
|
||||
await rightPanelPageObject.labelMapSegmentationPanel.tools.eraser.click();
|
||||
|
||||
// Use the largest eraser radius to help ensure the entire image is erased.
|
||||
await page.locator(`css=div[data-cy="eraser-radius"] input`).fill('1000');
|
||||
await rightPanelPageObject.labelMapSegmentationPanel.tools.eraser.setRadius(1000);
|
||||
|
||||
// Attempt to erase the segmentations by dragging the eraser tool across the image several times.
|
||||
await viewportPageObject.getById('default').normalizedDragAt({
|
||||
@ -61,6 +64,9 @@ test('should prevent editing of label map segmentations when panelSegmentation.d
|
||||
|
||||
test('should allow editing of label map segmentations when panelSegmentation.disableEditing is false', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
// disable editing of segmentations via the customization service
|
||||
@ -73,13 +79,13 @@ test('should allow editing of label map segmentations when panelSegmentation.dis
|
||||
);
|
||||
});
|
||||
|
||||
await page.getByTestId('panelSegmentationWithToolsLabelMap-btn').click();
|
||||
await rightPanelPageObject.labelMapSegmentationPanel.select();
|
||||
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
await leftPanelPageObject.loadSeriesByModality('SEG');
|
||||
// Wait for the segmentation to be loaded.
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
// Wait for the segmentation to hydrate.
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
@ -89,10 +95,10 @@ test('should allow editing of label map segmentations when panelSegmentation.dis
|
||||
await checkForScreenshot(page, page, screenShotPaths.labelMapSegLocking.globalUnlockedSegPreEdit);
|
||||
|
||||
// Attempt to erase the segmentations.
|
||||
await page.getByTestId('Eraser-btn').click();
|
||||
await rightPanelPageObject.labelMapSegmentationPanel.tools.eraser.click();
|
||||
|
||||
// Use the largest eraser radius to help ensure the eraser passes over the entire image.
|
||||
await page.locator(`css=div[data-cy="eraser-radius"] input`).fill('1000');
|
||||
await rightPanelPageObject.labelMapSegmentationPanel.tools.eraser.setRadius(1000);
|
||||
|
||||
// Attempt to erase the segmentations by dragging the eraser tool across the image several times.
|
||||
await viewportPageObject.getById('default').normalizedDragAt({
|
||||
|
||||
@ -8,6 +8,7 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should display the length tool', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
@ -16,6 +17,6 @@ test('should display the length tool', async ({
|
||||
{ x: 364, y: 234 },
|
||||
{ x: 544, y: 232 },
|
||||
]);
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
await checkForScreenshot(page, page, screenShotPaths.length.lengthDisplayedCorrectly);
|
||||
});
|
||||
|
||||
@ -8,6 +8,7 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should display the livewire tool', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
@ -20,6 +21,6 @@ test('should display the livewire tool', async ({
|
||||
{ x: 482, y: 493 },
|
||||
{ x: 383, y: 461 },
|
||||
]);
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
await checkForScreenshot(page, page, screenShotPaths.livewire.livewireDisplayedCorrectly);
|
||||
});
|
||||
|
||||
@ -25,16 +25,15 @@ test('should launch MPR with unhydrated RTSTRUCT chosen from the data overlay me
|
||||
|
||||
// Hover over the middle/sagittal viewport so that the data overlay menu is available.
|
||||
await viewportPageObject.getById('mpr-sagittal').pane.hover();
|
||||
await viewportPageObject.getById('mpr-sagittal').overlayMenu.dataOverlay.click();
|
||||
await page.getByTestId('AddSegmentationDataOverlay-mpr-sagittal').click();
|
||||
await page.getByText('SELECT A SEGMENTATION').click();
|
||||
await page.getByTestId('ARIA RadOnc Structure Sets').click();
|
||||
const dataOverlayPageObject = viewportPageObject.getById('mpr-sagittal').overlayMenu.dataOverlay;
|
||||
await dataOverlayPageObject.toggle('mpr-sagittal');
|
||||
await dataOverlayPageObject.addSegmentation('ARIA RadOnc Structure Sets', 'mpr-sagittal');
|
||||
|
||||
// Hide the overlay menu.
|
||||
await viewportPageObject.getById('mpr-sagittal').overlayMenu.dataOverlay.click();
|
||||
await dataOverlayPageObject.toggle('mpr-sagittal');
|
||||
|
||||
// Adding an overlay should not show the LOAD button.
|
||||
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
|
||||
await assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
|
||||
|
||||
// Wait 5 seconds for RT to load. This is necessary in particular when screen shots are added or replaced.
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
@ -9,10 +9,11 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should launch MPR with unhydrated SEG chosen from the data overlay menu', async ({
|
||||
page,
|
||||
rightPanelPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await rightPanelPageObject.toggle();
|
||||
|
||||
await mainToolbarPageObject.layoutSelection.MPR.click();
|
||||
|
||||
@ -25,17 +26,16 @@ test('should launch MPR with unhydrated SEG chosen from the data overlay menu',
|
||||
);
|
||||
|
||||
// Hover over the middle/sagittal viewport so that the data overlay menu is available.
|
||||
await viewportPageObject.getById('mpr-sagittal').pane.hover();
|
||||
await viewportPageObject.getById('mpr-sagittal').overlayMenu.dataOverlay.click();
|
||||
await page.getByTestId('AddSegmentationDataOverlay-mpr-sagittal').click();
|
||||
await page.getByText('SELECT A SEGMENTATION').click();
|
||||
await page.getByTestId('Segmentation').click();
|
||||
await viewportPageObject.getById('mpr-axial').pane.hover();
|
||||
const dataOverlayPageObject = viewportPageObject.getById('mpr-axial').overlayMenu.dataOverlay;
|
||||
await dataOverlayPageObject.toggle('mpr-axial');
|
||||
await dataOverlayPageObject.addSegmentation('Segmentation', 'mpr-axial');
|
||||
|
||||
// Hide the overlay menu.
|
||||
await viewportPageObject.getById('mpr-sagittal').overlayMenu.dataOverlay.click();
|
||||
await dataOverlayPageObject.toggle('mpr-axial');
|
||||
|
||||
// Adding an overlay should not show the LOAD button.
|
||||
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
|
||||
await assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
|
||||
@ -7,136 +7,114 @@ test.beforeEach(async ({ page }) => {
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('checks if Measurements right panel can be hidden/displayed', async ({ page }) => {
|
||||
const measurementsPanel = page.getByTestId('trackedMeasurements-panel').last();
|
||||
const rightCollapseBtn = page.getByTestId('side-panel-header-right');
|
||||
|
||||
// No data-cy exists in this panel, using Segmentation header button
|
||||
const segmentationPanel = page.getByRole('button', { name: 'Segmentations' });
|
||||
const measurementsBtn = page.getByTestId('trackedMeasurements-btn');
|
||||
const segmentationsBtn = page.getByTestId('panelSegmentation-btn');
|
||||
test('checks if Measurements right panel can be hidden/displayed', async ({
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
const measurementsPanel = rightPanelPageObject.measurementsPanel.panel.locator;
|
||||
const segmentationPanel = rightPanelPageObject.labelMapSegmentationPanel.panel.locator;
|
||||
|
||||
// Assert the measurements panel and segmentation panel is hidden initially
|
||||
await expect(measurementsPanel).toBeHidden();
|
||||
await expect(segmentationPanel).toBeHidden();
|
||||
|
||||
// Click the collapse button to show the panel container
|
||||
await rightCollapseBtn.click({ force: true });
|
||||
await rightPanelPageObject.toggle();
|
||||
|
||||
// The segmentation panel should now be visible by default
|
||||
await expect(segmentationPanel).toBeVisible();
|
||||
|
||||
// Switch to the measurements tab
|
||||
await measurementsBtn.click();
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
|
||||
// Assert the measurements panel is visible, and segmentation invisible
|
||||
await expect(measurementsPanel).toBeVisible();
|
||||
await expect(segmentationPanel).toBeHidden();
|
||||
|
||||
// Switch back to segmentations panel
|
||||
await segmentationsBtn.click();
|
||||
await rightPanelPageObject.noToolsSegmentationPanel.select();
|
||||
|
||||
// Assert the segmentations panel is now visible, measurements panel invisible
|
||||
await expect(segmentationPanel).toBeVisible();
|
||||
await expect(measurementsPanel).toBeHidden();
|
||||
|
||||
// Click the collapse button to hide the panel
|
||||
await rightCollapseBtn.click();
|
||||
await rightPanelPageObject.toggle();
|
||||
|
||||
// Assert the measurements and segmentation panel is now hidden
|
||||
await expect(measurementsPanel).toBeHidden();
|
||||
await expect(segmentationPanel).toBeHidden();
|
||||
});
|
||||
|
||||
test('checks if measurement item can be relabeled under Measurements panel', async ({ page }) => {
|
||||
test('checks if measurement item can be relabeled under Measurements panel', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
const relabelText = 'Relabel 12345';
|
||||
const measurementsBtn = page.getByTestId('trackedMeasurements-btn');
|
||||
|
||||
// Add measurement
|
||||
await addLengthMeasurement(page);
|
||||
|
||||
const viewportNotification = page.getByTestId('viewport-notification');
|
||||
const viewportNotification = DOMOverlayPageObject.viewport.measurementTracking.locator;
|
||||
await expect(viewportNotification).toBeVisible();
|
||||
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
|
||||
// Open measurement panel confirm default empty
|
||||
await measurementsBtn.click();
|
||||
const measurementRow = page.getByTestId('data-row').first();
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
const measurementRow = rightPanelPageObject.measurementsPanel.panel.nthMeasurement(0).locator;
|
||||
await expect(measurementRow).toContainText('(empty)');
|
||||
|
||||
// Expand and click rename
|
||||
const actionsButton = measurementRow.getByRole('button', { name: 'Actions' });
|
||||
await actionsButton.click();
|
||||
|
||||
const renameButton = page.getByRole('menuitem', { name: 'Rename' });
|
||||
await renameButton.click();
|
||||
|
||||
// Interact with dialog
|
||||
const renameDialog = page.getByRole('dialog', { name: 'Edit Measurement Label' });
|
||||
const renameInput = renameDialog.getByPlaceholder('Enter new label');
|
||||
const saveButton = renameDialog.getByRole('button', { name: 'Save' });
|
||||
|
||||
await expect(renameDialog).toBeVisible();
|
||||
await expect(renameInput).toBeVisible();
|
||||
await expect(saveButton).toBeEnabled();
|
||||
|
||||
await renameInput.fill(relabelText);
|
||||
await saveButton.click();
|
||||
await rightPanelPageObject.measurementsPanel.panel.nthMeasurement(0).actions.rename(relabelText);
|
||||
|
||||
// Check dialog closed and renamed
|
||||
await expect(renameDialog).toBeHidden();
|
||||
await expect(DOMOverlayPageObject.dialog.input.locator).toBeHidden();
|
||||
await expect(measurementRow).toContainText(relabelText);
|
||||
});
|
||||
|
||||
test('checks if measurement item can be relabeled through the context menu on the viewport', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
const relabelText = 'Relabel 12345';
|
||||
const measurementsBtn = page.getByTestId('trackedMeasurements-btn');
|
||||
|
||||
// Add measurement
|
||||
await addLengthMeasurement(page);
|
||||
|
||||
const viewportNotification = page.getByTestId('viewport-notification');
|
||||
const viewportNotification = DOMOverlayPageObject.viewport.measurementTracking.locator;
|
||||
await expect(viewportNotification).toBeVisible();
|
||||
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
|
||||
// Open measurement panel confirm default empty
|
||||
await measurementsBtn.click();
|
||||
const measurementRow = page.getByTestId('data-row').first();
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
const measurementRow = rightPanelPageObject.measurementsPanel.panel.nthMeasurement(0).locator;
|
||||
await expect(measurementRow).toContainText('(empty)');
|
||||
|
||||
// Right click and click rename
|
||||
await page.waitForTimeout(200); // small delay for context menu
|
||||
const measurementAnnotation = page.locator('g[data-annotation-uid]').first();
|
||||
await measurementAnnotation.click({ button: 'right', force: true });
|
||||
await viewportPageObject.active.nthAnnotation(0).contextMenu.open();
|
||||
await page.waitForTimeout(200); // small delay for context menu
|
||||
|
||||
const addLabelButton = page.getByTestId('context-menu-item').filter({ hasText: 'Add Label' });
|
||||
await expect(addLabelButton).toBeVisible();
|
||||
const addLabelButton = DOMOverlayPageObject.viewport.annotationContextMenu.addLabel;
|
||||
await expect(addLabelButton.locator).toBeVisible();
|
||||
await addLabelButton.click();
|
||||
|
||||
// Interact with dialog
|
||||
const renameDialog = page.getByRole('dialog', { name: 'Edit Measurement Label' });
|
||||
const renameInput = renameDialog.getByPlaceholder('Enter new label');
|
||||
const saveButton = renameDialog.getByRole('button', { name: 'Save' });
|
||||
|
||||
await expect(renameDialog).toBeVisible();
|
||||
await expect(renameInput).toBeVisible();
|
||||
await expect(saveButton).toBeEnabled();
|
||||
|
||||
await renameInput.fill(relabelText);
|
||||
await saveButton.click();
|
||||
await expect(DOMOverlayPageObject.dialog.title).toHaveText('Edit Measurement Label');
|
||||
await DOMOverlayPageObject.dialog.input.fillAndSave(relabelText);
|
||||
|
||||
// Check dialog closed and renamed
|
||||
await expect(renameDialog).toBeHidden();
|
||||
await expect(DOMOverlayPageObject.dialog.title).toBeHidden();
|
||||
await expect(measurementRow).toContainText(relabelText);
|
||||
});
|
||||
|
||||
test('checks if image would jump when clicked on a measurement item', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
const viewportInfoBottomRight = viewportPageObject.active.overlayText.bottomRight;
|
||||
@ -145,9 +123,8 @@ test('checks if image would jump when clicked on a measurement item', async ({
|
||||
await expect(viewportInfoBottomRight).toContainText('1/', { timeout: 10000 });
|
||||
await addLengthMeasurement(page);
|
||||
|
||||
const viewportNotification = page.getByTestId('viewport-notification');
|
||||
await expect(viewportNotification).toBeVisible();
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await expect(DOMOverlayPageObject.viewport.measurementTracking.locator).toBeVisible();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
|
||||
// Change to slice 2
|
||||
await scrollVolumeViewport(page, 'default', 1);
|
||||
@ -157,90 +134,79 @@ test('checks if image would jump when clicked on a measurement item', async ({
|
||||
await addLengthMeasurement(page);
|
||||
|
||||
// Open measurement panel and click first measurement
|
||||
const measurementsBtn = page.getByTestId('trackedMeasurements-btn');
|
||||
await measurementsBtn.click();
|
||||
const measurementRow = page.getByTestId('data-row').first();
|
||||
await measurementRow.click();
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
await rightPanelPageObject.measurementsPanel.panel.nthMeasurement(0).click();
|
||||
|
||||
// Confirm jumped to slice 1
|
||||
await expect(viewportInfoBottomRight).toContainText('1/', { timeout: 10000 });
|
||||
await expect(viewportInfoBottomRight).not.toContainText('2/');
|
||||
});
|
||||
|
||||
test('checks if measurement item can be deleted under Measurements panel', async ({ page }) => {
|
||||
const measurementsBtn = page.getByTestId('trackedMeasurements-btn');
|
||||
|
||||
test('checks if measurement item can be deleted under Measurements panel', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
// Add 3 measurements
|
||||
await addLengthMeasurement(page);
|
||||
|
||||
const viewportNotification = page.getByTestId('viewport-notification');
|
||||
await expect(viewportNotification).toBeVisible();
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await expect(DOMOverlayPageObject.viewport.measurementTracking.locator).toBeVisible();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
|
||||
await addLengthMeasurement(page, { firstClick: [170, 100], secondClick: [150, 170] });
|
||||
await addLengthMeasurement(page, { firstClick: [190, 100], secondClick: [170, 170] });
|
||||
|
||||
// Open measurement panel, confirm 3 measurements
|
||||
await measurementsBtn.click();
|
||||
await expect(page.getByTestId('data-row')).toHaveCount(3);
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
expect(await rightPanelPageObject.measurementsPanel.panel.getMeasurementCount()).toBe(3);
|
||||
|
||||
// Delete from measurement
|
||||
const measurementRow = page.getByTestId('data-row').first();
|
||||
const actionsButton = measurementRow.getByRole('button', { name: 'Actions' });
|
||||
await actionsButton.click();
|
||||
|
||||
const menuDeleteButton = page.getByRole('menuitem', { name: 'Delete' });
|
||||
await menuDeleteButton.click();
|
||||
await rightPanelPageObject.measurementsPanel.panel.nthMeasurement(0).actions.delete();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
// Confirm one measurement is gone
|
||||
await expect(page.getByTestId('data-row')).toHaveCount(2);
|
||||
expect(await rightPanelPageObject.measurementsPanel.panel.getMeasurementCount()).toBe(2);
|
||||
|
||||
// Delete all measurements via main Measurement Panel delete button and untrack
|
||||
const deleteButton = page.getByRole('button', { name: 'Delete' });
|
||||
deleteButton.click();
|
||||
await rightPanelPageObject.measurementsPanel.panel.deleteAll();
|
||||
|
||||
// Interact with dialog
|
||||
const untrackDialog = page.getByRole('dialog', { name: 'Untrack Study' });
|
||||
const untrackButton = untrackDialog.getByRole('button', { name: 'Untrack' });
|
||||
await expect(DOMOverlayPageObject.dialog.title).toHaveText('Untrack Study');
|
||||
|
||||
await expect(untrackDialog).toBeVisible();
|
||||
await expect(untrackButton).toBeEnabled();
|
||||
await expect(DOMOverlayPageObject.dialog.confirmation.confirm.button).toBeEnabled();
|
||||
|
||||
await untrackButton.click();
|
||||
await DOMOverlayPageObject.dialog.confirmation.confirm.click();
|
||||
|
||||
// Check dialog closed and measurements gone
|
||||
await expect(untrackDialog).toBeHidden();
|
||||
await expect(page.getByTestId('data-row')).toHaveCount(0);
|
||||
await expect(DOMOverlayPageObject.dialog.title).toBeHidden();
|
||||
expect(await rightPanelPageObject.measurementsPanel.panel.getMeasurementCount()).toBe(0);
|
||||
|
||||
const measurementsPanel = page.getByTestId('trackedMeasurements-panel').last();
|
||||
const measurementsPanel = rightPanelPageObject.measurementsPanel.panel.locator;
|
||||
await expect(measurementsPanel).toContainText('No tracked measurements');
|
||||
});
|
||||
|
||||
test('checks if measurement item can be deleted through the context menu on the viewport', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
const measurementsBtn = page.getByTestId('trackedMeasurements-btn');
|
||||
|
||||
// Add measurement
|
||||
await addLengthMeasurement(page);
|
||||
|
||||
const viewportNotification = page.getByTestId('viewport-notification');
|
||||
await expect(viewportNotification).toBeVisible();
|
||||
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await expect(DOMOverlayPageObject.viewport.measurementTracking.locator).toBeVisible();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
|
||||
// Right click and click rename
|
||||
await page.waitForTimeout(200); // small delay for context menu
|
||||
const measurementAnnotation = page.locator('g[data-annotation-uid]').first();
|
||||
await measurementAnnotation.click({ button: 'right', force: true });
|
||||
await viewportPageObject.active.nthAnnotation(0).contextMenu.open();
|
||||
await page.waitForTimeout(200); // small delay for context menu
|
||||
|
||||
const deleteButton = page.getByTestId('context-menu-item').filter({ hasText: 'Delete' });
|
||||
await expect(deleteButton).toBeVisible();
|
||||
const deleteButton = DOMOverlayPageObject.viewport.annotationContextMenu.delete;
|
||||
await expect(deleteButton.locator).toBeVisible();
|
||||
await deleteButton.click();
|
||||
|
||||
// Open measurement panel and confirm measurement is gone
|
||||
await measurementsBtn.click();
|
||||
await expect(measurementAnnotation).toBeHidden();
|
||||
await expect(page.getByTestId('data-row')).toHaveCount(0);
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
await expect(viewportPageObject.active.nthAnnotation(0).locator).toBeHidden();
|
||||
expect(await rightPanelPageObject.measurementsPanel.panel.getMeasurementCount()).toBe(0);
|
||||
});
|
||||
|
||||
@ -10,16 +10,15 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should display multiple segmentation overlays (both SEG and RT)', async ({
|
||||
page,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await rightPanelPageObject.toggle();
|
||||
|
||||
// Add multiple segmentation overlays and ensure the overlay menu reflects this change.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
|
||||
await page.getByTestId('AddSegmentationDataOverlay-default').click();
|
||||
await page.getByText('SELECT A SEGMENTATION').click();
|
||||
await page.getByTestId('2d-tta_nnU-Net_Segmentation').click();
|
||||
const dataOverlayPageObject = viewportPageObject.getById('default').overlayMenu.dataOverlay;
|
||||
await dataOverlayPageObject.toggle();
|
||||
await dataOverlayPageObject.addSegmentation('2d-tta_nnU-Net_Segmentation');
|
||||
|
||||
// A short wait after each overlay is selected to ensure it loads.
|
||||
await page.waitForTimeout(5000);
|
||||
@ -27,9 +26,7 @@ test('should display multiple segmentation overlays (both SEG and RT)', async ({
|
||||
// Adding an overlay should not show the LOAD button.
|
||||
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
|
||||
|
||||
await page.getByTestId('AddSegmentationDataOverlay-default').click();
|
||||
await page.getByText('SELECT A SEGMENTATION').click();
|
||||
await page.getByTestId('Segmentation').click();
|
||||
await dataOverlayPageObject.addSegmentation('Segmentation');
|
||||
|
||||
// A short wait after each overlay is selected to ensure it loads.
|
||||
await page.waitForTimeout(5000);
|
||||
@ -37,9 +34,7 @@ test('should display multiple segmentation overlays (both SEG and RT)', async ({
|
||||
// Adding an overlay should not show the LOAD button.
|
||||
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
|
||||
|
||||
await page.getByTestId('AddSegmentationDataOverlay-default').click();
|
||||
await page.getByText('SELECT A SEGMENTATION').click();
|
||||
await page.getByTestId('3d_lowres-tta_nnU-Net_Segmentation').click();
|
||||
await dataOverlayPageObject.addSegmentation('3d_lowres-tta_nnU-Net_Segmentation');
|
||||
|
||||
// A short wait after each overlay is selected to ensure it loads.
|
||||
await page.waitForTimeout(5000);
|
||||
@ -53,15 +48,15 @@ test('should display multiple segmentation overlays (both SEG and RT)', async ({
|
||||
});
|
||||
|
||||
// Hide the overlay menu and then show it again. The overlays from before should still be displayed.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click(); // hide
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click(); // show
|
||||
await dataOverlayPageObject.toggle(); // hide
|
||||
await dataOverlayPageObject.toggle(); // show
|
||||
|
||||
await checkForScreenshot({
|
||||
page,
|
||||
screenshotPath: screenShotPaths.multipleSegmentationDataOverlays.threeSegOverlaysInOverlayMenu,
|
||||
});
|
||||
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click(); // hide
|
||||
await dataOverlayPageObject.toggle(); // hide
|
||||
|
||||
// Navigate to image 56.
|
||||
await press({ page, key: 'ArrowDown', nTimes: 55 });
|
||||
@ -74,11 +69,9 @@ test('should display multiple segmentation overlays (both SEG and RT)', async ({
|
||||
});
|
||||
|
||||
// Now add the RT overlay
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await dataOverlayPageObject.toggle();
|
||||
|
||||
await page.getByTestId('AddSegmentationDataOverlay-default').click();
|
||||
await page.getByText('SELECT A SEGMENTATION').click();
|
||||
await page.getByTestId('Series 3 - RTSTRUCT').click();
|
||||
await dataOverlayPageObject.addSegmentation('Series 3 - RTSTRUCT');
|
||||
|
||||
// A short wait after each overlay is selected to ensure it loads.
|
||||
await page.waitForTimeout(5000);
|
||||
@ -92,8 +85,8 @@ test('should display multiple segmentation overlays (both SEG and RT)', async ({
|
||||
});
|
||||
|
||||
// Hide the overlay menu and then show it again. The overlays from before should still be displayed.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click(); // hide
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click(); // show
|
||||
await dataOverlayPageObject.toggle(); // hide
|
||||
await dataOverlayPageObject.toggle(); // show
|
||||
|
||||
await checkForScreenshot({
|
||||
page,
|
||||
|
||||
@ -8,11 +8,12 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should display the probe tool', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await mainToolbarPageObject.moreTools.probe.click();
|
||||
await viewportPageObject.active.clickAt([{ x: 550, y: 200 }]);
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
await checkForScreenshot(page, page, screenShotPaths.probe.probeDisplayedCorrectly);
|
||||
});
|
||||
|
||||
@ -12,16 +12,15 @@ test('should overlay an unhydrated RTSTRUCT over a display set that the RTSTRUCT
|
||||
page,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await page.getByTestId('AddSegmentationDataOverlay-default').click();
|
||||
await page.getByText('SELECT A SEGMENTATION').click();
|
||||
await page.getByTestId('Contours on PET').click();
|
||||
const dataOverlayPageObject = viewportPageObject.getById('default').overlayMenu.dataOverlay;
|
||||
await dataOverlayPageObject.toggle();
|
||||
await dataOverlayPageObject.addSegmentation('Contours on PET');
|
||||
|
||||
// Adding an overlay should not show the LOAD button.
|
||||
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
|
||||
|
||||
// Hide the overlay menu.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await dataOverlayPageObject.toggle();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
|
||||
@ -10,19 +10,19 @@ test.beforeEach(async ({ page }) => {
|
||||
test('should launch MPR with unhydrated RTSTRUCT chosen from the data overlay menu', async ({
|
||||
page,
|
||||
mainToolbarPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await page.getByTestId('AddSegmentationDataOverlay-default').click();
|
||||
await page.getByText('SELECT A SEGMENTATION').click();
|
||||
await page.getByTestId('ARIA RadOnc Structure Sets').click();
|
||||
await rightPanelPageObject.toggle();
|
||||
const dataOverlayPageObject = viewportPageObject.getById('default').overlayMenu.dataOverlay;
|
||||
await dataOverlayPageObject.toggle();
|
||||
await dataOverlayPageObject.addSegmentation('ARIA RadOnc Structure Sets');
|
||||
|
||||
// Adding an overlay should not show the LOAD button.
|
||||
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
|
||||
|
||||
// Hide the overlay menu.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await dataOverlayPageObject.toggle();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { test } from 'playwright-test-coverage';
|
||||
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
||||
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
const studyInstanceUID = '1.2.840.113619.2.290.3.3767434740.226.1600859119.501';
|
||||
@ -7,17 +6,24 @@ test.beforeEach(async ({ page }) => {
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('should hydrate RT reports correctly', async ({ page }) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
test('should hydrate RT reports correctly', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
await rightPanelPageObject.toggle();
|
||||
await leftPanelPageObject.loadSeriesByModality('RTSTRUCT');
|
||||
await page.waitForTimeout(5000);
|
||||
await checkForScreenshot(page, page, screenShotPaths.rtHydration.rtPreHydration);
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
await page.waitForTimeout(5000);
|
||||
await checkForScreenshot(page, page, screenShotPaths.rtHydration.rtPostHydration);
|
||||
|
||||
await page.getByText('Small Sphere').click();
|
||||
await rightPanelPageObject.labelMapSegmentationPanel.panel
|
||||
.segmentationByText('Small Sphere')
|
||||
.click();
|
||||
await page.waitForTimeout(5000);
|
||||
await checkForScreenshot(page, page, screenShotPaths.rtHydration.rtJumpToStructure);
|
||||
});
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { test } from 'playwright-test-coverage';
|
||||
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
||||
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
const studyInstanceUID = '1.3.6.1.4.1.5962.99.1.2968617883.1314880426.1493322302363.3.0';
|
||||
@ -7,9 +6,14 @@ test.beforeEach(async ({ page }) => {
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('should hydrate RT reports correctly', async ({ page }) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
test('should hydrate RT reports correctly', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
await rightPanelPageObject.toggle();
|
||||
await leftPanelPageObject.loadSeriesByModality('RTSTRUCT');
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.rtHydration2.rtPreHydration);
|
||||
// wait for 3 seconds
|
||||
@ -34,9 +38,7 @@ test('should hydrate RT reports correctly', async ({ page }) => {
|
||||
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
//
|
||||
|
||||
// should preserve zoom and pan and scroll position after hydration
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
await checkForScreenshot(page, page, screenShotPaths.rtHydration.rtPostHydration);
|
||||
});
|
||||
|
||||
@ -6,8 +6,14 @@ test.beforeEach(async ({ page }) => {
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('should hydrate an RTSTRUCT from MPR', async ({ page, mainToolbarPageObject }) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
test('should hydrate an RTSTRUCT from MPR', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
mainToolbarPageObject,
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
await rightPanelPageObject.toggle();
|
||||
|
||||
await mainToolbarPageObject.layoutSelection.MPR.click();
|
||||
|
||||
@ -15,13 +21,13 @@ test('should hydrate an RTSTRUCT from MPR', async ({ page, mainToolbarPageObject
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.rtHydrationFromMPR.mprBeforeRT);
|
||||
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
await leftPanelPageObject.loadSeriesByModality('RTSTRUCT');
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.rtHydrationFromMPR.mprAfterRT);
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
|
||||
@ -6,11 +6,17 @@ test.beforeEach(async ({ page }) => {
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('should hydrate an RTSTRUCT and then launch MPR', async ({ page, mainToolbarPageObject }) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
test('should hydrate an RTSTRUCT and then launch MPR', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
mainToolbarPageObject,
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
await rightPanelPageObject.toggle();
|
||||
await leftPanelPageObject.loadSeriesByModality('RTSTRUCT');
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
|
||||
@ -6,9 +6,14 @@ test.beforeEach(async ({ page }) => {
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('should launch MPR with unhydrated RTSTRUCT', async ({ page, mainToolbarPageObject }) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
test('should launch MPR with unhydrated RTSTRUCT', async ({
|
||||
page,
|
||||
leftPanelPageObject,
|
||||
mainToolbarPageObject,
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
await rightPanelPageObject.toggle();
|
||||
await leftPanelPageObject.loadSeriesByModality('RTSTRUCT');
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should display the rectangle tool', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
@ -16,6 +17,6 @@ test('should display the rectangle tool', async ({
|
||||
{ x: 476, y: 159 },
|
||||
{ x: 591, y: 217 },
|
||||
]);
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
await checkForScreenshot(page, page, screenShotPaths.rectangle.rectangleDisplayedCorrectly);
|
||||
});
|
||||
|
||||
@ -10,20 +10,21 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should overlay an unhydrated SEG over a display set that the SEG does NOT reference', async ({
|
||||
page,
|
||||
leftPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await page.getByTestId('study-browser-thumbnail').nth(2).dblclick();
|
||||
await leftPanelPageObject.loadSeriesByDescription('Apparent Diffusion Coefficient');
|
||||
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await page.getByTestId('AddSegmentationDataOverlay-default').click();
|
||||
await page.getByText('SELECT A SEGMENTATION').click();
|
||||
await page.getByTestId('T2 Weighted Axial Segmentations').click();
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.toggle();
|
||||
await viewportPageObject
|
||||
.getById('default')
|
||||
.overlayMenu.dataOverlay.addSegmentation('T2 Weighted Axial Segmentations');
|
||||
|
||||
// Adding an overlay should not show the LOAD button.
|
||||
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
|
||||
|
||||
// Hide the overlay menu.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.toggle();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
|
||||
@ -10,19 +10,20 @@ test.beforeEach(async ({ page }) => {
|
||||
test('should launch MPR with unhydrated SEG chosen from the data overlay menu', async ({
|
||||
page,
|
||||
mainToolbarPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await page.getByTestId('AddSegmentationDataOverlay-default').click();
|
||||
await page.getByText('SELECT A SEGMENTATION').click();
|
||||
await page.getByTestId('Segmentation').click();
|
||||
await rightPanelPageObject.toggle();
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.toggle();
|
||||
await viewportPageObject
|
||||
.getById('default')
|
||||
.overlayMenu.dataOverlay.addSegmentation('Segmentation');
|
||||
|
||||
// Adding an overlay should not show the LOAD button.
|
||||
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
|
||||
|
||||
// Hide the overlay menu.
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
|
||||
await viewportPageObject.getById('default').overlayMenu.dataOverlay.toggle();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
import { Page } from '@playwright/test';
|
||||
|
||||
import { ViewportPageObject } from './pages';
|
||||
import { RightPanelPageObject, ViewportPageObject } from './pages';
|
||||
import { checkForScreenshot, expect, screenShotPaths, test, visitStudy } from './utils';
|
||||
import { press } from './utils/keyboardUtils';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
test.beforeEach(async ({ page, rightPanelPageObject }) => {
|
||||
const studyInstanceUID = '1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046';
|
||||
const mode = 'segmentation';
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
|
||||
await page.getByTestId('panelSegmentationWithToolsLabelMap-btn').click();
|
||||
await page.getByTestId('addSegmentation').click();
|
||||
await rightPanelPageObject.labelMapSegmentationPanel.addSegmentationButton.click();
|
||||
|
||||
await page.waitForTimeout(500);
|
||||
});
|
||||
@ -18,9 +17,10 @@ test.beforeEach(async ({ page }) => {
|
||||
async function performDrawingToolInteraction(
|
||||
page: Page,
|
||||
toolName: string,
|
||||
rightPanelPageObject: RightPanelPageObject,
|
||||
viewportPageObject: ViewportPageObject
|
||||
) {
|
||||
const brushRadiusInput = page.getByTestId(`${toolName}-radius`).locator('input');
|
||||
const brushRadiusInput = rightPanelPageObject.labelMapSegmentationPanel.tools[toolName].input;
|
||||
const circle = viewportPageObject.active.svg('circle').first();
|
||||
|
||||
await expect(brushRadiusInput).toHaveValue('25');
|
||||
@ -57,10 +57,14 @@ async function performDrawingToolInteraction(
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
|
||||
test('should resize segmentation brush tool', async ({ page, viewportPageObject }) => {
|
||||
test('should resize segmentation brush tool', async ({
|
||||
page,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await page.getByTestId('Brush-btn').click();
|
||||
|
||||
await performDrawingToolInteraction(page, 'brush', viewportPageObject);
|
||||
await performDrawingToolInteraction(page, 'brush', rightPanelPageObject, viewportPageObject);
|
||||
|
||||
await checkForScreenshot(
|
||||
page,
|
||||
@ -69,7 +73,11 @@ test('should resize segmentation brush tool', async ({ page, viewportPageObject
|
||||
);
|
||||
});
|
||||
|
||||
test('should resize segmentation eraser tool', async ({ page, viewportPageObject }) => {
|
||||
test('should resize segmentation eraser tool', async ({
|
||||
page,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await page.getByTestId('Brush-btn').click();
|
||||
|
||||
await page.getByTestId('brush-radius').locator('input').fill('99.5');
|
||||
@ -82,7 +90,7 @@ test('should resize segmentation eraser tool', async ({ page, viewportPageObject
|
||||
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
await performDrawingToolInteraction(page, 'eraser', viewportPageObject);
|
||||
await performDrawingToolInteraction(page, 'eraser', rightPanelPageObject, viewportPageObject);
|
||||
|
||||
await checkForScreenshot(
|
||||
page,
|
||||
@ -91,8 +99,12 @@ test('should resize segmentation eraser tool', async ({ page, viewportPageObject
|
||||
);
|
||||
});
|
||||
|
||||
test('should resize segmentation threshold tool', async ({ page, viewportPageObject }) => {
|
||||
test('should resize segmentation threshold tool', async ({
|
||||
page,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
await page.getByTestId('Threshold-btn').click();
|
||||
|
||||
await performDrawingToolInteraction(page, 'threshold', viewportPageObject);
|
||||
await performDrawingToolInteraction(page, 'threshold', rightPanelPageObject, viewportPageObject);
|
||||
});
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { test } from 'playwright-test-coverage';
|
||||
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
||||
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.256467663913010332776401703474716742458';
|
||||
@ -7,9 +6,14 @@ test.beforeEach(async ({ page }) => {
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('should hydrate SEG reports correctly', async ({ page }) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
test('should hydrate SEG reports correctly', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
await rightPanelPageObject.toggle();
|
||||
await leftPanelPageObject.loadSeriesByDescription('SEG');
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
await checkForScreenshot(page, page, screenShotPaths.segHydration.segPreHydration);
|
||||
@ -33,7 +37,7 @@ test('should hydrate SEG reports correctly', async ({ page }) => {
|
||||
}
|
||||
});
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
await checkForScreenshot(page, page, screenShotPaths.segHydration.segPostHydration);
|
||||
|
||||
@ -16,6 +16,8 @@ test.beforeEach(async ({ page }) => {
|
||||
test.describe('3D four up SEG hydration', async () => {
|
||||
test('should properly hydrate SEG from 3D four up layout', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
mainToolbarPageObject,
|
||||
}) => {
|
||||
await mainToolbarPageObject.layoutSelection.threeDFourUp.click();
|
||||
@ -30,7 +32,7 @@ test.describe('3D four up SEG hydration', async () => {
|
||||
screenShotPaths.segHydrationFrom3DFourUp.threeDFourUpBeforeSEG
|
||||
);
|
||||
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
await leftPanelPageObject.loadSeriesByDescription('SEG');
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
await checkForScreenshot(
|
||||
@ -39,7 +41,7 @@ test.describe('3D four up SEG hydration', async () => {
|
||||
screenShotPaths.segHydrationFrom3DFourUp.threeDFourUpAfterSEG
|
||||
);
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
await checkForScreenshot(
|
||||
|
||||
@ -6,20 +6,26 @@ test.beforeEach(async ({ page }) => {
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('should properly display MPR for MR', async ({ page, mainToolbarPageObject }) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
test('should properly display MPR for MR', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
mainToolbarPageObject,
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
await rightPanelPageObject.toggle();
|
||||
|
||||
await mainToolbarPageObject.layoutSelection.MPR.click();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
await checkForScreenshot(page, page, screenShotPaths.segHydrationFromMPR.mprBeforeSEG);
|
||||
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
await leftPanelPageObject.loadSeriesByDescription('SEG');
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
await checkForScreenshot(page, page, screenShotPaths.segHydrationFromMPR.mprAfterSEG);
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
await checkForScreenshot(page, page, screenShotPaths.segHydrationFromMPR.mprAfterSegHydrated);
|
||||
|
||||
@ -6,11 +6,17 @@ test.beforeEach(async ({ page }) => {
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('should properly display MPR for MR', async ({ page, mainToolbarPageObject }) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
test('should properly display MPR for MR', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
mainToolbarPageObject,
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
await rightPanelPageObject.toggle();
|
||||
await leftPanelPageObject.loadSeriesByDescription('SEG');
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
await checkForScreenshot(page, page, screenShotPaths.segHydrationThenMPR.segPostHydration);
|
||||
|
||||
@ -6,9 +6,14 @@ test.beforeEach(async ({ page }) => {
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('should launch MPR with unhydrated SEG', async ({ page, mainToolbarPageObject }) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
test('should launch MPR with unhydrated SEG', async ({
|
||||
page,
|
||||
leftPanelPageObject,
|
||||
mainToolbarPageObject,
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
await rightPanelPageObject.toggle();
|
||||
await leftPanelPageObject.loadSeriesByDescription('SEG');
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { test } from 'playwright-test-coverage';
|
||||
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
||||
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.7695.4007.324475281161490036195179843543';
|
||||
@ -7,10 +6,15 @@ test.beforeEach(async ({ page }) => {
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('should hydrate SR reports correctly', async ({ page }) => {
|
||||
await page.getByTestId('side-panel-header-right').click();
|
||||
await page.getByTestId('trackedMeasurements-btn').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
test('should hydrate SR reports correctly', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
}) => {
|
||||
await rightPanelPageObject.toggle();
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
await leftPanelPageObject.loadSeriesByModality('SR');
|
||||
await page.waitForTimeout(2000);
|
||||
await checkForScreenshot(page, page, screenShotPaths.srHydration.srPreHydration);
|
||||
|
||||
@ -33,7 +37,7 @@ test('should hydrate SR reports correctly', async ({ page }) => {
|
||||
}
|
||||
});
|
||||
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
await page.waitForTimeout(2000);
|
||||
await checkForScreenshot(page, page, screenShotPaths.srHydration.srPostHydration);
|
||||
|
||||
@ -56,7 +60,7 @@ test('should hydrate SR reports correctly', async ({ page }) => {
|
||||
}
|
||||
});
|
||||
|
||||
await page.getByTestId('data-row').first().click();
|
||||
await rightPanelPageObject.measurementsPanel.panel.nthMeasurement(0).click();
|
||||
|
||||
await checkForScreenshot(page, page, screenShotPaths.srHydration.srJumpToMeasurement);
|
||||
});
|
||||
|
||||
@ -21,17 +21,20 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should hydrate SCOORD3D probe measurements correctly', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
// Wait for the side panel to be visible and clickable
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// Navigate to the tracked measurements panel
|
||||
await page.getByTestId('side-panel-header-right').click({ timeout: 15000 });
|
||||
await page.getByTestId('trackedMeasurements-btn').click();
|
||||
await rightPanelPageObject.toggle();
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
|
||||
// Double-click on the study browser thumbnail to load the SR
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
await leftPanelPageObject.loadSeriesByModality('SR');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Wait for the SR to load and stabilize before taking screenshot
|
||||
@ -68,10 +71,13 @@ test('should hydrate SCOORD3D probe measurements correctly', async ({
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Wait for the hydrate button to be visible and clickable
|
||||
await page.getByTestId('yes-hydrate-btn').waitFor({ state: 'visible', timeout: 15000 });
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.button.waitFor({
|
||||
state: 'visible',
|
||||
timeout: 15000,
|
||||
});
|
||||
|
||||
// Click the hydrate button to load the SCOORD3D probe measurements
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
// Wait for hydration to complete and rendering to stabilize
|
||||
await page.waitForTimeout(3000);
|
||||
@ -86,14 +92,17 @@ test('should hydrate SCOORD3D probe measurements correctly', async ({
|
||||
// Verify the measurements list has the correct probe measurements
|
||||
const measurementRows = page.getByTestId('data-row');
|
||||
const rowCount = await measurementRows.count();
|
||||
expect(rowCount).toBeGreaterThan(0);
|
||||
expect(await rightPanelPageObject.measurementsPanel.panel.getMeasurementCount()).toBeGreaterThan(
|
||||
0
|
||||
);
|
||||
|
||||
// Verify that the measurements are probe measurements (not other types)
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const row = measurementRows.nth(i);
|
||||
const rowText = await row.textContent();
|
||||
const measurementText = await rightPanelPageObject.measurementsPanel.panel
|
||||
.nthMeasurement(i)
|
||||
.locator.textContent();
|
||||
// Probe measurements should be present, verify they're not other measurement types
|
||||
expect(rowText).toBeTruthy();
|
||||
expect(measurementText).toBeTruthy();
|
||||
}
|
||||
|
||||
// Test jumping to a specific measurement by scrolling and clicking
|
||||
@ -117,7 +126,7 @@ test('should hydrate SCOORD3D probe measurements correctly', async ({
|
||||
});
|
||||
|
||||
// Click on a data row to jump to the measurement
|
||||
await page.getByTestId('data-row').first().click();
|
||||
await rightPanelPageObject.measurementsPanel.panel.nthMeasurement(0).click();
|
||||
|
||||
// Take screenshot showing the jump to measurement functionality - use viewport locator
|
||||
await checkForScreenshot(
|
||||
@ -129,20 +138,26 @@ test('should hydrate SCOORD3D probe measurements correctly', async ({
|
||||
|
||||
test('should display SCOORD3D probe measurements correctly', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
// Wait for the side panel to be visible and clickable
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// First hydrate the SR to load the measurements
|
||||
await page.getByTestId('side-panel-header-right').click({ timeout: 15000 });
|
||||
await page.getByTestId('trackedMeasurements-btn').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
await rightPanelPageObject.toggle();
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
await leftPanelPageObject.loadSeriesByModality('SR');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Wait for the hydrate button to be visible and clickable
|
||||
await page.getByTestId('yes-hydrate-btn').waitFor({ state: 'visible', timeout: 15000 });
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.button.waitFor({
|
||||
state: 'visible',
|
||||
timeout: 15000,
|
||||
});
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Zoom to show the probe measurements clearly
|
||||
@ -175,15 +190,15 @@ test('should display SCOORD3D probe measurements correctly', async ({
|
||||
);
|
||||
|
||||
// Verify the measurements list has the correct probe measurements and not others
|
||||
const measurementRows = page.getByTestId('data-row');
|
||||
const rowCount = await measurementRows.count();
|
||||
const rowCount = await rightPanelPageObject.measurementsPanel.panel.getMeasurementCount();
|
||||
expect(rowCount).toBeGreaterThan(0);
|
||||
|
||||
// Verify that the measurements are probe measurements (not other types like rectangle)
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const row = measurementRows.nth(i);
|
||||
const rowText = await row.textContent();
|
||||
const measurementText = await rightPanelPageObject.measurementsPanel.panel
|
||||
.nthMeasurement(i)
|
||||
.locator.textContent();
|
||||
// Probe measurements should be present, verify they're not other measurement types
|
||||
expect(rowText).toBeTruthy();
|
||||
expect(measurementText).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
@ -22,17 +22,20 @@ test.beforeEach(async ({ page }) => {
|
||||
//
|
||||
test('should hydrate SCOORD rectangle measurements correctly', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
// Wait for the side panel to be visible and clickable
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// Navigate to the tracked measurements panel
|
||||
await page.getByTestId('side-panel-header-right').click({ timeout: 15000 });
|
||||
await page.getByTestId('trackedMeasurements-btn').click();
|
||||
await rightPanelPageObject.toggle();
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
|
||||
// Double-click on the study browser thumbnail to load the SR
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
await leftPanelPageObject.loadSeriesByModality('SR');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Wait for the SR to load and stabilize before taking screenshot
|
||||
@ -69,10 +72,13 @@ test('should hydrate SCOORD rectangle measurements correctly', async ({
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Wait for the hydrate button to be visible and clickable
|
||||
await page.getByTestId('yes-hydrate-btn').waitFor({ state: 'visible', timeout: 15000 });
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.button.waitFor({
|
||||
state: 'visible',
|
||||
timeout: 15000,
|
||||
});
|
||||
|
||||
// Click the hydrate button to load the SCOORD rectangle measurements
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
// Wait for hydration to complete and rendering to stabilize
|
||||
await page.waitForTimeout(3000);
|
||||
@ -85,16 +91,16 @@ test('should hydrate SCOORD rectangle measurements correctly', async ({
|
||||
);
|
||||
|
||||
// Verify the measurements list has the correct rectangle measurements
|
||||
const measurementRows = page.getByTestId('data-row');
|
||||
const rowCount = await measurementRows.count();
|
||||
const rowCount = await rightPanelPageObject.measurementsPanel.panel.getMeasurementCount();
|
||||
expect(rowCount).toBeGreaterThan(0);
|
||||
|
||||
// Verify that the measurements are rectangle measurements (not other types)
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const row = measurementRows.nth(i);
|
||||
const rowText = await row.textContent();
|
||||
const measurementText = await rightPanelPageObject.measurementsPanel.panel
|
||||
.nthMeasurement(i)
|
||||
.locator.textContent();
|
||||
// Rectangle measurements should be present, verify they're not other measurement types
|
||||
expect(rowText).toBeTruthy();
|
||||
expect(measurementText).toBeTruthy();
|
||||
}
|
||||
|
||||
// Test jumping to a specific measurement by scrolling and clicking
|
||||
@ -118,7 +124,7 @@ test('should hydrate SCOORD rectangle measurements correctly', async ({
|
||||
});
|
||||
|
||||
// Click on a data row to jump to the measurement
|
||||
await page.getByTestId('data-row').first().click();
|
||||
await rightPanelPageObject.measurementsPanel.panel.nthMeasurement(0).click();
|
||||
|
||||
// Take screenshot showing the jump to measurement functionality - use viewport locator
|
||||
await checkForScreenshot(
|
||||
@ -130,20 +136,26 @@ test('should hydrate SCOORD rectangle measurements correctly', async ({
|
||||
|
||||
test('should display SCOORD rectangle measurements correctly', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
// Wait for the side panel to be visible and clickable
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// First hydrate the SR to load the measurements
|
||||
await page.getByTestId('side-panel-header-right').click({ timeout: 15000 });
|
||||
await page.getByTestId('trackedMeasurements-btn').click();
|
||||
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
|
||||
await rightPanelPageObject.toggle();
|
||||
await rightPanelPageObject.measurementsPanel.select();
|
||||
await leftPanelPageObject.loadSeriesByModality('SR');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Wait for the hydrate button to be visible and clickable
|
||||
await page.getByTestId('yes-hydrate-btn').waitFor({ state: 'visible', timeout: 15000 });
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.button.waitFor({
|
||||
state: 'visible',
|
||||
timeout: 15000,
|
||||
});
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Zoom to show the rectangle measurements clearly
|
||||
@ -176,15 +188,15 @@ test('should display SCOORD rectangle measurements correctly', async ({
|
||||
);
|
||||
|
||||
// Verify the measurements list has the correct rectangle measurements and not others
|
||||
const measurementRows = page.getByTestId('data-row');
|
||||
const rowCount = await measurementRows.count();
|
||||
const rowCount = await rightPanelPageObject.measurementsPanel.panel.getMeasurementCount();
|
||||
expect(rowCount).toBeGreaterThan(0);
|
||||
|
||||
// Verify that the measurements are rectangle measurements (not other types like probe)
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const row = measurementRows.nth(i);
|
||||
const rowText = await row.textContent();
|
||||
const measurementText = await rightPanelPageObject.measurementsPanel.panel
|
||||
.nthMeasurement(i)
|
||||
.locator.textContent();
|
||||
// Rectangle measurements should be present, verify they're not other measurement types
|
||||
expect(rowText).toBeTruthy();
|
||||
expect(measurementText).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
@ -7,55 +7,39 @@ test.beforeEach(async ({ page }) => {
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('checks basic add, rename, delete segments from panel', async ({ page }) => {
|
||||
test('checks basic add, rename, delete segments from panel', async ({ rightPanelPageObject }) => {
|
||||
// Segmentation Panel should already be open
|
||||
const segmentationPanel = page.getByTestId('panelSegmentationWithToolsLabelMap-btn');
|
||||
const segmentationPanel = rightPanelPageObject.labelMapSegmentationPanel.menuButton;
|
||||
await expect(segmentationPanel).toBeVisible();
|
||||
|
||||
// Switch to labelmap tab.
|
||||
segmentationPanel.click();
|
||||
|
||||
// Add segmentation
|
||||
const addSegmentationBtn = page.getByTestId('addSegmentation');
|
||||
await addSegmentationBtn.click();
|
||||
await rightPanelPageObject.labelMapSegmentationPanel.addSegmentationButton.click();
|
||||
|
||||
// Expect new segmentation and blank segment named "Segment 1"
|
||||
await expect(page.getByTestId('data-row')).toHaveCount(1);
|
||||
await expect(page.getByTestId('data-row')).toContainText('Segment 1');
|
||||
const segment1 = rightPanelPageObject.labelMapSegmentationPanel.panel.nthSegmentation(0);
|
||||
expect(await rightPanelPageObject.labelMapSegmentationPanel.panel.getSegmentationCount()).toBe(1);
|
||||
await expect(segment1.locator).toContainText('Segment 1');
|
||||
|
||||
// Rename
|
||||
const segment1Dropdown = page
|
||||
.getByTestId('data-row')
|
||||
.first()
|
||||
.getByRole('button', { name: 'Actions' });
|
||||
await segment1Dropdown.click();
|
||||
await segment1.actions.rename('Segment One');
|
||||
|
||||
const renameButton = page.getByRole('menuitem', { name: 'Rename' });
|
||||
await expect(renameButton).toBeVisible();
|
||||
await renameButton.click();
|
||||
|
||||
const renameDialog = page.getByRole('dialog', { name: 'Edit Segment Label' });
|
||||
await expect(renameDialog).toBeVisible();
|
||||
|
||||
const renameInput = page.getByRole('textbox', { name: 'Enter new label' });
|
||||
await renameInput.fill('Segment One');
|
||||
|
||||
await page.getByTestId('input-dialog-save-button').click();
|
||||
|
||||
await expect(page.getByTestId('data-row')).toContainText('Segment One');
|
||||
await expect(page.getByTestId('data-row')).not.toContainText('Segment 1');
|
||||
await expect(segment1.locator).toContainText('Segment One');
|
||||
await expect(segment1.locator).not.toContainText('Segment 1');
|
||||
|
||||
// Delete
|
||||
await segment1Dropdown.click();
|
||||
const deleteButton = page.getByRole('menuitem', { name: 'Delete' });
|
||||
await expect(deleteButton).toBeVisible();
|
||||
await deleteButton.click();
|
||||
await segment1.actions.delete();
|
||||
|
||||
await expect(page.getByTestId('data-row')).toHaveCount(0);
|
||||
expect(await rightPanelPageObject.labelMapSegmentationPanel.panel.getSegmentationCount()).toBe(0);
|
||||
});
|
||||
|
||||
test('checks saved segmentations loads and jumps to slices', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
const viewportInfoBottomRight = viewportPageObject.active.overlayText.bottomRight;
|
||||
@ -63,39 +47,34 @@ test('checks saved segmentations loads and jumps to slices', async ({
|
||||
await expect(viewportInfoBottomRight).toContainText('1/', { timeout: 10000 });
|
||||
|
||||
// Add Segmentations
|
||||
const segmentationsThumbnail = page
|
||||
.getByTestId('study-browser-thumbnail-no-image')
|
||||
.getByRole('button', { name: 'Segmentation' });
|
||||
await segmentationsThumbnail.dblclick();
|
||||
await leftPanelPageObject.loadSeriesByModality('SEG');
|
||||
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// Confirm open segmentation
|
||||
const viewportNotification = page.getByTestId('viewport-notification');
|
||||
await expect(viewportNotification).toBeVisible();
|
||||
await page.getByTestId('yes-hydrate-btn').click();
|
||||
await expect(DOMOverlayPageObject.viewport.segmentationHydration.locator).toBeVisible();
|
||||
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
|
||||
|
||||
// Segmentation Panel should already be open
|
||||
const segmentationPanel = page.getByTestId('panelSegmentationWithToolsLabelMap-btn');
|
||||
const segmentationPanel = rightPanelPageObject.labelMapSegmentationPanel.menuButton;
|
||||
await expect(segmentationPanel).toBeVisible();
|
||||
|
||||
// Confirm spleen jumps to slice 17
|
||||
// First iteration repeat to account for segmentation loading delays
|
||||
const spleenRow = page.getByTestId('data-row').filter({ hasText: 'Spleen' });
|
||||
await expect(async () => {
|
||||
await spleenRow.click();
|
||||
await rightPanelPageObject.labelMapSegmentationPanel.panel.segmentationByText('Spleen').click();
|
||||
await expect(viewportInfoBottomRight).toContainText('17/');
|
||||
}).toPass({
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
// Esophagus - 5
|
||||
const esophagusRow = page.getByTestId('data-row').filter({ hasText: 'Esophagus' });
|
||||
await esophagusRow.click();
|
||||
await rightPanelPageObject.labelMapSegmentationPanel.panel
|
||||
.segmentationByText('Esophagus')
|
||||
.click();
|
||||
await expect(viewportInfoBottomRight).toContainText('5/');
|
||||
|
||||
// Pancreas - 22
|
||||
const pancreasRow = page.getByTestId('data-row').filter({ hasText: 'Pancreas' });
|
||||
await pancreasRow.click();
|
||||
await rightPanelPageObject.labelMapSegmentationPanel.panel.segmentationByText('Pancreas').click();
|
||||
await expect(viewportInfoBottomRight).toContainText('22/');
|
||||
});
|
||||
|
||||
@ -8,6 +8,7 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test('should display the spline tool', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
@ -20,6 +21,6 @@ test('should display the spline tool', async ({
|
||||
{ x: 482, y: 493 },
|
||||
{ x: 383, y: 461 },
|
||||
]);
|
||||
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
|
||||
await DOMOverlayPageObject.viewport.measurementTracking.confirm.click();
|
||||
await checkForScreenshot(page, page, screenShotPaths.spline.splineDisplayedCorrectly);
|
||||
});
|
||||
|
||||
@ -3,21 +3,22 @@ import { downloadAsString } from './utils/download';
|
||||
|
||||
test('should create and download the TMTV CSV report correctly', async ({
|
||||
page,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
const studyInstanceUID = '1.2.840.113619.2.290.3.3767434740.226.1600859119.501';
|
||||
const mode = 'tmtv';
|
||||
await visitStudy(page, studyInstanceUID, mode, 10000);
|
||||
|
||||
await page.getByTestId('addSegmentation').click();
|
||||
await page.getByTestId('Brush-btn').click();
|
||||
await rightPanelPageObject.tmtvPanel.addSegmentationButton.click();
|
||||
await rightPanelPageObject.tmtvPanel.tools.brush.click();
|
||||
|
||||
await viewportPageObject.getById('ctAXIAL').normalizedClickAt([{ x: 0.5, y: 0.5 }]);
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
const downloadPromise = page.waitForEvent('download');
|
||||
await page.getByTestId('exportTmtvCsvReport').click();
|
||||
await rightPanelPageObject.tmtvPanel.exportTmtvCsvReport();
|
||||
const download = await downloadPromise;
|
||||
|
||||
expect(download.suggestedFilename(), 'Not the correct file name for the TMTV CSV report.').toBe(
|
||||
|
||||
@ -2,6 +2,7 @@ import { expect, clearAllAnnotations, getTMTVModalityUnit, test, visitStudy } fr
|
||||
|
||||
test.skip('pets where SUV cannot be calculated should show same unit in TMTV as in Basic Viewer.', async ({
|
||||
page,
|
||||
leftPanelPageObject,
|
||||
mainToolbarPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
@ -10,7 +11,7 @@ test.skip('pets where SUV cannot be calculated should show same unit in TMTV as
|
||||
await visitStudy(page, studyInstanceUID, mode, 10000);
|
||||
|
||||
// Show sidebar
|
||||
await page.getByTestId('side-panel-header-left').click();
|
||||
await leftPanelPageObject.toggle();
|
||||
|
||||
// Change to image where SUV cannot be calculated
|
||||
await viewportPageObject.getNth(3).normalizedClickAt([{ x: 0.5, y: 0.5 }]);
|
||||
|
||||
@ -2,6 +2,7 @@ import { expect, test, visitStudy } from './utils';
|
||||
|
||||
test('should restrict the percentage of max SUV to be between 0 and 1', async ({
|
||||
page,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
const studyInstanceUID = '1.2.840.113619.2.290.3.3767434740.226.1600859119.501';
|
||||
@ -10,49 +11,51 @@ test('should restrict the percentage of max SUV to be between 0 and 1', async ({
|
||||
|
||||
await viewportPageObject.getById('ptAXIAL').normalizedClickAt([{ x: 0.5, y: 0.5 }]);
|
||||
|
||||
await page.getByTestId('addSegmentation').click();
|
||||
await page.getByTestId('RectangleROIStartEndThreshold-btn').click();
|
||||
await rightPanelPageObject.tmtvPanel.addSegmentationButton.click();
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('0');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('0');
|
||||
const rectangleROIThreshold = rightPanelPageObject.tmtvPanel.tools.rectangleROIThreshold;
|
||||
await rectangleROIThreshold.click();
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('0.27');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('0.27');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('0');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('0');
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('0.9467');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('0.9467');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('0.27');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('0.27');
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('.');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('0.');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('0.9467');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('0.9467');
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('1');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('1');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('.');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('0.');
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('1.1');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('1');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('1');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('1');
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('1806');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('1');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('1.1');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('1');
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('1806');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('1');
|
||||
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('');
|
||||
|
||||
// Add some valid input for the tests that follow. Note that when invalid input is
|
||||
// entered the previous valid input is retained.
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('0.275');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('0.275');
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('9');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('0.275');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('9');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('0.275');
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('-678');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('0.275');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('-678');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('0.275');
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('+');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('0.275');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('+');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('0.275');
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('-');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('0.275');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('-');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('0.275');
|
||||
|
||||
await page.getByTestId('percentage-of-max-suv-input').fill('e');
|
||||
expect(await page.getByTestId('percentage-of-max-suv-input').inputValue()).toBe('0.275');
|
||||
await rectangleROIThreshold.setPercentageOfMaxSUV('e');
|
||||
expect(await rectangleROIThreshold.getPercentageOfMaxSUV()).toBe('0.275');
|
||||
});
|
||||
|
||||
@ -25,13 +25,13 @@ test('should render scroll bars with the correct look-and-feel', async ({ page }
|
||||
// Wait for the expanded row to be visible and rendered
|
||||
await expandedStudyRow.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await expandedStudyRow.scrollIntoViewIfNeeded();
|
||||
|
||||
|
||||
// Wait for content to load and stabilize, including any lazy-loaded items
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
|
||||
// Wait for network to be idle to ensure all content is loaded
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
|
||||
// Additional wait to ensure scrollbar rendering is stable
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
|
||||
134
tests/pages/DOMOverlayPageObject.ts
Normal file
134
tests/pages/DOMOverlayPageObject.ts
Normal file
@ -0,0 +1,134 @@
|
||||
import { Locator, Page } from '@playwright/test';
|
||||
|
||||
export class DOMOverlayPageObject {
|
||||
readonly page: Page;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
get dialog() {
|
||||
const page = this.page;
|
||||
|
||||
return {
|
||||
get confirmation() {
|
||||
const cancelButton = page.getByTestId('untracked-series-modal-cancel-button');
|
||||
const confirmButton = page.getByTestId('untracked-series-modal-confirm-button');
|
||||
return {
|
||||
cancel: {
|
||||
button: cancelButton,
|
||||
click: async () => {
|
||||
await cancelButton.click();
|
||||
},
|
||||
},
|
||||
confirm: {
|
||||
button: confirmButton,
|
||||
click: async () => {
|
||||
await confirmButton.click();
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
get input() {
|
||||
const locator = page.getByTestId('dialog-input');
|
||||
const saveButton = page.getByTestId('input-dialog-save-button');
|
||||
return {
|
||||
locator,
|
||||
fill: async (text: string) => {
|
||||
await locator.fill(text);
|
||||
},
|
||||
fillAndSave: async (text: string) => {
|
||||
await locator.fill(text);
|
||||
await saveButton.click();
|
||||
},
|
||||
save: async () => {
|
||||
await saveButton.click();
|
||||
},
|
||||
};
|
||||
},
|
||||
title: page.locator('[role="dialog"] h2'),
|
||||
};
|
||||
}
|
||||
|
||||
get viewport() {
|
||||
const page = this.page;
|
||||
|
||||
return {
|
||||
get annotationContextMenu() {
|
||||
return {
|
||||
get addLabel() {
|
||||
const button = page.getByTestId('context-menu-item').filter({ hasText: 'Add Label' });
|
||||
return {
|
||||
locator: button,
|
||||
click: async () => {
|
||||
await button.click();
|
||||
},
|
||||
};
|
||||
},
|
||||
get delete() {
|
||||
const button = page.getByTestId('context-menu-item').filter({ hasText: 'Delete' });
|
||||
return {
|
||||
locator: button,
|
||||
click: async () => {
|
||||
await button.click();
|
||||
},
|
||||
};
|
||||
},
|
||||
open: async (annotation: Locator) => {
|
||||
await annotation.click({ button: 'right', force: true });
|
||||
},
|
||||
};
|
||||
},
|
||||
get measurementTracking() {
|
||||
const cancelButton = page.getByTestId('prompt-begin-tracking-cancel-btn');
|
||||
const noAndNotAskAgainButton = page.getByTestId(
|
||||
'prompt-begin-tracking-no-do-not-ask-again-btn'
|
||||
);
|
||||
const confirmButton = page.getByTestId('prompt-begin-tracking-yes-btn');
|
||||
return {
|
||||
locator: page.getByTestId('viewport-notification'),
|
||||
cancel: {
|
||||
button: cancelButton,
|
||||
click: async () => {
|
||||
await cancelButton.click();
|
||||
},
|
||||
},
|
||||
noAndNotAskAgain: {
|
||||
button: noAndNotAskAgainButton,
|
||||
click: async () => {
|
||||
await noAndNotAskAgainButton.click();
|
||||
},
|
||||
},
|
||||
confirm: {
|
||||
button: confirmButton,
|
||||
click: async () => {
|
||||
await confirmButton.click();
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
get segmentationHydration() {
|
||||
const noButton = page.getByTestId('no-hydrate-btn');
|
||||
const yesButton = page.getByTestId('yes-hydrate-btn');
|
||||
return {
|
||||
locator: page.getByTestId('viewport-notification'),
|
||||
no: {
|
||||
button: noButton,
|
||||
click: async () => {
|
||||
await noButton.click();
|
||||
},
|
||||
},
|
||||
yes: {
|
||||
button: yesButton,
|
||||
click: async () => {
|
||||
await yesButton.click();
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
async getModalityLoadBadgeCount() {
|
||||
return await page.locator('css=div[data-cy^="ModalityLoadBadge-"]').count();
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
29
tests/pages/DataOverlayPageObject.ts
Normal file
29
tests/pages/DataOverlayPageObject.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { Page } from '@playwright/test';
|
||||
|
||||
export class DataOverlayPageObject {
|
||||
readonly page: Page;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
async toggle(viewportId: string = 'default') {
|
||||
await this.page.getByTestId(`dataOverlayMenu-${viewportId}-btn`).click();
|
||||
}
|
||||
|
||||
async addSegmentation(segmentation: string, viewportId: string = 'default') {
|
||||
await this.page.getByTestId(`AddSegmentationDataOverlay-${viewportId}`).click();
|
||||
await this.page.getByText('SELECT A SEGMENTATION').click();
|
||||
await this.page.getByTestId(segmentation).click();
|
||||
}
|
||||
|
||||
async changeSegmentation(from: string, to: string) {
|
||||
await this.page.getByTestId(`overlay-ds-select-value-${from.toUpperCase()}`).click();
|
||||
await this.page.getByTestId(`${to}-SEG`).click();
|
||||
}
|
||||
|
||||
async remove(segmentation: string) {
|
||||
await this.page.getByTestId(`overlay-ds-more-button-${segmentation}`).click();
|
||||
await this.page.getByTestId(`overlay-ds-remove-button-${segmentation}`).click();
|
||||
}
|
||||
}
|
||||
35
tests/pages/LeftPanelPageObject.ts
Normal file
35
tests/pages/LeftPanelPageObject.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { Page } from '@playwright/test';
|
||||
|
||||
export class LeftPanelPageObject {
|
||||
readonly page: Page;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
async toggle() {
|
||||
await this.page.getByTestId('side-panel-header-left').click();
|
||||
}
|
||||
|
||||
get thumbnails() {
|
||||
return this.page.locator('[data-cy^="study-browser-thumbnail"]');
|
||||
}
|
||||
|
||||
async loadSeriesByModality(modality: string, nth: number = 0) {
|
||||
const matchingThumbnail = this.thumbnails
|
||||
.filter({
|
||||
has: this.page.locator('[data-cy="series-modality-label"]', { hasText: modality }),
|
||||
})
|
||||
.nth(nth);
|
||||
await matchingThumbnail.dblclick();
|
||||
}
|
||||
|
||||
async loadSeriesByDescription(description: string, nth: number = 0) {
|
||||
const matchingThumbnail = this.thumbnails
|
||||
.filter({
|
||||
has: this.page.locator('[data-cy="series-description-label"]', { hasText: description }),
|
||||
})
|
||||
.nth(nth);
|
||||
await matchingThumbnail.dblclick();
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,15 @@ export class MainToolbarPageObject {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
get crosshairs() {
|
||||
const button = this.page.getByTestId('Crosshairs');
|
||||
return {
|
||||
button,
|
||||
async click() {
|
||||
await button.click();
|
||||
},
|
||||
};
|
||||
}
|
||||
get layoutSelection() {
|
||||
const page = this.page;
|
||||
|
||||
@ -96,6 +105,15 @@ export class MainToolbarPageObject {
|
||||
|
||||
return {
|
||||
...measurementTools,
|
||||
get selectedTool() {
|
||||
const button = page.getByTestId('MeasurementTools-split-button-primary');
|
||||
return {
|
||||
button,
|
||||
async click() {
|
||||
await button.click();
|
||||
},
|
||||
};
|
||||
},
|
||||
get arrowAnnotate() {
|
||||
const button = page.getByTestId('ArrowAnnotate');
|
||||
return {
|
||||
|
||||
271
tests/pages/RightPanelPageObject.ts
Normal file
271
tests/pages/RightPanelPageObject.ts
Normal file
@ -0,0 +1,271 @@
|
||||
import { Locator, Page } from '@playwright/test';
|
||||
|
||||
import { DOMOverlayPageObject } from './DOMOverlayPageObject';
|
||||
|
||||
export class RightPanelPageObject {
|
||||
readonly page: Page;
|
||||
private readonly DOMOverlayPageObject: DOMOverlayPageObject;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.DOMOverlayPageObject = new DOMOverlayPageObject(page);
|
||||
}
|
||||
|
||||
private getActionsMenu(row: Locator) {
|
||||
const actionsButton = row.getByTestId('actionsMenuTrigger');
|
||||
|
||||
return {
|
||||
button: actionsButton,
|
||||
click: async () => {
|
||||
await actionsButton.click();
|
||||
},
|
||||
delete: async () => {
|
||||
await actionsButton.click();
|
||||
await this.page.getByTestId('Delete').click();
|
||||
},
|
||||
toggleLock: async () => {
|
||||
await actionsButton.click();
|
||||
await this.page.getByTestId('LockToggle').click();
|
||||
},
|
||||
unlock: async () => {
|
||||
await actionsButton.click();
|
||||
await this.page.getByTestId('Unlock').click();
|
||||
},
|
||||
rename: async (text: string) => {
|
||||
await actionsButton.click();
|
||||
await this.page.getByTestId('Rename').click();
|
||||
await this.DOMOverlayPageObject.dialog.input.fillAndSave(text);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private getPanelRowDataObject(row: Locator) {
|
||||
const getActionsMenu = (row: Locator) => this.getActionsMenu.bind(this)(row);
|
||||
|
||||
return {
|
||||
get actions() {
|
||||
return getActionsMenu(row);
|
||||
},
|
||||
click: async () => {
|
||||
await row.click();
|
||||
},
|
||||
locator: row,
|
||||
toggleVisibility: async () => {
|
||||
await row.getByTestId('data-row-visibility-toggle').click();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private getPanelRowByIdx(index: number) {
|
||||
const row = this.page.getByTestId('data-row').nth(index);
|
||||
return this.getPanelRowDataObject(row);
|
||||
}
|
||||
|
||||
private getPanelRowByText(text: string) {
|
||||
const row = this.page.getByTestId('data-row').filter({ hasText: text });
|
||||
return this.getPanelRowDataObject(row);
|
||||
}
|
||||
|
||||
async toggle() {
|
||||
await this.page.getByTestId('side-panel-header-right').click();
|
||||
}
|
||||
|
||||
get measurementsPanel() {
|
||||
const page = this.page;
|
||||
const getMeasurementByIdx = (index: number) => this.getPanelRowByIdx(index);
|
||||
const getMeasurementByText = (text: string) => this.getPanelRowByText(text);
|
||||
const menuButton = page.getByTestId('trackedMeasurements-btn');
|
||||
|
||||
return {
|
||||
menuButton,
|
||||
panel: {
|
||||
deleteAll: async () => {
|
||||
await page.getByRole('button', { name: 'Delete' }).click();
|
||||
},
|
||||
getMeasurementCount: async () => {
|
||||
return await page.getByTestId('data-row').count();
|
||||
},
|
||||
locator: page.getByTestId('trackedMeasurements-panel').last(),
|
||||
nthMeasurement(index: number) {
|
||||
return getMeasurementByIdx(index);
|
||||
},
|
||||
measurementByText(text: string) {
|
||||
return getMeasurementByText(text);
|
||||
},
|
||||
},
|
||||
select: async () => {
|
||||
await menuButton.click();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private get addSegmentationButton() {
|
||||
const button = this.page.getByTestId('addSegmentation');
|
||||
return {
|
||||
button,
|
||||
click: async () => {
|
||||
await button.click();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private get segmentationPanel() {
|
||||
const page = this.page;
|
||||
const getSegmentationByIdx = (index: number) => this.getPanelRowByIdx(index);
|
||||
const getSegmentationByText = (text: string) => this.getPanelRowByText(text);
|
||||
|
||||
return {
|
||||
getSegmentationCount: async () => {
|
||||
return await page.getByTestId('data-row').count();
|
||||
},
|
||||
// No data-cy exists in this panel, using Segmentation header button
|
||||
locator: page.getByRole('button', { name: 'Segmentations' }),
|
||||
nthSegmentation(index: number) {
|
||||
return getSegmentationByIdx(index);
|
||||
},
|
||||
segmentationByText(text: string) {
|
||||
return getSegmentationByText(text);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
get contourSegmentationPanel() {
|
||||
const page = this.page;
|
||||
const addSegmentationButton = this.addSegmentationButton;
|
||||
const panel = this.segmentationPanel;
|
||||
const menuButton = page.getByTestId('panelSegmentationWithToolsContour-btn');
|
||||
|
||||
return {
|
||||
addSegmentationButton,
|
||||
menuButton,
|
||||
panel,
|
||||
select: async () => {
|
||||
await menuButton.click();
|
||||
},
|
||||
};
|
||||
}
|
||||
get labelMapSegmentationPanel() {
|
||||
const page = this.page;
|
||||
const addSegmentationButton = this.addSegmentationButton;
|
||||
const panel = this.segmentationPanel;
|
||||
const menuButton = page.getByTestId('panelSegmentationWithToolsLabelMap-btn');
|
||||
|
||||
return {
|
||||
addSegmentationButton,
|
||||
menuButton,
|
||||
panel,
|
||||
select: async () => {
|
||||
await menuButton.click();
|
||||
},
|
||||
tools: {
|
||||
get brush() {
|
||||
const button = page.getByTestId('Brush-btn');
|
||||
const input = page.locator(`css=div[data-cy="brush-radius"] input`);
|
||||
return {
|
||||
button,
|
||||
input,
|
||||
click: async () => {
|
||||
await button.click();
|
||||
},
|
||||
setRadius: async (radius: number) => {
|
||||
await input.fill(radius.toString());
|
||||
},
|
||||
};
|
||||
},
|
||||
get eraser() {
|
||||
const button = page.getByTestId('Eraser-btn');
|
||||
const input = page.locator(`css=div[data-cy="eraser-radius"] input`);
|
||||
return {
|
||||
button,
|
||||
input,
|
||||
click: async () => {
|
||||
await button.click();
|
||||
},
|
||||
setRadius: async (radius: number) => {
|
||||
await input.fill(radius.toString());
|
||||
},
|
||||
};
|
||||
},
|
||||
get threshold() {
|
||||
const button = page.getByTestId('Threshold-btn');
|
||||
const input = page.locator(`css=div[data-cy="threshold-radius"] input`);
|
||||
return {
|
||||
button,
|
||||
input,
|
||||
click: async () => {
|
||||
await button.click();
|
||||
},
|
||||
setRadius: async (radius: number) => {
|
||||
await input.fill(radius.toString());
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
get noToolsSegmentationPanel() {
|
||||
const page = this.page;
|
||||
const panel = this.segmentationPanel;
|
||||
const menuButton = page.getByTestId(/^panelSegmentation.*-btn$/).first();
|
||||
|
||||
return {
|
||||
menuButton,
|
||||
panel,
|
||||
select: async () => {
|
||||
await menuButton.click();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
get tmtvPanel() {
|
||||
const page = this.page;
|
||||
|
||||
return {
|
||||
get addSegmentationButton() {
|
||||
const button = page.getByTestId('addSegmentation');
|
||||
return {
|
||||
button,
|
||||
click: async () => {
|
||||
await button.click();
|
||||
},
|
||||
};
|
||||
},
|
||||
async exportTmtvCsvReport() {
|
||||
await page.getByTestId('exportTmtvCsvReport').click();
|
||||
},
|
||||
tools: {
|
||||
get brush() {
|
||||
const button = page.getByTestId('Brush-btn');
|
||||
const input = page.locator(`css=div[data-cy="brush-radius"] input`);
|
||||
return {
|
||||
button,
|
||||
input,
|
||||
click: async () => {
|
||||
await button.click();
|
||||
},
|
||||
setRadius: async (radius: number) => {
|
||||
await input.fill(radius.toString());
|
||||
},
|
||||
};
|
||||
},
|
||||
get rectangleROIThreshold() {
|
||||
const button = page.getByTestId('RectangleROIStartEndThreshold-btn');
|
||||
const input = page.getByTestId('percentage-of-max-suv-input');
|
||||
return {
|
||||
button,
|
||||
click: async () => {
|
||||
await button.click();
|
||||
},
|
||||
getPercentageOfMaxSUV: async () => {
|
||||
return await input.inputValue();
|
||||
},
|
||||
setPercentageOfMaxSUV: async (percentage: string) => {
|
||||
await input.fill(percentage);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,13 @@
|
||||
import { Locator, Page } from '@playwright/test';
|
||||
import {
|
||||
getMousePosition,
|
||||
simulateClicksOnElement,
|
||||
simulateDoubleClickOnElement,
|
||||
simulateNormalizedClicksOnElement,
|
||||
simulateNormalizedDragOnElement,
|
||||
} from '../utils';
|
||||
import { DataOverlayPageObject } from './DataOverlayPageObject';
|
||||
import { DOMOverlayPageObject } from './DOMOverlayPageObject';
|
||||
|
||||
type SvgInnerElement = 'circle' | 'path' | 'd';
|
||||
|
||||
@ -15,11 +18,18 @@ type NormalizedDragParams = {
|
||||
};
|
||||
|
||||
export interface IViewportPageObject {
|
||||
doubleClickAt: (point: { x: number; y: number }) => Promise<void>;
|
||||
nthAnnotation(nth: number): {
|
||||
locator: Locator;
|
||||
click: () => Promise<void>;
|
||||
contextMenu: {
|
||||
open: () => Promise<void>;
|
||||
};
|
||||
};
|
||||
clickAt: (
|
||||
points: { x: number; y: number }[],
|
||||
button?: 'left' | 'right' | 'middle'
|
||||
) => Promise<void>;
|
||||
doubleClickAt: (point: { x: number; y: number }) => Promise<void>;
|
||||
normalizedClickAt: (
|
||||
normalizedPoints: { x: number; y: number }[],
|
||||
button?: 'left' | 'right' | 'middle'
|
||||
@ -38,10 +48,7 @@ export interface IViewportPageObject {
|
||||
bottomRight: Locator;
|
||||
};
|
||||
overlayMenu: {
|
||||
dataOverlay: {
|
||||
button: Locator;
|
||||
click: () => Promise<void>;
|
||||
};
|
||||
dataOverlay: DataOverlayPageObject;
|
||||
orientation: {
|
||||
button: Locator;
|
||||
click: () => Promise<void>;
|
||||
@ -57,9 +64,29 @@ export interface IViewportPageObject {
|
||||
|
||||
export class ViewportPageObject {
|
||||
readonly page: Page;
|
||||
private readonly dataOverlayPageObject: DataOverlayPageObject;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.dataOverlayPageObject = new DataOverlayPageObject(page);
|
||||
}
|
||||
|
||||
private getAnnotation(viewport: Locator, nth: number) {
|
||||
const page = this.page;
|
||||
const domOverlayPageObject = new DOMOverlayPageObject(page);
|
||||
const annotation = viewport.locator('g[data-annotation-uid]').nth(nth);
|
||||
|
||||
return {
|
||||
locator: annotation,
|
||||
click: async () => {
|
||||
await annotation.click();
|
||||
},
|
||||
contextMenu: {
|
||||
open: async () => {
|
||||
await domOverlayPageObject.viewport.annotationContextMenu.open(annotation);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private getOrientationMarkers(viewport: Locator) {
|
||||
@ -82,15 +109,7 @@ export class ViewportPageObject {
|
||||
|
||||
private getOverlayMenu(viewport: Locator) {
|
||||
return {
|
||||
get dataOverlay() {
|
||||
const button = viewport.locator('[data-cy^="dataOverlayMenu"]').first();
|
||||
return {
|
||||
button,
|
||||
async click() {
|
||||
await button.click();
|
||||
},
|
||||
};
|
||||
},
|
||||
dataOverlay: this.dataOverlayPageObject,
|
||||
get orientation() {
|
||||
const button = viewport.locator('[data-cy^="orientationMenu"]');
|
||||
return {
|
||||
@ -118,6 +137,7 @@ export class ViewportPageObject {
|
||||
|
||||
private viewportPageObjectFactory(viewport: Locator): IViewportPageObject {
|
||||
return {
|
||||
nthAnnotation: (nth: number) => this.getAnnotation(viewport, nth),
|
||||
doubleClickAt: async (point: { x: number; y: number }) => {
|
||||
await simulateDoubleClickOnElement({
|
||||
locator: viewport,
|
||||
@ -166,6 +186,70 @@ export class ViewportPageObject {
|
||||
return this.viewportPageObjectFactory(viewport);
|
||||
}
|
||||
|
||||
get crosshairs() {
|
||||
const page = this.page;
|
||||
|
||||
async function increaseSlabThickness(locator: Locator, lineNumber: number, axis: string) {
|
||||
const lineLocator = locator.locator('line').nth(lineNumber);
|
||||
await lineLocator.click({ force: true });
|
||||
await lineLocator.hover({ force: true });
|
||||
|
||||
const circleLocator = locator.locator('rect').first();
|
||||
await circleLocator.hover({ force: true });
|
||||
|
||||
await page.mouse.down();
|
||||
|
||||
const position = await getMousePosition(page);
|
||||
switch (axis) {
|
||||
case 'x':
|
||||
await page.mouse.move(position.x + 100, position.y);
|
||||
break;
|
||||
case 'y':
|
||||
await page.mouse.move(position.x, position.y + 100);
|
||||
break;
|
||||
}
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
async function rotateCrosshairs(locator: Locator, lineNumber: number) {
|
||||
const lineLocator = locator.locator('line').nth(lineNumber);
|
||||
await lineLocator.click({ force: true });
|
||||
await lineLocator.hover({ force: true });
|
||||
|
||||
const circleLocator = locator.locator('circle').nth(1);
|
||||
await circleLocator.hover({ force: true });
|
||||
|
||||
await page.mouse.down();
|
||||
|
||||
const position = await getMousePosition(page);
|
||||
await page.mouse.move(position.x, position.y + 100);
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
function crosshairsFactory(
|
||||
locator: Locator,
|
||||
increaseLineNumber: number,
|
||||
increaseAxis: 'x' | 'y',
|
||||
rotateLineNumber: number
|
||||
) {
|
||||
return {
|
||||
increase: async () => {
|
||||
await increaseSlabThickness(locator, increaseLineNumber, increaseAxis);
|
||||
},
|
||||
locator,
|
||||
rotate: () => {
|
||||
return rotateCrosshairs(locator, rotateLineNumber);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
axial: crosshairsFactory(page.locator('#svg-layer-mpr-axial'), 0, 'x', 3),
|
||||
sagittal: crosshairsFactory(page.locator('#svg-layer-mpr-sagittal'), 2, 'x', 0),
|
||||
coronal: crosshairsFactory(page.locator('#svg-layer-mpr-coronal'), 0, 'y', 0),
|
||||
};
|
||||
}
|
||||
|
||||
async getAll(): Promise<IViewportPageObject[]> {
|
||||
const viewports = await this.page.getByTestId('viewport-pane').all();
|
||||
return viewports.map(viewport => this.viewportPageObjectFactory(viewport));
|
||||
|
||||
@ -1,4 +1,13 @@
|
||||
import { DOMOverlayPageObject } from './DOMOverlayPageObject';
|
||||
import { MainToolbarPageObject } from './MainToolbarPageObject';
|
||||
import { LeftPanelPageObject } from './LeftPanelPageObject';
|
||||
import { RightPanelPageObject } from './RightPanelPageObject';
|
||||
import { ViewportPageObject } from './ViewportPageObject';
|
||||
|
||||
export { MainToolbarPageObject, ViewportPageObject };
|
||||
export {
|
||||
DOMOverlayPageObject,
|
||||
MainToolbarPageObject,
|
||||
LeftPanelPageObject,
|
||||
RightPanelPageObject,
|
||||
ViewportPageObject,
|
||||
};
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { type Page, expect } from '@playwright/test';
|
||||
|
||||
import { MainToolbarPageObject, ViewportPageObject } from '../pages';
|
||||
|
||||
/**
|
||||
* Defines the optional parameters for the addLengthMeasurement function.
|
||||
*/
|
||||
@ -22,13 +24,16 @@ export async function addLengthMeasurement(
|
||||
page: Page,
|
||||
options: AddLengthMeasurementOptions = {}
|
||||
): Promise<void> {
|
||||
const mainToolbarPageObject = new MainToolbarPageObject(page);
|
||||
const viewportPageObject = new ViewportPageObject(page);
|
||||
|
||||
// Set default values for the click coordinates
|
||||
const { firstClick = [150, 100], secondClick = [130, 170] } = options;
|
||||
const [x1, y1] = firstClick;
|
||||
const [x2, y2] = secondClick;
|
||||
|
||||
const lengthButton = page.getByTestId('MeasurementTools-split-button-primary');
|
||||
const viewport = page.locator('.cornerstone-viewport-element').first();
|
||||
const lengthButton = mainToolbarPageObject.measurementTools.selectedTool.button;
|
||||
const viewport = viewportPageObject.active;
|
||||
|
||||
// Assert that the primary measurement button is 'Length' tool
|
||||
await expect(lengthButton).toHaveAttribute('data-tool', 'Length');
|
||||
@ -43,10 +48,10 @@ export async function addLengthMeasurement(
|
||||
await expect(lengthButton).toHaveAttribute('data-active', 'true');
|
||||
|
||||
// Perform the two clicks on the viewport canvas to draw the line
|
||||
await viewport.click({ position: { x: x1, y: y1 } });
|
||||
await viewport.clickAt([{ x: x1, y: y1 }]);
|
||||
|
||||
// Delay to allow canvas actions to finish/update
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
await viewport.click({ position: { x: x2, y: y2 } });
|
||||
await viewport.clickAt([{ x: x2, y: y2 }]);
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { Page } from '@playwright/test';
|
||||
import { expect } from 'playwright-test-coverage';
|
||||
|
||||
import { DOMOverlayPageObject } from '../pages';
|
||||
|
||||
/**
|
||||
* Asserts the number of Modality Load Badges present on the page.
|
||||
*/
|
||||
@ -11,5 +13,8 @@ export async function assertNumberOfModalityLoadBadges({
|
||||
page: Page;
|
||||
expectedCount: number;
|
||||
}) {
|
||||
await expect(page.locator('css=div[data-cy^="ModalityLoadBadge-"]')).toHaveCount(expectedCount);
|
||||
const domOverlayPageObject = new DOMOverlayPageObject(page);
|
||||
const count = await domOverlayPageObject.viewport.getModalityLoadBadgeCount();
|
||||
|
||||
expect(count).toBe(expectedCount);
|
||||
}
|
||||
|
||||
@ -1,15 +1,33 @@
|
||||
import { test as base } from 'playwright-test-coverage';
|
||||
import { MainToolbarPageObject, ViewportPageObject } from '../pages';
|
||||
import {
|
||||
DOMOverlayPageObject,
|
||||
MainToolbarPageObject,
|
||||
LeftPanelPageObject,
|
||||
RightPanelPageObject,
|
||||
ViewportPageObject,
|
||||
} from '../pages';
|
||||
|
||||
type PageObjects = {
|
||||
DOMOverlayPageObject: DOMOverlayPageObject;
|
||||
mainToolbarPageObject: MainToolbarPageObject;
|
||||
leftPanelPageObject: LeftPanelPageObject;
|
||||
rightPanelPageObject: RightPanelPageObject;
|
||||
viewportPageObject: ViewportPageObject;
|
||||
};
|
||||
|
||||
export const test = base.extend<PageObjects>({
|
||||
DOMOverlayPageObject: async ({ page }, use) => {
|
||||
await use(new DOMOverlayPageObject(page));
|
||||
},
|
||||
mainToolbarPageObject: async ({ page }, use) => {
|
||||
await use(new MainToolbarPageObject(page));
|
||||
},
|
||||
leftPanelPageObject: async ({ page }, use) => {
|
||||
await use(new LeftPanelPageObject(page));
|
||||
},
|
||||
rightPanelPageObject: async ({ page }, use) => {
|
||||
await use(new RightPanelPageObject(page));
|
||||
},
|
||||
viewportPageObject: async ({ page }, use) => {
|
||||
await use(new ViewportPageObject(page));
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user