Skip to content

Tests/labelmap color change tests#6054

Draft
diattamo wants to merge 2 commits into
OHIF:masterfrom
diattamo:feat/labelmap-color-change
Draft

Tests/labelmap color change tests#6054
diattamo wants to merge 2 commits into
OHIF:masterfrom
diattamo:feat/labelmap-color-change

Conversation

@diattamo

@diattamo diattamo commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Context

Add coverage for changing the color of labelmaps

Changes & Results

  • tests/utils/screenShotPaths.ts — registered new
    labelMapSegmentationColorChange baseline keys.
  • tests/LabelMapSegmentationColorChange.spec.ts — three tests
    covering: opening the dialog with the current hex prefilled, saving
    a new color, and cancelling the dialog. Verification uses
    checkForScreenshot scoped to the default viewport for the
    canvas-side check; four baseline screenshots are added under
    tests/screenshots/chromium/LabelMapSegmentationColorChange.spec.ts/.

Testing

  1. From the repo root, run both new specs:

    yarn playwright test tests/LabelMapSegmentationColorChange.spec.ts
  2. To regenerate the labelmap baselines after an intentional rendering
    change:

    yarn playwright test tests/LabelMapSegmentationColorChange.spec.ts --update-snapshots

Checklist

PR

  • My Pull Request title is descriptive, accurate and follows the
    semantic-release format and guidelines.

Code

  • My code has been well-documented (function documentation, inline comments, etc.)

Public Documentation Updates

  • The documentation page has been updated as necessary for any public API additions or removals.

Tested Environment

  • OS: macOS 15 (Darwin 25.3.0)
  • Node version: 25.4.0
  • Browser: Chrome 148.0.7778.179 (Chromium via Playwright)

Summary by CodeRabbit

  • Tests
    • Added comprehensive Playwright test suite for labelmap segmentation color editing functionality, including color picker dialog interactions and verification of color persistence and cancellation workflows.
    • Enhanced test page objects with color picker dialog controls and helper methods for color picker interaction testing.

Greptile Summary

This PR adds Playwright end-to-end test coverage for the labelmap segmentation color-change workflow, wiring up three tests (dialog opens with prefilled hex, save changes the color, cancel does not). Supporting changes add data-cy attributes to ColorPickerDialog and the DataRow color swatch, and extend the RightPanelPageObject / DOMOverlayPageObject with color-picker helpers.

  • Three new E2E tests cover opening the color picker, confirming a color change, and cancelling, each with before/after viewport screenshots.
  • data-cy attributes are added to the dialog wrapper and the Save/Cancel buttons in colorPickerDialog.tsx, and to the color swatch span in DataRow.tsx.

Confidence Score: 3/5

The production code changes (data-cy additions) are safe, but the new test infrastructure has three areas that may make the tests unreliable or always-failing on CI without further verification.

The hexInput locator uses getByLabel('hex') against ChromePicker, which does not expose a proper accessibility label — the locator may silently return no element. The hex value assertions and fill calls pass a '#'-prefixed string that ChromePicker's raw input may not accept or return. Finally, waitForViewportRenderCycle is captured before the multi-step changeColor action, so an intermediate render during the action sequence could let the screenshot race ahead of the actual color-change render.

tests/pages/DOMOverlayPageObject.ts (hexInput locator) and tests/LabelMapSegmentationColorChange.spec.ts (hex value format, render-cycle timing)

Important Files Changed

Filename Overview
extensions/default/src/utils/colorPickerDialog.tsx Adds data-cy attributes to the dialog wrapper div and Cancel/Save buttons to enable Playwright test targeting; change is minimal and correct.
platform/ui-next/src/components/DataRow/DataRow.tsx Adds data-cy="data-row-colorhex" to the color swatch span for test targeting; no functional change.
tests/LabelMapSegmentationColorChange.spec.ts New spec with three labelmap color-change tests; the hexInput selector relying on getByLabel('hex') may be fragile, and hex values are passed with '#' prefix whose presence in the ChromePicker input value is unverified.
tests/pages/DOMOverlayPageObject.ts Adds colorPicker page-object exposing hexInput, saveButton, cancelButton and helper methods; saveButton and cancelButton are page-scoped rather than locator-scoped, which is a minor inconsistency but not a bug.
tests/pages/RightPanelPageObject.ts Adds openChangeColor, changeColor, cancelChangeColor actions, rowDataColorHex accessor, and segmentsVisibilityToggle to the labelmap panel; follows existing patterns correctly.
tests/utils/screenShotPaths.ts Registers four new screenshot path keys under labelMapSegmentationColorChange; straightforward and consistent with the existing pattern.
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
tests/pages/DOMOverlayPageObject.ts:65
**`getByLabel('hex')` may not resolve to the ChromePicker input**

`react-color`'s `ChromePicker` uses a `<span>` as a visual label below the input — it is not a `<label>` element and carries no `for`/`aria-labelledby` association. Playwright's `getByLabel` relies on the accessibility tree; without a proper label association, this locator will either return no element or throw at runtime. A more reliable selector would be something like `locator.locator('input[id*="hex"], input[aria-label="hex"]')` or querying by the label-companion pattern that ChromePicker actually renders.

### Issue 2 of 3
tests/LabelMapSegmentationColorChange.spec.ts:44-46
**Hex value assertion may fail due to `#` prefix mismatch**

`ChromePicker` typically stores and displays the hex value as the 6-character string without the `#` (e.g. `9D6CA2`), while the `#` glyph is rendered as a static prefix outside the `<input>`. If that's the case here, `toHaveValue('#9D6CA2')` will always fail. The same concern applies to `hexInput.fill('#FF00FF')` in `fillHexAndSave` / `fillHexAndCancel` — passing the `#` prefix into an input that doesn't expect it may silently produce an unexpected color state.

### Issue 3 of 3
tests/LabelMapSegmentationColorChange.spec.ts:72-74
**Render-cycle promise captured before the action that triggers the render**

`waitForViewportRenderCycle(page)` is called before `segment.actions.changeColor(...)`, which itself performs four sequential interactions (open menu → click "Change Color" → fill hex → click Save). If the viewport renders for any intermediate reason during those steps — such as the color picker opening or focus events — the promise resolves early and `await colorChangeCycle` becomes a no-op. The screenshot that follows may then be captured before the actual color-change render completes. Capturing the promise _after_ `changeColor` resolves would remove this race.

Reviews (1): Last reviewed commit: "Merge branch 'master' into feat/labelmap..." | Re-trigger Greptile

Greptile also left 3 inline comments on this PR.

diattamo added 2 commits June 2, 2026 14:21
Moves the labelmap segmentation color-change E2E test and its
screenshots onto a dedicated branch.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@netlify

netlify Bot commented Jun 2, 2026

Copy link
Copy Markdown

Deploy Preview for ohif-dev ready!

Name Link
🔨 Latest commit aeed014
🔍 Latest deploy log https://app.netlify.com/projects/ohif-dev/deploys/6a1f232e10f80d000945a95f
😎 Deploy Preview https://deploy-preview-6054--ohif-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds comprehensive test infrastructure for the labelmap segmentation color-picker dialog. UI components receive data-cy attributes for deterministic selection. Page objects expose color-picker dialog interactions and "change color" row actions. A new test suite validates color-change and cancel workflows with visual regression screenshots.

Changes

Labelmap Segmentation Color Change Test Suite

Layer / File(s) Summary
Color-picker UI test attributes
extensions/default/src/utils/colorPickerDialog.tsx, platform/ui-next/src/components/DataRow/DataRow.tsx
Color picker dialog wrapper and data row color indicator receive data-cy attributes to enable deterministic element selection in tests.
Page-object infrastructure for color-picker interactions
tests/pages/DOMOverlayPageObject.ts, tests/pages/RightPanelPageObject.ts
DOMOverlayPageObject exposes a colorPicker section with dialog locators and async interaction methods. RightPanelPageObject adds "change color" row actions (openChangeColor, changeColor(hex), cancelChangeColor), a rowDataColorHex getter to read segment colors from the UI, and a segmentsVisibilityToggle control on the labelmap panel.
Labelmap color-change test suite
tests/LabelMapSegmentationColorChange.spec.ts
New test spec validates color-picker dialog visibility with prefilled HEX values, successful color changes with before/after screenshot capture, and color-change cancellation with unchanged state validation and screenshot capture.
Screenshot paths for color-change tests
tests/utils/screenShotPaths.ts
Registers four screenshot scenario keys under screenShotPaths.labelMapSegmentationColorChange: colorBeforeChange, colorAfterChange, colorBeforeCancel, colorAfterCancel.

Sequence Diagram(s)

sequenceDiagram
  participant Test
  participant RightPanel
  participant Dialog
  participant DOMOverlay
  Test->>RightPanel: openChangeColor()
  RightPanel->>Dialog: click "Change Color" action
  Test->>DOMOverlay: colorPicker.fillHex(hex)
  DOMOverlay->>Dialog: fill hex input + press Enter
  Test->>DOMOverlay: colorPicker.save()
  DOMOverlay->>Dialog: click save button
  Test->>RightPanel: rowDataColorHex
  RightPanel->>Test: return color indicator CSS value
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A color picker dance takes the stage,
With data-cy breadcrumbs on every page,
Page objects waltz through dialogs bright,
Screenshots capture each hue-filled flight,
From change to cancel, tests paint it right!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Tests/labelmap color change tests' does not follow the semantic-release format required by the repository (e.g., 'test(labelmap): add color change tests') and is somewhat redundant with its phrasing. Update the PR title to follow semantic-release format: 'test(labelmap): add segmentation color change coverage' or similar, which is more concise and follows convention.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description follows the template structure with all major sections completed: Context, Changes & Results, Testing, and Checklist all properly filled out with specific details.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.


get colorPicker() {
const locator = page.getByTestId('color-picker-dialog');
const hexInput = locator.getByLabel('hex');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 getByLabel('hex') may not resolve to the ChromePicker input

react-color's ChromePicker uses a <span> as a visual label below the input — it is not a <label> element and carries no for/aria-labelledby association. Playwright's getByLabel relies on the accessibility tree; without a proper label association, this locator will either return no element or throw at runtime. A more reliable selector would be something like locator.locator('input[id*="hex"], input[aria-label="hex"]') or querying by the label-companion pattern that ChromePicker actually renders.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tests/pages/DOMOverlayPageObject.ts
Line: 65

Comment:
**`getByLabel('hex')` may not resolve to the ChromePicker input**

`react-color`'s `ChromePicker` uses a `<span>` as a visual label below the input — it is not a `<label>` element and carries no `for`/`aria-labelledby` association. Playwright's `getByLabel` relies on the accessibility tree; without a proper label association, this locator will either return no element or throw at runtime. A more reliable selector would be something like `locator.locator('input[id*="hex"], input[aria-label="hex"]')` or querying by the label-companion pattern that ChromePicker actually renders.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +44 to +46
await expect(DOMOverlayPageObject.dialog.colorPicker.hexInput).toHaveValue(
LABELMAP_SEGMENT_0_DEFAULT_HEX
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Hex value assertion may fail due to # prefix mismatch

ChromePicker typically stores and displays the hex value as the 6-character string without the # (e.g. 9D6CA2), while the # glyph is rendered as a static prefix outside the <input>. If that's the case here, toHaveValue('#9D6CA2') will always fail. The same concern applies to hexInput.fill('#FF00FF') in fillHexAndSave / fillHexAndCancel — passing the # prefix into an input that doesn't expect it may silently produce an unexpected color state.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tests/LabelMapSegmentationColorChange.spec.ts
Line: 44-46

Comment:
**Hex value assertion may fail due to `#` prefix mismatch**

`ChromePicker` typically stores and displays the hex value as the 6-character string without the `#` (e.g. `9D6CA2`), while the `#` glyph is rendered as a static prefix outside the `<input>`. If that's the case here, `toHaveValue('#9D6CA2')` will always fail. The same concern applies to `hexInput.fill('#FF00FF')` in `fillHexAndSave` / `fillHexAndCancel` — passing the `#` prefix into an input that doesn't expect it may silently produce an unexpected color state.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +72 to +74
const colorChangeCycle = waitForViewportRenderCycle(page);
await segment.actions.changeColor(NEW_LABELMAP_SEGMENT_HEX);
await colorChangeCycle;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Render-cycle promise captured before the action that triggers the render

waitForViewportRenderCycle(page) is called before segment.actions.changeColor(...), which itself performs four sequential interactions (open menu → click "Change Color" → fill hex → click Save). If the viewport renders for any intermediate reason during those steps — such as the color picker opening or focus events — the promise resolves early and await colorChangeCycle becomes a no-op. The screenshot that follows may then be captured before the actual color-change render completes. Capturing the promise after changeColor resolves would remove this race.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tests/LabelMapSegmentationColorChange.spec.ts
Line: 72-74

Comment:
**Render-cycle promise captured before the action that triggers the render**

`waitForViewportRenderCycle(page)` is called before `segment.actions.changeColor(...)`, which itself performs four sequential interactions (open menu → click "Change Color" → fill hex → click Save). If the viewport renders for any intermediate reason during those steps — such as the color picker opening or focus events — the promise resolves early and `await colorChangeCycle` becomes a no-op. The screenshot that follows may then be captured before the actual color-change render completes. Capturing the promise _after_ `changeColor` resolves would remove this race.

How can I resolve this? If you propose a fix, please make it concise.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/pages/DOMOverlayPageObject.ts`:
- Around line 64-65: The hex input selection and assertions are brittle: replace
locator.getByLabel('hex') with a scoped query for the actual input element
inside the color picker (e.g., use the locator from
getByTestId('color-picker-dialog') and then find the input element via
locator.locator('input') or getByRole('textbox') scoped to that dialog) so you
reliably target the ChromePicker EditableInput, and when checking its value
normalize case and/or perform a case-insensitive match and ensure the string
contains the leading '#' (e.g., compare lowercased value or use a regex like
/^`#/i`) instead of asserting a specific uppercase hex string.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c3454003-0f70-4bf6-a421-d5920f8a6aef

📥 Commits

Reviewing files that changed from the base of the PR and between 0885468 and aeed014.

⛔ Files ignored due to path filters (4)
  • tests/screenshots/chromium/LabelMapSegmentationColorChange.spec.ts/labelMapSegmentationColor-afterCancel.png is excluded by !**/*.png
  • tests/screenshots/chromium/LabelMapSegmentationColorChange.spec.ts/labelMapSegmentationColor-afterChange.png is excluded by !**/*.png
  • tests/screenshots/chromium/LabelMapSegmentationColorChange.spec.ts/labelMapSegmentationColor-beforeCancel.png is excluded by !**/*.png
  • tests/screenshots/chromium/LabelMapSegmentationColorChange.spec.ts/labelMapSegmentationColor-beforeChange.png is excluded by !**/*.png
📒 Files selected for processing (6)
  • extensions/default/src/utils/colorPickerDialog.tsx
  • platform/ui-next/src/components/DataRow/DataRow.tsx
  • tests/LabelMapSegmentationColorChange.spec.ts
  • tests/pages/DOMOverlayPageObject.ts
  • tests/pages/RightPanelPageObject.ts
  • tests/utils/screenShotPaths.ts

Comment on lines +64 to +65
const locator = page.getByTestId('color-picker-dialog');
const hexInput = locator.getByLabel('hex');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In react-color 2.19.3, does the ChromePicker "hex" EditableInput render a <label> associated with its <input> (so a by-label query matches it), and is the displayed value uppercased and prefixed with "#"?

💡 Result:

Answer: No. In react-color 2.19.3, the ChromePicker “hex” field uses EditableInput that renders an without an associated (so a by-label query for the label text should not match the input). The displayed hex value is rendered as a plain hex string coming from tinycolor’s toHexString, which includes the “#” prefix but does not guarantee uppercase (it reflects tinycolor’s output/casing for the given color). Evidence: 1) The EditableInput implementation in react-color renders a wrapper

containing only an (with no element and no id/htmlFor linkage): the patched source shows render returning
<input is="input" value={ this.props.value } readOnly/>
.[1] 2) In the ChromePicker “hex” view, EditableInput is instantiated with label="hex" and value={ color.toHexString }, i.e., the input’s value comes from tinycolor toHexString and not from the label text.[2] So: - By-label query: should not match, because there is no associated element targeting the input.[1] - Value formatting: the value originates from toHexString (which includes the leading “#” prefix), but uppercase is not explicitly enforced in react-color; casing is determined by tinycolor.[2]

Citations:


Fix hexInput locator/value expectations for react-color ChromePicker

locator.getByLabel('hex') is unreliable with react-color 2.19.3: the ChromePicker “hex” EditableInput renders an <input> without a label/htmlFor association, so getByLabel('hex') may not resolve. The displayed value comes from tinycolor(...).toHexString (includes #), but casing isn’t guaranteed—avoid asserting a specific uppercase hex string (use a case-insensitive match or normalize case).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/pages/DOMOverlayPageObject.ts` around lines 64 - 65, The hex input
selection and assertions are brittle: replace locator.getByLabel('hex') with a
scoped query for the actual input element inside the color picker (e.g., use the
locator from getByTestId('color-picker-dialog') and then find the input element
via locator.locator('input') or getByRole('textbox') scoped to that dialog) so
you reliably target the ChromePicker EditableInput, and when checking its value
normalize case and/or perform a case-insensitive match and ensure the string
contains the leading '#' (e.g., compare lowercased value or use a regex like
/^`#/i`) instead of asserting a specific uppercase hex string.

@diattamo diattamo marked this pull request as draft June 2, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant