Skip to content

fix(testkit): fix e2e locators broken by vibe4 changes#3333

Merged
rivka-ungar merged 5 commits intovibe4from
fix/testkit-locators-vibe4
Mar 16, 2026
Merged

fix(testkit): fix e2e locators broken by vibe4 changes#3333
rivka-ungar merged 5 commits intovibe4from
fix/testkit-locators-vibe4

Conversation

@rivka-ungar
Copy link
Contributor

@rivka-ungar rivka-ungar commented Mar 15, 2026

User description

Summary

  • Fix 9 testkit test locators that timed out in CI on the vibe4 branch
  • Update Dropdown Overview story to work with the rewritten component

Root Cause

Test locators used exact data-testid matches (e.g. [data-testid="button-group"]), but Overview stories pass explicit id props. Since getTestId(componentType, id) appends a suffix, the rendered attribute becomes button-group_overview-button-group — no match, 30s timeout.

These bugs pre-existed on master but were never caught: test:changed only runs tests for components modified since master. The vibe4 batch of breaking changes touched all affected components simultaneously, exposing the issues.

Dropdown had a separate issue: the old .dropdown-stories-styles_spacing CSS module class was removed when the component was fully rewritten.

Changes

Test locators — switched from exact = to starts-with ^= selectors:

  • ButtonGroup, Checkbox, Link, RadioButton, SplitButton, Steps, MenuButtondata-testid^=
  • TextField#inputinput[data-testid^="text-field"] (story sets id="overview-textfield", not "input")
  • Dropdown.dropdown-stories-styles_spacing[data-vibe="Dropdown"]

Dropdown story — added searchable: true and inputAriaLabel: "Dropdown input" to Overview args so the testkit's open()/isDropdownOpen() and aria-label attribute tests work with the new component.

Test plan

  • CI testkit job passes for all previously failing components
  • No regressions on passing tests (ColorPicker, Combobox, EditableHeading, etc.)

🤖 Generated with Claude Code


PR Type

Bug fix, Tests


Description

  • Fix 14 testkit e2e locators broken by vibe4 component changes

    • Switch from exact data-testid= to starts-with data-testid^= selectors
    • Update Dropdown locator from CSS class to [data-vibe="Dropdown"] attribute
    • Update TextField locator from #input ID to input[data-testid^="text-field"]
  • Fix Checkbox testkit component to target actual input element

    • Change internal locator from div to input for check/uncheck operations
    • Update test assertions to target input directly with .locator("input")
    • Simplify attribute retrieval to use component's own method
  • Update Dropdown test story URL to searchable variant

  • Remove unused BaseElement imports from Checkbox and Dropdown tests


Diagram Walkthrough

flowchart LR
  A["Exact data-testid selectors"] -->|"Switch to starts-with"| B["Flexible ^= selectors"]
  C["CSS class locators"] -->|"Update to data-vibe"| D["Attribute-based locators"]
  E["Checkbox div targeting"] -->|"Fix to input element"| F["Correct checkbox operations"]
  G["Old story URLs"] -->|"Point to searchable"| H["Updated story variants"]
Loading

File Walkthrough

Relevant files
Bug fix
16 files
Button.test.ts
Switch to starts-with data-testid selector                             
+1/-1     
ButtonGroup.test.ts
Switch to starts-with data-testid selector                             
+1/-1     
Checkbox.test.ts
Fix locator and assertions to target input element             
+11/-15 
Dropdown.test.ts
Update locator to data-vibe attribute and simplify test   
+4/-8     
IconButton.test.ts
Switch to starts-with data-testid selector                             
+1/-1     
Link.test.ts
Switch to starts-with data-testid selector                             
+1/-1     
Loader.test.ts
Switch to starts-with data-testid selector                             
+1/-1     
MenuButton.test.ts
Switch to starts-with data-testid selector                             
+1/-1     
RadioButton.test.ts
Switch to starts-with data-testid selector                             
+1/-1     
SplitButton.test.ts
Switch to starts-with data-testid selector                             
+1/-1     
Steps.test.ts
Switch to starts-with data-testid selector                             
+1/-1     
TextArea.test.ts
Switch to starts-with data-testid selector                             
+1/-1     
TextField.test.ts
Update locator from ID to data-testid selector                     
+1/-1     
Toast.test.ts
Switch to starts-with data-testid selector                             
+1/-1     
Checkbox.ts
Fix internal locator and check/uncheck operations               
+3/-3     
url-helper.js
Update Dropdown story URL to searchable variant                   
+1/-1     

Test locators used exact data-testid matches, but Overview stories pass
explicit id props causing getTestId() to append a suffix
(e.g. "button-group_overview-button-group" instead of "button-group").
Switch to starts-with selectors (^=) so locators work regardless of id.

For Dropdown, the old .dropdown-stories-styles_spacing CSS module class
was removed when the component was rewritten in vibe4. Update the locator
to use [data-vibe="Dropdown"] and add searchable/inputAriaLabel to the
Overview story so the testkit's open/close and aria-label tests work.

These bugs pre-existed on master but were never caught because test:changed
only runs tests for components modified since master. The vibe4 batch of
breaking changes touched all affected components, exposing the issues.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@rivka-ungar rivka-ungar requested review from a team and hanan-monday as code owners March 15, 2026 15:52
@qodo-free-for-open-source-projects
Copy link
Contributor

Review Summary by Qodo

Fix testkit e2e locators for vibe4 breaking changes

🐞 Bug fix 🧪 Tests

Grey Divider

Walkthroughs

Description
• Fix 9 testkit e2e test locators broken by vibe4 component changes
• Switch from exact to starts-with data-testid selectors for robustness
• Update Dropdown story with searchable and inputAriaLabel props
• Replace removed CSS class with data-vibe attribute selector
Diagram
flowchart LR
  A["Exact data-testid selectors"] -->|"Switch to starts-with ^="| B["Flexible locators"]
  C["Removed CSS class"] -->|"Use data-vibe attribute"| D["Dropdown locator"]
  E["Missing story props"] -->|"Add searchable & inputAriaLabel"| F["Working Dropdown tests"]
  B --> G["All 9 components fixed"]
  D --> G
  F --> G
Loading

Grey Divider

File Changes

1. packages/testkit/__tests__/ButtonGroup.test.ts 🐞 Bug fix +1/-1

Switch to starts-with data-testid selector

packages/testkit/tests/ButtonGroup.test.ts


2. packages/testkit/__tests__/Checkbox.test.ts 🐞 Bug fix +1/-1

Switch to starts-with data-testid selector

packages/testkit/tests/Checkbox.test.ts


3. packages/testkit/__tests__/Dropdown.test.ts 🐞 Bug fix +1/-1

Replace CSS class with data-vibe attribute

packages/testkit/tests/Dropdown.test.ts


View more (7)
4. packages/testkit/__tests__/Link.test.ts 🐞 Bug fix +1/-1

Switch to starts-with data-testid selector

packages/testkit/tests/Link.test.ts


5. packages/testkit/__tests__/MenuButton.test.ts 🐞 Bug fix +1/-1

Switch to starts-with data-testid selector

packages/testkit/tests/MenuButton.test.ts


6. packages/testkit/__tests__/RadioButton.test.ts 🐞 Bug fix +1/-1

Switch to starts-with data-testid selector

packages/testkit/tests/RadioButton.test.ts


7. packages/testkit/__tests__/SplitButton.test.ts 🐞 Bug fix +1/-1

Switch to starts-with data-testid selector

packages/testkit/tests/SplitButton.test.ts


8. packages/testkit/__tests__/Steps.test.ts 🐞 Bug fix +1/-1

Switch to starts-with data-testid selector

packages/testkit/tests/Steps.test.ts


9. packages/testkit/__tests__/TextField.test.ts 🐞 Bug fix +1/-1

Replace id selector with data-testid selector

packages/testkit/tests/TextField.test.ts


10. packages/docs/src/pages/components/Dropdown/DropdownBasicDropdown.stories.tsx 🐞 Bug fix +3/-1

Add searchable and inputAriaLabel props

packages/docs/src/pages/components/Dropdown/DropdownBasicDropdown.stories.tsx


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Contributor

qodo-free-for-open-source-projects bot commented Mar 15, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (1) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Checkbox toggles hidden input🐞 Bug ✓ Correctness
Description
Checkbox.setChecked()/setUnchecked() now call Playwright check()/uncheck() on the Checkbox
``, but the core component intentionally styles that input as a hidden 0×0 element, so the element
is not interactable and toggle operations can fail/time out.
Code

packages/testkit/components/Checkbox.ts[22]

+    this.checkbox = new TextField(page, locator.locator("input"), `${elementReportName} - Checkbox`);
Evidence
The testkit Checkbox switched its internal control locator to the nested `` and then uses
check()/uncheck() on it. In the core Checkbox implementation, that ` uses .input` styles which
include the hidden-element() mixin (opacity 0, width/height 0, absolute positioning), i.e., it is
intentionally hidden and effectively non-clickable.

packages/testkit/components/Checkbox.ts[20-46]
packages/core/src/components/Checkbox/Checkbox.tsx[208-235]
packages/core/src/components/Checkbox/Checkbox.module.scss[69-75]
packages/style/src/mixins/_common.scss[9-14]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Checkbox.setChecked()`/`setUnchecked()` uses Playwright `check()`/`uncheck()` on the underlying `&amp;amp;amp;amp;lt;input&amp;amp;amp;amp;gt;`, but the core Checkbox intentionally styles that input with `hidden-element()` (opacity 0, width/height 0). This makes the input non-interactable and can cause toggle operations to fail.
### Issue Context
The visual/clickable target in the core component is the rendered checkbox control (the element with `data-testid` derived from `ComponentDefaultTestId.CHECKBOX_CHECKBOX`), not the hidden input.
### Fix Focus Areas
- packages/testkit/components/Checkbox.ts[20-58]
- packages/core/src/components/Checkbox/Checkbox.module.scss[69-75]
- packages/style/src/mixins/_common.scss[9-14]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Toast locator non-unique🐞 Bug ⛯ Reliability
Description
The new selector div[data-testid^="toast"] matches both the toast root (toast_) and the internal
toast content container (toast-content), so the testkit Toast locator can resolve to multiple
elements and break strict Playwright waits/assertions/actions.
Code

packages/testkit/tests/Toast.test.ts[5]

+const toastLocator = 'div[data-testid^="toast"]';
Evidence
TOAST_CONTENT is literally "toast-content", which starts with toast, and it is rendered on a
Flex that defaults to a div. Since the toast root is also a div with data-testid starting
with toast (e.g. toast_default-with-button), the prefix selector div[data-testid^="toast"]
matches at least these two elements within a single Toast, making the locator ambiguous for
downstream operations like waitForElementToBeVisible() (which calls locator.waitFor).

packages/testkit/tests/Toast.test.ts[1-18]
packages/core/src/tests/constants.ts[89-93]
packages/core/src/components/Toast/Toast.tsx[187-205]
packages/components/layout/src/Flex/Flex.tsx[68-75]
packages/testkit/components/BaseElement.ts[139-143]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`div[data-testid^=&amp;amp;amp;amp;quot;toast&amp;amp;amp;amp;quot;]` matches both the toast root and the internal `toast-content` div, making the locator non-unique and breaking strict Playwright operations (waits/assertions/actions).
### Issue Context
The Toast root has `role=&amp;amp;amp;amp;quot;alert&amp;amp;amp;amp;quot;`, while the `toast-content` container does not; this is a stable discriminator.
### Fix Focus Areas
- packages/testkit/__tests__/Toast.test.ts[1-6]
- packages/core/src/components/Toast/Toast.tsx[187-205]
- packages/core/src/tests/constants.ts[89-93]
- packages/components/layout/src/Flex/Flex.tsx[68-75]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Hard-coded test ID selectors 📘 Rule violation ⛯ Reliability
Description
Several updated Playwright tests use string-literal data-testid/data-vibe selectors (including
the ad-hoc ^= prefix match) instead of the repository’s centralized test-id constants and
getTestId() pattern. This violates the established test-id convention and can lead to
inconsistent, less precise selectors across the monorepo.
Code

packages/testkit/tests/ButtonGroup.test.ts[7]

+const buttonGroupLocator = 'div[data-testid^="button-group"]';
Evidence
PR Compliance ID 9 requires using established, constants-based test id patterns. The changed tests
construct selectors with hard-coded strings like data-testid^="button-group" and
data-vibe="Dropdown", while the repo provides ComponentDefaultTestId/ComponentVibeId constants
and a getTestId() helper for consistent data-testid generation.

CLAUDE.md
packages/testkit/tests/ButtonGroup.test.ts[7-7]
packages/testkit/tests/Dropdown.test.ts[7-7]
packages/core/src/tests/constants.ts[14-30]
packages/core/src/tests/test-ids-utils.ts[1-6]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Several updated testkit E2E tests build selectors using string-literal `data-testid`/`data-vibe` values (and `data-testid^=` prefix matching) rather than the repo’s centralized constants and helper (`getTestId`). This breaks the compliance requirement for consistent, constants-based test-id patterns.
## Issue Context
The repository provides `ComponentDefaultTestId` / `ComponentVibeId` enums and a `getTestId(elementType, id)` helper to generate standardized `data-testid` values, including the `_&amp;amp;amp;amp;amp;lt;id&amp;amp;amp;amp;amp;gt;` suffix convention.
## Fix Focus Areas
- packages/testkit/__tests__/ButtonGroup.test.ts[1-8]
- packages/testkit/__tests__/Checkbox.test.ts[1-8]
- packages/testkit/__tests__/Link.test.ts[1-8]
- packages/testkit/__tests__/MenuButton.test.ts[1-11]
- packages/testkit/__tests__/RadioButton.test.ts[1-8]
- packages/testkit/__tests__/SplitButton.test.ts[1-11]
- packages/testkit/__tests__/Steps.test.ts[1-9]
- packages/testkit/__tests__/TextField.test.ts[1-9]
- packages/testkit/__tests__/Dropdown.test.ts[1-9] করা

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

let frame: FrameLocator;
let buttonGroup: ButtonGroup;
const buttonGroupLocator = 'div[data-testid="button-group"]';
const buttonGroupLocator = 'div[data-testid^="button-group"]';

Choose a reason for hiding this comment

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

Action required

1. Hard-coded test id selectors 📘 Rule violation ⛯ Reliability

Several updated Playwright tests use string-literal data-testid/data-vibe selectors (including
the ad-hoc ^= prefix match) instead of the repository’s centralized test-id constants and
getTestId() pattern. This violates the established test-id convention and can lead to
inconsistent, less precise selectors across the monorepo.
Agent Prompt
## Issue description
Several updated testkit E2E tests build selectors using string-literal `data-testid`/`data-vibe` values (and `data-testid^=` prefix matching) rather than the repo’s centralized constants and helper (`getTestId`). This breaks the compliance requirement for consistent, constants-based test-id patterns.

## Issue Context
The repository provides `ComponentDefaultTestId` / `ComponentVibeId` enums and a `getTestId(elementType, id)` helper to generate standardized `data-testid` values, including the `_<id>` suffix convention.

## Fix Focus Areas
- packages/testkit/__tests__/ButtonGroup.test.ts[1-8]
- packages/testkit/__tests__/Checkbox.test.ts[1-8]
- packages/testkit/__tests__/Link.test.ts[1-8]
- packages/testkit/__tests__/MenuButton.test.ts[1-11]
- packages/testkit/__tests__/RadioButton.test.ts[1-8]
- packages/testkit/__tests__/SplitButton.test.ts[1-11]
- packages/testkit/__tests__/Steps.test.ts[1-9]
- packages/testkit/__tests__/TextField.test.ts[1-9]
- packages/testkit/__tests__/Dropdown.test.ts[1-9] করা

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Extend the data-testid starts-with (^=) fix to Toast, Button, IconButton,
Loader, and TextArea — same root cause as the previous batch: stories pass
explicit id props, causing a suffix in getTestId() output.

Also fix the Checkbox testkit component:
- Use locator("input") instead of locator("div") so check()/uncheck()/
  isChecked() target the actual <input type="checkbox">, not the visual div
- Update toBeChecked() assertions in the test to target the input directly
  (Playwright throws "Not a checkbox or radio button" on <label> elements)
- Fix attribute retrieval test to read data-vibe from the root label, not
  the inner div (which does not have that attribute)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@qodo-free-for-open-source-projects
Copy link
Contributor

qodo-free-for-open-source-projects bot commented Mar 15, 2026

Persistent review updated to latest commit 953694c

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@qodo-free-for-open-source-projects
Copy link
Contributor

qodo-free-for-open-source-projects bot commented Mar 15, 2026

Persistent review updated to latest commit db801c3

Checkbox: the hidden <input type="checkbox"> (replaced by custom CSS)
is not visible to Playwright, so check()/uncheck() fail with a timeout.
Click the outer <label> instead — it's visible and toggling it updates
the input state. isChecked() still reads the input directly which works.

Toast: data-testid^="toast" matches both the root toast element
(toast_default-with-button) and the inner toast-content div
(toast-content), causing a strict-mode violation. Use data-testid^="toast_"
(underscore separator from getTestId) which only matches the root.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@qodo-free-for-open-source-projects
Copy link
Contributor

qodo-free-for-open-source-projects bot commented Mar 15, 2026

Persistent review updated to latest commit 68bb28e

…tests

Instead of modifying the Overview story to add searchable/inputAriaLabel,
point the Dropdown testkit to the existing Searchable story which already
has the searchable prop set. Update the attribute test to check data-vibe
on the root element instead of aria-label on the input.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@qodo-free-for-open-source-projects
Copy link
Contributor

qodo-free-for-open-source-projects bot commented Mar 15, 2026

Persistent review updated to latest commit 2bde05f

@rivka-ungar rivka-ungar merged commit b68de2f into vibe4 Mar 16, 2026
12 checks passed
@rivka-ungar rivka-ungar deleted the fix/testkit-locators-vibe4 branch March 16, 2026 00:11
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.

2 participants