@@ -440,32 +440,38 @@ const renderEnvironmentsSection = (
440440 options . onUpdateAppSettings ?? vi . fn ( ) . mockResolvedValue ( undefined ) ;
441441 const onUpdateWorkspaceSettings =
442442 options . onUpdateWorkspaceSettings ?? vi . fn ( ) . mockResolvedValue ( undefined ) ;
443-
444- const props : ComponentProps < typeof SettingsView > = {
443+ const defaultGroupedWorkspaces =
444+ options . groupedWorkspaces ??
445+ [
446+ {
447+ id : null ,
448+ name : "Ungrouped" ,
449+ workspaces : [
450+ workspace ( {
451+ id : "w1" ,
452+ name : "Project One" ,
453+ settings : {
454+ sidebarCollapsed : false ,
455+ worktreeSetupScript : "echo one" ,
456+ } ,
457+ } ) ,
458+ ] ,
459+ } ,
460+ ] ;
461+
462+ const buildProps = (
463+ nextOptions : {
464+ appSettings ?: Partial < AppSettings > ;
465+ groupedWorkspaces ?: ComponentProps < typeof SettingsView > [ "groupedWorkspaces" ] ;
466+ } = { } ,
467+ ) : ComponentProps < typeof SettingsView > => ( {
445468 reduceTransparency : false ,
446469 onToggleTransparency : vi . fn ( ) ,
447- appSettings : { ...baseSettings , ...options . appSettings } ,
470+ appSettings : { ...baseSettings , ...options . appSettings , ... nextOptions . appSettings } ,
448471 openAppIconById : { } ,
449472 onUpdateAppSettings,
450473 workspaceGroups : [ ] ,
451- groupedWorkspaces :
452- options . groupedWorkspaces ??
453- [
454- {
455- id : null ,
456- name : "Ungrouped" ,
457- workspaces : [
458- workspace ( {
459- id : "w1" ,
460- name : "Project One" ,
461- settings : {
462- sidebarCollapsed : false ,
463- worktreeSetupScript : "echo one" ,
464- } ,
465- } ) ,
466- ] ,
467- } ,
468- ] ,
474+ groupedWorkspaces : nextOptions . groupedWorkspaces ?? defaultGroupedWorkspaces ,
469475 ungroupedLabel : "Ungrouped" ,
470476 onClose : vi . fn ( ) ,
471477 onMoveWorkspace : vi . fn ( ) ,
@@ -486,10 +492,19 @@ const renderEnvironmentsSection = (
486492 onCancelDictationDownload : vi . fn ( ) ,
487493 onRemoveDictationModel : vi . fn ( ) ,
488494 initialSection : "environments" ,
489- } ;
495+ } ) ;
490496
491- render ( < SettingsView { ...props } /> ) ;
492- return { onUpdateAppSettings, onUpdateWorkspaceSettings } ;
497+ const renderResult = render ( < SettingsView { ...buildProps ( ) } /> ) ;
498+ return {
499+ onUpdateAppSettings,
500+ onUpdateWorkspaceSettings,
501+ rerender : (
502+ nextOptions : {
503+ appSettings ?: Partial < AppSettings > ;
504+ groupedWorkspaces ?: ComponentProps < typeof SettingsView > [ "groupedWorkspaces" ] ;
505+ } = { } ,
506+ ) => renderResult . rerender ( < SettingsView { ...buildProps ( nextOptions ) } /> ) ,
507+ } ;
493508} ;
494509
495510describe ( "SettingsView Display" , ( ) => {
@@ -869,6 +884,33 @@ describe("SettingsView Environments", () => {
869884 } ) ;
870885 } ) ;
871886
887+ it ( "resyncs the global worktrees root baseline after dirty state clears" , async ( ) => {
888+ const { rerender } = renderEnvironmentsSection ( {
889+ groupedWorkspaces : [ ] ,
890+ appSettings : { globalWorktreesFolder : null } ,
891+ } ) ;
892+
893+ const input = screen . getByLabelText ( "Global worktrees root" ) ;
894+ fireEvent . change ( input , { target : { value : "I:/typing" } } ) ;
895+
896+ rerender ( {
897+ groupedWorkspaces : [ ] ,
898+ appSettings : { globalWorktreesFolder : "I:/loaded-from-settings" } ,
899+ } ) ;
900+
901+ expect ( ( screen . getByLabelText ( "Global worktrees root" ) as HTMLInputElement ) . value ) . toBe (
902+ "I:/typing" ,
903+ ) ;
904+
905+ fireEvent . click ( screen . getByRole ( "button" , { name : "Reset" } ) ) ;
906+
907+ await waitFor ( ( ) => {
908+ expect ( ( screen . getByLabelText ( "Global worktrees root" ) as HTMLInputElement ) . value ) . toBe (
909+ "I:/loaded-from-settings" ,
910+ ) ;
911+ } ) ;
912+ } ) ;
913+
872914 it ( "shows save errors for the global worktrees root when there are no projects" , async ( ) => {
873915 const onUpdateAppSettings = vi
874916 . fn ( )
0 commit comments