Skip to content

CONSOLE-5176: Refactor RTL Tests from fireEvent to userEvent#16265

Open
cajieh wants to merge 1 commit intoopenshift:mainfrom
cajieh:update-claude-skills-rtl-best-practices
Open

CONSOLE-5176: Refactor RTL Tests from fireEvent to userEvent#16265
cajieh wants to merge 1 commit intoopenshift:mainfrom
cajieh:update-claude-skills-rtl-best-practices

Conversation

@cajieh
Copy link
Copy Markdown
Contributor

@cajieh cajieh commented Apr 8, 2026

Summary by CodeRabbit

  • Tests

    • Updated testing infrastructure across multiple packages to use modern testing practices, improving test reliability and maintainability.
  • Documentation

    • Updated React Testing Library best-practices documentation to reflect current recommended patterns for user interaction testing.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Apr 8, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Apr 8, 2026

@cajieh: This pull request references CONSOLE-5176 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set.

Details

In response to this:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Apr 8, 2026
@openshift-ci openshift-ci bot requested review from jhadvig and sg00dwin April 8, 2026 13:48
@openshift-ci openshift-ci bot added the component/core Related to console core functionality label Apr 8, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Apr 8, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: cajieh
Once this PR has been reviewed and has the lgtm label, please assign rhamilto for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot added component/dev-console Related to dev-console component/knative Related to knative-plugin component/olm Related to OLM component/shared Related to console-shared component/topology Related to topology labels Apr 8, 2026
@cajieh cajieh changed the title [WIP] CONSOLE-5176: Refactor RTL Tests from fireEvent to userEvent CONSOLE-5176: Refactor RTL Tests from fireEvent to userEvent Apr 8, 2026
@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Apr 8, 2026
@cajieh
Copy link
Copy Markdown
Contributor Author

cajieh commented Apr 8, 2026

/retest

@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Apr 8, 2026

@cajieh: This pull request references CONSOLE-5176 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set.

Details

In response to this:

Summary by CodeRabbit

  • Tests

  • Updated testing infrastructure across multiple packages to use modern testing practices, improving test reliability and maintainability.

  • Documentation

  • Updated React Testing Library best-practices documentation to reflect current recommended patterns for user interaction testing.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 2026

📝 Walkthrough

Walkthrough

A systematic migration across the test suite to replace fireEvent interactions with @testing-library/user-event interactions. Updates include RTL testing documentation standardizing on userEvent with proper async handling, modified test files across multiple packages (console-app, console-shared, dev-console, operator-lifecycle-manager, and others) replacing fireEvent.change/fireEvent.click with async user.type()/user.click() patterns, marking affected tests as async, and removing fireEvent imports in favor of userEvent setup. Test utilities like verifyInputField and verifyIDPListInputFields are updated to use userEvent internally. No changes to exported or public entities.

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

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/packages/dev-console/src/components/deployments/__tests__/DeploymentForm.spec.tsx (1)

152-156: ⚠️ Potential issue | 🟠 Major

Move disabled/progress assertions inside waitFor to improve test determinism.

The assertions on saveButton.hasAttribute('disabled') and saveButton.querySelector('.pf-v6-c-button__progress') should be wrapped in waitFor() to ensure the async state updates have settled. This aligns with @testing-library best practices when testing async state changes and reduces test flakiness.

Suggested fix
     await user.click(saveButton);

-    expect(saveButton.hasAttribute('disabled')).toBeTruthy();
-    expect(saveButton.querySelector('.pf-v6-c-button__progress')).not.toBeNull();
-    await waitFor(() => {
-      expect(handleSubmit).toHaveBeenCalledTimes(1);
-    });
+    await waitFor(() => {
+      expect(saveButton.hasAttribute('disabled')).toBeTruthy();
+      expect(saveButton.querySelector('.pf-v6-c-button__progress')).not.toBeNull();
+      expect(handleSubmit).toHaveBeenCalledTimes(1);
+    });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/dev-console/src/components/deployments/__tests__/DeploymentForm.spec.tsx`
around lines 152 - 156, Move the two post-click assertions into the asynchronous
waitFor to avoid flakiness: after calling user.click(saveButton) keep the click,
then wrap both expect(saveButton.hasAttribute('disabled')).toBeTruthy() and
expect(saveButton.querySelector('.pf-v6-c-button__progress')).not.toBeNull()
inside a single await waitFor(() => { ... }) block so the saveButton disabled
state and the .pf-v6-c-button__progress element are asserted only after async
updates settle; reference the saveButton variable and the progress selector when
making the change.
🧹 Nitpick comments (3)
frontend/packages/webterminal-plugin/src/components/cloud-shell/__tests__/MultiTabbedTerminal.spec.tsx (1)

21-30: Avoid reusing a potentially stale DOM node in repeated clicks

clickMultipleTimes captures one HTMLElement and reuses it across async clicks. Around re-renders/removal boundaries (like max tabs), this can interact with a detached node and make the test brittle.

Suggested refactor
 const clickMultipleTimes = async (
   user: ReturnType<typeof userEvent.setup>,
-  element: HTMLElement,
+  getElement: () => HTMLElement | null,
   times: number,
 ) => {
   for (let i = 0; i < times; i++) {
+    const element = getElement();
+    if (!element) {
+      break;
+    }
     // eslint-disable-next-line no-await-in-loop
     await act(async () => {
       await user.click(element);
     });
   }
 };
@@
-    await clickMultipleTimes(user, addTerminalButton, 8);
+    await clickMultipleTimes(user, () => multiTabTerminalWrapper.queryByLabelText('Add new tab'), 8);
@@
-    await clickMultipleTimes(user, addTerminalButton, 8);
+    await clickMultipleTimes(user, () => multiTabTerminalWrapper.queryByLabelText('Add new tab'), 8);

Also applies to: 89-101

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/webterminal-plugin/src/components/cloud-shell/__tests__/MultiTabbedTerminal.spec.tsx`
around lines 21 - 30, The helper clickMultipleTimes reuses a captured
HTMLElement across async clicks which can become detached after re-renders;
change its signature (the function clickMultipleTimes) to accept a getter (e.g.,
elementGetter: () => HTMLElement | null or a query callback) instead of a single
HTMLElement, and inside the loop call the getter each iteration and assert the
returned element is not null before awaiting user.click on it; update all call
sites (including the other instance referenced around the second occurrence) to
pass a function that queries the DOM for the current node so each click uses a
fresh, non-stale element.
frontend/packages/knative-plugin/src/components/traffic-splitting/__tests__/TrafficSplittingModal.spec.tsx (1)

40-45: Scope the requestSubmit polyfill to avoid brittle global mutation.

This overrides HTMLFormElement.prototype.requestSubmit unconditionally and never restores it. Guard it and restore after tests to keep test behavior isolated and future-proof.

Proposed patch
+let originalRequestSubmit: typeof HTMLFormElement.prototype.requestSubmit;
+
 // jsdom does not implement requestSubmit; user-event uses it for type="submit" clicks
 beforeAll(() => {
-  HTMLFormElement.prototype.requestSubmit = function requestSubmitPolyfill(this: HTMLFormElement) {
-    this.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
-  };
+  originalRequestSubmit = HTMLFormElement.prototype.requestSubmit;
+  if (!HTMLFormElement.prototype.requestSubmit) {
+    HTMLFormElement.prototype.requestSubmit = function requestSubmitPolyfill(this: HTMLFormElement) {
+      this.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
+    };
+  }
 });
+
+afterAll(() => {
+  HTMLFormElement.prototype.requestSubmit = originalRequestSubmit;
+});

As per coding guidelines, "Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/knative-plugin/src/components/traffic-splitting/__tests__/TrafficSplittingModal.spec.tsx`
around lines 40 - 45, The global requestSubmit polyfill set in the beforeAll
hook unconditionally mutates HTMLFormElement.prototype and never restores it;
modify the test setup so beforeAll first saves the original
HTMLFormElement.prototype.requestSubmit (e.g., const _orig =
HTMLFormElement.prototype.requestSubmit), only assigns the polyfill if the
original is undefined, and add an afterAll that restores
HTMLFormElement.prototype.requestSubmit = _orig; keep the polyfill
implementation as the existing requestSubmitPolyfill function and use the same
event dispatch logic so test behavior remains identical while avoiding brittle
global mutation.
frontend/packages/knative-plugin/src/components/sink-source/__tests__/SinkSourceModal.spec.tsx (1)

43-48: Apply the same polyfill lifecycle guard here (beforeAll + afterAll).

This file has the same unconditional global requestSubmit override; make it conditional and restore original implementation after tests.

As per coding guidelines, "Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/knative-plugin/src/components/sink-source/__tests__/SinkSourceModal.spec.tsx`
around lines 43 - 48, The test file unconditionally overrides
HTMLFormElement.prototype.requestSubmit in the beforeAll block; make it
conditional and restore the original after tests by saving the original
requestSubmit, only assigning the polyfill if it is undefined, and restoring the
saved value in an afterAll cleanup. Update the existing
beforeAll/requestSubmitPolyfill usage and add a matching afterAll that
references the saved originalRequestSubmit to return behavior to its prior
state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/__tests__/ClusterExtensionForm.spec.tsx`:
- Around line 80-97: The test "should auto-generate namespace and service
account names based on ClusterExtension name" only asserts metadata.name but
must also verify the auto-generated namespace and serviceAccount fields; update
the assertion that checks mockOnChange (in the spec using ClusterExtensionForm
and mockOnChange) to expect objectContaining metadata.namespace and the service
account field (e.g., spec.serviceAccountName or metadata.serviceAccount
depending on impl) with the expected auto-generated values or patterns derived
from 'my-operator' so the test actually verifies namespace/serviceAccount
generation.

In
`@frontend/packages/topology/src/components/export-app/__tests__/ExportApplicationModal.spec.tsx`:
- Around line 146-156: The test "should call k8sKill with correct data on click
of cancel button when export app is in progress" is clicking the wrong element;
change the user click target from the 'export-restart-btn' test id to the cancel
button test id (e.g., 'export-cancel-btn') so the cancel path in
ExportApplicationModal is exercised for the exportData with completed=false;
update any related assertions that expect k8sKill to be called after rendering
via renderWithProviders and using the existing exportData/mockExportData setup.

In `@frontend/public/components/factory/__tests__/list-page.spec.tsx`:
- Around line 61-73: The test for TextFilter is asserting on onChange
immediately even though userEvent.type triggers multiple change events; update
the assertions to wait for the final call by using waitFor and assert on
toHaveBeenLastCalledWith (or check the last call) instead of
toHaveBeenCalledTimes(1) and toHaveBeenCalledWith; locate the test around the
TextFilter render and user.type invocation and replace the immediate count/check
with a waitFor that verifies onChange was called and that its last call received
the expected event and 'test-value' argument.

---

Outside diff comments:
In
`@frontend/packages/dev-console/src/components/deployments/__tests__/DeploymentForm.spec.tsx`:
- Around line 152-156: Move the two post-click assertions into the asynchronous
waitFor to avoid flakiness: after calling user.click(saveButton) keep the click,
then wrap both expect(saveButton.hasAttribute('disabled')).toBeTruthy() and
expect(saveButton.querySelector('.pf-v6-c-button__progress')).not.toBeNull()
inside a single await waitFor(() => { ... }) block so the saveButton disabled
state and the .pf-v6-c-button__progress element are asserted only after async
updates settle; reference the saveButton variable and the progress selector when
making the change.

---

Nitpick comments:
In
`@frontend/packages/knative-plugin/src/components/sink-source/__tests__/SinkSourceModal.spec.tsx`:
- Around line 43-48: The test file unconditionally overrides
HTMLFormElement.prototype.requestSubmit in the beforeAll block; make it
conditional and restore the original after tests by saving the original
requestSubmit, only assigning the polyfill if it is undefined, and restoring the
saved value in an afterAll cleanup. Update the existing
beforeAll/requestSubmitPolyfill usage and add a matching afterAll that
references the saved originalRequestSubmit to return behavior to its prior
state.

In
`@frontend/packages/knative-plugin/src/components/traffic-splitting/__tests__/TrafficSplittingModal.spec.tsx`:
- Around line 40-45: The global requestSubmit polyfill set in the beforeAll hook
unconditionally mutates HTMLFormElement.prototype and never restores it; modify
the test setup so beforeAll first saves the original
HTMLFormElement.prototype.requestSubmit (e.g., const _orig =
HTMLFormElement.prototype.requestSubmit), only assigns the polyfill if the
original is undefined, and add an afterAll that restores
HTMLFormElement.prototype.requestSubmit = _orig; keep the polyfill
implementation as the existing requestSubmitPolyfill function and use the same
event dispatch logic so test behavior remains identical while avoiding brittle
global mutation.

In
`@frontend/packages/webterminal-plugin/src/components/cloud-shell/__tests__/MultiTabbedTerminal.spec.tsx`:
- Around line 21-30: The helper clickMultipleTimes reuses a captured HTMLElement
across async clicks which can become detached after re-renders; change its
signature (the function clickMultipleTimes) to accept a getter (e.g.,
elementGetter: () => HTMLElement | null or a query callback) instead of a single
HTMLElement, and inside the loop call the getter each iteration and assert the
returned element is not null before awaiting user.click on it; update all call
sites (including the other instance referenced around the second occurrence) to
pass a function that queries the DOM for the current node so each click uses a
fresh, non-stale element.
🪄 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: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 10332720-6b23-4352-9c07-f1212708b573

📥 Commits

Reviewing files that changed from the base of the PR and between 62dd642 and 94de5ce.

📒 Files selected for processing (58)
  • .claude/skills/gen-rtl-test/SKILL.md
  • frontend/packages/console-app/src/__tests__/hooks/useCSPViolationDetector.spec.tsx
  • frontend/packages/console-app/src/components/modals/resource-limits/__tests__/ResourceLimitsModal.spec.tsx
  • frontend/packages/console-shared/src/components/alerts/__tests__/SwitchToYAMLAlert.spec.tsx
  • frontend/packages/console-shared/src/components/editor/__tests__/CodeEditorToolbar.spec.tsx
  • frontend/packages/console-shared/src/components/form-utils/__tests__/FlexForm.spec.tsx
  • frontend/packages/console-shared/src/components/form-utils/__tests__/FormFooter.spec.tsx
  • frontend/packages/console-shared/src/components/formik-fields/__tests__/NumberSpinnerField.spec.tsx
  • frontend/packages/console-shared/src/components/formik-fields/key-value-file-input-field/__tests__/KeyValueFileInputField.spec.tsx
  • frontend/packages/console-shared/src/components/formik-fields/multi-column-field/__tests__/MultiColumnFieldFooter.spec.tsx
  • frontend/packages/console-shared/src/components/getting-started/__tests__/GettingStartedCard.spec.tsx
  • frontend/packages/console-shared/src/components/getting-started/__tests__/RestoreGettingStartedButton.spec.tsx
  • frontend/packages/console-shared/src/components/modals/__tests__/FetchProgressModal.spec.tsx
  • frontend/packages/console-shared/src/components/modals/__tests__/TextInputModal.spec.tsx
  • frontend/packages/console-shared/src/components/progressive-list/__tests__/ProgressiveList.spec.tsx
  • frontend/packages/console-shared/src/components/toast/__tests__/ToastProvider.spec.tsx
  • frontend/packages/console-shared/src/test-utils/unit-test-utils.tsx
  • frontend/packages/container-security/src/components/__tests__/ImageVulnerabilityToggleGroup.spec.tsx
  • frontend/packages/dev-console/src/components/deployments/__tests__/AdvancedSection.spec.tsx
  • frontend/packages/dev-console/src/components/deployments/__tests__/DeploymentForm.spec.tsx
  • frontend/packages/dev-console/src/components/deployments/__tests__/DeploymentStrategySection.spec.tsx
  • frontend/packages/dev-console/src/components/deployments/__tests__/EnvironmentVariablesSection.spec.tsx
  • frontend/packages/dev-console/src/components/deployments/__tests__/ImagesSection.spec.tsx
  • frontend/packages/dev-console/src/components/deployments/__tests__/PauseRolloutsSection.spec.tsx
  • frontend/packages/dev-console/src/components/user-preferences/__tests__/SecureRouteFields.spec.tsx
  • frontend/packages/knative-plugin/src/components/overview/__tests__/RevisionsOverviewList.spec.tsx
  • frontend/packages/knative-plugin/src/components/sink-source/__tests__/SinkSourceModal.spec.tsx
  • frontend/packages/knative-plugin/src/components/traffic-splitting/__tests__/TrafficSplittingModal.spec.tsx
  • frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/__tests__/ClusterExtensionForm.spec.tsx
  • frontend/packages/operator-lifecycle-manager/src/components/__tests__/install-plan.spec.tsx
  • frontend/packages/operator-lifecycle-manager/src/components/descriptors/spec/__tests__/resource-requirements.spec.tsx
  • frontend/packages/operator-lifecycle-manager/src/components/modals/__tests__/installplan-approval-modal.spec.tsx
  • frontend/packages/operator-lifecycle-manager/src/components/modals/__tests__/subscription-channel-modal.spec.tsx
  • frontend/packages/operator-lifecycle-manager/src/components/modals/__tests__/uninstall-operator-modal.spec.tsx
  • frontend/packages/topology/src/__tests__/TopologySideBar.spec.tsx
  • frontend/packages/topology/src/components/export-app/__tests__/ExportApplicationModal.spec.tsx
  • frontend/packages/webterminal-plugin/src/components/cloud-shell/__tests__/MinimizeRestoreButton.spec.tsx
  • frontend/packages/webterminal-plugin/src/components/cloud-shell/__tests__/MultiTabbedTerminal.spec.tsx
  • frontend/public/components/__tests__/storage-class-form.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/basicauth-idp-form.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/github-idp-form.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/gitlab-idp-form.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/google-idp-form.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/htpasswd-idp-form.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/keystone-idp-form.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/ldap-idp-form.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/openid-idp-form.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/request-header-idp-form.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/test-utils.ts
  • frontend/public/components/factory/__tests__/list-page.spec.tsx
  • frontend/public/components/modals/__tests__/configure-update-strategy-modal.spec.tsx
  • frontend/public/components/modals/__tests__/impersonate-user-modal-integration.spec.tsx
  • frontend/public/components/modals/__tests__/impersonate-user-modal.spec.tsx
  • frontend/public/components/modals/__tests__/replace-code-modal.spec.tsx
  • frontend/public/components/utils/__tests__/download-button.spec.tsx
  • frontend/public/components/utils/__tests__/kebab.spec.tsx
  • frontend/public/components/utils/__tests__/name-value-editor.spec.tsx
  • frontend/public/components/utils/__tests__/single-typeahead-dropdown.spec.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • frontend/public/components/cluster-settings/__tests__/basicauth-idp-form.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/htpasswd-idp-form.spec.tsx
  • frontend/packages/console-shared/src/components/alerts/__tests__/SwitchToYAMLAlert.spec.tsx
  • frontend/packages/container-security/src/components/__tests__/ImageVulnerabilityToggleGroup.spec.tsx
  • frontend/packages/console-shared/src/components/getting-started/__tests__/RestoreGettingStartedButton.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/google-idp-form.spec.tsx
  • frontend/packages/console-app/src/components/modals/resource-limits/__tests__/ResourceLimitsModal.spec.tsx
  • frontend/packages/webterminal-plugin/src/components/cloud-shell/__tests__/MinimizeRestoreButton.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/keystone-idp-form.spec.tsx
  • frontend/packages/dev-console/src/components/deployments/__tests__/ImagesSection.spec.tsx
  • frontend/packages/console-shared/src/components/editor/__tests__/CodeEditorToolbar.spec.tsx
  • frontend/packages/operator-lifecycle-manager/src/components/modals/__tests__/uninstall-operator-modal.spec.tsx
  • frontend/packages/topology/src/__tests__/TopologySideBar.spec.tsx
  • frontend/packages/operator-lifecycle-manager/src/components/__tests__/install-plan.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/ldap-idp-form.spec.tsx
  • frontend/packages/dev-console/src/components/deployments/__tests__/EnvironmentVariablesSection.spec.tsx
  • frontend/packages/topology/src/components/export-app/__tests__/ExportApplicationModal.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/openid-idp-form.spec.tsx
  • frontend/packages/dev-console/src/components/deployments/__tests__/AdvancedSection.spec.tsx
  • frontend/packages/console-shared/src/components/getting-started/__tests__/GettingStartedCard.spec.tsx
  • frontend/packages/console-shared/src/components/form-utils/__tests__/FormFooter.spec.tsx
  • frontend/packages/console-shared/src/components/progressive-list/__tests__/ProgressiveList.spec.tsx
  • frontend/packages/console-app/src/__tests__/hooks/useCSPViolationDetector.spec.tsx
  • frontend/packages/dev-console/src/components/deployments/__tests__/DeploymentStrategySection.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/request-header-idp-form.spec.tsx
  • frontend/public/components/utils/__tests__/kebab.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/github-idp-form.spec.tsx
  • frontend/public/components/modals/__tests__/replace-code-modal.spec.tsx
  • frontend/packages/knative-plugin/src/components/overview/__tests__/RevisionsOverviewList.spec.tsx
  • frontend/packages/dev-console/src/components/user-preferences/__tests__/SecureRouteFields.spec.tsx
  • frontend/packages/operator-lifecycle-manager/src/components/modals/__tests__/subscription-channel-modal.spec.tsx
  • frontend/packages/console-shared/src/components/formik-fields/__tests__/NumberSpinnerField.spec.tsx
  • frontend/packages/console-shared/src/test-utils/unit-test-utils.tsx
  • frontend/public/components/utils/__tests__/name-value-editor.spec.tsx
  • frontend/packages/console-shared/src/components/formik-fields/multi-column-field/__tests__/MultiColumnFieldFooter.spec.tsx
  • frontend/public/components/modals/__tests__/configure-update-strategy-modal.spec.tsx
  • frontend/packages/knative-plugin/src/components/traffic-splitting/__tests__/TrafficSplittingModal.spec.tsx
  • frontend/public/components/modals/__tests__/impersonate-user-modal.spec.tsx
  • frontend/packages/console-shared/src/components/form-utils/__tests__/FlexForm.spec.tsx
  • frontend/public/components/factory/__tests__/list-page.spec.tsx
  • frontend/packages/console-shared/src/components/formik-fields/key-value-file-input-field/__tests__/KeyValueFileInputField.spec.tsx
  • frontend/packages/knative-plugin/src/components/sink-source/__tests__/SinkSourceModal.spec.tsx
  • frontend/packages/operator-lifecycle-manager/src/components/descriptors/spec/__tests__/resource-requirements.spec.tsx
  • frontend/packages/console-shared/src/components/toast/__tests__/ToastProvider.spec.tsx
  • frontend/packages/dev-console/src/components/deployments/__tests__/DeploymentForm.spec.tsx
  • frontend/packages/webterminal-plugin/src/components/cloud-shell/__tests__/MultiTabbedTerminal.spec.tsx
  • frontend/packages/operator-lifecycle-manager/src/components/modals/__tests__/installplan-approval-modal.spec.tsx
  • frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/__tests__/ClusterExtensionForm.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/gitlab-idp-form.spec.tsx
  • frontend/packages/console-shared/src/components/modals/__tests__/TextInputModal.spec.tsx
  • frontend/packages/console-shared/src/components/modals/__tests__/FetchProgressModal.spec.tsx
  • frontend/public/components/utils/__tests__/single-typeahead-dropdown.spec.tsx
  • frontend/public/components/cluster-settings/__tests__/test-utils.ts
  • frontend/public/components/modals/__tests__/impersonate-user-modal-integration.spec.tsx
  • frontend/packages/dev-console/src/components/deployments/__tests__/PauseRolloutsSection.spec.tsx
  • frontend/public/components/__tests__/storage-class-form.spec.tsx
  • frontend/public/components/utils/__tests__/download-button.spec.tsx
🔇 Additional comments (56)
frontend/packages/topology/src/__tests__/TopologySideBar.spec.tsx (2)

1-2: Good RTL migration import update.

Switching to userEvent import is aligned with current RTL interaction best practices and keeps the test API consistent with async user-driven events.


25-26: Async click flow is correctly implemented.

Using async test + userEvent.setup() + await user.click(...) is the right pattern, and the assertion remains clear and stable for this interaction.

Also applies to: 34-35

frontend/packages/container-security/src/components/__tests__/ImageVulnerabilityToggleGroup.spec.tsx (2)

1-2: userEvent import migration looks correct.

This aligns the test with the async interaction API used in the updated test body.


32-38: Async interaction update is implemented correctly.

Using async test + userEvent.setup() + await user.click(...) is the right RTL pattern and improves interaction realism/reliability.

frontend/packages/webterminal-plugin/src/components/cloud-shell/__tests__/MinimizeRestoreButton.spec.tsx (2)

1-2: Nice cleanup: userEvent import aligns with RTL interaction best practices.
Good shift away from low-level event dispatching here.


38-38: Async interaction flow is correctly implemented.
Using userEvent.setup() plus await user.click(...) for both button paths makes these assertions more realistic and stable.

Also applies to: 54-54, 71-71

frontend/packages/dev-console/src/components/user-preferences/__tests__/SecureRouteFields.spec.tsx (2)

1-2: Clean test-library migration import update.

The import changes are scoped and aligned with the PR objective to move from fireEvent to userEvent.


39-52: Good async interaction handling in both dropdown tests.

Using userEvent.setup() with await user.click(...) and querying the element with getByTestId before interaction makes these tests more deterministic and maintainable.

Also applies to: 60-73

frontend/public/components/modals/__tests__/replace-code-modal.spec.tsx (1)

36-69: Solid userEvent migration in interaction tests.

These async click updates are consistent and improve test reliability versus synthetic sync events, with assertions preserved across all modal actions.

frontend/packages/console-app/src/__tests__/hooks/useCSPViolationDetector.spec.tsx (2)

1-1: Correct removal of fireEvent import.

The import change is appropriate since fireEvent is no longer used. The test now uses native document.dispatchEvent() for CSP violation events, which is more explicit and suitable for security events.


81-81: Native document.dispatchEvent() is the right approach for CSP violation events.

Switching from RTL's fireEvent(document, testEvent) to native document.dispatchEvent(testEvent) is appropriate here. CSP violation events are security events on the document, not user interactions. Using the native DOM API:

  • Makes the test intent clearer
  • Removes unnecessary abstraction for non-interactive events
  • Properly simulates how the browser dispatches these events

The continued use of act() ensures React state updates are batched correctly.

Also applies to: 92-92, 107-107, 122-122

frontend/packages/webterminal-plugin/src/components/cloud-shell/__tests__/MultiTabbedTerminal.spec.tsx (2)

39-41: Good userEvent setup for fake timers

beforeEach initialization with userEvent.setup({ advanceTimers: jest.advanceTimersByTime }) is the right pattern for async user interactions under fake timers.


103-118: Nice improvement: re-querying close-tab controls per interaction

Refreshing the close-tab list before each click is more robust than relying on previously indexed elements during stateful tab updates.

frontend/packages/knative-plugin/src/components/overview/__tests__/RevisionsOverviewList.spec.tsx (1)

133-146: Good userEvent async migration for click flow.

userEvent.setup() + await user.click(...) is the right pattern here, and the assertion still verifies the intended modal launcher behavior.

frontend/packages/knative-plugin/src/components/traffic-splitting/__tests__/TrafficSplittingModal.spec.tsx (1)

68-72: Nice conversion to user-driven submit behavior.

Clicking the Save button via userEvent is a stronger end-user interaction path than direct form submit dispatch.

frontend/packages/knative-plugin/src/components/sink-source/__tests__/SinkSourceModal.spec.tsx (1)

82-86: Good userEvent submit-path update.

This now exercises the form submit through the Save button, which better matches real interaction behavior.

frontend/packages/dev-console/src/components/deployments/__tests__/ImagesSection.spec.tsx (1)

3-4: Solid userEvent migration in this spec.

The updates consistently use userEvent.setup() with awaited clicks, and the async assertions remain properly guarded with waitFor.

Also applies to: 45-45, 53-53, 62-62, 78-78, 95-95, 121-121, 138-138, 154-154

frontend/packages/dev-console/src/components/deployments/__tests__/EnvironmentVariablesSection.spec.tsx (1)

2-3: Good conversion to async user interactions.

This migration is consistent and correctly awaited across add/select/delete flows.

Also applies to: 57-57, 60-60, 74-74, 79-79, 84-84, 89-89, 96-96, 99-99

frontend/packages/dev-console/src/components/deployments/__tests__/PauseRolloutsSection.spec.tsx (1)

1-2: Looks good.

userEvent.setup() and await user.click(...) are applied correctly for this checkbox flow.

Also applies to: 9-9, 18-18

frontend/packages/operator-lifecycle-manager/src/components/modals/__tests__/subscription-channel-modal.spec.tsx (1)

1-2: Clean async migration for modal channel-change tests.

Awaited user.click usage and async test conversion are correctly applied.

Also applies to: 87-87, 91-91, 94-94, 111-111, 115-115, 118-118, 132-133, 140-140

frontend/packages/operator-lifecycle-manager/src/components/modals/__tests__/uninstall-operator-modal.spec.tsx (1)

1-2: Nicely done on the interaction updates here.

The uninstall flows now use userEvent with proper awaiting and preserve existing async assertions.

Also applies to: 80-80, 84-84, 104-104, 108-108, 133-133, 139-139, 147-147, 151-151

frontend/packages/operator-lifecycle-manager/src/components/__tests__/install-plan.spec.tsx (1)

1-2: This conversion is correct and stable.

await user.click(...) is the right replacement for this approval-path interaction.

Also applies to: 311-311, 313-313

frontend/packages/operator-lifecycle-manager/src/components/modals/__tests__/installplan-approval-modal.spec.tsx (1)

1-2: Great improvement to user-realistic submit behavior.

Switching from direct form submission events to clicking the Save button is a stronger, behavior-faithful test path.

Also applies to: 82-82, 88-88, 90-90, 107-107, 116-116, 118-118, 135-135, 138-138

frontend/packages/operator-lifecycle-manager/src/components/descriptors/spec/__tests__/resource-requirements.spec.tsx (1)

1-2: Excellent userEvent migration in this spec.

Clearing/typing inputs and submitting via awaited clicks is correctly implemented and better matches real interaction timing.

Also applies to: 65-65, 70-78, 81-81, 162-162, 165-165

frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/__tests__/ClusterExtensionForm.spec.tsx (1)

117-232: Good async userEvent migration in interaction-heavy tests

The updated await user.* calls plus waitFor/toHaveBeenLastCalledWith are a solid fit for per-keystroke onChange behavior and reduce flakiness across these cases.

frontend/public/components/modals/__tests__/impersonate-user-modal-integration.spec.tsx (1)

57-409: Migration looks sound

The conversion to awaited userEvent interactions preserves test behavior while matching async UI updates (waitFor) in the right places.

frontend/public/components/modals/__tests__/impersonate-user-modal.spec.tsx (1)

111-581: Solid fireEventuserEvent conversion

Async user interactions are awaited consistently, and callback assertions remain properly guarded with waitFor where needed.

frontend/public/components/modals/__tests__/configure-update-strategy-modal.spec.tsx (1)

65-129: Nice update for incremental input events

Using awaited user.clear/user.type with toHaveBeenLastCalledWith is the right adaptation for userEvent-driven change sequences.

.claude/skills/gen-rtl-test/SKILL.md (1)

514-583: Guidance update is aligned and actionable

The revised rules/examples consistently reflect async userEvent usage and the recommended post-interaction waiting patterns.

Also applies to: 998-1035, 1485-1492, 1616-1617

frontend/packages/topology/src/components/export-app/__tests__/ExportApplicationModal.spec.tsx (1)

95-139: Good interaction migration on create/restart flows

Awaited user.click usage is correctly applied and keeps call assertions deterministic for these action paths.

frontend/packages/dev-console/src/components/deployments/__tests__/AdvancedSection.spec.tsx (1)

37-127: Looks good

This is a clean userEvent migration with proper async handling and unchanged behavioral assertions.

frontend/packages/dev-console/src/components/deployments/__tests__/DeploymentStrategySection.spec.tsx (1)

21-191: Well-executed migration

Awaited userEvent clicks are applied consistently across dropdown/option interactions, and the existing async assertions remain stable.

frontend/packages/dev-console/src/components/deployments/__tests__/DeploymentForm.spec.tsx (1)

2-3: Good userEvent migration with async interactions.

Using userEvent.setup() + awaited click/clear/type is a solid update and makes these tests closer to real user behavior.

Also applies to: 106-151, 162-191

frontend/public/components/cluster-settings/__tests__/google-idp-form.spec.tsx (1)

25-26: Async helper usage is correctly applied.

These updates properly await field-verification helpers, which is the right pattern after moving interactions to async userEvent flows and should improve test stability.

Also applies to: 35-36, 43-44, 52-53

frontend/packages/console-shared/src/components/alerts/__tests__/SwitchToYAMLAlert.spec.tsx (1)

1-2: Good migration from fireEvent to awaited userEvent click.

The async test flow is correctly implemented and avoids timing issues common with synchronous click simulation.

Also applies to: 46-47, 52-52

frontend/public/components/cluster-settings/__tests__/ldap-idp-form.spec.tsx (1)

85-86: Async conversion for list-field assertions looks solid.

Awaiting verifyIDPListInputFields in each case is the correct change and should prevent false pass/fail behavior from unresolved async interactions.

Also applies to: 95-96, 105-106, 115-116

frontend/public/components/cluster-settings/__tests__/openid-idp-form.spec.tsx (1)

91-92: Nice update to awaited async field-list verification.

This is consistent with userEvent semantics and improves determinism of these claim/scope interaction tests.

Also applies to: 101-102, 111-112, 129-130

frontend/public/components/utils/__tests__/kebab.spec.tsx (1)

1-2: Kebab interaction tests were migrated cleanly to userEvent.

Using awaited clicks across these cases is the right move and keeps authorization/option-behavior assertions stable under async event processing.

Also applies to: 18-19, 23-23, 26-27, 31-31, 34-35, 39-39, 51-52, 63-63, 66-67, 78-78

frontend/packages/console-shared/src/components/progressive-list/__tests__/ProgressiveList.spec.tsx (1)

2-3: ProgressiveList click test migration is correct.

Awaiting the click before asserting callback/state effects is the correct sequencing for async RTL interactions.

Also applies to: 53-54, 72-72

frontend/public/components/cluster-settings/__tests__/request-header-idp-form.spec.tsx (1)

43-44: Async helper adoption is applied consistently here.

Awaiting both single-input and list-input helper calls is the right update and should reduce flaky behavior in this suite.

Also applies to: 58-59, 68-69, 89-90, 98-99, 108-109, 117-118, 126-127

frontend/public/components/cluster-settings/__tests__/github-idp-form.spec.tsx (1)

43-44: GitHub IDP test updates look good and consistent.

The async/await conversion around helper-driven interactions is correctly implemented and aligned with userEvent-based test behavior.

Also applies to: 53-54, 61-62, 70-71, 86-86, 101-101, 109-109, 124-124

frontend/packages/console-shared/src/components/getting-started/__tests__/GettingStartedCard.spec.tsx (1)

1-2: Good user-event migration for click flows.

Async userEvent.setup() + await user.click(...) is correctly applied in both onClick tests and keeps behavior assertions intact.

Also applies to: 45-46, 60-60, 64-65, 77-77

frontend/packages/console-shared/src/components/toast/__tests__/ToastProvider.spec.tsx (1)

2-3: Interaction updates are solid and less flaky.

The awaited user.click migration is consistent across button/link/close paths, and the anchor existence check before clicking is a good guard.

Also applies to: 74-74, 102-102, 145-145, 175-176, 186-186, 209-209

frontend/public/components/cluster-settings/__tests__/gitlab-idp-form.spec.tsx (1)

41-42: Nice async alignment with shared field helpers.

Converting these field checks to async + await verifyInputField(...) is correct and improves test reliability.

Also applies to: 51-52, 61-62, 69-70

frontend/packages/console-shared/src/components/editor/__tests__/CodeEditorToolbar.spec.tsx (1)

1-2: Correct conversion to user-event in dispatch test.

The async test setup and awaited click are correctly implemented for this interaction path.

Also applies to: 52-53, 57-57

frontend/packages/console-shared/src/components/form-utils/__tests__/FormFooter.spec.tsx (1)

1-2: Handler-click test migration is clean.

Using userEvent.setup() and awaiting all three clicks is the right pattern for stable callback assertions.

Also applies to: 85-86, 90-92

frontend/packages/console-shared/src/components/modals/__tests__/FetchProgressModal.spec.tsx (1)

1-2: Good coverage-preserving user-event conversion.

The cancel and close interaction paths were migrated correctly with awaited clicks and retained async assertions.

Also applies to: 167-167, 182-182, 199-200, 209-209, 318-318, 341-341

frontend/public/components/utils/__tests__/download-button.spec.tsx (1)

1-2: Looks good for async click behavior.

userEvent is applied correctly in both scenarios and preserves the intended fetch/downloading assertions.

Also applies to: 35-35, 44-44, 52-52, 71-71

frontend/packages/console-shared/src/components/formik-fields/key-value-file-input-field/__tests__/KeyValueFileInputField.spec.tsx (1)

2-3: Touched/blur and add-entry interactions are migrated correctly.

Using user.click + user.tab for validation and await user.click for add-entry keeps these tests realistic and reliable.

Also applies to: 45-49, 115-116

frontend/packages/console-shared/src/test-utils/unit-test-utils.tsx (1)

6-7: Solid migration of shared input helper to userEvent.

The updated interaction path is async-safe and better reflects real user behavior while keeping assertions stable.

Also applies to: 187-190

frontend/packages/console-shared/src/components/form-utils/__tests__/FlexForm.spec.tsx (1)

1-2: Form submission tests look correct after userEvent conversion.

The tests now await user interactions and still validate submit behavior clearly.

Also applies to: 26-39, 54-67

frontend/packages/console-shared/src/components/formik-fields/__tests__/NumberSpinnerField.spec.tsx (1)

1-2: NumberSpinnerField tests are migrated cleanly to userEvent.

The updated typing/click flows preserve behavior and improve realism of interaction simulation.

Also applies to: 29-31, 37-46

frontend/public/components/__tests__/storage-class-form.spec.tsx (1)

40-43: These test timing adjustments look good.

Using the shared helper directly with explicit presence checks keeps the tests readable and reliable.

Also applies to: 48-53

frontend/public/components/utils/__tests__/single-typeahead-dropdown.spec.tsx (1)

1-2: Comprehensive and correct fireEventuserEvent migration here.

Keyboard and combobox interaction paths are now closer to real usage while preserving existing assertions.

Also applies to: 34-52, 62-79, 88-108, 123-143, 161-190, 198-226

frontend/public/components/cluster-settings/__tests__/test-utils.ts (1)

179-194: Async conversion of verifyIDPListInputFields is well done.

The helper now uses realistic user input operations while maintaining clear structural assertions for add/remove behavior.

Also applies to: 210-243

frontend/packages/console-shared/src/components/modals/__tests__/TextInputModal.spec.tsx (1)

1-2: TextInputModal test migration is consistent and reliable.

The async userEvent flows cover click, typing, and Enter submission behavior cleanly.

Also applies to: 37-43, 48-55, 59-65, 71-79, 89-96, 107-125, 157-163, 176-183, 189-194

Comment on lines +80 to 97
it('should auto-generate namespace and service account names based on ClusterExtension name', async () => {
const user = userEvent.setup();
renderWithProviders(<ClusterExtensionForm formData={{}} onChange={mockOnChange} />);

const nameInput = screen.getByLabelText('Name');
fireEvent.change(nameInput, { target: { value: 'my-operator' } });
const nameInput = screen.getByRole('textbox', { name: /^Name$/i });
await user.clear(nameInput);
await user.type(nameInput, 'my-operator');

await waitFor(() => expect(nameInput).toHaveValue('my-operator'));
// Should call onChange with auto-generated names
expect(mockOnChange).toHaveBeenCalledWith(
expect.objectContaining({
metadata: expect.objectContaining({ name: 'my-operator' }),
}),
);
await waitFor(() => {
expect(mockOnChange).toHaveBeenLastCalledWith(
expect.objectContaining({
metadata: expect.objectContaining({ name: 'my-operator' }),
}),
);
});
});
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.

⚠️ Potential issue | 🟠 Major

Test intent regressed: namespace/serviceAccount auto-generation is no longer verified

On Line 80 the test promises namespace/service account auto-generation, but the assertion block on Line 91 only checks metadata.name. This weakens coverage for the exact behavior this test is named for.

Proposed fix
     await waitFor(() => {
       expect(mockOnChange).toHaveBeenLastCalledWith(
         expect.objectContaining({
           metadata: expect.objectContaining({ name: 'my-operator' }),
+          spec: expect.objectContaining({
+            namespace: 'my-operator',
+            serviceAccount: expect.objectContaining({
+              name: 'my-operator-service-account',
+            }),
+          }),
         }),
       );
     });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('should auto-generate namespace and service account names based on ClusterExtension name', async () => {
const user = userEvent.setup();
renderWithProviders(<ClusterExtensionForm formData={{}} onChange={mockOnChange} />);
const nameInput = screen.getByLabelText('Name');
fireEvent.change(nameInput, { target: { value: 'my-operator' } });
const nameInput = screen.getByRole('textbox', { name: /^Name$/i });
await user.clear(nameInput);
await user.type(nameInput, 'my-operator');
await waitFor(() => expect(nameInput).toHaveValue('my-operator'));
// Should call onChange with auto-generated names
expect(mockOnChange).toHaveBeenCalledWith(
expect.objectContaining({
metadata: expect.objectContaining({ name: 'my-operator' }),
}),
);
await waitFor(() => {
expect(mockOnChange).toHaveBeenLastCalledWith(
expect.objectContaining({
metadata: expect.objectContaining({ name: 'my-operator' }),
}),
);
});
});
it('should auto-generate namespace and service account names based on ClusterExtension name', async () => {
const user = userEvent.setup();
renderWithProviders(<ClusterExtensionForm formData={{}} onChange={mockOnChange} />);
const nameInput = screen.getByRole('textbox', { name: /^Name$/i });
await user.clear(nameInput);
await user.type(nameInput, 'my-operator');
await waitFor(() => expect(nameInput).toHaveValue('my-operator'));
// Should call onChange with auto-generated names
await waitFor(() => {
expect(mockOnChange).toHaveBeenLastCalledWith(
expect.objectContaining({
metadata: expect.objectContaining({ name: 'my-operator' }),
spec: expect.objectContaining({
namespace: 'my-operator',
serviceAccount: expect.objectContaining({
name: 'my-operator-service-account',
}),
}),
}),
);
});
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/__tests__/ClusterExtensionForm.spec.tsx`
around lines 80 - 97, The test "should auto-generate namespace and service
account names based on ClusterExtension name" only asserts metadata.name but
must also verify the auto-generated namespace and serviceAccount fields; update
the assertion that checks mockOnChange (in the spec using ClusterExtensionForm
and mockOnChange) to expect objectContaining metadata.namespace and the service
account field (e.g., spec.serviceAccountName or metadata.serviceAccount
depending on impl) with the expected auto-generated values or patterns derived
from 'my-operator' so the test actually verifies namespace/serviceAccount
generation.

Comment on lines 146 to 156
it('should call k8sKill with correct data on click of cancel button when export app is in progress', async () => {
const user = userEvent.setup();
const exportData = _.cloneDeep(mockExportData);
exportData.status.completed = false;
renderWithProviders(
<ExportApplicationModal name="my-export" namespace="my-app" exportResource={exportData} />,
);

await act(async () => {
fireEvent.click(screen.getByTestId('export-restart-btn'));
await user.click(screen.getByTestId('export-restart-btn'));
});
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.

⚠️ Potential issue | 🟠 Major

Cancel-flow test clicks the wrong button

On Line 146 the test states it validates cancel behavior, but Line 155 clicks export-restart-btn. That means the cancel path is not actually exercised.

Proposed fix
-      await user.click(screen.getByTestId('export-restart-btn'));
+      await user.click(screen.getByTestId('export-cancel-btn'));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('should call k8sKill with correct data on click of cancel button when export app is in progress', async () => {
const user = userEvent.setup();
const exportData = _.cloneDeep(mockExportData);
exportData.status.completed = false;
renderWithProviders(
<ExportApplicationModal name="my-export" namespace="my-app" exportResource={exportData} />,
);
await act(async () => {
fireEvent.click(screen.getByTestId('export-restart-btn'));
await user.click(screen.getByTestId('export-restart-btn'));
});
it('should call k8sKill with correct data on click of cancel button when export app is in progress', async () => {
const user = userEvent.setup();
const exportData = _.cloneDeep(mockExportData);
exportData.status.completed = false;
renderWithProviders(
<ExportApplicationModal name="my-export" namespace="my-app" exportResource={exportData} />,
);
await act(async () => {
await user.click(screen.getByTestId('export-cancel-btn'));
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/topology/src/components/export-app/__tests__/ExportApplicationModal.spec.tsx`
around lines 146 - 156, The test "should call k8sKill with correct data on click
of cancel button when export app is in progress" is clicking the wrong element;
change the user click target from the 'export-restart-btn' test id to the cancel
button test id (e.g., 'export-cancel-btn') so the cancel path in
ExportApplicationModal is exercised for the exportData with completed=false;
update any related assertions that expect k8sKill to be called after rendering
via renderWithProviders and using the existing exportData/mockExportData setup.

Comment on lines +61 to 73
it('calls onChange with event and new value when input changes', async () => {
const user = userEvent.setup();
const onChange = jest.fn();

renderWithProviders(<TextFilter onChange={onChange} defaultValue="" />);

const input = screen.getByRole('textbox');
fireEvent.change(input, { target: { value: 'test-value' } });
await user.type(input, 'test-value');

expect(onChange).toHaveBeenCalled();
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledWith(expect.any(Object), 'test-value');
});
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate TextFilter implementation =="
fd -i 'text-filter.(ts|tsx|js|jsx)' frontend

echo
echo "== Show onChange-related logic in TextFilter implementation(s) =="
fd -i 'text-filter.(ts|tsx|js|jsx)' frontend | while read -r f; do
  echo "--- $f ---"
  rg -n -C3 'onChange|deboun|setTimeout|thrott|useDebounce' "$f" || true
done

echo
echo "== Show the potentially brittle assertions in this test file =="
rg -n -C2 'user\.type\(|toHaveBeenCalledTimes\(1\)|toHaveBeenCalledWith\(expect\.any\(Object\),\s*'"'"'test-value'"'"'\)' frontend/public/components/factory/__tests__/list-page.spec.tsx

Repository: openshift/console

Length of output: 631


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== TextFilter component implementation =="
cat -n frontend/public/components/factory/text-filter.tsx

echo
echo "== Also check if there's any wrapping debounce hook used elsewhere =="
rg -n 'TextFilter|useDebounce|withDebounce' frontend/public/components/factory/ -A 2 -B 2

Repository: openshift/console

Length of output: 6618


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check other TextFilter tests or usage patterns =="
rg -B 5 -A 10 'TextFilter.*onChange' frontend/public/components/factory/__tests__/list-page.spec.tsx | head -80

echo
echo "== Check if waitFor is used in other parts of this test file =="
rg -n 'waitFor|screen\.' frontend/public/components/factory/__tests__/list-page.spec.tsx | head -30

echo
echo "== Check PatternFly TextInput usage patterns for onChange in console codebase =="
rg -l 'TextInput.*onChange|onChange.*TextInput' frontend --type ts --type tsx | head -5 | xargs -I {} rg -B 2 -A 2 'onChange' {} 2>/dev/null | head -60

Repository: openshift/console

Length of output: 3327


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check if this is a new test or modified test =="
git log -p --follow -S 'toHaveBeenCalledTimes(1)' -- frontend/public/components/factory/__tests__/list-page.spec.tsx | head -100

echo
echo "== Check if there are other 'user.type' tests with call count assertions =="
rg -B 5 -A 3 'user\.type.*await' frontend --type ts --type tsx | grep -A 8 'toHaveBeenCalledTimes' | head -40

echo
echo "== Search for PatternFly TextInput onChange behavior in codebase =="
rg 'TextInput.*onChange|onChange.*value' frontend --type ts --type tsx -C 2 | head -60

Repository: openshift/console

Length of output: 4208


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find ClusterExtensionForm tests =="
fd -i 'cluster.*extension.*form' frontend --type ts --type tsx | grep -i test | head -3

echo
echo "== Show the waitFor pattern from ClusterExtensionForm =="
find frontend -name '*cluster*extension*form*.spec.tsx' -o -name '*cluster*extension*form*.test.tsx' 2>/dev/null | head -1 | xargs cat 2>/dev/null | grep -B 5 -A 5 'toHaveBeenLastCalledWith' | head -40

Repository: openshift/console

Length of output: 285


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Search for toHaveBeenLastCalledWith pattern in tests =="
rg 'toHaveBeenLastCalledWith' frontend --follow | head -20

echo
echo "== Search for waitFor with user.type pattern =="
rg -B 3 'user\.type' frontend | grep -B 5 'waitFor' | head -40

echo
echo "== Search for any ClusterExtensionForm test file =="
find frontend -name '*[Cc]luster*[Ee]xtension*' 2>/dev/null | head -5

Repository: openshift/console

Length of output: 3640


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Show waitFor + user.type pattern from ClusterExtensionForm =="
rg -B 10 -A 3 'toHaveBeenLastCalledWith' 'frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/__tests__/ClusterExtensionForm.spec.tsx' | head -80

echo
echo "== Also search for waitFor import in that file =="
rg 'import.*waitFor|from.*testing-library' 'frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/__tests__/ClusterExtensionForm.spec.tsx' | head -10

Repository: openshift/console

Length of output: 3197


user.type() triggers multiple onChange events—wrap assertion in waitFor()

The test follows the commit message's own acknowledgment: "userEvent.type() triggers onChange for each character typed." The assertion at lines 71–72 uses toHaveBeenCalledTimes(1) without waitFor(), which contradicts the pattern applied to similar tests in the same commit (e.g., ClusterExtensionForm). Replace toHaveBeenCalledTimes(1) and toHaveBeenCalledWith() with toHaveBeenLastCalledWith() wrapped in waitFor() to ensure the assertion waits for the final callback.

Suggested test assertion update
   it('calls onChange with event and new value when input changes', async () => {
     const user = userEvent.setup();
     const onChange = jest.fn();

     renderWithProviders(<TextFilter onChange={onChange} defaultValue="" />);

     const input = screen.getByRole('textbox');
     await user.type(input, 'test-value');

-    expect(onChange).toHaveBeenCalled();
-    expect(onChange).toHaveBeenCalledTimes(1);
-    expect(onChange).toHaveBeenCalledWith(expect.any(Object), 'test-value');
+    await waitFor(() => {
+      expect(onChange).toHaveBeenLastCalledWith(expect.any(Object), 'test-value');
+    });
   });
-import { screen } from '@testing-library/react';
+import { screen, waitFor } from '@testing-library/react';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/public/components/factory/__tests__/list-page.spec.tsx` around lines
61 - 73, The test for TextFilter is asserting on onChange immediately even
though userEvent.type triggers multiple change events; update the assertions to
wait for the final call by using waitFor and assert on toHaveBeenLastCalledWith
(or check the last call) instead of toHaveBeenCalledTimes(1) and
toHaveBeenCalledWith; locate the test around the TextFilter render and user.type
invocation and replace the immediate count/check with a waitFor that verifies
onChange was called and that its last call received the expected event and
'test-value' argument.

@cajieh
Copy link
Copy Markdown
Contributor Author

cajieh commented Apr 8, 2026

/retest

cajieh added a commit to cajieh/console that referenced this pull request Apr 9, 2026
- ExportApplicationModal: Fix wrong button clicked in cancel test (line 155)
  - Test name says 'cancel button' but was clicking 'export-restart-btn'
  - Changed to correctly click 'export-cancel-btn'

- configure-update-strategy-modal: Wrap onChange assertions in waitFor()
  - userEvent.type() triggers onChange for each character
  - Assertions need to wait for final onChange call
  - Added waitFor() around onChangeMaxUnavailable and onChangeMaxSurge
  - Added test harness with local state to properly test async updates
  - Removed problematic beforeEach that rendered for all tests

Addresses CodeRabbit major findings from PR openshift#16265
cajieh added a commit to cajieh/console that referenced this pull request Apr 9, 2026
- installplan-approval-modal: Add Manual radio click before Save
  - Save button stays disabled when selected strategy matches resource
  - Must change strategy first to enable Save and test submit flow

- list-page (TextFilter): Wrap onChange assertion in waitFor()
  - userEvent.type() triggers onChange per character
  - Use toHaveBeenLastCalledWith instead of separate count check

- name-value-editor: Add test harness and wrap assertions in waitFor()
  - Created NameValueEditorHarness to maintain state for controlled inputs
  - Wraps all mockUpdate assertions in waitFor()
  - Ensures typed values match controlled input state

All changes address async timing issues with userEvent identified in PR openshift#16265
cajieh added a commit to cajieh/console that referenced this pull request Apr 9, 2026
- Created ClusterExtensionFormWithState harness to maintain form state
- Mirrors parent state updates so controlled fields reflect typed values
- Simplified version input test to use user.type instead of multiple keyboard calls
- Ensures all userEvent interactions work with properly controlled inputs

Completes async userEvent fixes for PR openshift#16265
cajieh added a commit to cajieh/console that referenced this pull request Apr 9, 2026
- Added assertions for spec.namespace (should match name)
- Added assertions for spec.serviceAccount.name (should be name + '-service-account')
- Fully addresses test name promise to verify auto-generation
- Resolves CodeRabbit major finding #1 for ClusterExtensionForm

Addresses CodeRabbit review comment on PR openshift#16265
@cajieh
Copy link
Copy Markdown
Contributor Author

cajieh commented Apr 9, 2026

/test all

@cajieh cajieh force-pushed the update-claude-skills-rtl-best-practices branch 3 times, most recently from 6f8257e to 6ee4ffc Compare April 9, 2026 14:28
@cajieh cajieh force-pushed the update-claude-skills-rtl-best-practices branch from 6ee4ffc to b4f9c59 Compare April 9, 2026 20:15
@cajieh
Copy link
Copy Markdown
Contributor Author

cajieh commented Apr 9, 2026

/retest

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Apr 10, 2026

@cajieh: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/core Related to console core functionality component/dev-console Related to dev-console component/knative Related to knative-plugin component/olm Related to OLM component/shared Related to console-shared component/topology Related to topology jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants