@@ -649,6 +649,31 @@ describe("Sidebar Environment Variables", () => {
649
649
jest . clearAllTimers ( ) ;
650
650
} ) ;
651
651
652
+ const getCopyButtons = ( ) => {
653
+ return {
654
+ serverEntry : screen . getByRole ( "button" , { name : / s e r v e r e n t r y / i } ) ,
655
+ serversFile : screen . getByRole ( "button" , { name : / s e r v e r s f i l e / i } ) ,
656
+ } ;
657
+ } ;
658
+
659
+ it ( "should render both copy buttons for all transport types" , ( ) => {
660
+ [ "stdio" , "sse" , "streamable-http" ] . forEach ( ( transportType ) => {
661
+ renderSidebar ( { transportType } ) ;
662
+ // There should be exactly one Server Entry and one Servers File button per render
663
+ const serverEntryButtons = screen . getAllByRole ( "button" , {
664
+ name : / s e r v e r e n t r y / i,
665
+ } ) ;
666
+ const serversFileButtons = screen . getAllByRole ( "button" , {
667
+ name : / s e r v e r s f i l e / i,
668
+ } ) ;
669
+ expect ( serverEntryButtons ) . toHaveLength ( 1 ) ;
670
+ expect ( serversFileButtons ) . toHaveLength ( 1 ) ;
671
+ // Clean up DOM for next iteration
672
+ // (Testing Library's render does not auto-unmount in a loop)
673
+ document . body . innerHTML = "" ;
674
+ } ) ;
675
+ } ) ;
676
+
652
677
it ( "should copy server entry configuration to clipboard for STDIO transport" , async ( ) => {
653
678
const command = "node" ;
654
679
const args = "--inspect server.js" ;
@@ -661,20 +686,13 @@ describe("Sidebar Environment Variables", () => {
661
686
env,
662
687
} ) ;
663
688
664
- // Use act to properly wrap the clipboard operations
665
689
await act ( async ( ) => {
666
- const copyServerEntryButton = screen . getByRole ( "button" , {
667
- name : / s e r v e r e n t r y / i,
668
- } ) ;
669
- fireEvent . click ( copyServerEntryButton ) ;
670
-
671
- // Fast-forward timers to handle the setTimeout
690
+ const { serverEntry } = getCopyButtons ( ) ;
691
+ fireEvent . click ( serverEntry ) ;
672
692
jest . runAllTimers ( ) ;
673
693
} ) ;
674
694
675
- // Check clipboard API was called with the correct configuration
676
695
expect ( mockClipboardWrite ) . toHaveBeenCalledTimes ( 1 ) ;
677
-
678
696
const expectedConfig = JSON . stringify (
679
697
{
680
698
command,
@@ -684,7 +702,6 @@ describe("Sidebar Environment Variables", () => {
684
702
null ,
685
703
2 ,
686
704
) ;
687
-
688
705
expect ( mockClipboardWrite ) . toHaveBeenCalledWith ( expectedConfig ) ;
689
706
} ) ;
690
707
@@ -701,18 +718,12 @@ describe("Sidebar Environment Variables", () => {
701
718
} ) ;
702
719
703
720
await act ( async ( ) => {
704
- const copyServersFileButton = screen . getByRole ( "button" , {
705
- name : / s e r v e r s f i l e / i,
706
- } ) ;
707
- fireEvent . click ( copyServersFileButton ) ;
708
-
709
- // Fast-forward timers to handle the setTimeout
721
+ const { serversFile } = getCopyButtons ( ) ;
722
+ fireEvent . click ( serversFile ) ;
710
723
jest . runAllTimers ( ) ;
711
724
} ) ;
712
725
713
- // Check clipboard API was called with the correct configuration
714
726
expect ( mockClipboardWrite ) . toHaveBeenCalledTimes ( 1 ) ;
715
-
716
727
const expectedConfig = JSON . stringify (
717
728
{
718
729
mcpServers : {
@@ -726,31 +737,43 @@ describe("Sidebar Environment Variables", () => {
726
737
null ,
727
738
2 ,
728
739
) ;
729
-
730
740
expect ( mockClipboardWrite ) . toHaveBeenCalledWith ( expectedConfig ) ;
731
741
} ) ;
732
742
733
- it ( "should copy servers file configuration to clipboard for SSE transport" , async ( ) => {
743
+ it ( "should copy server entry configuration to clipboard for SSE transport" , async ( ) => {
734
744
const sseUrl = "http://localhost:3000/events" ;
745
+ renderSidebar ( { transportType : "sse" , sseUrl } ) ;
735
746
736
- renderSidebar ( {
737
- transportType : "sse" ,
738
- sseUrl,
747
+ await act ( async ( ) => {
748
+ const { serverEntry } = getCopyButtons ( ) ;
749
+ fireEvent . click ( serverEntry ) ;
750
+ jest . runAllTimers ( ) ;
739
751
} ) ;
740
752
741
- await act ( async ( ) => {
742
- const copyServersFileButton = screen . getByRole ( "button" , {
743
- name : / s e r v e r s f i l e / i,
744
- } ) ;
745
- fireEvent . click ( copyServersFileButton ) ;
753
+ expect ( mockClipboardWrite ) . toHaveBeenCalledTimes ( 1 ) ;
754
+ const expectedConfig = JSON . stringify (
755
+ {
756
+ type : "sse" ,
757
+ url : sseUrl ,
758
+ note : "For SSE connections, add this URL directly in Client" ,
759
+ } ,
760
+ null ,
761
+ 2 ,
762
+ ) ;
763
+ expect ( mockClipboardWrite ) . toHaveBeenCalledWith ( expectedConfig ) ;
764
+ } ) ;
746
765
747
- // Fast-forward timers to handle the setTimeout
766
+ it ( "should copy servers file configuration to clipboard for SSE transport" , async ( ) => {
767
+ const sseUrl = "http://localhost:3000/events" ;
768
+ renderSidebar ( { transportType : "sse" , sseUrl } ) ;
769
+
770
+ await act ( async ( ) => {
771
+ const { serversFile } = getCopyButtons ( ) ;
772
+ fireEvent . click ( serversFile ) ;
748
773
jest . runAllTimers ( ) ;
749
774
} ) ;
750
775
751
- // Check clipboard API was called with the correct configuration
752
776
expect ( mockClipboardWrite ) . toHaveBeenCalledTimes ( 1 ) ;
753
-
754
777
const expectedConfig = JSON . stringify (
755
778
{
756
779
mcpServers : {
@@ -764,7 +787,56 @@ describe("Sidebar Environment Variables", () => {
764
787
null ,
765
788
2 ,
766
789
) ;
790
+ expect ( mockClipboardWrite ) . toHaveBeenCalledWith ( expectedConfig ) ;
791
+ } ) ;
792
+
793
+ it ( "should copy server entry configuration to clipboard for streamable-http transport" , async ( ) => {
794
+ const sseUrl = "http://localhost:3001/sse" ;
795
+ renderSidebar ( { transportType : "streamable-http" , sseUrl } ) ;
796
+
797
+ await act ( async ( ) => {
798
+ const { serverEntry } = getCopyButtons ( ) ;
799
+ fireEvent . click ( serverEntry ) ;
800
+ jest . runAllTimers ( ) ;
801
+ } ) ;
802
+
803
+ expect ( mockClipboardWrite ) . toHaveBeenCalledTimes ( 1 ) ;
804
+ const expectedConfig = JSON . stringify (
805
+ {
806
+ type : "streamable-http" ,
807
+ url : sseUrl ,
808
+ note : "For Streamable HTTP connections, add this URL directly in Client" ,
809
+ } ,
810
+ null ,
811
+ 2 ,
812
+ ) ;
813
+ expect ( mockClipboardWrite ) . toHaveBeenCalledWith ( expectedConfig ) ;
814
+ } ) ;
815
+
816
+ it ( "should copy servers file configuration to clipboard for streamable-http transport" , async ( ) => {
817
+ const sseUrl = "http://localhost:3001/sse" ;
818
+ renderSidebar ( { transportType : "streamable-http" , sseUrl } ) ;
819
+
820
+ await act ( async ( ) => {
821
+ const { serversFile } = getCopyButtons ( ) ;
822
+ fireEvent . click ( serversFile ) ;
823
+ jest . runAllTimers ( ) ;
824
+ } ) ;
767
825
826
+ expect ( mockClipboardWrite ) . toHaveBeenCalledTimes ( 1 ) ;
827
+ const expectedConfig = JSON . stringify (
828
+ {
829
+ mcpServers : {
830
+ "default-server" : {
831
+ type : "streamable-http" ,
832
+ url : sseUrl ,
833
+ note : "For Streamable HTTP connections, add this URL directly in Client" ,
834
+ } ,
835
+ } ,
836
+ } ,
837
+ null ,
838
+ 2 ,
839
+ ) ;
768
840
expect ( mockClipboardWrite ) . toHaveBeenCalledWith ( expectedConfig ) ;
769
841
} ) ;
770
842
@@ -779,18 +851,12 @@ describe("Sidebar Environment Variables", () => {
779
851
} ) ;
780
852
781
853
await act ( async ( ) => {
782
- const copyServerEntryButton = screen . getByRole ( "button" , {
783
- name : / s e r v e r e n t r y / i,
784
- } ) ;
785
- fireEvent . click ( copyServerEntryButton ) ;
786
-
787
- // Fast-forward timers to handle the setTimeout
854
+ const { serverEntry } = getCopyButtons ( ) ;
855
+ fireEvent . click ( serverEntry ) ;
788
856
jest . runAllTimers ( ) ;
789
857
} ) ;
790
858
791
- // Check clipboard API was called with empty args array
792
859
expect ( mockClipboardWrite ) . toHaveBeenCalledTimes ( 1 ) ;
793
-
794
860
const expectedConfig = JSON . stringify (
795
861
{
796
862
command,
@@ -800,7 +866,6 @@ describe("Sidebar Environment Variables", () => {
800
866
null ,
801
867
2 ,
802
868
) ;
803
-
804
869
expect ( mockClipboardWrite ) . toHaveBeenCalledWith ( expectedConfig ) ;
805
870
} ) ;
806
871
} ) ;
0 commit comments