@@ -61,23 +61,17 @@ vi.mock("../AutoApproveMenu", () => ({
6161 default : ( ) => null ,
6262} ) )
6363
64- vi . mock ( "@src/components/common/VersionIndicator" , ( ) => ( {
65- default : function MockVersionIndicator ( { onClick, className } : { onClick : ( ) => void ; className ?: string } ) {
66- // eslint-disable-next-line @typescript-eslint/no-require-imports
67- const React = require ( "react" )
68- return React . createElement (
69- "button" ,
70- {
71- onClick,
72- className,
73- "aria-label" : "chat:versionIndicator.ariaLabel" ,
74- "data-testid" : "version-indicator" ,
75- } ,
76- "v3.21.5" ,
77- )
78- } ,
64+ // Mock VersionIndicator - returns null by default to prevent rendering in tests
65+ vi . mock ( "../../common/VersionIndicator" , ( ) => ( {
66+ default : vi . fn ( ( ) => null ) ,
7967} ) )
8068
69+ // Get the mock function after the module is mocked
70+ const mockVersionIndicator = vi . mocked (
71+ // @ts -expect-error - accessing mocked module
72+ ( await import ( "../../common/VersionIndicator" ) ) . default ,
73+ )
74+
8175vi . mock ( "@src/components/modals/Announcement" , ( ) => ( {
8276 default : function MockAnnouncement ( { hideAnnouncement } : { hideAnnouncement : ( ) => void } ) {
8377 // eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -1122,6 +1116,20 @@ describe("ChatView - Version Indicator Tests", () => {
11221116 beforeEach ( ( ) => vi . clearAllMocks ( ) )
11231117
11241118 it ( "displays version indicator button" , ( ) => {
1119+ // Temporarily override the mock for this test
1120+ mockVersionIndicator . mockImplementation ( ( props ?: { onClick ?: ( ) => void ; className ?: string } ) => {
1121+ const { onClick, className } = props || { }
1122+ return (
1123+ < button
1124+ data-testid = "version-indicator"
1125+ onClick = { onClick }
1126+ className = { className }
1127+ aria-label = "chat:versionIndicator.ariaLabel" >
1128+ v3.21.5
1129+ </ button >
1130+ )
1131+ } )
1132+
11251133 const { getByLabelText } = renderChatView ( )
11261134
11271135 // First hydrate state
@@ -1133,26 +1141,60 @@ describe("ChatView - Version Indicator Tests", () => {
11331141 const versionButton = getByLabelText ( / v e r s i o n / i)
11341142 expect ( versionButton ) . toBeInTheDocument ( )
11351143 expect ( versionButton ) . toHaveTextContent ( / ^ v \d + \. \d + \. \d + / )
1144+
1145+ // Reset mock
1146+ mockVersionIndicator . mockReturnValue ( null )
11361147 } )
11371148
11381149 it ( "opens announcement modal when version indicator is clicked" , ( ) => {
1139- const { container } = renderChatView ( )
1150+ // Temporarily override the mock for this test
1151+ mockVersionIndicator . mockImplementation ( ( props ?: { onClick ?: ( ) => void ; className ?: string } ) => {
1152+ const { onClick, className } = props || { }
1153+ return (
1154+ < button
1155+ data-testid = "version-indicator"
1156+ onClick = { onClick }
1157+ className = { className }
1158+ aria-label = "Version 3.22.5" >
1159+ v3.22.5
1160+ </ button >
1161+ )
1162+ } )
1163+
1164+ const { getByTestId } = renderChatView ( )
11401165
11411166 // First hydrate state
11421167 mockPostMessage ( {
11431168 clineMessages : [ ] ,
11441169 } )
11451170
11461171 // Find version indicator
1147- const versionButton = container . querySelector ( 'button[aria-label*= "version"]' ) as HTMLButtonElement
1148- expect ( versionButton ) . toBeTruthy ( )
1172+ const versionButton = getByTestId ( "version-indicator" )
1173+ expect ( versionButton ) . toBeInTheDocument ( )
11491174
11501175 // Click should trigger modal - we'll just verify the button exists and is clickable
11511176 // The actual modal rendering is handled by the component state
11521177 expect ( versionButton . onclick ) . toBeDefined ( )
1178+
1179+ // Reset mock
1180+ mockVersionIndicator . mockReturnValue ( null )
11531181 } )
11541182
11551183 it ( "version indicator has correct styling classes" , ( ) => {
1184+ // Temporarily override the mock for this test
1185+ mockVersionIndicator . mockImplementation ( ( props ?: { onClick ?: ( ) => void ; className ?: string } ) => {
1186+ const { onClick, className } = props || { }
1187+ return (
1188+ < button
1189+ data-testid = "version-indicator"
1190+ onClick = { onClick }
1191+ className = { className }
1192+ aria-label = "Version 3.22.5" >
1193+ v3.22.5
1194+ </ button >
1195+ )
1196+ } )
1197+
11561198 const { getByTestId } = renderChatView ( )
11571199
11581200 // First hydrate state
@@ -1165,21 +1207,114 @@ describe("ChatView - Version Indicator Tests", () => {
11651207 expect ( versionButton ) . toBeInTheDocument ( )
11661208 // The className is passed as a prop to VersionIndicator
11671209 expect ( versionButton . className ) . toContain ( "absolute top-2 right-3 z-10" )
1210+
1211+ // Reset mock
1212+ mockVersionIndicator . mockReturnValue ( null )
11681213 } )
11691214
11701215 it ( "version indicator has proper accessibility attributes" , ( ) => {
1171- const { container } = renderChatView ( )
1216+ // Temporarily override the mock for this test
1217+ mockVersionIndicator . mockImplementation ( ( props ?: { onClick ?: ( ) => void ; className ?: string } ) => {
1218+ const { onClick, className } = props || { }
1219+ return (
1220+ < button
1221+ data-testid = "version-indicator"
1222+ onClick = { onClick }
1223+ className = { className }
1224+ aria-label = "Version 3.22.5" >
1225+ v3.22.5
1226+ </ button >
1227+ )
1228+ } )
1229+
1230+ const { getByTestId } = renderChatView ( )
11721231
11731232 // First hydrate state
11741233 mockPostMessage ( {
11751234 clineMessages : [ ] ,
11761235 } )
11771236
1178- // Check accessibility - find button by its content
1179- const versionButton = container . querySelector ( 'button[aria-label*="version"]' )
1180- expect ( versionButton ) . toBeTruthy ( )
1181- expect ( versionButton ) . toHaveAttribute ( "aria-label" )
1182- // The mock returns the key, so we check for that
1183- expect ( versionButton ?. getAttribute ( "aria-label" ) ) . toBe ( "chat:versionIndicator.ariaLabel" )
1237+ // Check accessibility
1238+ const versionButton = getByTestId ( "version-indicator" )
1239+ expect ( versionButton ) . toBeInTheDocument ( )
1240+ expect ( versionButton ) . toHaveAttribute ( "aria-label" , "Version 3.22.5" )
1241+
1242+ // Reset mock
1243+ mockVersionIndicator . mockReturnValue ( null )
1244+ } )
1245+
1246+ it ( "does not display version indicator when there is an active task" , ( ) => {
1247+ const { queryByTestId } = renderChatView ( )
1248+
1249+ // Hydrate state with an active task - any message in the array makes task truthy
1250+ mockPostMessage ( {
1251+ clineMessages : [
1252+ {
1253+ type : "say" ,
1254+ say : "task" ,
1255+ ts : Date . now ( ) ,
1256+ text : "Active task in progress" ,
1257+ } ,
1258+ ] ,
1259+ } )
1260+
1261+ // Version indicator should not be present during task execution
1262+ const versionButton = queryByTestId ( "version-indicator" )
1263+ expect ( versionButton ) . not . toBeInTheDocument ( )
1264+ } )
1265+
1266+ it ( "displays version indicator only on welcome screen (no task)" , ( ) => {
1267+ // Temporarily override the mock for this test
1268+ mockVersionIndicator . mockImplementation ( ( props ?: { onClick ?: ( ) => void ; className ?: string } ) => {
1269+ const { onClick, className } = props || { }
1270+ return (
1271+ < button
1272+ data-testid = "version-indicator"
1273+ onClick = { onClick }
1274+ className = { className }
1275+ aria-label = "Version 3.22.5" >
1276+ v3.22.5
1277+ </ button >
1278+ )
1279+ } )
1280+
1281+ const { queryByTestId, rerender } = renderChatView ( )
1282+
1283+ // First, hydrate with no messages (welcome screen)
1284+ mockPostMessage ( {
1285+ clineMessages : [ ] ,
1286+ } )
1287+
1288+ // Version indicator should be present
1289+ let versionButton = queryByTestId ( "version-indicator" )
1290+ expect ( versionButton ) . toBeInTheDocument ( )
1291+
1292+ // Reset mock to return null for the second part of the test
1293+ mockVersionIndicator . mockReturnValue ( null )
1294+
1295+ // Now add a task - any message makes task truthy
1296+ mockPostMessage ( {
1297+ clineMessages : [
1298+ {
1299+ type : "say" ,
1300+ say : "task" ,
1301+ ts : Date . now ( ) ,
1302+ text : "Starting a new task" ,
1303+ } ,
1304+ ] ,
1305+ } )
1306+
1307+ // Force a re-render to ensure the component updates
1308+ rerender (
1309+ < ExtensionStateContextProvider >
1310+ < QueryClientProvider client = { queryClient } >
1311+ < ChatView { ...defaultProps } />
1312+ </ QueryClientProvider >
1313+ </ ExtensionStateContextProvider > ,
1314+ )
1315+
1316+ // Version indicator should disappear
1317+ versionButton = queryByTestId ( "version-indicator" )
1318+ expect ( versionButton ) . not . toBeInTheDocument ( )
11841319 } )
11851320} )
0 commit comments