@@ -17,6 +17,23 @@ use common::calculator::Calculator;
1717
1818const STREAMABLE_HTTP_BIND_ADDRESS : & str = "127.0.0.1:8001" ;
1919const STREAMABLE_HTTP_JS_BIND_ADDRESS : & str = "127.0.0.1:8002" ;
20+ // These tests run concurrently, while npm mutates their shared node_modules directory.
21+ static JS_DEPENDENCIES_INSTALLED : tokio:: sync:: OnceCell < ( ) > = tokio:: sync:: OnceCell :: const_new ( ) ;
22+
23+ async fn install_js_dependencies ( ) -> anyhow:: Result < ( ) > {
24+ JS_DEPENDENCIES_INSTALLED
25+ . get_or_try_init ( || async {
26+ let status = tokio:: process:: Command :: new ( "npm" )
27+ . arg ( "install" )
28+ . current_dir ( "tests/test_with_js" )
29+ . status ( )
30+ . await ?;
31+ anyhow:: ensure!( status. success( ) , "npm install failed with {status}" ) ;
32+ Ok ( ( ) )
33+ } )
34+ . await ?;
35+ Ok ( ( ) )
36+ }
2037
2138#[ tokio:: test]
2239async fn test_with_js_stdio_server ( ) -> anyhow:: Result < ( ) > {
@@ -27,12 +44,7 @@ async fn test_with_js_stdio_server() -> anyhow::Result<()> {
2744 )
2845 . with ( tracing_subscriber:: fmt:: layer ( ) )
2946 . try_init ( ) ;
30- tokio:: process:: Command :: new ( "npm" )
31- . arg ( "install" )
32- . current_dir ( "tests/test_with_js" )
33- . spawn ( ) ?
34- . wait ( )
35- . await ?;
47+ install_js_dependencies ( ) . await ?;
3648 let transport =
3749 TokioChildProcess :: new ( tokio:: process:: Command :: new ( "node" ) . configure ( |cmd| {
3850 cmd. arg ( "tests/test_with_js/server.js" ) ;
@@ -57,12 +69,7 @@ async fn test_with_js_streamable_http_client() -> anyhow::Result<()> {
5769 )
5870 . with ( tracing_subscriber:: fmt:: layer ( ) )
5971 . try_init ( ) ;
60- tokio:: process:: Command :: new ( "npm" )
61- . arg ( "install" )
62- . current_dir ( "tests/test_with_js" )
63- . spawn ( ) ?
64- . wait ( )
65- . await ?;
72+ install_js_dependencies ( ) . await ?;
6673
6774 let ct = CancellationToken :: new ( ) ;
6875 let service: StreamableHttpService < Calculator , LocalSessionManager > =
@@ -104,12 +111,7 @@ async fn test_with_js_streamable_http_server() -> anyhow::Result<()> {
104111 )
105112 . with ( tracing_subscriber:: fmt:: layer ( ) )
106113 . try_init ( ) ;
107- tokio:: process:: Command :: new ( "npm" )
108- . arg ( "install" )
109- . current_dir ( "tests/test_with_js" )
110- . spawn ( ) ?
111- . wait ( )
112- . await ?;
114+ install_js_dependencies ( ) . await ?;
113115
114116 let transport = StreamableHttpClientTransport :: from_uri ( format ! (
115117 "http://{STREAMABLE_HTTP_JS_BIND_ADDRESS}/mcp"
0 commit comments