From 4e2c8341e33ac85099b6f6693871e28c9deefff6 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Wed, 29 Jul 2026 23:11:33 -0400 Subject: [PATCH] test: render the during-run hovercard eagerly instead of driving Ariakit The new spec passed locally and failed all four cases on CI's Ubuntu and Windows shards: Ariakit's show path keys off pointer geometry, which jsdom reports as zeros, so whether a synthetic mouseEnter opens the hovercard is environment-dependent. Driving it was testing Ariakit's hover behavior, not which rows this component disables. Mocking the three Ariakit primitives renders the rows unconditionally and drops the fake timers. Both counterfactuals still fail as they should: removing the gate fails the paused case, !canSteer fails the first-turn case. --- .../__tests__/DuringRunSendButton.test.tsx | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/client/src/components/Chat/Input/__tests__/DuringRunSendButton.test.tsx b/client/src/components/Chat/Input/__tests__/DuringRunSendButton.test.tsx index 7e68c48f9f..c1fb830776 100644 --- a/client/src/components/Chat/Input/__tests__/DuringRunSendButton.test.tsx +++ b/client/src/components/Chat/Input/__tests__/DuringRunSendButton.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { useForm } from 'react-hook-form'; -import { render, screen, fireEvent, act } from '@testing-library/react'; +import { render, screen, fireEvent } from '@testing-library/react'; import type { SteeringControls } from '~/hooks/Chat/useSteering'; import DuringRunSendButton from '../DuringRunSendButton'; @@ -8,6 +8,17 @@ jest.mock('~/hooks', () => ({ useLocalize: () => (key: string) => key, })); +/** + * Renders the hovercard eagerly. Ariakit's real show path depends on pointer + * geometry, which jsdom reports as zeros — driving it from a test asserts + * Ariakit's hover behavior rather than which rows this component disables. + */ +jest.mock('@ariakit/react', () => ({ + HovercardProvider: ({ children }: { children: React.ReactNode }) =>
{children}
, + HovercardAnchor: ({ render }: { render: React.ReactElement }) => render, + Hovercard: ({ children }: { children: React.ReactNode }) =>
{children}
, +})); + const TEXT = 'stop, do not run that command'; const mockInterruptSteer = jest.fn(() => true); @@ -42,25 +53,13 @@ function Harness({ steering }: { steering: SteeringControls }) { ); } -/** The rows only mount once the hovercard clears its show delay. */ -async function openMenu(options: StubOptions) { +function openMenu(options: StubOptions) { render(); - const anchor = screen.getByTestId('during-run-send-button'); - fireEvent.mouseEnter(anchor); - fireEvent.mouseMove(anchor); - await act(async () => { - jest.advanceTimersByTime(500); - }); expect(screen.getByText('com_ui_interrupt_steer')).toBeInTheDocument(); } beforeEach(() => { jest.clearAllMocks(); - jest.useFakeTimers(); -}); - -afterEach(() => { - jest.useRealTimers(); }); describe('DuringRunSendButton — Interrupt & steer availability', () => { @@ -69,8 +68,8 @@ describe('DuringRunSendButton — Interrupt & steer availability', () => { * approval, so a live row would silently do nothing at exactly the moment a * user is trying to stop a tool call. */ - test('disables Interrupt & steer while the run is paused on tool approval', async () => { - await openMenu({ pausedOnApproval: true, canSteer: false }); + test('disables Interrupt & steer while the run is paused on tool approval', () => { + openMenu({ pausedOnApproval: true, canSteer: false }); const row = screen.getByText('com_ui_interrupt_steer').closest('button'); expect(row).toHaveAttribute('aria-disabled', 'true'); @@ -86,8 +85,8 @@ describe('DuringRunSendButton — Interrupt & steer availability', () => { * `interruptSteer` deliberately falls back to interrupt & send — disabling * the row there would make it dead for the whole first turn. */ - test('keeps Interrupt & steer live before a conversation exists', async () => { - await openMenu({ pausedOnApproval: false, canSteer: false }); + test('keeps Interrupt & steer live before a conversation exists', () => { + openMenu({ pausedOnApproval: false, canSteer: false }); const row = screen.getByText('com_ui_interrupt_steer').closest('button'); expect(row).toHaveAttribute('aria-disabled', 'false'); @@ -97,8 +96,8 @@ describe('DuringRunSendButton — Interrupt & steer availability', () => { expect(mockOnConsumed).toHaveBeenCalled(); }); - test('the ordinary Steer row stays gated on canSteer', async () => { - await openMenu({ pausedOnApproval: false, canSteer: false }); + test('the ordinary Steer row stays gated on canSteer', () => { + openMenu({ pausedOnApproval: false, canSteer: false }); const row = screen.getByText('com_ui_steer').closest('button'); expect(row).toHaveAttribute('aria-disabled', 'true'); @@ -107,8 +106,8 @@ describe('DuringRunSendButton — Interrupt & steer availability', () => { expect(mockSteerFromComposer).not.toHaveBeenCalled(); }); - test('both actions are available during a normal run', async () => { - await openMenu({ pausedOnApproval: false, canSteer: true }); + test('both actions are available during a normal run', () => { + openMenu({ pausedOnApproval: false, canSteer: true }); expect(screen.getByText('com_ui_interrupt_steer').closest('button')).toHaveAttribute( 'aria-disabled',