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
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,13 +121,17 @@ 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 self .project_path = server_path
125132
126133 self .generate_server (server_path )
127- self .publish_module (f"quickstart-chat- { self .lang } " , capture_stderr = True , clear = True )
134+ self .publish_module (self ._module_name , capture_stderr = True , clear = True )
128135 return base_path / "client"
129136
130137 def generate_server (self , server_path : Path ):
@@ -133,7 +140,7 @@ def generate_server(self, server_path: Path):
133140 self .spacetime ("init" , "--lang" , self .lang , server_path , capture_stderr = True )
134141 shutil .copy2 (STDB_DIR / "rust-toolchain.toml" , server_path )
135142 # Replay the quickstart guide steps
136- _write_file (server_path / self .server_file , _parse_quickstart (self .server_doc , self .lang ))
143+ _write_file (server_path / self .server_file , _parse_quickstart (self .server_doc , self .lang , self . _module_name ))
137144 self .server_postprocess (server_path )
138145 self .spacetime ("build" , "-d" , "-p" , server_path , capture_stderr = True )
139146
@@ -155,13 +162,14 @@ def _test_quickstart(self):
155162
156163 run_cmd (* self .build_cmd , cwd = client_path , capture_stderr = True )
157164
165+ client_lang = self .client_lang or self .lang
158166 self .spacetime (
159- "generate" , "--lang" , self . lang ,
167+ "generate" , "--lang" , client_lang ,
160168 "--out-dir" , client_path / self .module_bindings ,
161169 "--project-path" , self .project_path , capture_stderr = True
162170 )
163171 # Replay the quickstart guide steps
164- main = _parse_quickstart (self .client_doc , self .lang )
172+ main = _parse_quickstart (self .client_doc , client_lang , self ._module_name )
165173 for src , dst in self .replacements .items ():
166174 main = main .replace (src , dst )
167175 main += "\n " + self .extra_code
@@ -314,3 +322,20 @@ def test_quickstart(self):
314322 if not smoketests .HAVE_DOTNET :
315323 self .skipTest ("C# SDK requires .NET to be installed." )
316324 self ._test_quickstart ()
325+
326+ # We use the Rust client for testing the TypeScript server quickstart because
327+ # the TypeScript client quickstart is a React app, which is difficult to
328+ # smoketest.
329+ class TypeScript (Rust ):
330+ lang = "typescript"
331+ client_lang = "rust"
332+ server_doc = STDB_DIR / "docs/docs/06-Server Module Languages/05-typescript-quickstart.md"
333+ server_file = "src/index.ts"
334+
335+ def server_postprocess (self , server_path : Path ):
336+ build_typescript_sdk ()
337+ run_cmd ("pnpm" , "install" , f"spacetimedb@file:{ TYPESCRIPT_BINDINGS_PATH } " , cwd = server_path )
338+
339+ def test_quickstart (self ):
340+ """Run the TypeScript quickstart guides for server."""
341+ self ._test_quickstart ()
0 commit comments