fix(seg hydration): auto-hydrate RT struct on second load with disableConfirmationPrompts (#5875)
This commit is contained in:
parent
0f822aaf48
commit
6f773f9972
@ -94,22 +94,30 @@ function promptHydrationDialog({
|
||||
if (type === HydrationType.SEG) {
|
||||
// SEG needs setTimeout
|
||||
window.setTimeout(async () => {
|
||||
const isHydrated = await hydrateCallback({
|
||||
segDisplaySet: displaySet,
|
||||
viewportId,
|
||||
});
|
||||
|
||||
resolve(isHydrated);
|
||||
try {
|
||||
const isHydrated = await hydrateCallback({
|
||||
segDisplaySet: displaySet,
|
||||
viewportId,
|
||||
});
|
||||
resolve(isHydrated);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
}, 0);
|
||||
} else if (type === HydrationType.RTSTRUCT) {
|
||||
// RT hydration
|
||||
const isHydrated = await hydrateCallback({
|
||||
rtDisplaySet: displaySet,
|
||||
viewportId,
|
||||
servicesManager,
|
||||
});
|
||||
|
||||
resolve(isHydrated);
|
||||
window.setTimeout(async () => {
|
||||
try {
|
||||
const isHydrated = await hydrateCallback({
|
||||
rtDisplaySet: displaySet,
|
||||
viewportId,
|
||||
servicesManager,
|
||||
});
|
||||
resolve(isHydrated);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
}, 0);
|
||||
} else if (type === HydrationType.SR) {
|
||||
// SR has a different result structure
|
||||
const hydrationResult = await hydrateCallback(displaySet);
|
||||
|
||||
@ -32,12 +32,19 @@ const SegmentationCollapsedHeader = ({ children }: { children: React.ReactNode }
|
||||
|
||||
// Dropdown menu component - specifically for dropdown menu content
|
||||
const SegmentationCollapsedDropdownMenu = ({ children }: { children: React.ReactNode }) => {
|
||||
const { segmentationRepresentationTypes } = useSegmentationTableContext(
|
||||
'SegmentationCollapsedDropdownMenu'
|
||||
);
|
||||
const dataCyTypeSuffix = segmentationRepresentationTypes?.[0]
|
||||
? `-${segmentationRepresentationTypes[0]}`
|
||||
: '';
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
data-cy={`segmentation-collapsed-more-btn${dataCyTypeSuffix}`}
|
||||
>
|
||||
<Icons.More className="h-6 w-6" />
|
||||
</Button>
|
||||
|
||||
81
tests/RTHydrationDisableConfirmation.spec.ts
Normal file
81
tests/RTHydrationDisableConfirmation.spec.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import {
|
||||
checkForScreenshot,
|
||||
expect,
|
||||
screenShotPaths,
|
||||
test,
|
||||
visitStudy,
|
||||
addOHIFConfiguration,
|
||||
} from './utils';
|
||||
import { press } from './utils/keyboardUtils';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await addOHIFConfiguration(page, {
|
||||
disableConfirmationPrompts: true,
|
||||
});
|
||||
|
||||
const studyInstanceUID = '1.2.840.113619.2.290.3.3767434740.226.1600859119.501';
|
||||
const mode = 'viewer';
|
||||
await visitStudy(page, studyInstanceUID, mode, 2000);
|
||||
});
|
||||
|
||||
test('should auto hydrate RT STRUCT on the second load and keep viewport stable after deleting segmentations', async ({
|
||||
page,
|
||||
DOMOverlayPageObject,
|
||||
leftPanelPageObject,
|
||||
rightPanelPageObject,
|
||||
viewportPageObject,
|
||||
}) => {
|
||||
// First load
|
||||
await leftPanelPageObject.loadSeriesByModality('RTSTRUCT');
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
const loadBadgeCountAfterFirstLoad =
|
||||
await DOMOverlayPageObject.viewport.getModalityLoadBadgeCount();
|
||||
expect(loadBadgeCountAfterFirstLoad).toBe(0);
|
||||
|
||||
await press({ page, key: 'ArrowDown', nTimes: 12 });
|
||||
|
||||
await checkForScreenshot(
|
||||
page,
|
||||
viewportPageObject.active.pane,
|
||||
screenShotPaths.rtHydrationDisableConfirmation.firstLoadPostHydration
|
||||
);
|
||||
|
||||
await rightPanelPageObject.toggle();
|
||||
|
||||
await rightPanelPageObject.noToolsSegmentationPanel.panel.moreMenu.delete();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await checkForScreenshot(
|
||||
page,
|
||||
viewportPageObject.active.pane,
|
||||
screenShotPaths.rtHydrationDisableConfirmation.viewportAfterFirstDelete
|
||||
);
|
||||
|
||||
// Second load
|
||||
await leftPanelPageObject.loadSeriesByModality('RTSTRUCT');
|
||||
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
const loadBadgeCountAfterSecondLoad =
|
||||
await DOMOverlayPageObject.viewport.getModalityLoadBadgeCount();
|
||||
expect(loadBadgeCountAfterSecondLoad).toBe(0);
|
||||
|
||||
await press({ page, key: 'ArrowDown', nTimes: 12 });
|
||||
|
||||
await checkForScreenshot(
|
||||
page,
|
||||
viewportPageObject.active.pane,
|
||||
screenShotPaths.rtHydrationDisableConfirmation.secondLoadPostHydration
|
||||
);
|
||||
|
||||
await rightPanelPageObject.noToolsSegmentationPanel.panel.moreMenu.delete();
|
||||
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await checkForScreenshot(
|
||||
page,
|
||||
viewportPageObject.active.pane,
|
||||
screenShotPaths.rtHydrationDisableConfirmation.viewportAfterSecondDelete
|
||||
);
|
||||
});
|
||||
@ -11,6 +11,30 @@ export class RightPanelPageObject {
|
||||
this.DOMOverlayPageObject = new DOMOverlayPageObject(page);
|
||||
}
|
||||
|
||||
private getCollapsedMoreMenu(typeSuffix?: string) {
|
||||
const page = this.page;
|
||||
const testId = typeSuffix
|
||||
? `segmentation-collapsed-more-btn-${typeSuffix}`
|
||||
: 'segmentation-collapsed-more-btn';
|
||||
const button = page.getByTestId(testId);
|
||||
|
||||
return {
|
||||
button,
|
||||
click: async () => {
|
||||
await button.click();
|
||||
},
|
||||
delete: async () => {
|
||||
await button.click();
|
||||
await page.getByRole('menuitem', { name: 'Delete' }).click();
|
||||
},
|
||||
rename: async (text: string) => {
|
||||
await button.click();
|
||||
await page.getByRole('menuitem', { name: 'Rename' }).click();
|
||||
await this.DOMOverlayPageObject.dialog.input.fillAndSave(text);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private getActionsMenu(row: Locator) {
|
||||
const actionsButton = row.getByTestId('actionsMenuTrigger');
|
||||
|
||||
@ -112,12 +136,14 @@ export class RightPanelPageObject {
|
||||
};
|
||||
}
|
||||
|
||||
private get segmentationPanel() {
|
||||
private getSegmentationPanel(typeSuffix?: string) {
|
||||
const page = this.page;
|
||||
const getSegmentByIdx = (index: number) => this.getPanelRowByIdx(index);
|
||||
const getSegmentByText = (text: string) => this.getPanelRowByText(text);
|
||||
const moreMenu = this.getCollapsedMoreMenu(typeSuffix);
|
||||
|
||||
return {
|
||||
moreMenu,
|
||||
getSegmentCount: async () => {
|
||||
return await page.getByTestId('data-row').count();
|
||||
},
|
||||
@ -135,7 +161,7 @@ export class RightPanelPageObject {
|
||||
get contourSegmentationPanel() {
|
||||
const page = this.page;
|
||||
const addSegmentationButton = this.addSegmentationButton;
|
||||
const panel = this.segmentationPanel;
|
||||
const panel = this.getSegmentationPanel('Contour');
|
||||
const menuButton = page.getByTestId('panelSegmentationWithToolsContour-btn');
|
||||
|
||||
return {
|
||||
@ -150,7 +176,7 @@ export class RightPanelPageObject {
|
||||
get labelMapSegmentationPanel() {
|
||||
const page = this.page;
|
||||
const addSegmentationButton = this.addSegmentationButton;
|
||||
const panel = this.segmentationPanel;
|
||||
const panel = this.getSegmentationPanel('Labelmap');
|
||||
const menuButton = page.getByTestId('panelSegmentationWithToolsLabelMap-btn');
|
||||
|
||||
return {
|
||||
@ -264,7 +290,7 @@ export class RightPanelPageObject {
|
||||
|
||||
get noToolsSegmentationPanel() {
|
||||
const page = this.page;
|
||||
const panel = this.segmentationPanel;
|
||||
const panel = this.getSegmentationPanel();
|
||||
const menuButton = page.getByTestId(/^panelSegmentation.*-btn$/).first();
|
||||
|
||||
return {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
19
tests/utils/OHIFConfiguration.ts
Normal file
19
tests/utils/OHIFConfiguration.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { Page } from 'playwright-test-coverage';
|
||||
|
||||
export async function addOHIFConfiguration(page: Page, configToAdd: Record<string, unknown>) {
|
||||
await page.addInitScript(config => {
|
||||
let _config;
|
||||
Object.defineProperty(window, 'config', {
|
||||
get() {
|
||||
return _config;
|
||||
},
|
||||
set(value) {
|
||||
_config = {
|
||||
...value,
|
||||
...config,
|
||||
};
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
}, configToAdd);
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
import { visitStudy } from './visitStudy';
|
||||
import { addOHIFConfiguration } from './OHIFConfiguration';
|
||||
import { checkForScreenshot } from './checkForScreenshot';
|
||||
import { screenShotPaths } from './screenShotPaths';
|
||||
import {
|
||||
@ -23,6 +24,7 @@ import { subscribeToMeasurementAdded } from './subscribeToMeasurement';
|
||||
|
||||
export {
|
||||
visitStudy,
|
||||
addOHIFConfiguration,
|
||||
checkForScreenshot,
|
||||
screenShotPaths,
|
||||
simulateClicksOnElement,
|
||||
|
||||
@ -177,6 +177,12 @@ const screenShotPaths = {
|
||||
rtPostHydration: 'rtPostHydration.png',
|
||||
rtPreHydration: 'rtPreHydration.png',
|
||||
},
|
||||
rtHydrationDisableConfirmation: {
|
||||
firstLoadPostHydration: 'firstLoadPostHydration.png',
|
||||
viewportAfterFirstDelete: 'viewportAfterFirstDelete.png',
|
||||
secondLoadPostHydration: 'secondLoadPostHydration.png',
|
||||
viewportAfterSecondDelete: 'viewportAfterSecondDelete.png',
|
||||
},
|
||||
crosshairs: {
|
||||
crosshairsRendered: 'crosshairsRendered.png',
|
||||
crosshairsRotated: 'crosshairsRotated.png',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user