diff --git a/plugins/ohif/README.md b/plugins/ohif/README.md index ed189fc..09743f4 100644 --- a/plugins/ohif/README.md +++ b/plugins/ohif/README.md @@ -82,3 +82,36 @@ sudo wget https://lsb.orthanc-server.com/plugin-dicom-web/1.6/libOrthancDicomWeb sudo service orthanc restart ``` + +### Unit Tests +#### Setup + +The test pipeline for Javascript is configured in JEST and NPM. +Add more unit tests, create *.test.js file under `__tests__` folder. +Here are steps to setup test ENV: + +##### Install Jest + +```bash +npm install --save-dev jest +npm install --save-dev jest-environment-jsdom --legacy-peer-deps + +``` + +##### Configure Jest + +``` +"scripts": { + "test": "jest" +}, +"jest": { + "verbose": true, + "testEnvironment": "jsdom" +} +``` + +##### Run Tests + +```bash +npm test +``` \ No newline at end of file diff --git a/plugins/ohif/extensions/monai-service/jest.config.js b/plugins/ohif/extensions/monai-service/jest.config.js new file mode 100644 index 0000000..6f3d284 --- /dev/null +++ b/plugins/ohif/extensions/monai-service/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + testEnvironment: 'jest-environment-jsdom' +}; \ No newline at end of file diff --git a/plugins/ohif/extensions/monai-service/package.json b/plugins/ohif/extensions/monai-service/package.json index 7fb2ce3..fa6f3e7 100644 --- a/plugins/ohif/extensions/monai-service/package.json +++ b/plugins/ohif/extensions/monai-service/package.json @@ -1,64 +1,5 @@ { - "name": "@ohif/extension-monai-service", - "version": "0.0.1", - "description": "OHIFv3 extension for MONAI Service", - "author": "OHIF,NVIDIA", - "license": "MIT", - "main": "dist/umd/extension-monai-service/index.umd.js", - "files": [ - "dist/**", - "public/**", - "README.md" - ], - "repository": "OHIF/Viewers", - "keywords": [ - "ohif-extension" - ], - "module": "src/index.tsx", - "publishConfig": { - "access": "public" - }, - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1.18.0" - }, - "scripts": { - "dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo", - "dev:my-extension": "yarn run dev", - "build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js", - "build:package": "yarn run build", - "start": "yarn run dev" - }, - "peerDependencies": { - "@ohif/core": "^3.7.0-beta.80", - "@ohif/extension-default": "^3.7.0-beta.80", - "@ohif/extension-cornerstone": "^3.7.0-beta.80", - "@ohif/i18n": "^3.7.0-beta.80", - "prop-types": "^15.6.2", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "react-i18next": "^12.2.2", - "react-router": "^6.8.1", - "react-router-dom": "^6.8.1" - }, - "dependencies": { - "@babel/runtime": "^7.20.13", - "md5.js": "^1.3.5", - "axios": "^0.21.1", - "arraybuffer-concat": "^0.0.1", - "ndarray": "^1.0.19", - "nrrd-js": "^0.2.1", - "pako": "^2.0.3", - "react-color": "^2.19.3", - "bootstrap": "^5.0.2", - "react-select": "^4.3.1", - "chroma-js": "^2.1.2" - }, - "devDependencies": { - "@cornerstonejs/tools": "^1.16.0", - "@babel/runtime": "^7.20.13", - "@cornerstonejs/tools": "^1.16.4", - "react-color": "^2.19.3" - } + "devDependencies": { + "svgo": "^1.3.2" + } } diff --git a/plugins/ohif/extensions/monai-service/src/__tests__/inference.test.js b/plugins/ohif/extensions/monai-service/src/__tests__/inference.test.js new file mode 100644 index 0000000..1c08cb8 --- /dev/null +++ b/plugins/ohif/extensions/monai-service/src/__tests__/inference.test.js @@ -0,0 +1,73 @@ +import React from 'react'; +import { render, fireEvent, waitFor } from '@testing-library/react'; +import AutoSegmentation from './AutoSegmentation'; +import ModelSelector from '../ModelSelector'; + +jest.mock('../ModelSelector', () => (props) => ( + +)); +jest.mock('../../utils/GenericUtils', () => ({ + hideNotification: jest.fn(), +})); + +describe('AutoSegmentation', () => { + let props; + + beforeEach(() => { + props = { + client: () => ({ + inference: jest.fn().mockResolvedValue({ status: 201 }), + }), + updateView: jest.fn(), + notification: { + show: jest.fn(), + hide: jest.fn(), + }, + servicesManager: { + services: { + displaySetService: { + activeDisplaySets: [{ Modality: 'CT', SeriesInstanceUID: '123' }], + } + } + }, + info: { + models: [{ id: 'model1', network_arch: 'monai_vista3d' }], + modelLabelNames: { 'model1': ['Label1', 'Label2'] }, + modelLabelIndices: { 'model1': [1, 2] }, + modelLabelToIdxMap: { + 'model1': { 'kidney': 1, 'lung': 2, 'bone': 3 } + } + }, + viewConstants: { + SeriesInstanceUID: 'defaultSeriesInstanceUID' + } + }; + }); + + it('renders correctly', () => { + const { getByText } = render(); + expect(getByText('Auto-Segmentation')).toBeInTheDocument(); + }); + + it('calls onSelectModel when model is selected', () => { + const { getByText } = render(); + const selectButton = getByText('Select Model'); + fireEvent.click(selectButton); + expect(props.info.models.length).toBeGreaterThan(0); + }); + + it('calls onSegmentation when model is run', async () => { + const { getByText } = render(); + const selectButton = getByText('Select Model'); + fireEvent.click(selectButton); + await waitFor(() => { + expect(props.client().inference).toHaveBeenCalled(); + }); + expect(props.notification.show).toHaveBeenCalledWith(expect.objectContaining({ + title: 'MONAI Service', + message: 'Run Segmentation - Successful', + type: 'success', + })); + }); +}); + diff --git a/plugins/ohif/extensions/monai-service/src/__tests__/monaiServicePanel.test.js b/plugins/ohif/extensions/monai-service/src/__tests__/monaiServicePanel.test.js new file mode 100644 index 0000000..e75819f --- /dev/null +++ b/plugins/ohif/extensions/monai-service/src/__tests__/monaiServicePanel.test.js @@ -0,0 +1,63 @@ +import React from 'react'; +import { MonaiServicePanel } from './MonaiServicePanel'; +import { render, waitFor } from '@testing-library/react'; + +jest.mock('../services/MonaiServiceClient', () => { + return { + MonaiServiceClient: jest.fn().mockImplementation(() => ({ + getAuthorizationHeader: () => ({ Authorization: 'Bearer fake_token' }), + list_models: jest.fn().mockResolvedValue({ + status: 200, + data: [] + }), + cache_image: jest.fn().mockResolvedValue({}) + })) + }; +}); + +const mockNotificationService = { + show: jest.fn(), + hide: jest.fn() +}; + +const mockDisplaySetService = { + activeDisplaySets: [{ + SeriesInstanceUID: '123', + StudyInstanceUID: '456', + instances: [{ + FrameOfReferenceUID: '789' + }], + displaySetInstanceUID: '101112' + }] +}; + +// Test suite +describe('MonaiServicePanel', () => { + it('handles model and dataset information on successful connection', async () => { + const props = { + servicesManager: { + services: { + uiNotificationService: mockNotificationService, + displaySetService: mockDisplaySetService + } + } + }; + + const { container } = render(); + + const instance = container.querySelector('MonaiServicePanel'); + await instance.onInfo(); + + expect(mockNotificationService.show).toHaveBeenCalledWith(expect.objectContaining({ + type: 'info', + message: 'Connecting to MONAI Service' + })); + await waitFor(() => { + expect(mockNotificationService.show).toHaveBeenCalledWith(expect.objectContaining({ + type: 'success', + message: 'Connected to MONAI Service Server - Successful' + })); + }); + expect(instance.state.info.models.length).toBeGreaterThan(0); + }); +}); diff --git a/plugins/ohif/jest.config.js b/plugins/ohif/jest.config.js new file mode 100644 index 0000000..6f3d284 --- /dev/null +++ b/plugins/ohif/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + testEnvironment: 'jest-environment-jsdom' +}; \ No newline at end of file