11// npx vitest run src/components/chat/checkpoints/__tests__/CheckpointSaved.spec.tsx
22
3- import { render , waitFor } from "@/utils/test-utils"
4- import React from "react"
5- import { CheckpointSaved } from "../CheckpointSaved"
6-
7- // Capture onOpenChange from Popover to control open/close in tests
8- let lastOnOpenChange : ( ( open : boolean ) => void ) | undefined
9-
10- vi . mock ( "@/components/ui" , async ( ) => {
11- const actual = await vi . importActual < any > ( "@/components/ui" )
3+ vi . mock ( "@/components/ui" , ( ) => {
4+ // Minimal UI primitives to ensure deterministic behavior in tests
125 return {
13- ...actual ,
14- Popover : ( {
15- children,
16- onOpenChange,
17- open,
18- } : {
19- children : React . ReactNode
20- open ?: boolean
21- onOpenChange ?: ( open : boolean ) => void
22- } ) => {
6+ Button : ( { children, ...rest } : any ) => < button { ...rest } > { children } </ button > ,
7+ StandardTooltip : ( { children } : any ) => < > { children } </ > ,
8+ Popover : ( { children, onOpenChange, open } : any ) => {
239 lastOnOpenChange = onOpenChange
2410 return (
2511 < div data-testid = "popover-root" data-open = { open } >
2612 { children }
2713 </ div >
2814 )
2915 } ,
30- PopoverTrigger : ( { children } : { children : React . ReactNode } ) => (
31- < div data-testid = "popover-trigger" > { children } </ div >
32- ) ,
33- PopoverContent : ( { children } : { children : React . ReactNode } ) => (
34- < div data-testid = "popover-content" > { children } </ div >
35- ) ,
16+ PopoverTrigger : ( { children } : any ) => < div data-testid = "popover-trigger" > { children } </ div > ,
17+ PopoverContent : ( { children } : any ) => < div data-testid = "popover-content" > { children } </ div > ,
3618 }
3719} )
3820
21+ import { render , waitFor , screen } from "@/utils/test-utils"
22+ import React from "react"
23+ import userEvent from "@testing-library/user-event"
24+ import { CheckpointSaved } from "../CheckpointSaved"
25+
26+ // Capture onOpenChange from Popover to control open/close in tests
27+ let lastOnOpenChange : ( ( open : boolean ) => void ) | undefined
28+
29+ const waitForOpenHandler = async ( ) => {
30+ await waitFor ( ( ) => {
31+ // ensure Popover mock captured the onOpenChange handler before using it
32+ expect ( lastOnOpenChange ) . toBeTruthy ( )
33+ } )
34+ }
35+
3936describe ( "CheckpointSaved popover visibility" , ( ) => {
37+ // Timers are controlled per-test to avoid interfering with i18n init
4038 const baseProps = {
4139 ts : 123 ,
4240 commitHash : "abc123" ,
@@ -45,27 +43,99 @@ describe("CheckpointSaved popover visibility", () => {
4543 }
4644
4745 it ( "shows menu while popover is open and hides when closed" , async ( ) => {
48- const { container } = render ( < CheckpointSaved { ...baseProps } /> )
46+ const { getByTestId } = render ( < CheckpointSaved { ...baseProps } /> )
4947
50- const getMenu = ( ) => container . querySelector ( "div.h-4.-mt-2 ") as HTMLElement
48+ const getMenu = ( ) => getByTestId ( "checkpoint-menu-container ") as HTMLElement
5149
5250 // Initially hidden (relies on group-hover)
5351 expect ( getMenu ( ) ) . toBeTruthy ( )
5452 expect ( getMenu ( ) . className ) . toContain ( "hidden" )
5553
5654 // Open via captured handler
55+ await waitForOpenHandler ( )
5756 lastOnOpenChange ?.( true )
5857
5958 await waitFor ( ( ) => {
6059 expect ( getMenu ( ) . className ) . toContain ( "block" )
6160 expect ( getMenu ( ) . className ) . not . toContain ( "hidden" )
6261 } )
6362
64- // Close via captured handler
63+ // Close via captured handler — menu remains visible briefly, then hides
6564 lastOnOpenChange ?.( false )
6665
66+ await waitFor ( ( ) => {
67+ expect ( getMenu ( ) . className ) . toContain ( "block" )
68+ } )
69+
6770 await waitFor ( ( ) => {
6871 expect ( getMenu ( ) . className ) . toContain ( "hidden" )
6972 } )
7073 } )
74+
75+ it ( "resets confirm state when popover closes" , async ( ) => {
76+ const { getByTestId } = render ( < CheckpointSaved { ...baseProps } /> )
77+
78+ // Open the popover
79+ await waitForOpenHandler ( )
80+ lastOnOpenChange ?.( true )
81+
82+ // Enter confirm state
83+ const restoreFilesAndTaskBtn = await waitFor ( ( ) => getByTestId ( "restore-files-and-task-btn" ) )
84+ await userEvent . click ( restoreFilesAndTaskBtn )
85+
86+ // Confirm warning should be visible
87+ expect ( getByTestId ( "checkpoint-confirm-warning" ) ) . toBeTruthy ( )
88+
89+ // Close popover -> confirm state should reset
90+ lastOnOpenChange ?.( false )
91+
92+ // Reopen
93+ lastOnOpenChange ?.( true )
94+
95+ // Confirm warning should be gone after reopening
96+ await waitFor ( ( ) => {
97+ expect ( screen . queryByTestId ( "checkpoint-confirm-warning" ) ) . toBeNull ( )
98+ } )
99+ } )
100+
101+ it ( "closes popover after preview and after confirm restore" , async ( ) => {
102+ const { getByTestId } = render ( < CheckpointSaved { ...baseProps } /> )
103+
104+ const popoverRoot = ( ) => getByTestId ( "popover-root" )
105+ const menuContainer = ( ) => getByTestId ( "checkpoint-menu-container" )
106+
107+ // Open
108+ await waitForOpenHandler ( )
109+ lastOnOpenChange ?.( true )
110+ await waitFor ( ( ) => {
111+ expect ( popoverRoot ( ) . getAttribute ( "data-open" ) ) . toBe ( "true" )
112+ expect ( menuContainer ( ) . className ) . toContain ( "block" )
113+ } )
114+
115+ // Click preview -> popover closes; menu remains briefly visible, then hides
116+ await userEvent . click ( getByTestId ( "restore-files-btn" ) )
117+ await waitFor ( ( ) => {
118+ expect ( popoverRoot ( ) . getAttribute ( "data-open" ) ) . toBe ( "false" )
119+ expect ( menuContainer ( ) . className ) . toContain ( "block" )
120+ } )
121+ await waitFor ( ( ) => {
122+ expect ( menuContainer ( ) . className ) . toContain ( "hidden" )
123+ } )
124+
125+ // Reopen
126+ lastOnOpenChange ?.( true )
127+ await waitFor ( ( ) => {
128+ expect ( popoverRoot ( ) . getAttribute ( "data-open" ) ) . toBe ( "true" )
129+ } )
130+
131+ // Enter confirm and confirm restore -> popover closes; menu then hides
132+ await userEvent . click ( getByTestId ( "restore-files-and-task-btn" ) )
133+ await userEvent . click ( getByTestId ( "confirm-restore-btn" ) )
134+ await waitFor ( ( ) => {
135+ expect ( popoverRoot ( ) . getAttribute ( "data-open" ) ) . toBe ( "false" )
136+ } )
137+ await waitFor ( ( ) => {
138+ expect ( menuContainer ( ) . className ) . toContain ( "hidden" )
139+ } )
140+ } )
71141} )
0 commit comments