607 lines
16 KiB
TypeScript
607 lines
16 KiB
TypeScript
import toggleVOISliceSync from './toggleVOISliceSync';
|
|
|
|
describe('toggleVOISliceSync', () => {
|
|
const mockSyncGroupService = {
|
|
getSynchronizersForViewport: jest.fn(),
|
|
addViewportToSyncGroup: jest.fn(),
|
|
removeViewportFromSyncGroup: jest.fn(),
|
|
};
|
|
|
|
const mockViewportGridService = {
|
|
getState: jest.fn(),
|
|
};
|
|
|
|
const mockDisplaySetService = {
|
|
getDisplaySetByUID: jest.fn(),
|
|
};
|
|
|
|
const mockCornerstoneViewportService = {
|
|
getCornerstoneViewport: jest.fn(),
|
|
};
|
|
|
|
const mockServicesManager = {
|
|
services: {
|
|
syncGroupService: mockSyncGroupService,
|
|
viewportGridService: mockViewportGridService,
|
|
displaySetService: mockDisplaySetService,
|
|
cornerstoneViewportService: mockCornerstoneViewportService,
|
|
},
|
|
};
|
|
|
|
const mockViewport = {
|
|
id: 'viewport-1',
|
|
getRenderingEngine: jest.fn(() => ({ id: 'rendering-engine-1' })),
|
|
};
|
|
|
|
const mockViewport2 = {
|
|
id: 'viewport-2',
|
|
getRenderingEngine: jest.fn(() => ({ id: 'rendering-engine-2' })),
|
|
};
|
|
|
|
const mockGridViewport = {
|
|
viewportOptions: {
|
|
viewportId: 'viewport-1',
|
|
},
|
|
displaySetInstanceUIDs: ['displaySet-1'],
|
|
};
|
|
|
|
const mockDisplaySet = {
|
|
Modality: 'CT',
|
|
};
|
|
|
|
const defaultParameters = {
|
|
servicesManager: mockServicesManager as unknown as AppTypes.ServicesManager,
|
|
viewports: null,
|
|
syncId: null,
|
|
};
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
mockCornerstoneViewportService.getCornerstoneViewport.mockReturnValue(mockViewport);
|
|
mockDisplaySetService.getDisplaySetByUID.mockReturnValue(mockDisplaySet);
|
|
});
|
|
|
|
it('should enable sync when no sync exists for single modality', () => {
|
|
const viewports = {
|
|
CT: [mockGridViewport],
|
|
};
|
|
|
|
mockSyncGroupService.getSynchronizersForViewport.mockReturnValue([]);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports,
|
|
});
|
|
|
|
expect(mockSyncGroupService.getSynchronizersForViewport).toHaveBeenCalledWith('viewport-1');
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenCalledWith(
|
|
'viewport-1',
|
|
'rendering-engine-1',
|
|
{
|
|
type: 'voi',
|
|
id: 'VOI_SYNC_CT',
|
|
source: true,
|
|
target: true,
|
|
}
|
|
);
|
|
});
|
|
|
|
it('should disable sync when sync already exists', () => {
|
|
const viewports = {
|
|
CT: [mockGridViewport],
|
|
};
|
|
|
|
const mockSyncState = {
|
|
id: 'VOI_SYNC_CT',
|
|
};
|
|
|
|
mockSyncGroupService.getSynchronizersForViewport.mockReturnValue([mockSyncState]);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports,
|
|
});
|
|
|
|
expect(mockSyncGroupService.removeViewportFromSyncGroup).toHaveBeenCalledWith(
|
|
'viewport-1',
|
|
'rendering-engine-1',
|
|
'VOI_SYNC_CT'
|
|
);
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should use custom syncId when provided', () => {
|
|
const viewports = {
|
|
CT: [mockGridViewport],
|
|
};
|
|
|
|
mockSyncGroupService.getSynchronizersForViewport.mockReturnValue([]);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports,
|
|
syncId: 'CUSTOM_SYNC_ID',
|
|
});
|
|
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenCalledWith(
|
|
'viewport-1',
|
|
'rendering-engine-1',
|
|
{
|
|
type: 'voi',
|
|
id: 'CUSTOM_SYNC_ID',
|
|
source: true,
|
|
target: true,
|
|
}
|
|
);
|
|
});
|
|
|
|
it('should handle multiple viewports in same modality', () => {
|
|
const mockGridViewport2 = {
|
|
viewportOptions: {
|
|
viewportId: 'viewport-2',
|
|
},
|
|
displaySetInstanceUIDs: ['displaySet-2'],
|
|
};
|
|
|
|
const viewports = {
|
|
CT: [mockGridViewport, mockGridViewport2],
|
|
};
|
|
|
|
mockCornerstoneViewportService.getCornerstoneViewport
|
|
.mockReturnValueOnce(mockViewport)
|
|
.mockReturnValueOnce(mockViewport2);
|
|
|
|
mockSyncGroupService.getSynchronizersForViewport.mockReturnValue([]);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports,
|
|
});
|
|
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenCalledTimes(2);
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenNthCalledWith(
|
|
1,
|
|
'viewport-1',
|
|
'rendering-engine-1',
|
|
{
|
|
type: 'voi',
|
|
id: 'VOI_SYNC_CT',
|
|
source: true,
|
|
target: true,
|
|
}
|
|
);
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenNthCalledWith(
|
|
2,
|
|
'viewport-2',
|
|
'rendering-engine-2',
|
|
{
|
|
type: 'voi',
|
|
id: 'VOI_SYNC_CT',
|
|
source: true,
|
|
target: true,
|
|
}
|
|
);
|
|
});
|
|
|
|
it('should handle multiple modalities separately', () => {
|
|
const mockGridViewportMR = {
|
|
viewportOptions: {
|
|
viewportId: 'viewport-mr',
|
|
},
|
|
displaySetInstanceUIDs: ['displaySet-mr'],
|
|
};
|
|
|
|
const mockViewportMR = {
|
|
id: 'viewport-mr',
|
|
getRenderingEngine: jest.fn(() => ({ id: 'rendering-engine-mr' })),
|
|
};
|
|
|
|
const viewports = {
|
|
CT: [mockGridViewport],
|
|
MR: [mockGridViewportMR],
|
|
};
|
|
|
|
mockCornerstoneViewportService.getCornerstoneViewport
|
|
.mockReturnValueOnce(mockViewport)
|
|
.mockReturnValueOnce(mockViewportMR);
|
|
|
|
mockSyncGroupService.getSynchronizersForViewport.mockReturnValue([]);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports,
|
|
});
|
|
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenCalledTimes(2);
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenNthCalledWith(
|
|
1,
|
|
'viewport-1',
|
|
'rendering-engine-1',
|
|
{
|
|
type: 'voi',
|
|
id: 'VOI_SYNC_CT',
|
|
source: true,
|
|
target: true,
|
|
}
|
|
);
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenNthCalledWith(
|
|
2,
|
|
'viewport-mr',
|
|
'rendering-engine-mr',
|
|
{
|
|
type: 'voi',
|
|
id: 'VOI_SYNC_MR',
|
|
source: true,
|
|
target: true,
|
|
}
|
|
);
|
|
});
|
|
|
|
it('should skip viewport when cornerstone viewport is not found', () => {
|
|
const viewports = {
|
|
CT: [mockGridViewport],
|
|
};
|
|
|
|
mockCornerstoneViewportService.getCornerstoneViewport.mockReturnValue(null);
|
|
mockSyncGroupService.getSynchronizersForViewport.mockReturnValue([]);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports,
|
|
});
|
|
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should generate viewports from grid service when not provided', () => {
|
|
const mockViewportsMap = new Map([
|
|
[
|
|
'viewport-1',
|
|
{
|
|
...mockGridViewport,
|
|
},
|
|
],
|
|
]);
|
|
|
|
const mockState = {
|
|
viewports: mockViewportsMap,
|
|
};
|
|
|
|
mockViewportGridService.getState.mockReturnValue(mockState);
|
|
mockSyncGroupService.getSynchronizersForViewport.mockReturnValue([]);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports: null,
|
|
});
|
|
|
|
expect(mockViewportGridService.getState).toHaveBeenCalled();
|
|
expect(mockDisplaySetService.getDisplaySetByUID).toHaveBeenCalledWith('displaySet-1');
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenCalledWith(
|
|
'viewport-1',
|
|
'rendering-engine-1',
|
|
{
|
|
type: 'voi',
|
|
id: 'VOI_SYNC_CT',
|
|
source: true,
|
|
target: true,
|
|
}
|
|
);
|
|
});
|
|
|
|
it('should handle sync state with different id not matching', () => {
|
|
const viewports = {
|
|
CT: [mockGridViewport],
|
|
};
|
|
|
|
const mockSyncState = {
|
|
id: 'DIFFERENT_SYNC_ID',
|
|
};
|
|
|
|
mockSyncGroupService.getSynchronizersForViewport.mockReturnValue([mockSyncState]);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports,
|
|
});
|
|
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenCalledWith(
|
|
'viewport-1',
|
|
'rendering-engine-1',
|
|
{
|
|
type: 'voi',
|
|
id: 'VOI_SYNC_CT',
|
|
source: true,
|
|
target: true,
|
|
}
|
|
);
|
|
expect(mockSyncGroupService.removeViewportFromSyncGroup).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should handle mixed sync states where some match and some do not', () => {
|
|
const mockGridViewport2 = {
|
|
viewportOptions: {
|
|
viewportId: 'viewport-2',
|
|
},
|
|
displaySetInstanceUIDs: ['displaySet-2'],
|
|
};
|
|
|
|
const viewports = {
|
|
CT: [mockGridViewport, mockGridViewport2],
|
|
};
|
|
|
|
const mockSyncState = {
|
|
id: 'VOI_SYNC_CT',
|
|
};
|
|
|
|
mockSyncGroupService.getSynchronizersForViewport
|
|
.mockReturnValueOnce([mockSyncState])
|
|
.mockReturnValueOnce([]);
|
|
|
|
mockCornerstoneViewportService.getCornerstoneViewport
|
|
.mockReturnValueOnce(mockViewport)
|
|
.mockReturnValueOnce(mockViewport2);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports,
|
|
});
|
|
|
|
expect(mockSyncGroupService.removeViewportFromSyncGroup).toHaveBeenCalledWith(
|
|
'viewport-1',
|
|
'rendering-engine-1',
|
|
'VOI_SYNC_CT'
|
|
);
|
|
expect(mockSyncGroupService.removeViewportFromSyncGroup).toHaveBeenCalledWith(
|
|
'viewport-2',
|
|
'rendering-engine-2',
|
|
'VOI_SYNC_CT'
|
|
);
|
|
});
|
|
|
|
it('should disable sync for multiple viewports when sync exists', () => {
|
|
const mockGridViewport2 = {
|
|
viewportOptions: {
|
|
viewportId: 'viewport-2',
|
|
},
|
|
displaySetInstanceUIDs: ['displaySet-2'],
|
|
};
|
|
|
|
const mockViewport2 = {
|
|
id: 'viewport-2',
|
|
getRenderingEngine: jest.fn(() => ({ id: 'rendering-engine-2' })),
|
|
};
|
|
|
|
const viewports = {
|
|
CT: [mockGridViewport, mockGridViewport2],
|
|
};
|
|
|
|
const mockSyncState = {
|
|
id: 'VOI_SYNC_CT',
|
|
};
|
|
|
|
mockCornerstoneViewportService.getCornerstoneViewport
|
|
.mockReturnValueOnce(mockViewport)
|
|
.mockReturnValueOnce(mockViewport2);
|
|
|
|
mockSyncGroupService.getSynchronizersForViewport.mockReturnValue([mockSyncState]);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports,
|
|
});
|
|
|
|
expect(mockSyncGroupService.removeViewportFromSyncGroup).toHaveBeenCalledTimes(2);
|
|
expect(mockSyncGroupService.removeViewportFromSyncGroup).toHaveBeenNthCalledWith(
|
|
1,
|
|
'viewport-1',
|
|
'rendering-engine-1',
|
|
'VOI_SYNC_CT'
|
|
);
|
|
expect(mockSyncGroupService.removeViewportFromSyncGroup).toHaveBeenNthCalledWith(
|
|
2,
|
|
'viewport-2',
|
|
'rendering-engine-2',
|
|
'VOI_SYNC_CT'
|
|
);
|
|
});
|
|
|
|
it('should skip viewport during disable when cornerstone viewport is not found', () => {
|
|
const mockGridViewport2 = {
|
|
viewportOptions: {
|
|
viewportId: 'viewport-2',
|
|
},
|
|
displaySetInstanceUIDs: ['displaySet-2'],
|
|
};
|
|
|
|
const viewports = {
|
|
CT: [mockGridViewport, mockGridViewport2],
|
|
};
|
|
|
|
const mockSyncState = {
|
|
id: 'VOI_SYNC_CT',
|
|
};
|
|
|
|
mockCornerstoneViewportService.getCornerstoneViewport
|
|
.mockReturnValueOnce(mockViewport)
|
|
.mockReturnValueOnce(null);
|
|
|
|
mockSyncGroupService.getSynchronizersForViewport.mockReturnValue([mockSyncState]);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports,
|
|
});
|
|
|
|
expect(mockSyncGroupService.removeViewportFromSyncGroup).toHaveBeenCalledTimes(1);
|
|
expect(mockSyncGroupService.removeViewportFromSyncGroup).toHaveBeenCalledWith(
|
|
'viewport-1',
|
|
'rendering-engine-1',
|
|
'VOI_SYNC_CT'
|
|
);
|
|
});
|
|
|
|
it('should handle empty viewports object', () => {
|
|
const viewports = {};
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports,
|
|
});
|
|
|
|
expect(mockSyncGroupService.getSynchronizersForViewport).not.toHaveBeenCalled();
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).not.toHaveBeenCalled();
|
|
expect(mockSyncGroupService.removeViewportFromSyncGroup).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should handle modality with empty viewport array', () => {
|
|
const viewports = {
|
|
CT: [],
|
|
};
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports,
|
|
});
|
|
|
|
expect(mockSyncGroupService.getSynchronizersForViewport).not.toHaveBeenCalled();
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).not.toHaveBeenCalled();
|
|
expect(mockSyncGroupService.removeViewportFromSyncGroup).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should handle multiple displaySetInstanceUIDs by using first one', () => {
|
|
const mockGridViewportMultipleDisplaySets = {
|
|
viewportOptions: {
|
|
viewportId: 'viewport-1',
|
|
},
|
|
displaySetInstanceUIDs: ['displaySet-1', 'displaySet-2', 'displaySet-3'],
|
|
};
|
|
|
|
mockViewportGridService.getState.mockReturnValue({
|
|
viewports: new Map([['viewport-1', mockGridViewportMultipleDisplaySets]]),
|
|
});
|
|
mockSyncGroupService.getSynchronizersForViewport.mockReturnValue([]);
|
|
mockDisplaySetService.getDisplaySetByUID.mockReturnValue(mockDisplaySet);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
});
|
|
|
|
expect(mockDisplaySetService.getDisplaySetByUID).toHaveBeenCalledWith('displaySet-1');
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenCalledWith(
|
|
'viewport-1',
|
|
'rendering-engine-1',
|
|
{
|
|
type: 'voi',
|
|
id: 'VOI_SYNC_CT',
|
|
source: true,
|
|
target: true,
|
|
}
|
|
);
|
|
});
|
|
|
|
it('should group viewports by modality correctly when generating from grid', () => {
|
|
const mockViewportsMap = new Map([
|
|
[
|
|
'viewport-ct-1',
|
|
{
|
|
viewportOptions: {
|
|
viewportId: 'viewport-ct-1',
|
|
},
|
|
displaySetInstanceUIDs: ['displaySet-ct-1'],
|
|
},
|
|
],
|
|
[
|
|
'viewport-ct-2',
|
|
{
|
|
viewportOptions: {
|
|
viewportId: 'viewport-ct-2',
|
|
},
|
|
displaySetInstanceUIDs: ['displaySet-ct-2'],
|
|
},
|
|
],
|
|
[
|
|
'viewport-mr-1',
|
|
{
|
|
viewportOptions: {
|
|
viewportId: 'viewport-mr-1',
|
|
},
|
|
displaySetInstanceUIDs: ['displaySet-mr-1'],
|
|
},
|
|
],
|
|
]);
|
|
|
|
const mockState = {
|
|
viewports: mockViewportsMap,
|
|
};
|
|
|
|
const mockDisplaySetCT = { Modality: 'CT' };
|
|
const mockDisplaySetMR = { Modality: 'MR' };
|
|
const mockViewportCT1 = {
|
|
id: 'viewport-ct-1',
|
|
getRenderingEngine: jest.fn(() => ({ id: 'rendering-engine-ct-1' })),
|
|
};
|
|
const mockViewportCT2 = {
|
|
id: 'viewport-ct-2',
|
|
getRenderingEngine: jest.fn(() => ({ id: 'rendering-engine-ct-2' })),
|
|
};
|
|
const mockViewportMR1 = {
|
|
id: 'viewport-mr-1',
|
|
getRenderingEngine: jest.fn(() => ({ id: 'rendering-engine-mr-1' })),
|
|
};
|
|
|
|
mockViewportGridService.getState.mockReturnValue(mockState);
|
|
mockDisplaySetService.getDisplaySetByUID
|
|
.mockReturnValueOnce(mockDisplaySetCT)
|
|
.mockReturnValueOnce(mockDisplaySetCT)
|
|
.mockReturnValueOnce(mockDisplaySetMR);
|
|
|
|
mockCornerstoneViewportService.getCornerstoneViewport
|
|
.mockReturnValueOnce(mockViewportCT1)
|
|
.mockReturnValueOnce(mockViewportCT2)
|
|
.mockReturnValueOnce(mockViewportMR1);
|
|
|
|
mockSyncGroupService.getSynchronizersForViewport.mockReturnValue([]);
|
|
|
|
toggleVOISliceSync({
|
|
...defaultParameters,
|
|
viewports: null,
|
|
});
|
|
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenCalledTimes(3);
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenNthCalledWith(
|
|
1,
|
|
'viewport-ct-1',
|
|
'rendering-engine-ct-1',
|
|
{
|
|
type: 'voi',
|
|
id: 'VOI_SYNC_CT',
|
|
source: true,
|
|
target: true,
|
|
}
|
|
);
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenNthCalledWith(
|
|
2,
|
|
'viewport-ct-2',
|
|
'rendering-engine-ct-2',
|
|
{
|
|
type: 'voi',
|
|
id: 'VOI_SYNC_CT',
|
|
source: true,
|
|
target: true,
|
|
}
|
|
);
|
|
expect(mockSyncGroupService.addViewportToSyncGroup).toHaveBeenNthCalledWith(
|
|
3,
|
|
'viewport-mr-1',
|
|
'rendering-engine-mr-1',
|
|
{
|
|
type: 'voi',
|
|
id: 'VOI_SYNC_MR',
|
|
source: true,
|
|
target: true,
|
|
}
|
|
);
|
|
});
|
|
});
|