Skip to content
26 changes: 25 additions & 1 deletion tests/Angle.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import {
checkForScreenshot,
expect,
expectAnnotationStatsText,
measurementTextFormatters,
screenShotPaths,
test,
visitStudy,
} from './utils';

test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
Expand All @@ -10,6 +18,7 @@ test('should display the angle tool', async ({
page,
DOMOverlayPageObject,
mainToolbarPageObject,
rightPanelPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.moreTools.angle.click();
Expand All @@ -26,4 +35,19 @@ test('should display the angle tool', async ({
viewportPageObject.grid,
screenShotPaths.angle.angleDisplayedCorrectly
);

await rightPanelPageObject.measurementsPanel.select();

// AngleTool: panel and SVG both use roundNumber – format is identical.
await expectAnnotationStatsText({
page,
activeViewport,
rightPanelPageObject,
toolName: 'Angle',
formatPanelPrimaryLines: [measurementTextFormatters.angleLine],
formatSvgLines: [measurementTextFormatters.angleLine],
assertStats: stats => {
expect(stats.angle as number).toBeCloseTo(53.1, 1);
},
});
});
49 changes: 7 additions & 42 deletions tests/ArrowAnnotate.spec.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,14 @@
import {
checkForScreenshot,
expect,
expectAnnotationLabelText,
getAnnotationStats,
screenShotPaths,
test,
visitStudy,
waitForViewportRenderCycle,
} from './utils';

/**
* Asserts the arrow annotation text across every surface that should reflect it:
* - the tracked measurements side panel row title,
* - the DOM SVG linked text box rendered in the viewport, and
* - the source-of-truth cornerstone annotation state (`data.label`).
*
* This avoids relying on the screenshot alone (whose font rendering differs
* between systems) to assert the text is correct, mirroring the DOM/state
* assertions in the SCOORD rectangle test.
*/
async function expectArrowText({
page,
activeViewport,
rightPanelPageObject,
annotationUID,
expectedText,
}) {
// Side panel: the measurement row title reflects the arrow text.
await expect(rightPanelPageObject.measurementsPanel.panel.nthMeasurement(0).title).toHaveText(
expectedText
);

// DOM SVG: the arrow's linked text box renders the arrow text, independent of
// any system font differences.
const svgTextLines = activeViewport.getSvgAnnotationStatTextLines(annotationUID);
await expect(svgTextLines).toHaveCount(1);
await expect(svgTextLines.nth(0)).toHaveText(expectedText);

// Source-of-truth annotation state. ArrowAnnotate stores its text on
// `data.label` rather than computed `cachedStats`, so read with requireStats: false.
const arrows = await getAnnotationStats(page, {
toolName: 'ArrowAnnotate',
requireStats: false,
});
const arrow = arrows.find(a => a.annotationUID === annotationUID);
expect(arrow).toBeDefined();
expect(arrow.label).toBe(expectedText);
}

test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
const mode = 'viewer';
Expand Down Expand Up @@ -93,10 +55,11 @@ test('should display the arrow tool and allow free-form text to be entered', asy
expect(arrows.length).toBeGreaterThan(0);
const annotationUID = arrows[0].annotationUID;

await expectArrowText({
await expectAnnotationLabelText({
page,
activeViewport,
rightPanelPageObject,
toolName: 'ArrowAnnotate',
annotationUID,
expectedText: 'Ringo Starr was the drummer for The Beatles',
});
Expand All @@ -114,10 +77,11 @@ test('should display the arrow tool and allow free-form text to be entered', asy
screenshotPath: screenShotPaths.arrowAnnotate.arrowAnnotateDisplayedCorrectly1,
});

await expectArrowText({
await expectAnnotationLabelText({
page,
activeViewport,
rightPanelPageObject,
toolName: 'ArrowAnnotate',
annotationUID,
expectedText: 'Neil Peart was the drummer for Rush',
});
Expand All @@ -134,10 +98,11 @@ test('should display the arrow tool and allow free-form text to be entered', asy
screenshotPath: screenShotPaths.arrowAnnotate.arrowAnnotateDisplayedCorrectly2,
});

await expectArrowText({
await expectAnnotationLabelText({
page,
activeViewport,
rightPanelPageObject,
toolName: 'ArrowAnnotate',
annotationUID,
expectedText: 'Drummer annotation arrow',
});
Expand Down
33 changes: 32 additions & 1 deletion tests/Bidirectional.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import {
checkForScreenshot,
expect,
expectAnnotationStatsText,
measurementTextFormatters,
screenShotPaths,
test,
visitStudy,
} from './utils';

test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
Expand All @@ -10,6 +18,7 @@ test('should display the bidirectional tool', async ({
page,
DOMOverlayPageObject,
mainToolbarPageObject,
rightPanelPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.measurementTools.bidirectional.click();
Expand All @@ -25,4 +34,26 @@ test('should display the bidirectional tool', async ({
viewportPageObject.grid,
screenShotPaths.bidirectional.bidirectionalDisplayedCorrectly
);

await rightPanelPageObject.measurementsPanel.select();

await expectAnnotationStatsText({
page,
activeViewport,
rightPanelPageObject,
toolName: 'Bidirectional',
formatPanelPrimaryLines: [
measurementTextFormatters.bidirectionalLengthLine,
measurementTextFormatters.bidirectionalWidthLine,
],
formatSvgLines: [
measurementTextFormatters.bidirectionalLengthLine,
measurementTextFormatters.bidirectionalWidthLine,
],
assertStats: stats => {
expect(stats.unit).toBe('mm');
expect(Math.round(stats.length as number)).toBe(195);
expect(Math.round(stats.width as number)).toBe(130);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jbocce I do think It's good to pass hardcoded numbers to assert the stats as well. If you agree with that I can update the rest of the tests in this PR to do the same.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that is perfect as along as we are confident the values are to be expected.

},
});
});
41 changes: 40 additions & 1 deletion tests/Circle.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import {
checkForScreenshot,
expect,
expectAnnotationStatsText,
measurementTextFormatters,
screenShotPaths,
test,
visitStudy,
} from './utils';

test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
Expand All @@ -10,6 +18,7 @@ test('should display the circle tool', async ({
page,
DOMOverlayPageObject,
mainToolbarPageObject,
rightPanelPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.measurementTools.circleROI.click();
Expand All @@ -24,4 +33,34 @@ test('should display the circle tool', async ({
viewportPageObject.grid,
screenShotPaths.circle.circleDisplayedCorrectly
);

await rightPanelPageObject.measurementsPanel.select();

// CircleROI panel: area (no prefix) + Max (with prefix).
// CircleROI SVG: Radius, Area, Mean, Max, Min, Std Dev (6 lines for CT modality).
await expectAnnotationStatsText({
page,
activeViewport,
rightPanelPageObject,
toolName: 'CircleROI',
formatPanelPrimaryLines: [
measurementTextFormatters.areaPanelLine,
measurementTextFormatters.maxLine,
],
formatSvgLines: [
measurementTextFormatters.circleRadiusSvgLine,
measurementTextFormatters.areaSvgLine,
measurementTextFormatters.meanSvgLine,
measurementTextFormatters.maxLine,
measurementTextFormatters.minSvgLine,
measurementTextFormatters.stdDevSvgLine,
],
assertStats: stats => {
expect(stats.areaUnit).toBe('mm²');
expect(stats.area as number).toBeGreaterThan(0);
expect(stats.radiusUnit).toBe('mm');
expect(stats.radius as number).toBeGreaterThan(0);
expect(stats.modalityUnit).toBe('HU');
},
});
});
27 changes: 26 additions & 1 deletion tests/CobbAngle.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import {
checkForScreenshot,
expect,
expectAnnotationStatsText,
measurementTextFormatters,
screenShotPaths,
test,
visitStudy,
} from './utils';

test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
Expand All @@ -10,6 +18,7 @@ test('should display the cobb angle tool', async ({
page,
DOMOverlayPageObject,
mainToolbarPageObject,
rightPanelPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.moreTools.cobbAngle.click();
Expand All @@ -27,4 +36,20 @@ test('should display the cobb angle tool', async ({
viewportPageObject.grid,
screenShotPaths.cobbangle.cobbangleDisplayedCorrectly
);

await rightPanelPageObject.measurementsPanel.select();

// CobbAngle panel uses roundNumber (angleLine), but its SVG uses
// angle.toFixed(2) directly (cobbAngleSvgLine).
await expectAnnotationStatsText({
page,
activeViewport,
rightPanelPageObject,
toolName: 'CobbAngle',
formatPanelPrimaryLines: [measurementTextFormatters.angleLine],
formatSvgLines: [measurementTextFormatters.cobbAngleSvgLine],
assertStats: stats => {
expect(stats.angle as number).toBeCloseTo(1.66, 2);
},
});
});
42 changes: 41 additions & 1 deletion tests/Ellipse.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import {
checkForScreenshot,
expect,
expectAnnotationStatsText,
measurementTextFormatters,
screenShotPaths,
test,
visitStudy,
} from './utils';

test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
Expand All @@ -10,6 +18,7 @@ test('should display the ellipse tool', async ({
page,
DOMOverlayPageObject,
mainToolbarPageObject,
rightPanelPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.measurementTools.ellipticalROI.click();
Expand All @@ -25,4 +34,35 @@ test('should display the ellipse tool', async ({
viewportPageObject.grid,
screenShotPaths.ellipse.ellipseDisplayedCorrectly
);

await rightPanelPageObject.measurementsPanel.select();

// EllipticalROI panel: area (no prefix) + Max (with prefix).
// EllipticalROI SVG: Area, Mean, Max, Min, Std Dev (5 lines for CT modality).
await expectAnnotationStatsText({
page,
activeViewport,
rightPanelPageObject,
toolName: 'EllipticalROI',
formatPanelPrimaryLines: [
measurementTextFormatters.areaPanelLine,
measurementTextFormatters.maxLine,
],
formatSvgLines: [
measurementTextFormatters.areaSvgLine,
measurementTextFormatters.meanSvgLine,
measurementTextFormatters.maxLine,
measurementTextFormatters.minSvgLine,
measurementTextFormatters.stdDevSvgLine,
],
assertStats: stats => {
expect(stats.areaUnit).toBe('mm²');
expect(Math.round(stats.area as number)).toBe(16778);
Comment thread
jbocce marked this conversation as resolved.
Outdated
expect(stats.modalityUnit).toBe('HU');
expect(stats.mean as number).toBeCloseTo(83.1, 1);
expect(Math.round(stats.max as number)).toBe(296);
expect(Math.round(stats.min as number)).toBe(-64.0);
expect(stats.stdDev as number).toBeCloseTo(46.3, 1);
},
});
});
26 changes: 25 additions & 1 deletion tests/Length.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { checkForScreenshot, screenShotPaths, test, visitStudy } from './utils';
import {
checkForScreenshot,
expect,
expectAnnotationStatsText,
measurementTextFormatters,
screenShotPaths,
test,
visitStudy,
} from './utils';

test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5';
Expand All @@ -10,6 +18,7 @@ test('should display the length tool', async ({
page,
DOMOverlayPageObject,
mainToolbarPageObject,
rightPanelPageObject,
viewportPageObject,
}) => {
await mainToolbarPageObject.measurementTools.length.click();
Expand All @@ -25,4 +34,19 @@ test('should display the length tool', async ({
viewportPageObject.grid,
screenShotPaths.length.lengthDisplayedCorrectly
);

await rightPanelPageObject.measurementsPanel.select();

await expectAnnotationStatsText({
page,
activeViewport,
rightPanelPageObject,
toolName: 'Length',
formatPanelPrimaryLines: [measurementTextFormatters.lengthLine],
formatSvgLines: [measurementTextFormatters.lengthLine],
assertStats: stats => {
expect(stats.unit).toBe('mm');
expect(Math.round(stats.length as number)).toBe(278);
},
});
});
Loading
Loading