import {
inflateInitialScanState,
inflateScanState,
} from '@/functions/modelHelper';
import {
AnchorPoint,
FrontEndInterfaces,
PositionData,
ScanMovementActions,
SlidersActions,
} from '@3cr/types-ts';
import { flushPromises, mount } from '@vue/test-utils';
import { spyOn } from '@vitest/spy';
import {
cSlider,
currentGreyscalePreset,
isLayout1x3,
isLayout2x2,
setInitialScanStateFromPayload,
setScanState,
sSlider,
thresholdSlider,
transactionStarted,
tSlider,
windowSlider,
} from '@/models/scanState';
import { defineComponent, ref, unref } from 'vue';
import { Viewer3crServiceImpl } from '@/services/viewer-3cr.service';
import { VDialog } from 'vuetify/components';
import Viewer3cr from '@/components/modal/Viewer3cr.vue';
import SettingsMenu from '@/components/modal/menus/SettingsMenu.vue';
import { useDemoStore } from '@/stores/demo.store';
import { storeToRefs } from 'pinia';
import { useViewer3cr } from '@/composables/useViewer3cr';
import { MockInstance } from '@vitest/spy';
import ViewerNavigationDrawer from '@/components/modal/ViewerNavigationDrawer.vue';
import ViewerAppBar from '@/components/modal/app-bars/ViewerAppBar.vue';
import DemoNotificationNavigationDrawer from '@/components/demo/DemoNotificationNavigationDrawer.vue';
import ViewerIntro from '@/components/intro/ViewerIntro.vue';
import ViewerTour from '@/components/intro/ViewerTour.vue';
import { ViewerPayload } from '@3cr/viewer-types-ts';
let spy: MockInstance;
const app = defineComponent({
template: '',
components: { Viewer3cr },
setup() {
const webgl = ref();
return { webgl };
},
});
describe('Viewer3cr tests', () => {
const viewer3cr = useViewer3cr() as Viewer3crServiceImpl;
const { isDemo } = storeToRefs(useDemoStore());
let wrapper = mount(app, { global: { stubs: ['Viewer3crWebGL'] } });
spy = spyOn(viewer3cr, 'sendPayload').mockResolvedValue();
beforeEach(() => {
transactionStarted.value = false;
spy = spyOn(viewer3cr, 'sendPayload').mockResolvedValue();
wrapper = mount(app, { global: { stubs: ['Viewer3crWebGL'] } });
});
afterEach(() => {
isDemo.value = false;
vi.clearAllMocks();
wrapper.unmount();
});
it('inflates', () => {
expect(wrapper).toBeTruthy();
});
describe('watchers', () => {
it('scanState.value.Display.Brightness', async () => {
await testWatcherForDisplay('Brightness', SlidersActions.sl01);
});
it('scanState.value.Display.Contrast', async () => {
await testWatcherForDisplay('Contrast', SlidersActions.sl02);
});
it('scanState.value.Display.Opacity', async () => {
await testWatcherForDisplay('Opacity', SlidersActions.sl03);
});
it('scanState.value.Display.WindowLower', async () => {
await testWatcherForDisplay('WindowLower', SlidersActions.sl04);
});
it('scanState.value.Display.WindowUpper', async () => {
await testWatcherForDisplay('WindowUpper', SlidersActions.sl05);
});
it('scanState.value.Display.ThresholdLower', async () => {
await testWatcherForDisplay('ThresholdLower', SlidersActions.sl06);
});
it('scanState.value.Display.ThresholdUpper', async () => {
await testWatcherForDisplay('ThresholdUpper', SlidersActions.sl07);
});
it('scanState.value.Slice.TransverseLower', async () => {
await testWatcherForSlice('TransverseLower', SlidersActions.sl08);
});
it('scanState.value.Orientations.Transverse.Slice', async () => {
await testWatcherForOrientation('Transverse', SlidersActions.sl09);
});
it('scanState.value.Slice.TransverseUpper', async () => {
await testWatcherForSlice('TransverseUpper', SlidersActions.sl10);
});
it('scanState.value.Slice.SagittalLower', async () => {
await testWatcherForSlice('SagittalLower', SlidersActions.sl11);
});
it('scanState.value.Orientations.Sagittal.Slice', async () => {
await testWatcherForOrientation('Sagittal', SlidersActions.sl12);
});
it('scanState.value.Slice.SagittalUpper', async () => {
await testWatcherForSlice('SagittalUpper', SlidersActions.sl13);
});
it('scanState.value.Slice.CoronalLower', async () => {
await testWatcherForSlice('CoronalLower', SlidersActions.sl14);
});
it('scanState.value.Orientations.Coronal.Slice', async () => {
await testWatcherForOrientation('Coronal', SlidersActions.sl15);
});
it('scanState.value.Slice.CoronalUpper', async () => {
await testWatcherForSlice('CoronalUpper', SlidersActions.sl16);
});
it('scanState.value.Slice.CoronalUpper transaction disabled', async () => {
transactionStarted.value = true;
await testWatcherForSlice('CoronalUpper', SlidersActions.sl16, true);
});
it('scanState.value.InteractionSettings.PanSensivitity transaction disabled', async () => {
transactionStarted.value = true;
await testWatcherForInteractionSettings(
'PanSensivitity1',
ScanMovementActions.sm05,
true,
);
});
it('scanState.value.InteractionSettings.PanSensivitity', async () => {
await testWatcherForInteractionSettings(
'PanSensivitity',
ScanMovementActions.sm05,
);
});
it('scanState.value.InteractionSettings.ZoomSensitivity', async () => {
await testWatcherForInteractionSettings(
'ZoomSensitivity',
ScanMovementActions.sm08,
);
});
it('scanState.value.InteractionSettings.RotateSensitivity', async () => {
await testWatcherForInteractionSettings(
'RotateSensitivity',
ScanMovementActions.sm10,
);
});
it('scanState.value.InteractionSettings.CameraRotateSensitivity', async () => {
await testWatcherForInteractionSettings(
'CameraRotateSensitivity',
ScanMovementActions.sm12,
);
});
});
it('watches scanState', () => {
expect(wrapper).toBeTruthy();
});
it('tSlider should be set', () => {
expect(unref(tSlider)).toStrictEqual([0, 0]);
});
it('sSlider should be set', () => {
expect(unref(sSlider)).toStrictEqual([0, 0]);
});
it('cSlider should be set', () => {
expect(unref(cSlider)).toStrictEqual([0, 0]);
});
it('windowSlider should set', async () => {
const newVals: [number, number] = [20, 20];
windowSlider.value = newVals;
await flushPromises();
expect(windowSlider.value).toStrictEqual(newVals);
});
it('thresholdSlider should set', async () => {
const newVals: [number, number] = [20, 20];
thresholdSlider.value = newVals;
await flushPromises();
expect(thresholdSlider.value).toStrictEqual(newVals);
});
it('tSlider should set', async () => {
const newVals: [number, number] = [0, 0];
tSlider.value = newVals;
await flushPromises();
expect(tSlider.value).toStrictEqual(newVals);
});
it('sSlider should set', async () => {
const newVals: [number, number] = [0, 0];
sSlider.value = newVals;
await flushPromises();
expect(sSlider.value).toStrictEqual(newVals);
});
it('cSlider should set', async () => {
const newVals: [number, number] = [0, 0];
cSlider.value = newVals;
await flushPromises();
expect(cSlider.value).toStrictEqual(newVals);
});
it('should isLayout2x2', async () => {
const scanState = inflateScanState();
scanState.Layout.PositionData = [
{ Anchor: AnchorPoint.TOP_LEFT } as PositionData,
{ Anchor: AnchorPoint.TOP_RIGHT } as PositionData,
{ Anchor: AnchorPoint.BOTTOM_LEFT } as PositionData,
{ Anchor: AnchorPoint.BOTTOM_RIGHT } as PositionData,
];
setScanState(JSON.stringify(scanState));
expect(unref(isLayout2x2)).toBeTruthy();
expect(unref(isLayout1x3)).toBeFalsy();
});
it('should isLayout1x3', async () => {
const scanState = inflateScanState();
scanState.Layout.PositionData = [
{ Anchor: AnchorPoint.CENTER } as PositionData,
{ Anchor: AnchorPoint.TOP_RIGHT } as PositionData,
{ Anchor: AnchorPoint.RIGHT } as PositionData,
{ Anchor: AnchorPoint.BOTTOM_RIGHT } as PositionData,
];
setScanState(JSON.stringify(scanState));
expect(unref(isLayout1x3)).toBeTruthy();
expect(unref(isLayout2x2)).toBeFalsy();
});
it('should getCurrentGreyscalePreset', async () => {
const initial = inflateInitialScanState();
initial.GreyscalePresets = [
{ Name: 'testing', Lower: 30, Upper: 60, Version: '1.0.0' },
];
setInitialScanStateFromPayload(JSON.stringify(initial));
await flushPromises();
const scanState = inflateScanState();
scanState.Display.WindowLower = 30;
scanState.Display.WindowUpper = 60;
setScanState(JSON.stringify(scanState));
await flushPromises();
expect(unref(currentGreyscalePreset)?.Name).toBe('testing');
});
it('should getCurrentGreyscalePreset', async () => {
const initial = inflateInitialScanState();
initial.GreyscalePresets = [
{ Name: 'testing', Lower: 30, Upper: 60, Version: '1.0.0' },
];
initial.HuLower = 40;
initial.HuUpper = 50;
setInitialScanStateFromPayload(JSON.stringify(initial));
await flushPromises();
const scanState = inflateScanState();
scanState.Display.WindowLower = 40;
scanState.Display.WindowUpper = 50;
setScanState(JSON.stringify(scanState));
await flushPromises();
expect(unref(currentGreyscalePreset)?.Name).toBe('testing');
});
it('should getCurrentGreyscalePreset', async () => {
const initial = inflateInitialScanState();
initial.GreyscalePresets = [
{ Name: 'testing', Lower: 30, Upper: 60, Version: '1.0.0' },
];
initial.HuLower = 40;
initial.HuUpper = 50;
setInitialScanStateFromPayload(JSON.stringify(initial));
await flushPromises();
const scanState = inflateScanState();
scanState.Display.WindowLower = 45;
scanState.Display.WindowUpper = 46;
setScanState(JSON.stringify(scanState));
await flushPromises();
expect(unref(currentGreyscalePreset)).toBe(undefined);
});
it('should getCurrentGreyscalePreset', async () => {
expect(unref(currentGreyscalePreset)).toBe(undefined);
});
it('should close dialog', async () => {
const wrapper = mount(Viewer3cr);
expect(wrapper.vm.m_closeDialog).toBe(false);
wrapper.findComponent(ViewerNavigationDrawer).vm.$emit('close');
expect(wrapper.vm.m_closeDialog).toBe(true);
});
it('should close dialog appbar', async () => {
const wrapper = mount(Viewer3cr);
expect(wrapper.vm.m_closeDialog).toBe(false);
wrapper.findComponent(ViewerAppBar).vm.$emit('close');
expect(wrapper.vm.m_closeDialog).toBe(true);
});
it('should ViewerIntro emit start', async () => {
const wrapper = mount(Viewer3cr);
expect(wrapper.vm.tourActive).toBe(false);
wrapper.findComponent(ViewerIntro).vm.$emit('start');
await flushPromises();
expect(wrapper.vm.tourActive).toBe(true);
});
it('should ViewerIntro set value', async () => {
const wrapper = mount(Viewer3cr);
expect(wrapper.vm.introActive).toBe(false);
await wrapper.findComponent(ViewerIntro).setValue(true);
expect(wrapper.vm.introActive).toBe(true);
});
it('should ViewerTour set value', async () => {
const wrapper = mount(Viewer3cr);
expect(wrapper.vm.tourActive).toBe(false);
await wrapper.findComponent(ViewerTour).setValue(true);
expect(wrapper.vm.tourActive).toBe(true);
});
it('should setValue', async () => {
const wrapper = mount(Viewer3cr);
const { notificationDropdown, isDemo } = storeToRefs(useDemoStore());
isDemo.value = true;
await wrapper.setProps({
payload: {
Url: 'https://webgl-3dr.singular.health/demo-1',
} as ViewerPayload,
});
await flushPromises();
expect(notificationDropdown.value).toStrictEqual({
modal: false,
x: 0,
y: 0,
});
await wrapper
.findComponent(DemoNotificationNavigationDrawer)
.setValue(true);
expect(notificationDropdown.value).toStrictEqual({
modal: true,
x: 0,
y: 0,
});
});
it('should v-model modals', async () => {
const wrapper = mount(Viewer3cr);
const modals = wrapper.findAllComponents(VDialog);
for (const modal of modals) {
await modal.setValue(false);
}
});
it('should set settings-menu model', async () => {
await wrapper.findComponent(SettingsMenu).setValue(false);
});
});
async function testWatcherForDisplay(
key: string,
action: SlidersActions,
not: boolean = false,
) {
const scanState = inflateScanState();
(scanState.Display as any)[key] = 60;
setScanState(JSON.stringify(scanState));
await flushPromises();
if (not) {
expect(spy).not.toHaveBeenCalledWith(FrontEndInterfaces.sliders, action, {
message: {
Version: '0.0.1',
Value: (scanState.Display as any)[key],
},
});
} else {
expect(spy).toHaveBeenCalledWith(FrontEndInterfaces.sliders, action, {
message: {
Version: '0.0.1',
Value: (scanState.Display as any)[key],
},
});
}
}
async function testWatcherForSlice(
key: string,
action: SlidersActions,
not: boolean = false,
) {
const scanState = inflateScanState();
(scanState.Slice as any)[key] = 100;
setScanState(JSON.stringify(scanState));
await flushPromises();
if (not) {
expect(spy).not.toHaveBeenCalledWith(FrontEndInterfaces.sliders, action, {
message: {
Version: '0.0.1',
Value: (scanState.Slice as any)[key],
},
});
} else {
expect(spy).toHaveBeenCalledWith(FrontEndInterfaces.sliders, action, {
message: {
Version: '0.0.1',
Value: (scanState.Slice as any)[key],
},
});
}
}
async function testWatcherForOrientation(
key: string,
action: SlidersActions,
not: boolean = false,
) {
const scanState = inflateScanState();
(scanState.Orientations as any)[key].Slice = 100;
setScanState(JSON.stringify(scanState));
await flushPromises();
if (not) {
expect(spy).not.toHaveBeenCalledWith(FrontEndInterfaces.sliders, action, {
message: {
Version: '0.0.1',
Value: (scanState.Orientations as any)[key].Slice,
},
});
} else {
expect(spy).toHaveBeenCalledWith(FrontEndInterfaces.sliders, action, {
message: {
Version: '0.0.1',
Value: (scanState.Orientations as any)[key].Slice,
},
});
}
}
async function testWatcherForInteractionSettings(
key: string,
action: ScanMovementActions,
not: boolean = false,
) {
const scanState = inflateScanState();
(scanState.InteractionSettings as any)[key] = 100;
setScanState(JSON.stringify(scanState));
await flushPromises();
if (not) {
expect(spy).not.toHaveBeenCalledWith(
FrontEndInterfaces.scan_movement,
action,
{
message: {
Version: '0.0.1',
Value: (scanState.InteractionSettings as any)[key],
},
},
);
} else {
expect(spy).toHaveBeenCalledWith(FrontEndInterfaces.scan_movement, action, {
message: {
Version: '0.0.1',
Value: (scanState.InteractionSettings as any)[key],
},
});
}
}