Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified tests/baseline/layers_max_opacity_2d_view-chrome-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file added tests/fixtures/layering/prostate-3-slices.zip
Binary file not shown.
98 changes: 82 additions & 16 deletions tests/specs/layers-and-rendering.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
import { DOWNLOAD_TIMEOUT } from '@/wdio.shared.conf';
import * as fs from 'fs';
import * as path from 'path';
import { cleanuptotal } from 'wdio-cleanuptotal-service';
import { DOWNLOAD_TIMEOUT, FIXTURES, TEMP_DIR } from '@/wdio.shared.conf';
import { volViewPage } from '../pageobjects/volview.page';
import { openUrls } from './utils';
import { PROSTATEX_DATASET, MRA_HEAD_NECK_DATASET } from './configTestUtils';
import { openUrls, openVolViewPage, writeManifestToFile } from './utils';
import { PROSTATEX_DATASET } from './configTestUtils';

const openLayeringFixtures = async () => {
const fixtureNames = ['prostate-3-slices.zip', 'mra-head-neck-3-slices.zip'];
await Promise.all(
fixtureNames.map(async (name) => {
const target = path.join(TEMP_DIR, name);
await fs.promises.copyFile(path.join(FIXTURES, 'layering', name), target);
cleanuptotal.addCleanup(async () => {
fs.unlinkSync(target);
});
})
);

const manifestName = `layering-fixtures-${Date.now()}.json`;
await writeManifestToFile(
{
resources: fixtureNames.map((name) => ({ url: `/tmp/${name}` })),
},
manifestName
);
await openVolViewPage(manifestName);
};

describe('Layers and Rendering', () => {
it('should show 3D rendering controls regardless of active view', async () => {
Expand Down Expand Up @@ -33,7 +58,7 @@ describe('Layers and Rendering', () => {
});

it('should create overlay with 2 DICOM images', async () => {
await openUrls([PROSTATEX_DATASET, MRA_HEAD_NECK_DATASET]);
await openLayeringFixtures();

await browser.waitUntil(
async () => {
Expand All @@ -46,6 +71,9 @@ describe('Layers and Rendering', () => {
}
);

const mraCard = await $('.volume-card[html-title^="**TOF"]');
await mraCard.click();

const inactiveMenuSelector =
'.volume-card:not(.volume-card-active) button[data-testid="dataset-menu-button"]';

Expand Down Expand Up @@ -87,6 +115,23 @@ describe('Layers and Rendering', () => {
);
await addLayerButton.click();

await browser.waitUntil(
() =>
browser.execute(() => {
const app = (document.querySelector('#app') as any)?.__vue_app__;
const pinia = app?.config?.globalProperties?.$pinia;
const imageCache = pinia?._s?.get('image-cache');
const layerId = imageCache?.imageIds?.find((id: string) =>
id.includes('::')
);
return layerId && imageCache.imageStatus[layerId] === 'complete';
}),
{
timeout: DOWNLOAD_TIMEOUT,
timeoutMsg: 'Expected the layer image to finish loading',
}
);

const renderTab = await volViewPage.renderingModuleTab;
await renderTab.click();

Expand All @@ -103,36 +148,57 @@ describe('Layers and Rendering', () => {

const layerOpacitySliders = await volViewPage.layerOpacitySliders;
const firstSlider = layerOpacitySliders[0];
const sliderThumb = await firstSlider.$('[role="slider"]');
const inputElement = await firstSlider.$('input');
const views2D = await volViewPage.getViews2D();
const viewCount = await views2D.length;
if (!views2D || viewCount === 0) {
throw new Error('Could not find 2D views for screenshot');
}
const firstView2D = views2D[0];
const beforeOpacityChange = await firstView2D.takeScreenshot();

await firstSlider.click();
await browser.execute((element) => {
(element as HTMLElement).focus();
}, sliderThumb);

// Use keyboard to set to maximum (End key goes to max)
await browser.keys('End');

await browser.waitUntil(
async () => {
const inputElement = await firstSlider.$('input');
const value = await inputElement.getValue();
return value === '1';
},
{
timeoutMsg: 'Expected slider value to be 1 (max opacity)',
timeoutMsg: 'Expected slider value to be 1',
timeout: 5000,
}
);

const views2D = await volViewPage.getViews2D();
const viewCount = await views2D.length;
if (!views2D || viewCount === 0) {
throw new Error('Could not find 2D views for screenshot');
}
const firstView2D = views2D[0];
await browser.waitUntil(
async () => (await firstView2D.takeScreenshot()) !== beforeOpacityChange,
{
timeout: 5000,
timeoutMsg: 'Expected the 2D view to render the opacity change',
}
);

const result = await browser.checkElement(
firstView2D,
'layers_max_opacity_2d_view'
'layers_max_opacity_2d_view',
{
pixelmatch: { threshold: 0.2 },
// Compare where the resampled prostate layer intersects the MRA.
blockOut: [
{ x: 0, y: 0, width: 371, height: 130 },
{ x: 0, y: 240, width: 371, height: 92 },
{ x: 0, y: 130, width: 20, height: 110 },
{ x: 340, y: 130, width: 31, height: 110 },
],
}
);

const THRESHOLD = 5; // percent
const THRESHOLD = 1; // percent
await expect(result).toBeLessThan(THRESHOLD);
});
});
Loading