tests(Playwright): Introduction of Page Object Models (POMs) to Playwright tests (#5557)

This commit is contained in:
Vinícius Alves de Faria Resende 2025-11-20 11:29:14 -03:00 committed by GitHub
parent 1c991037ee
commit bdad2264ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
59 changed files with 1040 additions and 756 deletions

View File

@ -273,6 +273,7 @@ function ViewerViewportGrid(props: withAppTypes) {
>
<div
data-cy="viewport-pane"
data-is-active={isActive}
className="flex h-full w-full min-w-[5px] flex-col"
>
<ViewportComponent

View File

@ -1,10 +1,10 @@
import { test } from 'playwright-test-coverage';
import {
visitStudy,
checkForScreenshot,
screenShotPaths,
reduce3DViewportSize,
attemptAction,
checkForScreenshot,
reduce3DViewportSize,
screenShotPaths,
test,
visitStudy,
} from './utils';
test.beforeEach(async ({ page }) => {
@ -14,13 +14,8 @@ test.beforeEach(async ({ page }) => {
});
test.describe('3D four up Test', async () => {
test('should render 3D four up correctly.', async ({ page }) => {
await page.getByTestId('Layout').click();
await page
.locator('div')
.filter({ hasText: /^3D four up$/ })
.first()
.click();
test('should render 3D four up correctly.', async ({ page, mainToolbarPageObject }) => {
await mainToolbarPageObject.layoutSelection.threeDFourUp.click();
await attemptAction(() => reduce3DViewportSize(page), 10, 100);

View File

@ -1,10 +1,10 @@
import { test } from 'playwright-test-coverage';
import {
visitStudy,
checkForScreenshot,
screenShotPaths,
reduce3DViewportSize,
attemptAction,
checkForScreenshot,
reduce3DViewportSize,
screenShotPaths,
test,
visitStudy,
} from './utils';
test.beforeEach(async ({ page }) => {
@ -14,13 +14,8 @@ test.beforeEach(async ({ page }) => {
});
test.describe('3D main Test', async () => {
test('should render 3D main correctly.', async ({ page }) => {
await page.getByTestId('Layout').click();
await page
.locator('div')
.filter({ hasText: /^3D main$/ })
.first()
.click();
test('should render 3D main correctly.', async ({ page, mainToolbarPageObject }) => {
await mainToolbarPageObject.layoutSelection.threeDMain.click();
await attemptAction(() => reduce3DViewportSize(page), 10, 100);
await page.waitForTimeout(5000);
await checkForScreenshot(page, page, screenShotPaths.threeDMain.threeDMainDisplayedCorrectly);

View File

@ -1,10 +1,10 @@
import { test } from 'playwright-test-coverage';
import {
visitStudy,
checkForScreenshot,
screenShotPaths,
reduce3DViewportSize,
attemptAction,
checkForScreenshot,
reduce3DViewportSize,
screenShotPaths,
test,
visitStudy,
} from './utils';
test.beforeEach(async ({ page }) => {
@ -14,13 +14,8 @@ test.beforeEach(async ({ page }) => {
});
test.describe('3D only Test', async () => {
test('should render 3D only correctly.', async ({ page }) => {
await page.getByTestId('Layout').click();
await page
.locator('div')
.filter({ hasText: /^3D only$/ })
.first()
.click();
test('should render 3D only correctly.', async ({ page, mainToolbarPageObject }) => {
await mainToolbarPageObject.layoutSelection.threeDOnly.click();
await attemptAction(() => reduce3DViewportSize(page), 10, 100);
await page.waitForTimeout(5000);
// Use a 4 percent diff pixel ratio to account for slight color differences in the 3D viewport

View File

@ -1,10 +1,10 @@
import { test } from 'playwright-test-coverage';
import {
visitStudy,
checkForScreenshot,
screenShotPaths,
reduce3DViewportSize,
attemptAction,
checkForScreenshot,
reduce3DViewportSize,
screenShotPaths,
test,
visitStudy,
} from './utils';
test.beforeEach(async ({ page }) => {
@ -14,13 +14,8 @@ test.beforeEach(async ({ page }) => {
});
test.describe('3D primary Test', async () => {
test('should render 3D primary correctly.', async ({ page }) => {
await page.getByTestId('Layout').click();
await page
.locator('div')
.filter({ hasText: /^3D primary$/ })
.first()
.click();
test('should render 3D primary correctly.', async ({ page, mainToolbarPageObject }) => {
await mainToolbarPageObject.layoutSelection.threeDPrimary.click();
await attemptAction(() => reduce3DViewportSize(page), 10, 100);
await page.waitForTimeout(5000);

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -7,27 +6,17 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should display the angle tool', async ({ page }) => {
await page.getByTestId('MoreTools-split-button-secondary').click();
await page.getByTestId('Angle').click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateClicksOnElement({
locator,
points: [
{
x: 550,
y: 200,
},
{
x: 450,
y: 250,
},
{
x: 550,
y: 300,
},
],
});
test('should display the angle tool', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.moreTools.angle.click();
await viewportPageObject.active.clickAt([
{ x: 550, y: 200 },
{ x: 450, y: 250 },
{ x: 550, y: 300 },
]);
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
await checkForScreenshot(page, page, screenShotPaths.angle.angleDisplayedCorrectly);
});

View File

@ -1,11 +1,4 @@
import { test } from 'playwright-test-coverage';
import {
visitStudy,
checkForScreenshot,
screenShotPaths,
simulateClicksOnElement,
simulateDoubleClickOnElement,
} from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -13,26 +6,19 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should display the arrow tool and allow free-form text to be entered', async ({ page }) => {
test('should display the arrow tool and allow free-form text to be entered', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await page.getByTestId('trackedMeasurements-btn').click();
await page.getByTestId('MeasurementTools-split-button-secondary').click();
await page.getByTestId('ArrowAnnotate').click();
await mainToolbarPageObject.measurementTools.arrowAnnotate.click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateClicksOnElement({
locator,
points: [
{
x: 164,
y: 234,
},
{
x: 344,
y: 232,
},
],
});
await viewportPageObject.active.clickAt([
{ x: 164, y: 234 },
{ 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();
@ -49,13 +35,7 @@ test('should display the arrow tool and allow free-form text to be entered', asy
// Now edit the arrow text and the label should not change.
await simulateDoubleClickOnElement({
locator,
point: {
x: 164,
y: 234,
},
});
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();

View File

@ -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.1706.8374.643249677828306008300337414785';
@ -8,13 +7,8 @@ test.beforeEach(async ({ page }) => {
});
test.describe('Axial Primary Test', async () => {
test('should render Axial Primary correctly.', async ({ page }) => {
await page.getByTestId('Layout').click();
await page
.locator('div')
.filter({ hasText: /^Axial Primary$/ })
.first()
.click();
test('should render Axial Primary correctly.', async ({ page, mainToolbarPageObject }) => {
await mainToolbarPageObject.layoutSelection.axialPrimary.click();
await checkForScreenshot(
page,
page,

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -7,24 +6,16 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should display the bidirectional tool', async ({ page }) => {
await page.getByTestId('MeasurementTools-split-button-secondary').click();
await page.getByTestId('Bidirectional').click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateClicksOnElement({
locator,
points: [
{
x: 405,
y: 277,
},
{
x: 515,
y: 339,
},
],
});
test('should display the bidirectional tool', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.measurementTools.bidirectional.click();
await viewportPageObject.active.clickAt([
{ x: 405, y: 277 },
{ x: 515, y: 339 },
]);
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
await checkForScreenshot(
page,

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -7,23 +6,16 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should display the circle tool', async ({ page }) => {
await page.getByTestId('MeasurementTools-split-button-secondary').click();
await page.getByTestId('CircleROI').click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateClicksOnElement({
locator,
points: [
{
x: 480,
y: 205,
},
{
x: 488,
y: 247,
},
],
});
test('should display the circle tool', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.measurementTools.circleROI.click();
await viewportPageObject.active.clickAt([
{ x: 480, y: 205 },
{ x: 488, y: 247 },
]);
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
await checkForScreenshot(page, page, screenShotPaths.circle.circleDisplayedCorrectly);
});

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -7,31 +6,18 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should display the cobb angle tool', async ({ page }) => {
await page.getByTestId('MoreTools-split-button-secondary').click();
await page.getByTestId('CobbAngle').click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateClicksOnElement({
locator,
points: [
{
x: 515,
y: 212,
},
{
x: 616,
y: 207,
},
{
x: 527,
y: 293,
},
{
x: 625,
y: 291,
},
],
});
test('should display the cobb angle tool', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.moreTools.cobbAngle.click();
await viewportPageObject.active.clickAt([
{ x: 515, y: 212 },
{ x: 616, y: 207 },
{ x: 527, y: 293 },
{ x: 625, y: 291 },
]);
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
await checkForScreenshot(page, page, screenShotPaths.cobbangle.cobbangleDisplayedCorrectly);
});

View File

@ -1,11 +1,4 @@
import { test } from 'playwright-test-coverage';
import {
visitStudy,
checkForScreenshot,
screenShotPaths,
simulateNormalizedClicksOnElement,
simulateNormalizedClickOnElement,
} from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -15,36 +8,20 @@ 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,
mainToolbarPageObject,
viewportPageObject,
}) => {
await page.getByTestId('MeasurementTools-split-button-secondary').click();
await page.locator('css=div[data-cy="Length"]').click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateNormalizedClicksOnElement({
locator,
normalizedPoints: [
{
x: 0.45,
y: 0.98,
},
{
x: 0.55,
y: 0.98,
},
],
});
await mainToolbarPageObject.measurementTools.length.click();
await viewportPageObject.active.normalizedClickAt([
{ x: 0.45, y: 0.98 },
{ x: 0.55, y: 0.98 },
]);
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
await checkForScreenshot(page, page, screenShotPaths.contextMenu.preContextMenuNearBottomEdge);
await simulateNormalizedClickOnElement({
locator,
normalizedPoint: {
x: 0.55,
y: 0.98,
},
button: 'right',
});
await viewportPageObject.active.normalizedClickAt([{ x: 0.55, y: 0.98 }], 'right');
await checkForScreenshot({
page,

View File

@ -1,11 +1,12 @@
import { test, expect } from 'playwright-test-coverage';
import { visitStudy } from './utils';
import { viewportSVGPathLocator } from './utils/locators';
import { expect, test, visitStudy } from './utils';
import { simulateNormalizedDragOnElement } from './utils/simulateDragOnElement';
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 }) => {
test('should not allow contours to be edited in basic viewer mode', async ({
page,
viewportPageObject,
}) => {
const mode = 'viewer';
await visitStudy(page, studyInstanceUID, mode, 2000);
@ -19,7 +20,7 @@ test('should not allow contours to be edited in basic viewer mode', async ({ pag
// Wait for the segmentation to hydrate.
await page.waitForTimeout(5000);
const svgPathLocatorPreEdit = viewportSVGPathLocator({ page, viewportId: 'default' });
const svgPathLocatorPreEdit = viewportPageObject.getById('default').svg();
expect(
await svgPathLocatorPreEdit.count(),
@ -35,7 +36,7 @@ test('should not allow contours to be edited in basic viewer mode', async ({ pag
end: { x: 0.1, y: -0.2 },
});
const svgPathLocatorPostEdit = viewportSVGPathLocator({ page, viewportId: 'default' });
const svgPathLocatorPostEdit = viewportPageObject.getById('default').svg();
expect(
await svgPathLocatorPostEdit.getAttribute('d'),
@ -45,6 +46,7 @@ test('should not allow contours to be edited in basic viewer mode', async ({ pag
test('should not allow contours to be edited when panelSegmentation.disableEditing is true', async ({
page,
viewportPageObject,
}) => {
const mode = 'segmentation';
await visitStudy(page, studyInstanceUID, mode, 2000);
@ -69,7 +71,7 @@ test('should not allow contours to be edited when panelSegmentation.disableEditi
// Wait for the segmentation to hydrate.
await page.waitForTimeout(5000);
const svgPathLocatorPreEdit = viewportSVGPathLocator({ page, viewportId: 'default' });
const svgPathLocatorPreEdit = viewportPageObject.getById('default').svg();
expect(
await svgPathLocatorPreEdit.count(),
@ -85,7 +87,7 @@ test('should not allow contours to be edited when panelSegmentation.disableEditi
end: { x: 0.1, y: -0.2 },
});
const svgPathLocatorPostEdit = viewportSVGPathLocator({ page, viewportId: 'default' });
const svgPathLocatorPostEdit = viewportPageObject.getById('default').svg();
expect(
await svgPathLocatorPostEdit.getAttribute('d'),
@ -95,6 +97,7 @@ 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,
viewportPageObject,
}) => {
const mode = 'segmentation';
await visitStudy(page, studyInstanceUID, mode, 2000);
@ -119,7 +122,7 @@ test('should allow contours to be edited when panelSegmentation.disableEditing i
// Wait for the segmentation to hydrate.
await page.waitForTimeout(5000);
const svgPathLocatorPreEdit = viewportSVGPathLocator({ page, viewportId: 'default' });
const svgPathLocatorPreEdit = viewportPageObject.getById('default').svg('path');
expect(
await svgPathLocatorPreEdit.count(),
@ -135,7 +138,7 @@ test('should allow contours to be edited when panelSegmentation.disableEditing i
end: { x: 0.1, y: -0.2 },
});
const svgPathLocatorPostEdit = viewportSVGPathLocator({ page, viewportId: 'default' });
const svgPathLocatorPostEdit = viewportPageObject.getById('default').svg('path');
expect(
await svgPathLocatorPostEdit.getAttribute('d'),

View File

@ -1,17 +1,18 @@
import { Page, test } from 'playwright-test-coverage';
import { Page } from '@playwright/test';
import {
visitStudy,
checkForScreenshot,
screenShotPaths,
initializeMousePositionTracker,
getMousePosition,
initializeMousePositionTracker,
screenShotPaths,
test,
visitStudy,
} from './utils/index.js';
const rotateCrosshairs = async (page: Page, id: string, lineNumber: number) => {
const locator = await page.locator(id).locator('line').nth(lineNumber);
const locator = page.locator(id).locator('line').nth(lineNumber);
await locator.click({ force: true });
await locator.hover({ force: true });
const circleLocator = await page.locator(id).locator('circle').nth(1);
const circleLocator = page.locator(id).locator('circle').nth(1);
await circleLocator.hover({ force: true });
await page.mouse.down();
const position = await getMousePosition(page);
@ -20,10 +21,10 @@ const rotateCrosshairs = async (page: Page, id: string, lineNumber: number) => {
};
const increaseSlabThickness = async (page: Page, id: string, lineNumber: number, axis: string) => {
const locator = await page.locator(id).locator('line').nth(lineNumber);
const locator = page.locator(id).locator('line').nth(lineNumber);
await locator.click({ force: true });
await locator.hover({ force: true });
const circleLocator = await page.locator(id).locator('rect').first();
const circleLocator = page.locator(id).locator('rect').first();
await circleLocator.hover({ force: true });
await page.mouse.down();
const position = await getMousePosition(page);
@ -46,17 +47,18 @@ test.beforeEach(async ({ page }) => {
});
test.describe('Crosshairs Test', async () => {
test('should render the crosshairs correctly.', async ({ page }) => {
await page.getByTestId('Layout').click();
await page.locator('div').filter({ hasText: /^MPR$/ }).first().click();
test('should render the crosshairs correctly.', async ({ page, mainToolbarPageObject }) => {
await mainToolbarPageObject.layoutSelection.MPR.click();
await page.getByTestId('Crosshairs').click();
await checkForScreenshot(page, page, screenShotPaths.crosshairs.crosshairsRendered);
});
test('should allow the user to rotate the crosshairs', async ({ page }) => {
await page.getByTestId('Layout').click();
await page.locator('div').filter({ hasText: /^MPR$/ }).first().click();
test('should allow the user to rotate the crosshairs', async ({
page,
mainToolbarPageObject,
}) => {
await mainToolbarPageObject.layoutSelection.MPR.click();
await page.getByTestId('Crosshairs').click();
await rotateCrosshairs(page, '#svg-layer-mpr-axial', 3);
@ -66,9 +68,11 @@ test.describe('Crosshairs Test', async () => {
await checkForScreenshot(page, page, screenShotPaths.crosshairs.crosshairsRotated);
});
test('should allow the user to adjust the slab thickness', async ({ page }) => {
await page.getByTestId('Layout').click();
await page.locator('div').filter({ hasText: /^MPR$/ }).first().click();
test('should allow the user to adjust the slab thickness', async ({
page,
mainToolbarPageObject,
}) => {
await mainToolbarPageObject.layoutSelection.MPR.click();
await page.getByTestId('Crosshairs').click();
await increaseSlabThickness(page, '#svg-layer-mpr-axial', 0, 'x');
@ -80,9 +84,9 @@ test.describe('Crosshairs Test', async () => {
test('should reset the crosshairs to the initial position when reset is clicked', async ({
page,
mainToolbarPageObject,
}) => {
await page.getByTestId('Layout').click();
await page.locator('div').filter({ hasText: /^MPR$/ }).first().click();
await mainToolbarPageObject.layoutSelection.MPR.click();
await page.getByTestId('Crosshairs').click();
await rotateCrosshairs(page, '#svg-layer-mpr-axial', 3);
@ -94,9 +98,11 @@ test.describe('Crosshairs Test', async () => {
await checkForScreenshot(page, page, screenShotPaths.crosshairs.crosshairsResetToolbar);
});
test('should reset the crosshairs when a new displayset is loaded', async ({ page }) => {
await page.getByTestId('Layout').click();
await page.locator('div').filter({ hasText: /^MPR$/ }).first().click();
test('should reset the crosshairs when a new displayset is loaded', async ({
page,
mainToolbarPageObject,
}) => {
await mainToolbarPageObject.layoutSelection.MPR.click();
await page.getByTestId('Crosshairs').click();
await rotateCrosshairs(page, '#svg-layer-mpr-axial', 0);

View File

@ -1,14 +1,16 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import { press } from './utils/keyboardUtils';
test('should display added, selected and removed segmentation promptly', async ({ page }) => {
test('should display added, selected and removed segmentation promptly', async ({
page,
viewportPageObject,
}) => {
const studyInstanceUID = '1.3.6.1.4.1.32722.99.99.239341353911714368772597187099978969331';
const mode = 'segmentation';
await visitStudy(page, studyInstanceUID, mode, 2000);
// Add a segmentation overlay and ensure the overlay menu reflects this change.
await page.getByTestId('dataOverlayMenu-default-btn').click();
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();
@ -22,7 +24,7 @@ test('should display added, selected and removed segmentation promptly', async (
});
// Hide the overlay menu.
await page.getByTestId('dataOverlayMenu-default-btn').click();
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
// navigate to the 51st image and ensure the correct overlay is displayed
await press({ page, key: 'ArrowDown', nTimes: 50 });
@ -35,7 +37,7 @@ test('should display added, selected and removed segmentation promptly', async (
});
// Show the overlay menu.
await page.getByTestId('dataOverlayMenu-default-btn').click();
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
// 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();
@ -49,7 +51,7 @@ test('should display added, selected and removed segmentation promptly', async (
});
// Hide the overlay menu.
await page.getByTestId('dataOverlayMenu-default-btn').click();
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
// navigate to the 51st image and ensure the correct overlay is displayed
await press({ page, key: 'ArrowDown', nTimes: 50 });
@ -62,7 +64,7 @@ test('should display added, selected and removed segmentation promptly', async (
});
// Show the overlay menu.
await page.getByTestId('dataOverlayMenu-default-btn').click();
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
// Remove the segmentation overlay and ensure the overlay menu reflects this change.
await page.getByTestId('overlay-ds-more-button-SEGMENTATION').click();
@ -76,7 +78,7 @@ test('should display added, selected and removed segmentation promptly', async (
});
// Hide the overlay menu.
await page.getByTestId('dataOverlayMenu-default-btn').click();
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
// navigate to the 51st image and ensure no overlay is displayed
await press({ page, key: 'ArrowDown', nTimes: 50 });

View File

@ -1,13 +1,11 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test('should display the dicom tag browser', async ({ page }) => {
test('should display the dicom tag browser', async ({ page, mainToolbarPageObject }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
const mode = 'viewer';
await visitStudy(page, studyInstanceUID, mode, 2000);
await page.getByTestId('MoreTools-split-button-secondary').click();
await page.getByTestId('TagBrowser').click();
await mainToolbarPageObject.moreTools.tagBrowser.click();
await checkForScreenshot(
page,
page,
@ -15,13 +13,15 @@ test('should display the dicom tag browser', async ({ page }) => {
);
});
test('should render the scroll bar with the correct look-and-feel', async ({ page }) => {
test('should render the scroll bar with the correct look-and-feel', async ({
page,
mainToolbarPageObject,
}) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
const mode = 'viewer';
await visitStudy(page, studyInstanceUID, mode, 2000);
await page.getByTestId('MoreTools-split-button-secondary').click();
await page.getByTestId('TagBrowser').click();
await mainToolbarPageObject.moreTools.tagBrowser.click();
await checkForScreenshot({
page,
normalizedClip: { x: 0.77, y: 0.25, width: 0.03, height: 0.75 },

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -7,23 +6,16 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should display the ellipse tool', async ({ page }) => {
await page.getByTestId('MeasurementTools-split-button-secondary').click();
await page.getByTestId('EllipticalROI').click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateClicksOnElement({
locator,
points: [
{
x: 446,
y: 245,
},
{
x: 508,
y: 281,
},
],
});
test('should display the ellipse tool', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.measurementTools.ellipticalROI.click();
await viewportPageObject.active.clickAt([
{ x: 446, y: 245 },
{ x: 508, y: 281 },
]);
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
await checkForScreenshot(page, page, screenShotPaths.ellipse.ellipseDisplayedCorrectly);
});

View File

@ -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 = '2.16.840.1.114362.1.11972228.22789312658.616067305.306.2';
@ -7,9 +6,8 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should flip the image horizontally', async ({ page }) => {
await page.getByTestId('MoreTools-split-button-secondary').click();
await page.getByTestId('flipHorizontal').click();
test('should flip the image horizontally', async ({ page, mainToolbarPageObject }) => {
await mainToolbarPageObject.moreTools.flipHorizontal.click();
await checkForScreenshot(
page,
page,

View File

@ -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.25403.345050719074.3824.20170125095438.5';
@ -7,8 +6,7 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should invert the image', async ({ page }) => {
await page.getByTestId('MoreTools-split-button-secondary').click();
await page.getByTestId('invert').click();
test('should invert the image', async ({ page, mainToolbarPageObject }) => {
await mainToolbarPageObject.moreTools.invert.click();
await checkForScreenshot(page, page, screenShotPaths.invert.invertDisplayedCorrectly);
});

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -7,7 +6,11 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 5000);
});
test('should hydrate in MPR correctly', async ({ page }) => {
test('should hydrate in MPR correctly', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await page.getByTestId('side-panel-header-right').click();
await page.getByTestId('trackedMeasurements-btn').click();
@ -38,23 +41,11 @@ test('should hydrate in MPR correctly', async ({ page }) => {
await page.waitForTimeout(5000);
await page.getByTestId('MeasurementTools-split-button-secondary').click();
await page.getByTestId('Bidirectional').click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateClicksOnElement({
locator,
points: [
{
x: 405,
y: 277,
},
{
x: 515,
y: 339,
},
],
});
await mainToolbarPageObject.measurementTools.bidirectional.click();
await viewportPageObject.active.clickAt([
{ x: 405, y: 277 },
{ x: 515, y: 339 },
]);
// wait 2 seconds
await page.waitForTimeout(2000);
@ -93,8 +84,7 @@ test('should hydrate in MPR correctly', async ({ page }) => {
await checkForScreenshot(page, page, screenShotPaths.jumpToMeasurementMPR.jumpToMeasurementStack);
await page.getByTestId('Layout').click();
await page.locator('div').filter({ hasText: /^MPR$/ }).first().click();
await mainToolbarPageObject.layoutSelection.MPR.click();
// wait 5 seconds
await page.waitForTimeout(5000);

View File

@ -1,8 +1,5 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import { press } from './utils/keyboardUtils';
import { simulateNormalizedDragOnElement } from './utils/simulateDragOnElement';
import { viewportLocator } from './utils/locators';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.256467663913010332776401703474716742458';
@ -12,6 +9,7 @@ test.beforeEach(async ({ page }) => {
test('should prevent editing of label map segmentations when panelSegmentation.disableEditing is true', async ({
page,
viewportPageObject,
}) => {
// disable editing of segmentations via the customization service
await page.evaluate(() => {
@ -45,18 +43,15 @@ test('should prevent editing of label map segmentations when panelSegmentation.d
await page.locator(`css=div[data-cy="eraser-radius"] input`).fill('1000');
// Attempt to erase the segmentations by dragging the eraser tool across the image several times.
await simulateNormalizedDragOnElement({
locator: viewportLocator({ page, viewportId: 'default' }),
await viewportPageObject.getById('default').normalizedDragAt({
start: { x: 0.01, y: 0.25 },
end: { x: 1.0, y: 0.25 },
});
await simulateNormalizedDragOnElement({
locator: viewportLocator({ page, viewportId: 'default' }),
await viewportPageObject.getById('default').normalizedDragAt({
start: { x: 0.01, y: 0.5 },
end: { x: 1.0, y: 0.5 },
});
await simulateNormalizedDragOnElement({
locator: viewportLocator({ page, viewportId: 'default' }),
await viewportPageObject.getById('default').normalizedDragAt({
start: { x: 0.01, y: 0.75 },
end: { x: 1.0, y: 0.75 },
});
@ -66,6 +61,7 @@ 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,
viewportPageObject,
}) => {
// disable editing of segmentations via the customization service
await page.evaluate(() => {
@ -99,18 +95,15 @@ test('should allow editing of label map segmentations when panelSegmentation.dis
await page.locator(`css=div[data-cy="eraser-radius"] input`).fill('1000');
// Attempt to erase the segmentations by dragging the eraser tool across the image several times.
await simulateNormalizedDragOnElement({
locator: viewportLocator({ page, viewportId: 'default' }),
await viewportPageObject.getById('default').normalizedDragAt({
start: { x: 0.01, y: 0.25 },
end: { x: 1.0, y: 0.25 },
});
await simulateNormalizedDragOnElement({
locator: viewportLocator({ page, viewportId: 'default' }),
await viewportPageObject.getById('default').normalizedDragAt({
start: { x: 0.01, y: 0.5 },
end: { x: 1.0, y: 0.5 },
});
await simulateNormalizedDragOnElement({
locator: viewportLocator({ page, viewportId: 'default' }),
await viewportPageObject.getById('default').normalizedDragAt({
start: { x: 0.01, y: 0.75 },
end: { x: 1.0, y: 0.75 },
});

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -7,22 +6,16 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should display the length tool', async ({ page }) => {
await page.getByTestId('MeasurementTools-split-button-primary').click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateClicksOnElement({
locator,
points: [
{
x: 364,
y: 234,
},
{
x: 544,
y: 232,
},
],
});
test('should display the length tool', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.measurementTools.length.click();
await viewportPageObject.active.clickAt([
{ x: 364, y: 234 },
{ x: 544, y: 232 },
]);
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
await checkForScreenshot(page, page, screenShotPaths.length.lengthDisplayedCorrectly);
});

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -7,39 +6,20 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should display the livewire tool', async ({ page }) => {
await page.getByTestId('MeasurementTools-split-button-secondary').click();
await page.getByTestId('LivewireContour').click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateClicksOnElement({
locator,
points: [
{
x: 380,
y: 459,
},
{
x: 420,
y: 396,
},
{
x: 523,
y: 392,
},
{
x: 581,
y: 447,
},
{
x: 482,
y: 493,
},
{
x: 383,
y: 461,
},
],
});
test('should display the livewire tool', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.measurementTools.livewireContour.click();
await viewportPageObject.active.clickAt([
{ x: 380, y: 459 },
{ x: 420, y: 396 },
{ x: 523, y: 392 },
{ x: 581, y: 447 },
{ x: 482, y: 493 },
{ x: 383, y: 461 },
]);
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
await checkForScreenshot(page, page, screenShotPaths.livewire.livewireDisplayedCorrectly);
});

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils/index.js';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils/index.js';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.1706.8374.643249677828306008300337414785';
@ -8,9 +7,8 @@ test.beforeEach(async ({ page }) => {
});
test.describe('MPR Test', async () => {
test('should render MPR correctly.', async ({ page }) => {
await page.getByTestId('Layout').click();
await page.locator('div').filter({ hasText: /^MPR$/ }).first().click();
test('should render MPR correctly.', async ({ page, mainToolbarPageObject }) => {
await mainToolbarPageObject.layoutSelection.MPR.click();
await checkForScreenshot(page, page, screenShotPaths.mpr.mprDisplayedCorrectly);
});
});

View File

@ -1,7 +1,5 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import { assertNumberOfModalityLoadBadges } from './utils/assertions';
import { viewportLocator } from './utils/locators';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.5962.99.1.2968617883.1314880426.1493322302363.3.0';
@ -11,9 +9,10 @@ test.beforeEach(async ({ page }) => {
test('should launch MPR with unhydrated RTSTRUCT chosen from the data overlay menu', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await page.getByTestId('Layout').click();
await page.getByTestId('MPR').click();
await mainToolbarPageObject.layoutSelection.MPR.click();
// Wait 5 seconds for MPR to load. This is necessary in particular when screen shots are added or replaced.
await page.waitForTimeout(10000);
@ -25,14 +24,14 @@ 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 viewportLocator({ viewportId: 'mpr-sagittal', page }).hover();
await page.getByTestId('dataOverlayMenu-mpr-sagittal-btn').click();
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();
// Hide the overlay menu.
await page.getByTestId('dataOverlayMenu-mpr-sagittal-btn').click();
await viewportPageObject.getById('mpr-sagittal').overlayMenu.dataOverlay.click();
// Adding an overlay should not show the LOAD button.
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });

View File

@ -1,7 +1,5 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import { assertNumberOfModalityLoadBadges } from './utils/assertions';
import { viewportLocator } from './utils/locators';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046';
@ -11,11 +9,12 @@ test.beforeEach(async ({ page }) => {
test('should launch MPR with unhydrated SEG chosen from the data overlay menu', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await page.getByTestId('side-panel-header-right').click();
await page.getByTestId('Layout').click();
await page.getByTestId('MPR').click();
await mainToolbarPageObject.layoutSelection.MPR.click();
await page.waitForTimeout(5000);
@ -26,14 +25,14 @@ 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 viewportLocator({ viewportId: 'mpr-sagittal', page }).hover();
await page.getByTestId('dataOverlayMenu-mpr-sagittal-btn').click();
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();
// Hide the overlay menu.
await page.getByTestId('dataOverlayMenu-mpr-sagittal-btn').click();
await viewportPageObject.getById('mpr-sagittal').overlayMenu.dataOverlay.click();
// Adding an overlay should not show the LOAD button.
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });

View File

@ -1,5 +1,4 @@
import { test, expect } from 'playwright-test-coverage';
import { visitStudy, addLengthMeasurement, scrollVolumeViewport } from './utils';
import { addLengthMeasurement, expect, scrollVolumeViewport, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
// Using same one as JumpToMeasurementMPR.spec.ts
@ -136,8 +135,11 @@ test('checks if measurement item can be relabeled through the context menu on th
await expect(measurementRow).toContainText(relabelText);
});
test('checks if image would jump when clicked on a measurement item', async ({ page }) => {
const viewportInfoBottomRight = page.getByTestId('viewport-overlay-bottom-right');
test('checks if image would jump when clicked on a measurement item', async ({
page,
viewportPageObject,
}) => {
const viewportInfoBottomRight = viewportPageObject.active.overlayText.bottomRight;
// Image loads on slice 1, confirm on slice 1 then add measurement
await expect(viewportInfoBottomRight).toContainText('1/', { timeout: 10000 });

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import { press } from './utils/keyboardUtils';
import { assertNumberOfModalityLoadBadges } from './utils/assertions';
@ -9,11 +8,14 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should display multiple segmentation overlays (both SEG and RT)', async ({ page }) => {
test('should display multiple segmentation overlays (both SEG and RT)', async ({
page,
viewportPageObject,
}) => {
await page.getByTestId('side-panel-header-right').click();
// Add multiple segmentation overlays and ensure the overlay menu reflects this change.
await page.getByTestId('dataOverlayMenu-default-btn').click();
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
await page.getByTestId('AddSegmentationDataOverlay-default').click();
await page.getByText('SELECT A SEGMENTATION').click();
@ -51,15 +53,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 page.getByTestId('dataOverlayMenu-default-btn').click(); // hide
await page.getByTestId('dataOverlayMenu-default-btn').click(); // show
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click(); // hide
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click(); // show
await checkForScreenshot({
page,
screenshotPath: screenShotPaths.multipleSegmentationDataOverlays.threeSegOverlaysInOverlayMenu,
});
await page.getByTestId('dataOverlayMenu-default-btn').click(); // hide
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click(); // hide
// Navigate to image 56.
await press({ page, key: 'ArrowDown', nTimes: 55 });
@ -72,7 +74,7 @@ test('should display multiple segmentation overlays (both SEG and RT)', async ({
});
// Now add the RT overlay
await page.getByTestId('dataOverlayMenu-default-btn').click();
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
await page.getByTestId('AddSegmentationDataOverlay-default').click();
await page.getByText('SELECT A SEGMENTATION').click();
@ -90,8 +92,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 page.getByTestId('dataOverlayMenu-default-btn').click(); // hide
await page.getByTestId('dataOverlayMenu-default-btn').click(); // show
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click(); // hide
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click(); // show
await checkForScreenshot({
page,

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -7,19 +6,13 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should display the probe tool', async ({ page }) => {
await page.getByTestId('MoreTools-split-button-secondary').click();
await page.getByTestId('Probe').click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateClicksOnElement({
locator,
points: [
{
x: 550,
y: 200,
},
],
});
test('should display the probe tool', async ({
page,
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 checkForScreenshot(page, page, screenShotPaths.probe.probeDisplayedCorrectly);
});

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import { press } from './utils/keyboardUtils';
import { assertNumberOfModalityLoadBadges } from './utils/assertions';
@ -11,8 +10,9 @@ test.beforeEach(async ({ page }) => {
test('should overlay an unhydrated RTSTRUCT over a display set that the RTSTRUCT does NOT reference', async ({
page,
viewportPageObject,
}) => {
await page.getByTestId('dataOverlayMenu-default-btn').click();
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();
@ -21,7 +21,7 @@ test('should overlay an unhydrated RTSTRUCT over a display set that the RTSTRUCT
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
// Hide the overlay menu.
await page.getByTestId('dataOverlayMenu-default-btn').click();
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
await page.waitForTimeout(5000);

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import { assertNumberOfModalityLoadBadges } from './utils/assertions';
test.beforeEach(async ({ page }) => {
@ -10,9 +9,11 @@ test.beforeEach(async ({ page }) => {
test('should launch MPR with unhydrated RTSTRUCT chosen from the data overlay menu', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await page.getByTestId('side-panel-header-right').click();
await page.getByTestId('dataOverlayMenu-default-btn').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();
@ -21,7 +22,7 @@ test('should launch MPR with unhydrated RTSTRUCT chosen from the data overlay me
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
// Hide the overlay menu.
await page.getByTestId('dataOverlayMenu-default-btn').click();
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
await page.waitForTimeout(5000);
@ -31,8 +32,7 @@ test('should launch MPR with unhydrated RTSTRUCT chosen from the data overlay me
screenShotPaths.rtDataOverlayNoHydrationThenMPR.rtDataOverlayNoHydrationPreMPR
);
await page.getByTestId('Layout').click();
await page.getByTestId('MPR').click();
await mainToolbarPageObject.layoutSelection.MPR.click();
await page.waitForTimeout(5000);

View File

@ -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,11 +6,10 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should hydrate an RTSTRUCT from MPR', async ({ page }) => {
test('should hydrate an RTSTRUCT from MPR', async ({ page, mainToolbarPageObject }) => {
await page.getByTestId('side-panel-header-right').click();
await page.getByTestId('Layout').click();
await page.getByTestId('MPR').click();
await mainToolbarPageObject.layoutSelection.MPR.click();
await page.waitForTimeout(10000);
@ -29,8 +27,7 @@ test('should hydrate an RTSTRUCT from MPR', async ({ page }) => {
await checkForScreenshot(page, page, screenShotPaths.rtHydrationFromMPR.mprAfterRTHydrated);
await page.getByTestId('Layout').click();
await page.getByTestId('Axial Primary').click();
await mainToolbarPageObject.layoutSelection.axialPrimary.click();
await checkForScreenshot(
page,

View File

@ -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,7 +6,7 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should hydrate an RTSTRUCT and then launch MPR', async ({ page }) => {
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();
@ -17,8 +16,7 @@ test('should hydrate an RTSTRUCT and then launch MPR', async ({ page }) => {
await checkForScreenshot(page, page, screenShotPaths.rtHydrationThenMPR.rtPostHydration);
await page.getByTestId('Layout').click();
await page.getByTestId('Axial Primary').click();
await mainToolbarPageObject.layoutSelection.axialPrimary.click();
await page.waitForTimeout(5000);

View File

@ -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,7 +6,7 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should launch MPR with unhydrated RTSTRUCT', async ({ page }) => {
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();
@ -15,8 +14,7 @@ test('should launch MPR with unhydrated RTSTRUCT', async ({ page }) => {
await checkForScreenshot(page, page, screenShotPaths.rtNoHydrationThenMPR.rtNoHydrationPreMPR);
await page.getByTestId('Layout').click();
await page.getByTestId('MPR').click();
await mainToolbarPageObject.layoutSelection.MPR.click();
await page.waitForTimeout(5000);

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -7,23 +6,16 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should display the rectangle tool', async ({ page }) => {
await page.getByTestId('MeasurementTools-split-button-secondary').click();
await page.getByTestId('RectangleROI').click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateClicksOnElement({
locator,
points: [
{
x: 476,
y: 159,
},
{
x: 591,
y: 217,
},
],
});
test('should display the rectangle tool', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.measurementTools.rectangleROI.click();
await viewportPageObject.active.clickAt([
{ x: 476, y: 159 },
{ x: 591, y: 217 },
]);
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
await checkForScreenshot(page, page, screenShotPaths.rectangle.rectangleDisplayedCorrectly);
});

View File

@ -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 = '2.16.840.1.114362.1.11972228.22789312658.616067305.306.2';
@ -7,12 +6,9 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should reset the image to its original state', async ({ page }) => {
await page.getByTestId('MoreTools-split-button-secondary').click();
await page.getByTestId('rotate-right').click();
await page.getByTestId('MoreTools-split-button-secondary').click();
await page.getByTestId('invert').click();
await page.getByTestId('MoreTools-split-button-secondary').click();
await page.getByText('Reset View').click();
test('should reset the image to its original state', async ({ page, mainToolbarPageObject }) => {
await mainToolbarPageObject.moreTools.rotateRight.click();
await mainToolbarPageObject.moreTools.invert.click();
await mainToolbarPageObject.moreTools.reset.click();
await checkForScreenshot(page, page, screenShotPaths.reset.resetDisplayedCorrectly);
});

View File

@ -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.25403.345050719074.3824.20170125095438.5';
@ -7,8 +6,7 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should rotate the image to the right', async ({ page }) => {
await page.getByTestId('MoreTools-split-button-secondary').click();
await page.getByTestId('rotate-right').click();
test('should rotate the image to the right', async ({ page, mainToolbarPageObject }) => {
await mainToolbarPageObject.moreTools.rotateRight.click();
await checkForScreenshot(page, page, screenShotPaths.rotateRight.rotateRightDisplayedCorrectly);
});

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import { press } from './utils/keyboardUtils';
import { assertNumberOfModalityLoadBadges } from './utils/assertions';
@ -11,10 +10,11 @@ test.beforeEach(async ({ page }) => {
test('should overlay an unhydrated SEG over a display set that the SEG does NOT reference', async ({
page,
viewportPageObject,
}) => {
await page.getByTestId('study-browser-thumbnail').nth(2).dblclick();
await page.getByTestId('dataOverlayMenu-default-btn').click();
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();
@ -23,7 +23,7 @@ test('should overlay an unhydrated SEG over a display set that the SEG does NOT
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
// Hide the overlay menu.
await page.getByTestId('dataOverlayMenu-default-btn').click();
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
await page.waitForTimeout(5000);

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import { assertNumberOfModalityLoadBadges } from './utils/assertions';
test.beforeEach(async ({ page }) => {
@ -10,9 +9,11 @@ test.beforeEach(async ({ page }) => {
test('should launch MPR with unhydrated SEG chosen from the data overlay menu', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await page.getByTestId('side-panel-header-right').click();
await page.getByTestId('dataOverlayMenu-default-btn').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();
@ -21,7 +22,7 @@ test('should launch MPR with unhydrated SEG chosen from the data overlay menu',
assertNumberOfModalityLoadBadges({ page, expectedCount: 0 });
// Hide the overlay menu.
await page.getByTestId('dataOverlayMenu-default-btn').click();
await viewportPageObject.getById('default').overlayMenu.dataOverlay.click();
await page.waitForTimeout(5000);
@ -31,8 +32,7 @@ test('should launch MPR with unhydrated SEG chosen from the data overlay menu',
screenShotPaths.segDataOverlayNoHydrationThenMPR.segDataOverlayNoHydrationPreMPR
);
await page.getByTestId('Layout').click();
await page.getByTestId('MPR').click();
await mainToolbarPageObject.layoutSelection.MPR.click();
await page.waitForTimeout(5000);

View File

@ -1,7 +1,7 @@
import { test, expect } from 'playwright-test-coverage';
import { Page } from '@playwright/test';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { ViewportPageObject } from './pages';
import { checkForScreenshot, expect, screenShotPaths, test, visitStudy } from './utils';
import { press } from './utils/keyboardUtils';
test.beforeEach(async ({ page }) => {
@ -15,13 +15,16 @@ test.beforeEach(async ({ page }) => {
await page.waitForTimeout(500);
});
async function performDrawingToolInteraction(page: Page, toolName: string) {
async function performDrawingToolInteraction(
page: Page,
toolName: string,
viewportPageObject: ViewportPageObject
) {
const brushRadiusInput = page.getByTestId(`${toolName}-radius`).locator('input');
const viewportGrid = page.getByTestId('viewport-grid');
const circle = viewportGrid.locator('svg.svg-layer circle').first();
const circle = viewportPageObject.active.svg('circle').first();
await expect(brushRadiusInput).toHaveValue('25');
await viewportGrid.click({ position: { x: 275, y: 300 } });
await viewportPageObject.active.clickAt([{ x: 275, y: 300 }]);
let radius = parseFloat(await circle.getAttribute('r'));
expect(radius).toBeGreaterThanOrEqual(65);
expect(radius).toBeLessThanOrEqual(68);
@ -29,7 +32,7 @@ async function performDrawingToolInteraction(page: Page, toolName: string) {
await page.waitForTimeout(500);
await press({ page, key: '[', nTimes: 2 });
await expect(brushRadiusInput).toHaveValue('19');
await viewportGrid.click({ position: { x: 500, y: 300 } });
await viewportPageObject.active.clickAt([{ x: 500, y: 300 }]);
radius = parseFloat(await circle.getAttribute('r'));
expect(radius).toBeGreaterThanOrEqual(49);
expect(radius).toBeLessThanOrEqual(52);
@ -38,7 +41,7 @@ async function performDrawingToolInteraction(page: Page, toolName: string) {
await press({ page, key: ']', nTimes: 5 });
await expect(brushRadiusInput).toHaveValue('34');
await viewportGrid.click({ position: { x: 275, y: 500 } });
await viewportPageObject.active.clickAt([{ x: 275, y: 500 }]);
radius = parseFloat(await circle.getAttribute('r'));
expect(radius).toBeGreaterThanOrEqual(87);
expect(radius).toBeLessThanOrEqual(90);
@ -46,7 +49,7 @@ async function performDrawingToolInteraction(page: Page, toolName: string) {
await page.waitForTimeout(500);
await brushRadiusInput.fill('42');
await viewportGrid.click({ position: { x: 500, y: 500 } });
await viewportPageObject.active.clickAt([{ x: 500, y: 500 }]);
radius = parseFloat(await circle.getAttribute('r'));
expect(radius).toBeGreaterThanOrEqual(108);
expect(radius).toBeLessThanOrEqual(111);
@ -54,23 +57,23 @@ async function performDrawingToolInteraction(page: Page, toolName: string) {
await page.waitForTimeout(500);
}
test('(shouldUpdateThis) should resize segmentation brush tool', async ({ page }) => {
test('should resize segmentation brush tool', async ({ page, viewportPageObject }) => {
await page.getByTestId('Brush-btn').click();
await performDrawingToolInteraction(page, 'brush');
await performDrawingToolInteraction(page, 'brush', viewportPageObject);
await checkForScreenshot(
page,
page.getByTestId('viewport-grid'),
viewportPageObject.active.pane,
screenShotPaths.segDrawingToolsResizing.brushTool
);
});
test('(shouldUpdateThis) should resize segmentation eraser tool', async ({ page }) => {
test('should resize segmentation eraser tool', async ({ page, viewportPageObject }) => {
await page.getByTestId('Brush-btn').click();
await page.getByTestId('brush-radius').locator('input').fill('99.5');
await page.getByTestId('viewport-grid').click({ position: { x: 400, y: 400 } });
await viewportPageObject.active.clickAt([{ x: 400, y: 400 }]);
await page.waitForTimeout(500);
@ -79,17 +82,17 @@ test('(shouldUpdateThis) should resize segmentation eraser tool', async ({ page
await page.waitForTimeout(500);
await performDrawingToolInteraction(page, 'eraser');
await performDrawingToolInteraction(page, 'eraser', viewportPageObject);
await checkForScreenshot(
page,
page.getByTestId('viewport-grid'),
viewportPageObject.active.pane,
screenShotPaths.segDrawingToolsResizing.eraserTool
);
});
test('(shouldUpdateThis) should resize segmentation threshold tool', async ({ page }) => {
test('should resize segmentation threshold tool', async ({ page, viewportPageObject }) => {
await page.getByTestId('Threshold-btn').click();
await performDrawingToolInteraction(page, 'threshold');
await performDrawingToolInteraction(page, 'threshold', viewportPageObject);
});

View File

@ -1,10 +1,10 @@
import { test } from 'playwright-test-coverage';
import {
visitStudy,
checkForScreenshot,
screenShotPaths,
reduce3DViewportSize,
attemptAction,
checkForScreenshot,
reduce3DViewportSize,
screenShotPaths,
test,
visitStudy,
} from './utils';
test.beforeEach(async ({ page }) => {
@ -14,9 +14,11 @@ test.beforeEach(async ({ page }) => {
});
test.describe('3D four up SEG hydration', async () => {
test('should properly hydrate SEG from 3D four up layout', async ({ page }) => {
await page.getByTestId('Layout').click();
await page.getByTestId('3D four up').click();
test('should properly hydrate SEG from 3D four up layout', async ({
page,
mainToolbarPageObject,
}) => {
await mainToolbarPageObject.layoutSelection.threeDFourUp.click();
await attemptAction(() => reduce3DViewportSize(page), 10, 100);

View File

@ -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.12.2.1107.5.2.32.35162.30000015050317233592200000046';
@ -7,11 +6,10 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should properly display MPR for MR', async ({ page }) => {
test('should properly display MPR for MR', async ({ page, mainToolbarPageObject }) => {
await page.getByTestId('side-panel-header-right').click();
await page.getByTestId('Layout').click();
await page.getByTestId('MPR').click();
await mainToolbarPageObject.layoutSelection.MPR.click();
await page.waitForTimeout(5000);
await checkForScreenshot(page, page, screenShotPaths.segHydrationFromMPR.mprBeforeSEG);
@ -26,8 +24,7 @@ test('should properly display MPR for MR', async ({ page }) => {
await page.waitForTimeout(5000);
await checkForScreenshot(page, page, screenShotPaths.segHydrationFromMPR.mprAfterSegHydrated);
await page.getByTestId('Layout').click();
await page.getByTestId('Axial Primary').click();
await mainToolbarPageObject.layoutSelection.axialPrimary.click();
await page.waitForTimeout(5000);
await checkForScreenshot(

View File

@ -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.12.2.1107.5.2.32.35162.30000015050317233592200000046';
@ -7,7 +6,7 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should properly display MPR for MR', async ({ page }) => {
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();
@ -16,8 +15,7 @@ test('should properly display MPR for MR', async ({ page }) => {
await page.waitForTimeout(5000);
await checkForScreenshot(page, page, screenShotPaths.segHydrationThenMPR.segPostHydration);
await page.getByTestId('Layout').click();
await page.getByTestId('Axial Primary').click();
await mainToolbarPageObject.layoutSelection.axialPrimary.click();
await page.waitForTimeout(5000);
await checkForScreenshot(

View File

@ -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.12.2.1107.5.2.32.35162.30000015050317233592200000046';
@ -7,7 +6,7 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should launch MPR with unhydrated SEG', async ({ page }) => {
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();
@ -15,8 +14,7 @@ test('should launch MPR with unhydrated SEG', async ({ page }) => {
await checkForScreenshot(page, page, screenShotPaths.segNoHydrationThenMPR.segNoHydrationPreMPR);
await page.getByTestId('Layout').click();
await page.getByTestId('MPR').click();
await mainToolbarPageObject.layoutSelection.MPR.click();
await page.waitForTimeout(5000);

View File

@ -1,17 +1,15 @@
import { test, expect } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { viewportLocator } from './utils/locators';
import { checkForScreenshot, expect, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.7310.5101.860473186348887719777907797922';
const mode = 'viewer';
await visitStudy(page, studyInstanceUID, mode, 5000);
// Log the actual URL that was loaded
const currentUrl = page.url();
console.log(`✅ Actual page URL: ${currentUrl}\n`);
// Remove any webpack dev server overlays that might be blocking interactions
await page.evaluate(() => {
const overlay = document.getElementById('webpack-dev-server-client-overlay');
@ -21,23 +19,30 @@ test.beforeEach(async ({ page }) => {
});
});
test('should hydrate SCOORD3D probe measurements correctly', async ({ page }) => {
test('should hydrate SCOORD3D probe measurements correctly', async ({
page,
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();
// Double-click on the study browser thumbnail to load the SR
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
await page.waitForTimeout(2000);
// Wait for the SR to load and stabilize before taking screenshot
await page.waitForTimeout(1000);
// Take screenshot before hydration - use viewport locator instead of full page
await checkForScreenshot(page, viewportLocator({ page, viewportId: 'default' }), screenShotPaths.scoord3dProbe.scoord3dProbePreHydration);
await checkForScreenshot(
page,
viewportPageObject.active.pane,
screenShotPaths.scoord3dProbe.scoord3dProbePreHydration
);
// Zoom in to better see the measurements
await page.evaluate(() => {
@ -58,27 +63,31 @@ test('should hydrate SCOORD3D probe measurements correctly', async ({ page }) =>
viewport.render();
}
});
// Wait for rendering to complete
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 });
// Click the hydrate button to load the SCOORD3D probe measurements
await page.getByTestId('yes-hydrate-btn').click();
// Wait for hydration to complete and rendering to stabilize
await page.waitForTimeout(3000);
// Take screenshot after hydration showing the probe measurements - use viewport locator
await checkForScreenshot(page, viewportLocator({ page, viewportId: 'default' }), screenShotPaths.scoord3dProbe.scoord3dProbePostHydration);
await checkForScreenshot(
page,
viewportPageObject.active.pane,
screenShotPaths.scoord3dProbe.scoord3dProbePostHydration
);
// Verify the measurements list has the correct probe measurements
const measurementRows = page.getByTestId('data-row');
const rowCount = await measurementRows.count();
expect(rowCount).toBeGreaterThan(0);
// Verify that the measurements are probe measurements (not other types)
for (let i = 0; i < rowCount; i++) {
const row = measurementRows.nth(i);
@ -111,19 +120,26 @@ test('should hydrate SCOORD3D probe measurements correctly', async ({ page }) =>
await page.getByTestId('data-row').first().click();
// Take screenshot showing the jump to measurement functionality - use viewport locator
await checkForScreenshot(page, viewportLocator({ page, viewportId: 'default' }), screenShotPaths.scoord3dProbe.scoord3dProbeJumpToMeasurement);
await checkForScreenshot(
page,
viewportPageObject.active.pane,
screenShotPaths.scoord3dProbe.scoord3dProbeJumpToMeasurement
);
});
test('should display SCOORD3D probe measurements correctly', async ({ page }) => {
test('should display SCOORD3D probe measurements correctly', async ({
page,
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 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();
@ -147,18 +163,22 @@ test('should display SCOORD3D probe measurements correctly', async ({ page }) =>
viewport.render();
}
});
// Wait for rendering to complete before taking screenshot
await page.waitForTimeout(2000);
// Take screenshot showing the SCOORD3D probe measurements rendered correctly - use viewport locator
await checkForScreenshot(page, viewportLocator({ page, viewportId: 'default' }), screenShotPaths.scoord3dProbe.scoord3dProbeDisplayedCorrectly);
await checkForScreenshot(
page,
viewportPageObject.active.pane,
screenShotPaths.scoord3dProbe.scoord3dProbeDisplayedCorrectly
);
// Verify the measurements list has the correct probe measurements and not others
const measurementRows = page.getByTestId('data-row');
const rowCount = await measurementRows.count();
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);

View File

@ -1,17 +1,15 @@
import { test, expect } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
import { viewportLocator } from './utils/locators';
import { checkForScreenshot, expect, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.2.840.113654.2.55.242841386983064378162007136685545369722';
const mode = 'viewer';
await visitStudy(page, studyInstanceUID, mode, 5000);
// Log the actual URL that was loaded
const currentUrl = page.url();
console.log(`✅ Actual page URL: ${currentUrl}\n`);
// Remove any webpack dev server overlays that might be blocking interactions
await page.evaluate(() => {
const overlay = document.getElementById('webpack-dev-server-client-overlay');
@ -22,23 +20,30 @@ test.beforeEach(async ({ page }) => {
});
//
test('should hydrate SCOORD rectangle measurements correctly', async ({ page }) => {
test('should hydrate SCOORD rectangle measurements correctly', async ({
page,
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();
// Double-click on the study browser thumbnail to load the SR
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
await page.waitForTimeout(2000);
// Wait for the SR to load and stabilize before taking screenshot
await page.waitForTimeout(1000);
// Take screenshot before hydration - use viewport locator instead of full page
await checkForScreenshot(page, viewportLocator({ page, viewportId: 'default' }), screenShotPaths.scoordRectangle.scoordRectanglePreHydration);
await checkForScreenshot(
page,
viewportPageObject.active.pane,
screenShotPaths.scoordRectangle.scoordRectanglePreHydration
);
// Zoom in to better see the measurements
await page.evaluate(() => {
@ -59,27 +64,31 @@ test('should hydrate SCOORD rectangle measurements correctly', async ({ page })
viewport.render();
}
});
// Wait for rendering to complete
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 });
// Click the hydrate button to load the SCOORD rectangle measurements
await page.getByTestId('yes-hydrate-btn').click();
// Wait for hydration to complete and rendering to stabilize
await page.waitForTimeout(3000);
// Take screenshot after hydration showing the rectangle measurements - use viewport locator
await checkForScreenshot(page, viewportLocator({ page, viewportId: 'default' }), screenShotPaths.scoordRectangle.scoordRectanglePostHydration);
await checkForScreenshot(
page,
viewportPageObject.active.pane,
screenShotPaths.scoordRectangle.scoordRectanglePostHydration
);
// Verify the measurements list has the correct rectangle measurements
const measurementRows = page.getByTestId('data-row');
const rowCount = await measurementRows.count();
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);
@ -112,19 +121,26 @@ test('should hydrate SCOORD rectangle measurements correctly', async ({ page })
await page.getByTestId('data-row').first().click();
// Take screenshot showing the jump to measurement functionality - use viewport locator
await checkForScreenshot(page, viewportLocator({ page, viewportId: 'default' }), screenShotPaths.scoordRectangle.scoordRectangleJumpToMeasurement);
await checkForScreenshot(
page,
viewportPageObject.active.pane,
screenShotPaths.scoordRectangle.scoordRectangleJumpToMeasurement
);
});
test('should display SCOORD rectangle measurements correctly', async ({ page }) => {
test('should display SCOORD rectangle measurements correctly', async ({
page,
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 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();
@ -148,18 +164,22 @@ test('should display SCOORD rectangle measurements correctly', async ({ page })
viewport.render();
}
});
// Wait for rendering to complete before taking screenshot
await page.waitForTimeout(2000);
// Take screenshot showing the SCOORD rectangle measurements rendered correctly - use viewport locator
await checkForScreenshot(page, viewportLocator({ page, viewportId: 'default' }), screenShotPaths.scoordRectangle.scoordRectangleDisplayedCorrectly);
await checkForScreenshot(
page,
viewportPageObject.active.pane,
screenShotPaths.scoordRectangle.scoordRectangleDisplayedCorrectly
);
// Verify the measurements list has the correct rectangle measurements and not others
const measurementRows = page.getByTestId('data-row');
const rowCount = await measurementRows.count();
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);

View File

@ -1,5 +1,4 @@
import { test, expect } from 'playwright-test-coverage';
import { visitStudy } from './utils';
import { expect, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
// Using same one as JumpToMeasurementMPR.spec.ts
@ -55,9 +54,11 @@ test('checks basic add, rename, delete segments from panel', async ({ page }) =>
await expect(page.getByTestId('data-row')).toHaveCount(0);
});
test('checks saved segmentations loads and jumps to slices', async ({ page }) => {
const viewportInfoBottomRight = page.getByTestId('viewport-overlay-bottom-right');
test('checks saved segmentations loads and jumps to slices', async ({
page,
viewportPageObject,
}) => {
const viewportInfoBottomRight = viewportPageObject.active.overlayText.bottomRight;
// Image loads on slice 1, confirm on slice 1
await expect(viewportInfoBottomRight).toContainText('1/', { timeout: 10000 });

View File

@ -1,5 +1,4 @@
import { test } from 'playwright-test-coverage';
import { visitStudy, checkForScreenshot, screenShotPaths, simulateClicksOnElement } from './utils';
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
@ -7,39 +6,20 @@ test.beforeEach(async ({ page }) => {
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should display the spline tool', async ({ page }) => {
await page.getByTestId('MeasurementTools-split-button-secondary').click();
await page.getByTestId('SplineROI').click();
const locator = page.getByTestId('viewport-pane').locator('canvas');
await simulateClicksOnElement({
locator,
points: [
{
x: 380,
y: 459,
},
{
x: 420,
y: 396,
},
{
x: 523,
y: 392,
},
{
x: 581,
y: 447,
},
{
x: 482,
y: 493,
},
{
x: 383,
y: 461,
},
],
});
test('should display the spline tool', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.measurementTools.splineROI.click();
await viewportPageObject.active.clickAt([
{ x: 380, y: 459 },
{ x: 420, y: 396 },
{ x: 523, y: 392 },
{ x: 581, y: 447 },
{ x: 482, y: 493 },
{ x: 383, y: 461 },
]);
await page.getByTestId('prompt-begin-tracking-yes-btn').click();
await checkForScreenshot(page, page, screenShotPaths.spline.splineDisplayedCorrectly);
});

View File

@ -1,54 +1,55 @@
import { test, expect } from 'playwright-test-coverage';
import { visitStudy, scrollVolumeViewport } from './utils';
import { expect, scrollVolumeViewport, test, visitStudy } from './utils';
test.skip('PT should show slice closest to CT', async ({ page }) => {
test.skip('PT should show slice closest to CT', async ({ page, viewportPageObject }) => {
const studyInstanceUID = '1.2.840.113619.2.290.3.3767434740.226.1600859119.501';
const mode = 'tmtv';
await visitStudy(page, studyInstanceUID, mode);
const vp = page.getByTestId('viewport-pane');
const getNthViewportPane = (index: number) => viewportPageObject.getNth(index).pane;
// Sagittal
await expect(vp.nth(1)).toContainText('257/512', { useInnerText: true }); // Should default i 257
await expect.soft(vp.nth(4)).toContainText('97/192');
await expect(getNthViewportPane(1)).toContainText('257/512', {
useInnerText: true,
}); // Should default i 257
await expect.soft(getNthViewportPane(4)).toContainText('97/192');
await scrollVolumeViewport(page, 'ctSAGITTAL', -1); // CT i 256
await expect(vp.nth(1)).toContainText('256/512');
await expect.soft(vp.nth(4)).toContainText('96/192');
await expect(getNthViewportPane(1)).toContainText('256/512');
await expect.soft(getNthViewportPane(4)).toContainText('96/192');
await scrollVolumeViewport(page, 'ctSAGITTAL', -1); // CT i 255
await expect(vp.nth(1)).toContainText('255/512');
await expect.soft(vp.nth(4)).toContainText('95/192');
await expect(getNthViewportPane(1)).toContainText('255/512');
await expect.soft(getNthViewportPane(4)).toContainText('95/192');
await scrollVolumeViewport(page, 'ctSAGITTAL', -1); // CT i 254
await expect(vp.nth(1)).toContainText('254/512');
await expect.soft(vp.nth(4)).toContainText('95/192');
await expect(getNthViewportPane(1)).toContainText('254/512');
await expect.soft(getNthViewportPane(4)).toContainText('95/192');
await scrollVolumeViewport(page, 'ctSAGITTAL', -1); // CT i 253
await expect(vp.nth(1)).toContainText('253/512');
await expect.soft(vp.nth(4)).toContainText('94/192');
await expect(getNthViewportPane(1)).toContainText('253/512');
await expect.soft(getNthViewportPane(4)).toContainText('94/192');
await scrollVolumeViewport(page, 'ctSAGITTAL', -1); // CT i 252
await expect(vp.nth(1)).toContainText('252/512');
await expect.soft(vp.nth(4)).toContainText('94/192');
await expect(getNthViewportPane(1)).toContainText('252/512');
await expect.soft(getNthViewportPane(4)).toContainText('94/192');
await scrollVolumeViewport(page, 'ctSAGITTAL', -1); // CT i 251
await expect(vp.nth(1)).toContainText('251/512');
await expect.soft(vp.nth(4)).toContainText('93/192');
await expect(getNthViewportPane(1)).toContainText('251/512');
await expect.soft(getNthViewportPane(4)).toContainText('93/192');
// Coronal
await expect(vp.nth(2)).toContainText('256/512'); // Should default i 256
await expect.soft(vp.nth(5)).toContainText('96/192');
await expect(getNthViewportPane(2)).toContainText('256/512'); // Should default i 256
await expect.soft(getNthViewportPane(5)).toContainText('96/192');
await scrollVolumeViewport(page, 'ctCORONAL', -1); // CT i 255
await expect(vp.nth(2)).toContainText('255/512');
await expect.soft(vp.nth(5)).toContainText('96/192');
await expect(getNthViewportPane(2)).toContainText('255/512');
await expect.soft(getNthViewportPane(5)).toContainText('96/192');
await scrollVolumeViewport(page, 'ctCORONAL', -1); // CT i 254
await expect(vp.nth(2)).toContainText('254/512');
await expect.soft(vp.nth(5)).toContainText('95/192');
await expect(getNthViewportPane(2)).toContainText('254/512');
await expect.soft(getNthViewportPane(5)).toContainText('95/192');
await scrollVolumeViewport(page, 'ctCORONAL', -1); // CT i 253
await expect(vp.nth(2)).toContainText('253/512');
await expect.soft(vp.nth(5)).toContainText('95/192');
await expect(getNthViewportPane(2)).toContainText('253/512');
await expect.soft(getNthViewportPane(5)).toContainText('95/192');
await scrollVolumeViewport(page, 'ctCORONAL', -1); // CT i 252
await expect(vp.nth(2)).toContainText('252/512');
await expect.soft(vp.nth(5)).toContainText('94/192');
await expect(getNthViewportPane(2)).toContainText('252/512');
await expect.soft(getNthViewportPane(5)).toContainText('94/192');
await scrollVolumeViewport(page, 'ctCORONAL', -1); // CT i 251
await expect(vp.nth(2)).toContainText('251/512');
await expect.soft(vp.nth(5)).toContainText('94/192');
await expect(getNthViewportPane(2)).toContainText('251/512');
await expect.soft(getNthViewportPane(5)).toContainText('94/192');
await scrollVolumeViewport(page, 'ctCORONAL', -1); // CT i 250
await expect(vp.nth(2)).toContainText('250/512');
await expect.soft(vp.nth(5)).toContainText('93/192');
await expect(getNthViewportPane(2)).toContainText('250/512');
await expect.soft(getNthViewportPane(5)).toContainText('93/192');
});

View File

@ -1,9 +1,10 @@
import { test, expect } from 'playwright-test-coverage';
import { visitStudy, simulateNormalizedClickOnElement } from './utils/index';
import { viewportLocator } from './utils/locators';
import { expect, test, visitStudy } from './utils';
import { downloadAsString } from './utils/download';
test('should create and download the TMTV CSV report correctly', async ({ page }) => {
test('should create and download the TMTV CSV report correctly', async ({
page,
viewportPageObject,
}) => {
const studyInstanceUID = '1.2.840.113619.2.290.3.3767434740.226.1600859119.501';
const mode = 'tmtv';
await visitStudy(page, studyInstanceUID, mode, 10000);
@ -11,10 +12,7 @@ test('should create and download the TMTV CSV report correctly', async ({ page }
await page.getByTestId('addSegmentation').click();
await page.getByTestId('Brush-btn').click();
await simulateNormalizedClickOnElement({
locator: viewportLocator({ viewportId: 'ctAXIAL', page }),
normalizedPoint: { x: 0.5, y: 0.5 },
});
await viewportPageObject.getById('ctAXIAL').normalizedClickAt([{ x: 0.5, y: 0.5 }]);
await page.waitForTimeout(5000);

View File

@ -1,13 +1,9 @@
import { test, expect } from 'playwright-test-coverage';
import {
visitStudy,
simulateClicksOnElement,
getTMTVModalityUnit,
clearAllAnnotations,
} from './utils/index';
import { expect, clearAllAnnotations, getTMTVModalityUnit, test, visitStudy } from './utils';
test.skip('pets where SUV cannot be calculated should show same unit in TMTV as in Basic Viewer.', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
const studyInstanceUID = '1.2.840.113619.2.290.3.3767434740.226.1600859119.501';
const mode = 'tmtv';
@ -17,31 +13,20 @@ test.skip('pets where SUV cannot be calculated should show same unit in TMTV as
await page.getByTestId('side-panel-header-left').click();
// Change to image where SUV cannot be calculated
await page.getByTestId('viewport-grid').locator('canvas').nth(3).click();
await viewportPageObject.getNth(3).normalizedClickAt([{ x: 0.5, y: 0.5 }]);
await page.getByRole('button', { name: 'NAC' }).nth(1).dblclick();
// Wait for the new series to load
await page.waitForLoadState('networkidle');
// Add ROI annotation
await page.getByTestId('MeasurementTools-split-button-secondary').click();
await page.getByTestId('EllipticalROI').click();
const locator = page.getByTestId('viewport-pane').locator('canvas').first();
mainToolbarPageObject.measurementTools.ellipticalROI.click();
await clearAllAnnotations(page);
await simulateClicksOnElement({
locator,
points: [
{
x: 100,
y: 100,
},
{
x: 150,
y: 150,
},
],
});
await viewportPageObject.active.clickAt([
{ x: 100, y: 100 },
{ x: 150, y: 150 },
]);
const modalityUnit = await getTMTVModalityUnit(page);

View File

@ -1,31 +1,23 @@
import { expect, test } from 'playwright-test-coverage';
import { visitStudy, simulateClicksOnElement, getSUV, clearAllAnnotations } from './utils/index';
import { expect, clearAllAnnotations, getSUV, test, visitStudy } from './utils';
test.skip('should update SUV values correctly.', async ({ page }) => {
test.skip('should update SUV values correctly.', async ({
page,
mainToolbarPageObject,
viewportPageObject,
}) => {
const studyInstanceUID = '1.2.840.113619.2.290.3.3767434740.226.1600859119.501';
const mode = 'tmtv';
await visitStudy(page, studyInstanceUID, mode, 10000);
// Create ROI
await page.getByTestId('petSUV-btn').click();
await page.getByTestId('MeasurementTools-split-button-secondary').click();
await page.getByTestId('EllipticalROI').click();
const locator = page.getByTestId('viewport-pane').locator('canvas').first();
await mainToolbarPageObject.measurementTools.ellipticalROI.click();
await clearAllAnnotations(page);
await simulateClicksOnElement({
locator,
points: [
{
x: 100,
y: 100,
},
{
x: 150,
y: 150,
},
],
});
await viewportPageObject.active.clickAt([
{ x: 100, y: 100 },
{ x: 150, y: 150 },
]);
// Get current SUV text
let oldSUV = await getSUV(page);

View File

@ -1,14 +1,14 @@
import { test, expect } from 'playwright-test-coverage';
import { visitStudy, simulateNormalizedClickOnElement } from './utils/index';
import { viewportLocator } from './utils/locators';
import { downloadAsString } from './utils/download';
import { expect, test, visitStudy } from './utils';
test('should restrict the percentage of max SUV to be between 0 and 1', async ({ page }) => {
test('should restrict the percentage of max SUV to be between 0 and 1', async ({
page,
viewportPageObject,
}) => {
const studyInstanceUID = '1.2.840.113619.2.290.3.3767434740.226.1600859119.501';
const mode = 'tmtv';
await visitStudy(page, studyInstanceUID, mode, 10000);
await viewportLocator({ viewportId: 'ptAXIAL', page }).click();
await viewportPageObject.getById('ptAXIAL').normalizedClickAt([{ x: 0.5, y: 0.5 }]);
await page.getByTestId('addSegmentation').click();
await page.getByTestId('RectangleROIStartEndThreshold-btn').click();

View File

@ -0,0 +1,287 @@
import { Page } from '@playwright/test';
export class MainToolbarPageObject {
readonly page: Page;
constructor(page: Page) {
this.page = page;
}
get layoutSelection() {
const page = this.page;
const button = page.getByTestId('Layout');
const layoutSelection = {
button,
async click() {
await button.click();
},
};
return {
...layoutSelection,
get axialPrimary() {
const button = page.getByTestId('Axial Primary');
return {
button,
async click() {
await layoutSelection.click();
await button.click();
},
};
},
get MPR() {
const button = page.getByTestId('MPR');
return {
button,
async click() {
await layoutSelection.click();
await button.click();
},
};
},
get threeDFourUp() {
const button = page.getByTestId('3D four up');
return {
button,
async click() {
await layoutSelection.click();
await button.click();
},
};
},
get threeDMain() {
const button = page.getByTestId('3D main');
return {
button,
async click() {
await layoutSelection.click();
await button.click();
},
};
},
get threeDOnly() {
const button = page.getByTestId('3D only');
return {
button,
async click() {
await layoutSelection.click();
await button.click();
},
};
},
get threeDPrimary() {
const button = page.getByTestId('3D primary');
return {
button,
async click() {
await layoutSelection.click();
await button.click();
},
};
},
};
}
get measurementTools() {
const page = this.page;
const button = page.getByTestId('MeasurementTools-split-button-secondary');
const measurementTools = {
button,
async click() {
await button.click();
},
};
return {
...measurementTools,
get arrowAnnotate() {
const button = page.getByTestId('ArrowAnnotate');
return {
button,
async click() {
await measurementTools.click();
await button.click();
},
};
},
get bidirectional() {
const button = page.getByTestId('Bidirectional');
return {
button,
async click() {
await measurementTools.click();
await button.click();
},
};
},
get circleROI() {
const button = page.getByTestId('CircleROI');
return {
button,
async click() {
await measurementTools.click();
await button.click();
},
};
},
get ellipticalROI() {
const button = page.getByTestId('EllipticalROI');
return {
button,
async click() {
await measurementTools.click();
await button.click();
},
};
},
get length() {
const button = page.locator('[data-cy="Length"][role="menuitem"]');
return {
button,
async click() {
await measurementTools.click();
await button.click();
},
};
},
get livewireContour() {
const button = page.getByTestId('LivewireContour');
return {
button,
async click() {
await measurementTools.click();
await button.click();
},
};
},
get rectangleROI() {
const button = page.getByTestId('RectangleROI');
return {
button,
async click() {
await measurementTools.click();
await button.click();
},
};
},
get splineROI() {
const button = page.getByTestId('SplineROI');
return {
button,
async click() {
await measurementTools.click();
await button.click();
},
};
},
};
}
get moreTools() {
const page = this.page;
const button = page.getByTestId('MoreTools-split-button-secondary');
const moreTools = {
button,
async click() {
await button.click();
},
};
return {
...moreTools,
get angle() {
const button = page.getByTestId('Angle');
return {
button,
async click() {
await moreTools.click();
await button.click();
},
};
},
get cobbAngle() {
const button = page.getByTestId('CobbAngle');
return {
button,
async click() {
await moreTools.click();
await button.click();
},
};
},
get flipHorizontal() {
const button = page.getByTestId('flipHorizontal');
return {
button,
async click() {
await moreTools.click();
await button.click();
},
};
},
get invert() {
const button = page.getByTestId('invert');
return {
button,
async click() {
await moreTools.click();
await button.click();
},
};
},
get probe() {
const button = page.getByTestId('Probe');
return {
button,
async click() {
await moreTools.click();
await button.click();
},
};
},
get reset() {
const button = page.locator('[data-cy="Reset"][role="menuitem"]');
return {
button,
async click() {
await moreTools.click();
await button.click();
},
};
},
get rotateRight() {
const button = page.getByTestId('rotate-right');
return {
button,
async click() {
await moreTools.click();
await button.click();
},
};
},
get tagBrowser() {
const button = page.getByTestId('TagBrowser');
return {
button,
async click() {
await moreTools.click();
await button.click();
},
};
},
};
}
get panTool() {
const button = this.page.getByTestId('Pan');
return {
button,
async click() {
await button.click();
},
};
}
}

View File

@ -0,0 +1,189 @@
import { Locator, Page } from '@playwright/test';
import {
simulateClicksOnElement,
simulateDoubleClickOnElement,
simulateNormalizedClicksOnElement,
simulateNormalizedDragOnElement,
} from '../utils';
type SvgInnerElement = 'circle' | 'path' | 'd';
type NormalizedDragParams = {
start: { x: number; y: number };
end: { x: number; y: number };
config?: { button?: 'left' | 'right' | 'middle'; delay?: number; steps?: number };
};
export interface IViewportPageObject {
doubleClickAt: (point: { x: number; y: number }) => Promise<void>;
clickAt: (
points: { x: number; y: number }[],
button?: 'left' | 'right' | 'middle'
) => Promise<void>;
normalizedClickAt: (
normalizedPoints: { x: number; y: number }[],
button?: 'left' | 'right' | 'middle'
) => Promise<void>;
normalizedDragAt: (params: NormalizedDragParams) => Promise<void>;
orientationMarkers: {
topMid: Locator;
leftMid: Locator;
rightMid: Locator;
bottomMid: Locator;
};
overlayText: {
topLeft: Locator;
topRight: Locator;
bottomLeft: Locator;
bottomRight: Locator;
};
overlayMenu: {
dataOverlay: {
button: Locator;
click: () => Promise<void>;
};
orientation: {
button: Locator;
click: () => Promise<void>;
};
windowLevel: {
button: Locator;
click: () => Promise<void>;
};
};
pane: Locator;
svg: (innerElement?: SvgInnerElement) => Locator;
}
export class ViewportPageObject {
readonly page: Page;
constructor(page: Page) {
this.page = page;
}
private getOrientationMarkers(viewport: Locator) {
return {
topMid: viewport.locator('.top-mid.orientation-marker'),
leftMid: viewport.locator('.left-mid.orientation-marker'),
rightMid: viewport.locator('.right-mid.orientation-marker'),
bottomMid: viewport.locator('.bottom-mid.orientation-marker'),
};
}
private getOverlayText(viewport: Locator) {
return {
topLeft: viewport.getByTestId('viewport-overlay-top-left'),
topRight: viewport.getByTestId('viewport-overlay-top-right'),
bottomLeft: viewport.getByTestId('viewport-overlay-bottom-left'),
bottomRight: viewport.getByTestId('viewport-overlay-bottom-right'),
};
}
private getOverlayMenu(viewport: Locator) {
return {
get dataOverlay() {
const button = viewport.locator('[data-cy^="dataOverlayMenu"]').first();
return {
button,
async click() {
await button.click();
},
};
},
get orientation() {
const button = viewport.locator('[data-cy^="orientationMenu"]');
return {
button,
async click() {
await button.click();
},
};
},
get windowLevel() {
const button = viewport.locator('[data-cy^="windowLevelMenu"]');
return {
button,
async click() {
await button.click();
},
};
},
};
}
private getSvg(viewport: Locator, innerElement?: SvgInnerElement) {
return viewport.locator(`svg.svg-layer${innerElement ? ` ${innerElement}` : ''}`);
}
private viewportPageObjectFactory(viewport: Locator): IViewportPageObject {
return {
doubleClickAt: async (point: { x: number; y: number }) => {
await simulateDoubleClickOnElement({
locator: viewport,
point,
});
},
clickAt: async (points: { x: number; y: number }[], button?: 'left' | 'right' | 'middle') => {
await simulateClicksOnElement({
locator: viewport,
points,
button,
});
},
normalizedClickAt: async (
normalizedPoints: { x: number; y: number }[],
button?: 'left' | 'right' | 'middle'
) => {
await simulateNormalizedClicksOnElement({
locator: viewport,
normalizedPoints,
button,
});
},
normalizedDragAt: async (params: NormalizedDragParams) => {
await simulateNormalizedDragOnElement({
locator: viewport,
start: params.start,
end: params.end,
button: params.config?.button,
delay: params.config?.delay,
steps: params.config?.steps,
});
},
orientationMarkers: this.getOrientationMarkers(viewport),
overlayText: this.getOverlayText(viewport),
overlayMenu: this.getOverlayMenu(viewport),
pane: viewport,
svg: (innerElement?: SvgInnerElement) => {
return this.getSvg(viewport, innerElement);
},
};
}
get active(): IViewportPageObject {
const viewport = this.page.locator('[data-cy="viewport-pane"][data-is-active="true"]');
return this.viewportPageObjectFactory(viewport);
}
async getAll(): Promise<IViewportPageObject[]> {
const viewports = await this.page.getByTestId('viewport-pane').all();
return viewports.map(viewport => this.viewportPageObjectFactory(viewport));
}
getNth(index: number): IViewportPageObject {
const viewport = this.page.getByTestId('viewport-pane').nth(index);
return this.viewportPageObjectFactory(viewport);
}
getById(viewportId: string): IViewportPageObject {
const viewport = this.page.locator(
`[data-cy="viewport-pane"]:has(div[data-viewportid="${viewportId}"])`
);
return this.viewportPageObjectFactory(viewport);
}
get grid() {
return this.page.getByTestId('viewport-grid');
}
}

4
tests/pages/index.ts Normal file
View File

@ -0,0 +1,4 @@
import { MainToolbarPageObject } from './MainToolbarPageObject';
import { ViewportPageObject } from './ViewportPageObject';
export { MainToolbarPageObject, ViewportPageObject };

18
tests/utils/fixture.ts Normal file
View File

@ -0,0 +1,18 @@
import { test as base } from 'playwright-test-coverage';
import { MainToolbarPageObject, ViewportPageObject } from '../pages';
type PageObjects = {
mainToolbarPageObject: MainToolbarPageObject;
viewportPageObject: ViewportPageObject;
};
export const test = base.extend<PageObjects>({
mainToolbarPageObject: async ({ page }, use) => {
await use(new MainToolbarPageObject(page));
},
viewportPageObject: async ({ page }, use) => {
await use(new ViewportPageObject(page));
},
});
export { expect } from 'playwright-test-coverage';

View File

@ -7,6 +7,7 @@ import {
simulateNormalizedClickOnElement,
simulateNormalizedClicksOnElement,
} from './simulateClicksOnElement';
import { simulateNormalizedDragOnElement } from './simulateDragOnElement';
import { reduce3DViewportSize } from './reduce3DviewportSize';
import { getMousePosition, initializeMousePositionTracker } from './mouseUtils';
import { getSUV } from './getSUV';
@ -15,6 +16,7 @@ import { clearAllAnnotations } from './clearAllAnnotations';
import { scrollVolumeViewport } from './scrollVolumeViewport';
import { attemptAction } from './attemptAction';
import { addLengthMeasurement } from './addLengthMeasurement';
import { test, expect } from './fixture';
export {
visitStudy,
@ -24,6 +26,7 @@ export {
simulateDoubleClickOnElement,
simulateNormalizedClickOnElement,
simulateNormalizedClicksOnElement,
simulateNormalizedDragOnElement,
reduce3DViewportSize,
getMousePosition,
initializeMousePositionTracker,
@ -33,4 +36,6 @@ export {
scrollVolumeViewport,
attemptAction,
addLengthMeasurement,
test,
expect,
};

View File

@ -1,31 +0,0 @@
import { Locator, Page } from '@playwright/test';
export const viewportLocator = ({
page,
viewportId,
}: {
page: Page;
viewportId: string;
}): Locator => {
return page.locator(`css=div[data-viewportid="${viewportId}"]`);
};
export const viewportSVGLocator = ({
page,
viewportId,
}: {
page: Page;
viewportId: string;
}): Locator => {
return page.locator(`css=div[data-viewportid="${viewportId}"] svg`);
};
export const viewportSVGPathLocator = ({
page,
viewportId,
}: {
page: Page;
viewportId: string;
}): Locator => {
return page.locator(`css=div[data-viewportid="${viewportId}"] svg path`);
};