8.6 KiB
Seed specs by feature area
When writing a new OHIF test, find the closest feature area below and read the listed spec in full before writing. Playwright's own guidance says the seed test "serves as an example of all the generated tests" — that applies here.
If a spec listed below has moved or been renamed, grep
tests/for a remaining example (e.g.grep -rn "loadSeriesByModality('RTSTRUCT')" tests/). The pattern matters more than the exact filename — specs get renamed, the feature area persists.No close match below? This list only covers areas with a seed worth copying; don't add a stub for every untested area. See Feature area not listed above?.
Canonical study UIDs
| UID | Mode(s) | What it has |
|---|---|---|
1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5 |
viewer |
CT — default for measurement/annotation tests |
1.3.6.1.4.1.14519.5.2.1.1706.8374.643249677828306008300337414785 |
viewer |
CT volume for 3D/MPR/crosshairs |
1.3.6.1.4.1.14519.5.2.1.256467663913010332776401703474716742458 |
viewer or segmentation |
CT + SEG for labelmap tests |
1.2.840.113619.2.290.3.3767434740.226.1600859119.501 |
viewer / segmentation / tmtv |
CT + RTSTRUCT + PET, used for contour and TMTV |
1.3.6.1.4.1.14519.5.2.1.7695.4007.324475281161490036195179843543 |
viewer |
SR structured report |
Do not invent UIDs — they must exist on the e2e data server.
1. Simple measurement tools (length, angle, bidirectional, rectangle, ellipse, circle)
Seed: tests/Length.spec.ts, tests/Angle.spec.ts
Pattern: select tool via mainToolbarPageObject.measurementTools.<tool>.click(), place N points via activeViewport.normalizedClickAt([...]), confirm the tracking prompt, screenshot via screenShotPaths.<name>.<name>DisplayedCorrectly.
2. Freehand / spline / livewire ROIs
Seed: tests/FreehandROI.spec.ts, tests/Livewire.spec.ts, tests/Spline.spec.ts
Pattern: normalizedDragAt({ start, end, config: { steps: 20, delay: 30 } }) for smooth strokes; subscribeToMeasurementAdded to assert the event fires; activeViewport.nthAnnotation(0) to reference what was drawn.
3. Annotations (arrow, probe)
Seed: tests/ArrowAnnotate.spec.ts, tests/Probe.spec.ts
Arrow annotate opens DOMOverlayPageObject.dialog.input for the label. Use fillAndSave(label).
4. Measurement panel interactions
Seed: tests/MeasurementPanel.spec.ts
Panel access: rightPanelPageObject.toggle() → .measurementsPanel.select() → .panel.nthMeasurement(i) → .actions.rename|delete|toggleLock|duplicate|.... Also demonstrates addLengthMeasurement(page) and panel-row click() for jump-to.
5. Context menu (right-click on annotation)
Seed: tests/ContextMenu.spec.ts
Two ways to open: activeViewport.normalizedClickAt([{...}], 'right') on an empty area, or activeViewport.nthAnnotation(0).contextMenu.open() on a drawn annotation. Then DOMOverlayPageObject.viewport.annotationContextMenu.addLabel|delete.click().
6. Labelmap segmentation (SEG) hydration
Seed: tests/SEGHydration.spec.ts, tests/SEGHydrationThenMPR.spec.ts
Flow: leftPanelPageObject.loadSeriesByModality('SEG') → waitForTimeout(3000) → DOMOverlayPageObject.viewport.segmentationHydration.yes.click(). Often pokes Cornerstone state directly via page.evaluate(() => window.cornerstone...) for zoom/render.
7. Contour segmentation (RTSTRUCT) + interactions
Seeds:
- Hydration:
tests/RTHydration.spec.ts - Rename:
tests/ContourSegmentRename.spec.ts - Navigation between segments:
tests/ContourSegNavigation.spec.ts - Duplicate:
tests/ContourSegmentDuplicate.spec.ts - Visibility:
tests/ContourSegmentToggleVisibility.spec.ts - Locking:
tests/ContourSegLocking.spec.ts
Pattern: load RTSTRUCT series → hydrate → use rightPanelPageObject.contourSegmentationPanel.panel.nthSegment(i) / .segmentByText('Small Sphere') and their .actions.rename|delete, or the segment's .click() to jump.
8. Labelmap segmentation editing (brush / eraser / threshold)
Seed: tests/LabelMapSegLocking.spec.ts, tests/SEGDrawingToolsResizing.spec.ts
Pattern: rightPanelPageObject.labelMapSegmentationPanel.tools.brush.setRadius(n) / .click(), then activeViewport.normalizedDragAt(...) to paint.
9. TMTV / PET
Seeds: tests/TMTVCSVReport.spec.ts, tests/TMTVSUV.spec.ts, tests/TMTVAlignment.spec.ts, tests/TMTVRendering.spec.ts
Visit mode: 'tmtv' with a longer delay (10000). rightPanelPageObject.tmtvPanel for the side panel. Exporting a report uses page.waitForEvent('download') + downloadAsString(download).
10. MPR and 3D layouts
Seeds: tests/MPR.spec.ts, tests/3DOnly.spec.ts, tests/3DFourUp.spec.ts, tests/3DMain.spec.ts, tests/AxialPrimary.spec.ts
Pattern: mainToolbarPageObject.layoutSelection.<layoutName>.click(). For 3D, wrap stabilization with attemptAction(() => reduce3DViewportSize(page), 10, 100) to settle the render before asserting.
11. Crosshairs
Seed: tests/Crosshairs.spec.ts
Pattern: initializeMousePositionTracker(page) in beforeEach, mainToolbarPageObject.crosshairs.click(), then viewportPageObject.crosshairs.axial.rotate() / .increase().
12. Overlays — data overlay menu, window/level, orientation
Seeds: tests/DataOverlayMenu.spec.ts, tests/WindowLevelOverlayText.spec.ts, tests/MultipleSegmentationDataOverlays.spec.ts
Pattern: viewportPageObject.getById('default').overlayMenu.dataOverlay.toggle(), then .addSegmentation(name) / .changeSegmentation(from, to) / .remove(name). For keyboard navigation, remember press({ page, key, nTimes }) imports from ./utils/keyboardUtils.
13. DICOM Tag Browser
Seed: tests/DicomTagBrowser.spec.ts
Open with mainToolbarPageObject.moreTools.tagBrowser.click(), then interact via DOMOverlayPageObject.dialog.dicomTagBrowser.waitVisible() / .seriesSelect.selectOption(i) / .seriesSelect.getOptionText(i).
14. Study validation / not-found / worklist
Seeds: tests/StudyValidation.spec.ts, tests/Worklist.spec.ts
These are the rare specs that use page.goto(...) directly instead of visitStudy() — because they test error states or non-study pages. notFoundStudyPageObject gives you errorMessage, returnMessage, studyListLink.
15. SR (Structured Report) hydration
Seeds: tests/SRHydration.spec.ts, tests/SRHydrationThenReload.spec.ts
Same shape as SEG hydration but load via loadSeriesByModality('SR').
Feature area not listed above? (no existing seed)
Don't add a stub section here for an untested area. When your target isn't listed:
- Look for an indirect seed. Grep
tests/for the controls or flow you need (grep -rn "options-menu" tests/, a related panel/dialog). An adjacent area's seed usually still shows how the harness is driven. - If genuinely uncovered, you're creating page objects. Read
page-objects.md → "When the control you need isn't covered yet", then:
- One page object per new control. Dialogs follow
DicomTagBrowserPageObject(reached throughDOMOverlayPageObject); toolbar buttons get a getter onMainToolbarPageObject. - Add a
data-cyto any control that lacks one. - Verify the real effect, not a proxy — drag and screenshot that the image moved via
locator: viewportPageObject.grid, not just that a button gaineddata-active.
- One page object per new control. Dialogs follow
Example — user preferences / hotkeys (no seed today): open the options menu and User
Preferences dialog (options-menu accessor on DOMOverlayPageObject + a userPreferences
dialog page object reached through it), set the hotkey, save, then trigger it and confirm the
viewport effect (activate Zoom, drag, screenshot the zoom). Add the Zoom button as a getter on
MainToolbarPageObject.
Advanced patterns worth knowing
subscribeToMeasurementAdded(tests/FreehandROI.spec.ts) — for async "was a measurement actually added?" assertions. Alwaystry { ... } finally { await measurementAdded.unsubscribe() }.attemptAction(tests/3DOnly.spec.ts) — retry flaky setup (3D render, heavy layout change) without silencing real failures.addOHIFConfiguration(tests/RTHydrationDisableConfirmation.spec.ts) — pre-load config overrides beforevisitStudy.page.evaluate(() => window.services...)— used in several SEG/SR specs to set customizations or poke viewport state. Treat as an escape hatch, not a default.expect.toPass({ timeout })— wrap flaky assertions (common for jump-to-measurement tests where rendering settles asynchronously).