From 79d0ee1560950e54234353f77b22b8257cc47540 Mon Sep 17 00:00:00 2001 From: "M.D" <26860200+md-prog@users.noreply.github.com> Date: Mon, 27 Mar 2023 15:57:46 -0400 Subject: [PATCH] fix(ellipticalROI): give default values for cachedStats values to avoid undefined error (#1537) * [bugfix] give default values for cachedStats values to avoid undefined error * coding rule fix * added new tests to increaes coverage * test refactor --- src/tools/annotation/EllipticalRoiTool.js | 2 +- .../annotation/EllipticalRoiTool.test.js | 81 +++++++++++++++++++ src/tools/annotation/RectangleRoiTool.js | 2 +- src/tools/annotation/RectangleRoiTool.test.js | 81 ++++++++++++++++++- 4 files changed, 162 insertions(+), 4 deletions(-) diff --git a/src/tools/annotation/EllipticalRoiTool.js b/src/tools/annotation/EllipticalRoiTool.js index 43ffbff5f..fe7e3baa4 100644 --- a/src/tools/annotation/EllipticalRoiTool.js +++ b/src/tools/annotation/EllipticalRoiTool.js @@ -355,7 +355,7 @@ function _getUnit(modality, showHounsfieldUnits) { function _createTextBoxContent( context, isColorImage, - { area, mean, stdDev, min, max, meanStdDevSUV } = {}, + { area = 0, mean = 0, stdDev = 0, min = 0, max = 0, meanStdDevSUV = 0 } = {}, modality, hasPixelSpacing, options = {} diff --git a/src/tools/annotation/EllipticalRoiTool.test.js b/src/tools/annotation/EllipticalRoiTool.test.js index cb67e91f6..0d3ae6fcd 100644 --- a/src/tools/annotation/EllipticalRoiTool.test.js +++ b/src/tools/annotation/EllipticalRoiTool.test.js @@ -1,11 +1,27 @@ import EllipticalRoiTool from './EllipticalRoiTool.js'; import { getToolState } from './../../stateManagement/toolState.js'; import { getLogger } from '../../util/logger.js'; +import getNewContext from '../../drawing/getNewContext.js'; +import drawEllipse from '../../drawing/drawEllipse.js'; + +/* ~ Setup + * To mock properly, Jest needs jest.mock('moduleName') to be in the + * same scope as the require/import statement. + */ +import external from '../../externalModules.js'; jest.mock('../../util/logger.js'); jest.mock('./../../stateManagement/toolState.js', () => ({ getToolState: jest.fn(), })); +jest.mock('../../drawing/drawEllipse', () => ({ + __esModule: true, + default: jest.fn(), +})); +jest.mock('../../drawing/getNewContext', () => ({ + __esModule: true, + default: jest.fn(), +})); jest.mock('./../../importInternal.js', () => ({ default: jest.fn(), @@ -19,6 +35,7 @@ jest.mock('./../../externalModules.js', () => ({ /* eslint-disable prettier/prettier */ getPixels: () => [100, 100, 100, 100, 4, 5, 100, 3, 6], /* eslint-enable prettier/prettier */ + pixelToCanvas: jest.fn(), }, })); @@ -215,6 +232,20 @@ describe('EllipticalRoiTool.js', () => { }); describe('renderToolData', () => { + beforeAll(() => { + getNewContext.mockReturnValue({ + save: jest.fn(), + restore: jest.fn(), + beginPath: jest.fn(), + arc: jest.fn(), + stroke: jest.fn(), + fillRect: jest.fn(), + fillText: jest.fn(), + measureText: jest.fn(() => ({ width: 1 })), + }); + external.cornerstone.pixelToCanvas.mockImplementation((comp, val) => val); + }); + it('returns undefined when no toolData exists for the tool', () => { const instantiatedTool = new EllipticalRoiTool(); const mockEvent = { @@ -228,5 +259,55 @@ describe('EllipticalRoiTool.js', () => { expect(renderResult).toBe(undefined); }); + + describe('draw ellipse with color', () => { + const defaulColor = 'white'; + const mockEvent = { + detail: { + element: {}, + canvasContext: { + canvas: {}, + }, + image: {}, + viewport: {}, + }, + }; + const instantiatedTool = new EllipticalRoiTool({ + configuration: {}, + }); + + const toolState = { + data: [ + { + visible: true, + active: false, + handles: { + start: { + x: 0, + y: 0, + }, + end: { + x: 3, + y: 3, + }, + textBox: {}, + }, + }, + ], + }; + + const expectDraw = color => { + expect(drawEllipse.mock.calls.length).toBe(1); + }; + + it('should draw an ellipse with the inactive color', () => { + toolState.data[0].active = false; + getToolState.mockReturnValue(toolState); + + instantiatedTool.renderToolData(mockEvent); + + expectDraw(defaulColor); + }); + }); }); }); diff --git a/src/tools/annotation/RectangleRoiTool.js b/src/tools/annotation/RectangleRoiTool.js index 173692f38..f0c1ce3bf 100644 --- a/src/tools/annotation/RectangleRoiTool.js +++ b/src/tools/annotation/RectangleRoiTool.js @@ -478,7 +478,7 @@ function _getUnit(modality, showHounsfieldUnits) { function _createTextBoxContent( context, isColorImage, - { area, mean, stdDev, min, max, meanStdDevSUV }, + { area = 0, mean = 0, stdDev = 0, min = 0, max = 0, meanStdDevSUV = 0 } = {}, modality, hasPixelSpacing, options = {} diff --git a/src/tools/annotation/RectangleRoiTool.test.js b/src/tools/annotation/RectangleRoiTool.test.js index 03c43e3a4..49726902c 100644 --- a/src/tools/annotation/RectangleRoiTool.test.js +++ b/src/tools/annotation/RectangleRoiTool.test.js @@ -1,13 +1,25 @@ import RectangleRoiTool from './RectangleRoiTool.js'; import { getToolState } from './../../stateManagement/toolState.js'; import { getLogger } from '../../util/logger.js'; +import getNewContext from '../../drawing/getNewContext.js'; +import drawRect from '../../drawing/drawRect.js'; + +/* ~ Setup + * To mock properly, Jest needs jest.mock('moduleName') to be in the + * same scope as the require/import statement. + */ +import external from '../../externalModules.js'; jest.mock('../../util/logger.js'); jest.mock('./../../stateManagement/toolState.js', () => ({ getToolState: jest.fn(), })); - -jest.mock('./../../importInternal.js', () => ({ +jest.mock('../../drawing/drawRect', () => ({ + __esModule: true, + default: jest.fn(), +})); +jest.mock('../../drawing/getNewContext', () => ({ + __esModule: true, default: jest.fn(), })); @@ -19,6 +31,7 @@ jest.mock('./../../externalModules.js', () => ({ /* eslint-enable prettier/prettier */ getPixels: () => [100, 100, 100, 100, 4, 5, 100, 3, 6], /* eslint-enable prettier/prettier */ + pixelToCanvas: jest.fn(), }, })); @@ -218,6 +231,20 @@ describe('RectangleRoiTool.js', () => { }); describe('renderToolData', () => { + beforeAll(() => { + getNewContext.mockReturnValue({ + save: jest.fn(), + restore: jest.fn(), + beginPath: jest.fn(), + arc: jest.fn(), + stroke: jest.fn(), + fillRect: jest.fn(), + fillText: jest.fn(), + measureText: jest.fn(() => ({ width: 1 })), + }); + external.cornerstone.pixelToCanvas.mockImplementation((comp, val) => val); + }); + it('returns undefined when no toolData exists for the tool', () => { const instantiatedTool = new RectangleRoiTool(); const mockEvent = { @@ -231,5 +258,55 @@ describe('RectangleRoiTool.js', () => { expect(renderResult).toBe(undefined); }); + + describe('draw rectangle with color', () => { + const defaulColor = 'white'; + const mockEvent = { + detail: { + element: {}, + canvasContext: { + canvas: {}, + }, + image: {}, + viewport: {}, + }, + }; + const instantiatedTool = new RectangleRoiTool({ + configuration: {}, + }); + + const toolState = { + data: [ + { + visible: true, + active: false, + handles: { + start: { + x: 0, + y: 0, + }, + end: { + x: 3, + y: 3, + }, + textBox: {}, + }, + }, + ], + }; + + const expectDraw = color => { + expect(drawRect.mock.calls.length).toBe(1); + }; + + it('should draw a rectangle with the inactive color', () => { + toolState.data[0].active = false; + getToolState.mockReturnValue(toolState); + + instantiatedTool.renderToolData(mockEvent); + + expectDraw(defaulColor); + }); + }); }); });