fix(TMTV): The TMTV CSV file now has the correct name and contents (#5215)
This commit is contained in:
parent
fceb515a68
commit
522d2aa764
@ -78,6 +78,7 @@ export default function PanelRoiThresholdSegmentation() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Button
|
<Button
|
||||||
|
dataCY="exportTmtvCsvReport"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className="text-blue-500"
|
className="text-blue-500"
|
||||||
|
|||||||
@ -362,7 +362,9 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const referencedVolume =
|
const referencedVolume =
|
||||||
csTools.utilities.segmentation.getReferenceVolumeForSegmentationVolume(segmentationId);
|
csTools.utilities.segmentation.getReferenceVolumeForSegmentationVolume(
|
||||||
|
labelmapVolume.volumeId
|
||||||
|
);
|
||||||
|
|
||||||
if (!referencedVolume) {
|
if (!referencedVolume) {
|
||||||
report[id] = segReport;
|
report[id] = segReport;
|
||||||
|
|||||||
@ -1,14 +1,26 @@
|
|||||||
export default function createAndDownloadTMTVReport(segReport, additionalReportRows, options = {}) {
|
export default function createAndDownloadTMTVReport(segReport, additionalReportRows, options = {}) {
|
||||||
const firstReport = segReport[Object.keys(segReport)[0]];
|
const firstReport = segReport[Object.keys(segReport)[0]];
|
||||||
const columns = Object.keys(firstReport);
|
const columns = Object.keys(firstReport);
|
||||||
const csv = [columns.join(',')];
|
const csv = [
|
||||||
|
columns
|
||||||
|
.map(column =>
|
||||||
|
column.toLowerCase().startsWith('namedstats_') ? column.substring(11) : column
|
||||||
|
)
|
||||||
|
.join(','),
|
||||||
|
];
|
||||||
|
|
||||||
Object.values(segReport).forEach(segmentation => {
|
Object.values(segReport).forEach(segmentation => {
|
||||||
const row = [];
|
const row = [];
|
||||||
columns.forEach(column => {
|
columns.forEach(column => {
|
||||||
// if it is array then we need to replace , with space to avoid csv parsing error
|
// if it is array then we need to replace , with space to avoid csv parsing error
|
||||||
row.push(
|
row.push(
|
||||||
Array.isArray(segmentation[column]) ? segmentation[column].join(' ') : segmentation[column]
|
segmentation[column] && typeof segmentation[column] === 'object'
|
||||||
|
? Array.isArray(segmentation[column])
|
||||||
|
? segmentation[column].join(' ')
|
||||||
|
: segmentation[column].value && Array.isArray(segmentation[column].value)
|
||||||
|
? segmentation[column].value.join(' ')
|
||||||
|
: (segmentation[column].value ?? segmentation[column])
|
||||||
|
: segmentation[column]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
csv.push(row.join(','));
|
csv.push(row.join(','));
|
||||||
|
|||||||
@ -23,6 +23,7 @@ export const AddSegmentationRow: React.FC<{ children?: React.ReactNode }> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
data-cy="addSegmentation"
|
||||||
className={`group ${disabled ? 'pointer-events-none cursor-not-allowed opacity-70' : ''}`}
|
className={`group ${disabled ? 'pointer-events-none cursor-not-allowed opacity-70' : ''}`}
|
||||||
onClick={() => !disabled && onSegmentationAdd('')}
|
onClick={() => !disabled && onSegmentationAdd('')}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { test } from 'playwright-test-coverage';
|
import { test } from 'playwright-test-coverage';
|
||||||
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
||||||
import { assertNumberOfModalityLoadBadges } from './utils/assertions';
|
import { assertNumberOfModalityLoadBadges } from './utils/assertions';
|
||||||
|
import { viewportLocator } from './utils/locators';
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
const studyInstanceUID = '1.3.6.1.4.1.5962.99.1.2968617883.1314880426.1493322302363.3.0';
|
const studyInstanceUID = '1.3.6.1.4.1.5962.99.1.2968617883.1314880426.1493322302363.3.0';
|
||||||
@ -24,7 +25,7 @@ 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.
|
// Hover over the middle/sagittal viewport so that the data overlay menu is available.
|
||||||
await page.locator('css=div[data-viewportid="mpr-sagittal"]').hover();
|
await viewportLocator({ viewportId: 'mpr-sagittal', page }).hover();
|
||||||
await page.getByTestId('dataOverlayMenu-mpr-sagittal-btn').click();
|
await page.getByTestId('dataOverlayMenu-mpr-sagittal-btn').click();
|
||||||
await page.getByTestId('AddSegmentationDataOverlay-mpr-sagittal').click();
|
await page.getByTestId('AddSegmentationDataOverlay-mpr-sagittal').click();
|
||||||
await page.getByText('SELECT A SEGMENTATION').click();
|
await page.getByText('SELECT A SEGMENTATION').click();
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { test } from 'playwright-test-coverage';
|
import { test } from 'playwright-test-coverage';
|
||||||
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
|
||||||
import { assertNumberOfModalityLoadBadges } from './utils/assertions';
|
import { assertNumberOfModalityLoadBadges } from './utils/assertions';
|
||||||
|
import { viewportLocator } from './utils/locators';
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
const studyInstanceUID = '1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046';
|
const studyInstanceUID = '1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046';
|
||||||
@ -25,7 +26,7 @@ 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.
|
// Hover over the middle/sagittal viewport so that the data overlay menu is available.
|
||||||
await page.locator('css=div[data-viewportid="mpr-sagittal"]').hover();
|
await viewportLocator({ viewportId: 'mpr-sagittal', page }).hover();
|
||||||
await page.getByTestId('dataOverlayMenu-mpr-sagittal-btn').click();
|
await page.getByTestId('dataOverlayMenu-mpr-sagittal-btn').click();
|
||||||
await page.getByTestId('AddSegmentationDataOverlay-mpr-sagittal').click();
|
await page.getByTestId('AddSegmentationDataOverlay-mpr-sagittal').click();
|
||||||
await page.getByText('SELECT A SEGMENTATION').click();
|
await page.getByText('SELECT A SEGMENTATION').click();
|
||||||
|
|||||||
45
tests/TMTVCSVReport.spec.ts
Normal file
45
tests/TMTVCSVReport.spec.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { test, expect } from 'playwright-test-coverage';
|
||||||
|
import { visitStudy, simulateNormalizedClickOnElement } from './utils/index';
|
||||||
|
import { viewportLocator } from './utils/locators';
|
||||||
|
import { downloadAsString } from './utils/download';
|
||||||
|
|
||||||
|
test('should create and download the TMTV CSV report correctly', async ({ page }) => {
|
||||||
|
const studyInstanceUID = '1.2.840.113619.2.290.3.3767434740.226.1600859119.501';
|
||||||
|
const mode = 'tmtv';
|
||||||
|
await visitStudy(page, studyInstanceUID, mode, 10000);
|
||||||
|
|
||||||
|
await page.getByTestId('addSegmentation').click();
|
||||||
|
await page.getByTestId('Brush-btn').click();
|
||||||
|
|
||||||
|
await simulateNormalizedClickOnElement({
|
||||||
|
locator: viewportLocator({ viewportId: 'ctAXIAL', page }),
|
||||||
|
normalizedPoint: { x: 0.5, y: 0.5 },
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.waitForTimeout(5000);
|
||||||
|
|
||||||
|
const downloadPromise = page.waitForEvent('download');
|
||||||
|
await page.getByTestId('exportTmtvCsvReport').click();
|
||||||
|
const download = await downloadPromise;
|
||||||
|
|
||||||
|
expect(download.suggestedFilename(), 'Not the correct file name for the TMTV CSV report.').toBe(
|
||||||
|
'202009231_tmtv.csv'
|
||||||
|
);
|
||||||
|
|
||||||
|
const tmtvCSVReportContent = await downloadAsString(download);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
tmtvCSVReportContent,
|
||||||
|
'Expected the file to start with specific column/value headers'
|
||||||
|
).toMatch(
|
||||||
|
/^id,label,min,max,mean,stdDev,median,skewness,kurtosis,count,maxLPS,minLPS,center,volume,peakValue,peakLPS,lesionGlycolysis,PatientID,PatientName,StudyInstanceUID,SeriesInstanceUID,StudyDate/
|
||||||
|
);
|
||||||
|
expect(tmtvCSVReportContent, 'Expected the patient name to be present').toContain(
|
||||||
|
'Water Phantom'
|
||||||
|
);
|
||||||
|
expect(tmtvCSVReportContent).toContain('Patient ID,202009231');
|
||||||
|
expect(tmtvCSVReportContent).toContain('Study Date,20200923');
|
||||||
|
expect(tmtvCSVReportContent, 'Expected no objects to be output.').not.toContain(
|
||||||
|
'[object Object]'
|
||||||
|
);
|
||||||
|
});
|
||||||
15
tests/utils/download.ts
Normal file
15
tests/utils/download.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Readable } from 'stream';
|
||||||
|
|
||||||
|
const _streamToString = async (stream: Readable) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const chunks = [];
|
||||||
|
stream.on('data', chunk => chunks.push(chunk));
|
||||||
|
stream.on('error', err => reject(err));
|
||||||
|
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const downloadAsString = async download => {
|
||||||
|
const stream = await download.createReadStream();
|
||||||
|
return _streamToString(stream);
|
||||||
|
};
|
||||||
11
tests/utils/locators.ts
Normal file
11
tests/utils/locators.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { Locator, Page } from '@playwright/test';
|
||||||
|
|
||||||
|
export const viewportLocator = ({
|
||||||
|
page,
|
||||||
|
viewportId,
|
||||||
|
}: {
|
||||||
|
page: Page;
|
||||||
|
viewportId: string;
|
||||||
|
}): Locator => {
|
||||||
|
return page.locator(`css=div[data-viewportid="${viewportId}"]`);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user