fix(seg): prevent segmentations from spreading to all viewports before hydration confirmation in 3D four-up (#5967)
This commit is contained in:
1 parent
c9c4f11b82
commit
f8ccf9ff2e
23 files changed
+558
-39
No files matched your search
@@ -0,0 +1,163 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
|
||||
type WaitForAnyViewportNeedsRenderOptions = {
|
||||
timeout?: number;
|
||||
};
|
||||
|
||||
type WaitForViewportsRenderedOptions = {
|
||||
timeout?: number;
|
||||
/**
|
||||
* If true (default), also waits for any volume actors referenced by the
|
||||
* viewports to report loaded.
|
||||
*/
|
||||
waitVolumeLoad?: boolean;
|
||||
};
|
||||
|
||||
type WaitForRenderCycleToCompleteOptions = {
|
||||
/**
|
||||
* Timeout for waiting until at least one viewport reaches `needsRender`.
|
||||
*/
|
||||
needsRenderTimeout?: number;
|
||||
/**
|
||||
* Timeout for waiting until all viewports are `rendered`
|
||||
* (and optionally volume-loaded).
|
||||
*/
|
||||
renderedTimeout?: number;
|
||||
/**
|
||||
* If true (default), also waits for any volume actors referenced by the
|
||||
* viewports to report loaded during the rendered phase.
|
||||
*/
|
||||
waitVolumeLoad?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Waits for a full render cycle:
|
||||
* 1) any viewport requests render (`needsRender`)
|
||||
* 2) all viewports finish rendering (`rendered`)
|
||||
*/
|
||||
const waitForViewportRenderCycle = async (
|
||||
page: Page,
|
||||
options: WaitForRenderCycleToCompleteOptions = {}
|
||||
) => {
|
||||
const { needsRenderTimeout = 5000, renderedTimeout = 15000, waitVolumeLoad = true } = options;
|
||||
await waitForAnyViewportNeedsRender(page, { timeout: needsRenderTimeout });
|
||||
await waitForViewportsRendered(page, { timeout: renderedTimeout, waitVolumeLoad });
|
||||
};
|
||||
|
||||
/**
|
||||
* Waits until at least one viewport enters the 'needsRender' state, indicating
|
||||
* that a render has been requested but not yet started.
|
||||
*/
|
||||
const waitForAnyViewportNeedsRender = async (
|
||||
page: Page,
|
||||
options: WaitForAnyViewportNeedsRenderOptions = {}
|
||||
) => {
|
||||
const { timeout = 5000 } = options;
|
||||
await page.waitForFunction(
|
||||
() => {
|
||||
const cornerstone = (window as any).cornerstone;
|
||||
if (!cornerstone?.getRenderingEngines) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const renderingEngines = cornerstone.getRenderingEngines();
|
||||
const viewports = renderingEngines.flatMap(engine =>
|
||||
engine.getViewports ? engine.getViewports() : []
|
||||
);
|
||||
|
||||
if (!viewports.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const needsRender = viewports.some(viewport => viewport?.viewportStatus === 'needsRender');
|
||||
|
||||
return needsRender;
|
||||
},
|
||||
{},
|
||||
{ timeout }
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Stabilize tests by waiting for a short tick, network idle, then viewport render completion.
|
||||
* To use this method safely, you may need to make changes to OHIF and/or CS3D
|
||||
* methods handling clicks (SHOULD be commands modules only). These should set the
|
||||
* state to needs render synchronously so that this method can safely wait for the render to complete.
|
||||
* Examples such as changing the hanging protocol currently don't set such a state
|
||||
* and thus can't be rendered without a delay.
|
||||
*
|
||||
* If options.waitVolumeLoad is not false, then this method will wait for all volumes
|
||||
* associated with viewports to be loaded.
|
||||
*/
|
||||
const waitForViewportsRendered = async (
|
||||
page: Page,
|
||||
options: WaitForViewportsRenderedOptions = {}
|
||||
) => {
|
||||
const { timeout = 15000, waitVolumeLoad = true } = options;
|
||||
|
||||
await page.waitForFunction(
|
||||
({ waitVolumeLoad }) => {
|
||||
const cornerstone = (window as any).cornerstone;
|
||||
if (!cornerstone?.getRenderingEngines) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const renderingEngines = cornerstone.getRenderingEngines();
|
||||
const viewports = renderingEngines.flatMap(engine =>
|
||||
engine.getViewports ? engine.getViewports() : []
|
||||
);
|
||||
|
||||
if (!viewports.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const allRendered = viewports.every(viewport => viewport?.viewportStatus === 'rendered');
|
||||
|
||||
if (!allRendered) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!waitVolumeLoad) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const cache = cornerstone.cache;
|
||||
if (!cache?.getVolume) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const actorEntries = viewports.flatMap(viewport =>
|
||||
viewport?.getActors ? viewport.getActors() : []
|
||||
);
|
||||
|
||||
for (const actorEntry of actorEntries) {
|
||||
const id = actorEntry?.referencedId || actorEntry?.uid;
|
||||
if (!id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let volume: any;
|
||||
try {
|
||||
volume = cache.getVolume(id);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
const loaded =
|
||||
volume?.loadStatus && typeof volume.loadStatus.loaded === 'boolean'
|
||||
? volume.loadStatus.loaded
|
||||
: true;
|
||||
|
||||
if (!loaded) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
{ waitVolumeLoad },
|
||||
{ timeout }
|
||||
);
|
||||
};
|
||||
|
||||
export { waitForViewportsRendered, waitForAnyViewportNeedsRender, waitForViewportRenderCycle };
|
||||
Reference in new issue
Block a user