66import xmltodict
77
88import smoketests
9- from .. import Smoketest , STDB_DIR , run_cmd , TEMPLATE_CARGO_TOML
9+ from .. import Smoketest , STDB_DIR , run_cmd , TEMPLATE_CARGO_TOML , TYPESCRIPT_BINDINGS_PATH , build_typescript_sdk , pnpm
1010
1111
1212def _write_file (path : Path , content : str ):
@@ -19,12 +19,13 @@ def _append_to_file(path: Path, content: str):
1919 f .write (content )
2020
2121
22- def _parse_quickstart (doc_path : Path , language : str ) -> str :
22+ def _parse_quickstart (doc_path : Path , language : str , module_name : str ) -> str :
2323 """Extract code blocks from `quickstart.md` docs.
2424 This will replicate the steps in the quickstart guide, so if it fails the quickstart guide is broken.
2525 """
2626 content = Path (doc_path ).read_text ()
27- blocks = re .findall (rf"```{ language } \n(.*?)\n```" , content , re .DOTALL )
27+ codeblock_lang = "ts" if language == "typescript" else language
28+ blocks = re .findall (rf"```{ codeblock_lang } \n(.*?)\n```" , content , re .DOTALL )
2829
2930 end = ""
3031 if language == "csharp" :
@@ -42,7 +43,7 @@ def _parse_quickstart(doc_path: Path, language: str) -> str:
4243 filtered_blocks .append (block )
4344 blocks = filtered_blocks
4445 # So we could have a different db for each language
45- return "\n " .join (blocks ).replace ("quickstart-chat" , f"quickstart-chat- { language } " ) + end
46+ return "\n " .join (blocks ).replace ("quickstart-chat" , module_name ) + end
4647
4748def load_nuget_config (p : Path ):
4849 if p .exists ():
@@ -101,6 +102,8 @@ class BaseQuickstart(Smoketest):
101102 MODULE_CODE = ""
102103
103104 lang = None
105+ client_lang = None
106+ codeblock_langs = None
104107 server_doc = None
105108 client_doc = None
106109 server_file = None
@@ -118,12 +121,16 @@ def project_init(self, path: Path):
118121 def sdk_setup (self , path : Path ):
119122 raise NotImplementedError
120123
124+ @property
125+ def _module_name (self ):
126+ return f"quickstart-chat-{ self .lang } "
127+
121128 def _publish (self ) -> Path :
122129 base_path = Path (self .enterClassContext (tempfile .TemporaryDirectory ()))
123130 server_path = base_path / "server"
124131
125132 self .generate_server (server_path )
126- self .publish_module (f"quickstart-chat- { self .lang } " , capture_stderr = True , clear = True )
133+ self .publish_module (self ._module_name , capture_stderr = True , clear = True )
127134 return base_path / "client"
128135
129136 def generate_server (self , server_path : Path ):
@@ -141,7 +148,7 @@ def generate_server(self, server_path: Path):
141148 )
142149 self .project_path = server_path / "spacetimedb"
143150 shutil .copy2 (STDB_DIR / "rust-toolchain.toml" , self .project_path )
144- _write_file (self .project_path / self .server_file , _parse_quickstart (self .server_doc , self .lang ))
151+ _write_file (self .project_path / self .server_file , _parse_quickstart (self .server_doc , self .lang , self . _module_name ))
145152 self .server_postprocess (self .project_path )
146153 self .spacetime ("build" , "-d" , "-p" , self .project_path , capture_stderr = True )
147154
@@ -163,13 +170,14 @@ def _test_quickstart(self):
163170
164171 run_cmd (* self .build_cmd , cwd = client_path , capture_stderr = True )
165172
173+ client_lang = self .client_lang or self .lang
166174 self .spacetime (
167- "generate" , "--lang" , self . lang ,
175+ "generate" , "--lang" , client_lang ,
168176 "--out-dir" , client_path / self .module_bindings ,
169177 "--project-path" , self .project_path , capture_stderr = True
170178 )
171179 # Replay the quickstart guide steps
172- main = _parse_quickstart (self .client_doc , self .lang )
180+ main = _parse_quickstart (self .client_doc , client_lang , self ._module_name )
173181 for src , dst in self .replacements .items ():
174182 main = main .replace (src , dst )
175183 main += "\n " + self .extra_code
@@ -301,6 +309,19 @@ def sdk_setup(self, path: Path):
301309 source_dir = (STDB_DIR / "crates/bindings-csharp/BSATN.Runtime" ).absolute (),
302310 build_subdir = "bin/Release"
303311 )
312+ # This one is only needed because the regression-tests subdir uses it
313+ override_nuget_package (
314+ project_dir = STDB_DIR / "sdks/csharp" ,
315+ package = "SpacetimeDB.Runtime" ,
316+ source_dir = (STDB_DIR / "crates/bindings-csharp/Runtime" ).absolute (),
317+ build_subdir = "bin/Release"
318+ )
319+ override_nuget_package (
320+ project_dir = path ,
321+ package = "SpacetimeDB.BSATN.Runtime" ,
322+ source_dir = (STDB_DIR / "crates/bindings-csharp/BSATN.Runtime" ).absolute (),
323+ build_subdir = "bin/Release"
324+ )
304325 override_nuget_package (
305326 project_dir = path ,
306327 package = "SpacetimeDB.ClientSDK" ,
@@ -316,9 +337,32 @@ def server_postprocess(self, server_path: Path):
316337 source_dir = (STDB_DIR / "crates/bindings-csharp/Runtime" ).absolute (),
317338 build_subdir = "bin/Release"
318339 )
340+ override_nuget_package (
341+ project_dir = server_path ,
342+ package = "SpacetimeDB.BSATN.Runtime" ,
343+ source_dir = (STDB_DIR / "crates/bindings-csharp/BSATN.Runtime" ).absolute (),
344+ build_subdir = "bin/Release"
345+ )
319346
320347 def test_quickstart (self ):
321348 """Run the C# quickstart guides for server and client."""
322349 if not smoketests .HAVE_DOTNET :
323350 self .skipTest ("C# SDK requires .NET to be installed." )
324351 self ._test_quickstart ()
352+
353+ # We use the Rust client for testing the TypeScript server quickstart because
354+ # the TypeScript client quickstart is a React app, which is difficult to
355+ # smoketest.
356+ class TypeScript (Rust ):
357+ lang = "typescript"
358+ client_lang = "rust"
359+ server_doc = STDB_DIR / "docs/docs/06-Server Module Languages/05-typescript-quickstart.md"
360+ server_file = "src/index.ts"
361+
362+ def server_postprocess (self , server_path : Path ):
363+ build_typescript_sdk ()
364+ pnpm ("install" , TYPESCRIPT_BINDINGS_PATH , cwd = server_path )
365+
366+ def test_quickstart (self ):
367+ """Run the TypeScript quickstart guides for server."""
368+ self ._test_quickstart ()
0 commit comments