jac-client 0.2.8__py3-none-any.whl → 0.2.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jac_client/examples/all-in-one/button.jac +4 -3
- jac_client/examples/all-in-one/components/CategoryFilter.jac +36 -24
- jac_client/examples/all-in-one/components/Header.jac +12 -8
- jac_client/examples/all-in-one/components/ProfitOverview.jac +49 -35
- jac_client/examples/all-in-one/components/Summary.jac +59 -36
- jac_client/examples/all-in-one/components/TransactionForm.jac +142 -112
- jac_client/examples/all-in-one/components/TransactionItem.jac +37 -30
- jac_client/examples/all-in-one/components/TransactionList.jac +33 -26
- jac_client/examples/all-in-one/components/button.jac +4 -3
- jac_client/examples/all-in-one/components/navigation.jac +111 -117
- jac_client/examples/all-in-one/constants/categories.jac +23 -24
- jac_client/examples/all-in-one/constants/clients.jac +7 -8
- jac_client/examples/all-in-one/context/BudgetContext.jac +9 -6
- jac_client/examples/all-in-one/hooks/useBudget.jac +18 -12
- jac_client/examples/all-in-one/hooks/useLocalStorage.jac +14 -13
- jac_client/examples/all-in-one/main.jac +542 -0
- jac_client/examples/all-in-one/pages/BudgetPlanner.jac +26 -12
- jac_client/examples/all-in-one/pages/FeaturesTest.jac +43 -12
- jac_client/examples/all-in-one/pages/LandingPage.jac +113 -90
- jac_client/examples/all-in-one/pages/budget_planner_ui.cl.jac +65 -0
- jac_client/examples/all-in-one/pages/features_test_ui.cl.jac +675 -0
- jac_client/examples/all-in-one/pages/loginPage.jac +114 -119
- jac_client/examples/all-in-one/pages/nestedDemo.jac +44 -51
- jac_client/examples/all-in-one/pages/notFound.jac +15 -21
- jac_client/examples/all-in-one/pages/signupPage.jac +113 -119
- jac_client/examples/all-in-one/utils/formatters.jac +5 -8
- jac_client/examples/asset-serving/css-with-image/main.jac +92 -0
- jac_client/examples/asset-serving/image-asset/main.jac +56 -0
- jac_client/examples/asset-serving/import-alias/main.jac +109 -0
- jac_client/examples/basic/main.jac +23 -0
- jac_client/examples/basic-auth/main.jac +363 -0
- jac_client/examples/basic-auth-with-router/main.jac +451 -0
- jac_client/examples/basic-full-stack/main.jac +362 -0
- jac_client/examples/css-styling/js-styling/main.jac +63 -0
- jac_client/examples/css-styling/material-ui/main.jac +122 -0
- jac_client/examples/css-styling/pure-css/main.jac +55 -0
- jac_client/examples/css-styling/sass-example/main.jac +55 -0
- jac_client/examples/css-styling/styled-components/main.jac +62 -0
- jac_client/examples/css-styling/tailwind-example/main.jac +74 -0
- jac_client/examples/full-stack-with-auth/main.jac +696 -0
- jac_client/examples/little-x/main.jac +681 -0
- jac_client/examples/little-x/src/submit-button.jac +15 -14
- jac_client/examples/nested-folders/nested-advance/main.jac +26 -0
- jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +4 -6
- jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +9 -13
- jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac +29 -32
- jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +12 -18
- jac_client/examples/nested-folders/nested-basic/{src/app.jac → main.jac} +7 -5
- jac_client/examples/nested-folders/nested-basic/src/button.jac +4 -3
- jac_client/examples/nested-folders/nested-basic/src/components/button.jac +4 -3
- jac_client/examples/ts-support/main.jac +35 -0
- jac_client/examples/with-router/main.jac +286 -0
- jac_client/plugin/cli.jac +491 -411
- jac_client/plugin/client.jac +25 -0
- jac_client/plugin/client_runtime.cl.jac +10 -4
- jac_client/plugin/impl/client.impl.jac +96 -55
- jac_client/plugin/impl/client_runtime.impl.jac +155 -1
- jac_client/plugin/plugin_config.jac +211 -29
- jac_client/plugin/src/__init__.jac +0 -2
- jac_client/plugin/src/compiler.jac +0 -1
- jac_client/plugin/src/config_loader.jac +1 -0
- jac_client/plugin/src/desktop_config.jac +31 -0
- jac_client/plugin/src/impl/compiler.impl.jac +49 -17
- jac_client/plugin/src/impl/config_loader.impl.jac +8 -0
- jac_client/plugin/src/impl/desktop_config.impl.jac +191 -0
- jac_client/plugin/src/impl/jac_to_js.impl.jac +5 -1
- jac_client/plugin/src/impl/package_installer.impl.jac +20 -20
- jac_client/plugin/src/impl/vite_bundler.impl.jac +191 -64
- jac_client/plugin/src/targets/desktop/sidecar/main.py +144 -0
- jac_client/plugin/src/targets/desktop_target.jac +37 -0
- jac_client/plugin/src/targets/impl/desktop_target.impl.jac +2347 -0
- jac_client/plugin/src/targets/impl/registry.impl.jac +64 -0
- jac_client/plugin/src/targets/impl/web_target.impl.jac +157 -0
- jac_client/plugin/src/targets/register.jac +21 -0
- jac_client/plugin/src/targets/registry.jac +87 -0
- jac_client/plugin/src/targets/web_target.jac +35 -0
- jac_client/plugin/src/vite_bundler.jac +6 -0
- jac_client/plugin/utils/__init__.jac +3 -0
- jac_client/plugin/utils/bun_installer.jac +16 -0
- jac_client/plugin/utils/impl/bun_installer.impl.jac +99 -0
- jac_client/templates/client.jacpack +72 -0
- jac_client/templates/fullstack.jacpack +61 -0
- jac_client/tests/conftest.py +103 -47
- jac_client/tests/fixtures/spawn_test/app.jac +49 -52
- jac_client/tests/fixtures/with-ts/app.jac +27 -27
- jac_client/tests/test_cli.py +182 -71
- jac_client/tests/test_e2e.py +232 -0
- jac_client/tests/test_helpers.py +58 -0
- jac_client/tests/test_it.py +91 -135
- jac_client/tests/test_it_desktop.py +891 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/METADATA +6 -6
- jac_client-0.2.11.dist-info/RECORD +113 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/WHEEL +1 -1
- jac_client/examples/all-in-one/app.jac +0 -573
- jac_client/examples/all-in-one/pages/BudgetPlanner.cl.jac +0 -70
- jac_client/examples/all-in-one/pages/FeaturesTest.cl.jac +0 -552
- jac_client/examples/asset-serving/css-with-image/src/app.jac +0 -88
- jac_client/examples/asset-serving/image-asset/src/app.jac +0 -55
- jac_client/examples/asset-serving/import-alias/src/app.jac +0 -111
- jac_client/examples/basic/src/app.jac +0 -21
- jac_client/examples/basic-auth/src/app.jac +0 -371
- jac_client/examples/basic-auth-with-router/src/app.jac +0 -464
- jac_client/examples/basic-full-stack/src/app.jac +0 -359
- jac_client/examples/css-styling/js-styling/src/app.jac +0 -84
- jac_client/examples/css-styling/material-ui/src/app.jac +0 -122
- jac_client/examples/css-styling/pure-css/src/app.jac +0 -64
- jac_client/examples/css-styling/sass-example/src/app.jac +0 -64
- jac_client/examples/css-styling/styled-components/src/app.jac +0 -71
- jac_client/examples/css-styling/tailwind-example/src/app.jac +0 -63
- jac_client/examples/full-stack-with-auth/src/app.jac +0 -722
- jac_client/examples/little-x/src/app.jac +0 -719
- jac_client/examples/nested-folders/nested-advance/src/app.jac +0 -35
- jac_client/examples/ts-support/src/app.jac +0 -35
- jac_client/examples/with-router/src/app.jac +0 -323
- jac_client/plugin/src/babel_processor.jac +0 -18
- jac_client/plugin/src/impl/babel_processor.impl.jac +0 -89
- jac_client-0.2.8.dist-info/RECORD +0 -97
- {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/entry_points.txt +0 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/top_level.txt +0 -0
jac_client/tests/test_it.py
CHANGED
|
@@ -6,87 +6,21 @@ import gc
|
|
|
6
6
|
import json
|
|
7
7
|
import os
|
|
8
8
|
import shutil
|
|
9
|
-
import socket
|
|
10
|
-
import sys
|
|
11
9
|
import tempfile
|
|
12
10
|
import time
|
|
13
11
|
from http.client import RemoteDisconnected
|
|
14
|
-
from pathlib import Path
|
|
15
12
|
from subprocess import PIPE, Popen, run
|
|
16
13
|
from urllib.error import HTTPError, URLError
|
|
17
14
|
from urllib.request import Request, urlopen
|
|
18
15
|
|
|
19
16
|
import pytest
|
|
20
17
|
|
|
21
|
-
from
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if jac_path:
|
|
28
|
-
return [jac_path]
|
|
29
|
-
return [sys.executable, "-m", "jaclang"]
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def _get_env_with_npm() -> dict[str, str]:
|
|
33
|
-
"""Get environment dict with npm in PATH."""
|
|
34
|
-
env = os.environ.copy()
|
|
35
|
-
npm_path = shutil.which("npm")
|
|
36
|
-
if npm_path:
|
|
37
|
-
npm_dir = str(Path(npm_path).parent)
|
|
38
|
-
current_path = env.get("PATH", "")
|
|
39
|
-
if npm_dir not in current_path:
|
|
40
|
-
env["PATH"] = f"{npm_dir}:{current_path}"
|
|
41
|
-
# Also check common nvm locations
|
|
42
|
-
nvm_dir = os.environ.get("NVM_DIR", os.path.expanduser("~/.nvm"))
|
|
43
|
-
nvm_node_bin = Path(nvm_dir) / "versions" / "node"
|
|
44
|
-
if nvm_node_bin.exists():
|
|
45
|
-
for version_dir in nvm_node_bin.iterdir():
|
|
46
|
-
bin_dir = version_dir / "bin"
|
|
47
|
-
if bin_dir.exists() and (bin_dir / "npm").exists():
|
|
48
|
-
current_path = env.get("PATH", "")
|
|
49
|
-
if str(bin_dir) not in current_path:
|
|
50
|
-
env["PATH"] = f"{bin_dir}:{current_path}"
|
|
51
|
-
break
|
|
52
|
-
return env
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
@pytest.fixture(autouse=True)
|
|
56
|
-
def reset_jac_machine():
|
|
57
|
-
"""Reset Jac machine before and after each test."""
|
|
58
|
-
Jac.reset_machine()
|
|
59
|
-
yield
|
|
60
|
-
Jac.reset_machine()
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def _wait_for_port(
|
|
64
|
-
host: str,
|
|
65
|
-
port: int,
|
|
66
|
-
timeout: float = 60.0,
|
|
67
|
-
poll_interval: float = 0.5,
|
|
68
|
-
) -> None:
|
|
69
|
-
"""Block until a TCP port is accepting connections or timeout.
|
|
70
|
-
|
|
71
|
-
Raises:
|
|
72
|
-
TimeoutError: if the port is not accepting connections within timeout.
|
|
73
|
-
"""
|
|
74
|
-
deadline = time.time() + timeout
|
|
75
|
-
last_err: Exception | None = None
|
|
76
|
-
|
|
77
|
-
while time.time() < deadline:
|
|
78
|
-
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
79
|
-
sock.settimeout(poll_interval)
|
|
80
|
-
try:
|
|
81
|
-
sock.connect((host, port))
|
|
82
|
-
return
|
|
83
|
-
except OSError as exc: # Connection refused / timeout
|
|
84
|
-
last_err = exc
|
|
85
|
-
time.sleep(poll_interval)
|
|
86
|
-
|
|
87
|
-
raise TimeoutError(
|
|
88
|
-
f"Timed out waiting for {host}:{port} to become available. Last error: {last_err}"
|
|
89
|
-
)
|
|
18
|
+
from .test_helpers import (
|
|
19
|
+
get_env_with_npm, # Backward compat alias
|
|
20
|
+
get_free_port,
|
|
21
|
+
get_jac_command,
|
|
22
|
+
wait_for_port,
|
|
23
|
+
)
|
|
90
24
|
|
|
91
25
|
|
|
92
26
|
def _wait_for_endpoint(
|
|
@@ -150,7 +84,7 @@ def _wait_for_endpoint(
|
|
|
150
84
|
def test_all_in_one_app_endpoints() -> None:
|
|
151
85
|
"""Create a Jac app, copy @all-in-one into it, install packages from jac.toml, then verify endpoints."""
|
|
152
86
|
print(
|
|
153
|
-
"[DEBUG] Starting test_all_in_one_app_endpoints using jac create --
|
|
87
|
+
"[DEBUG] Starting test_all_in_one_app_endpoints using jac create --use client + @all-in-one"
|
|
154
88
|
)
|
|
155
89
|
|
|
156
90
|
# Resolve the path to jac_client/examples/all-in-one relative to this test file.
|
|
@@ -171,9 +105,9 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
171
105
|
print(f"[DEBUG] Changed working directory to {temp_dir}")
|
|
172
106
|
|
|
173
107
|
# 1. Create a new Jac app via CLI (requires jac + jac-client plugin installed)
|
|
174
|
-
print(f"[DEBUG] Running 'jac create --
|
|
108
|
+
print(f"[DEBUG] Running 'jac create --use client {app_name}'")
|
|
175
109
|
process = Popen(
|
|
176
|
-
["jac", "create", "--
|
|
110
|
+
["jac", "create", "--use", "client", app_name],
|
|
177
111
|
stdin=PIPE,
|
|
178
112
|
stdout=PIPE,
|
|
179
113
|
stderr=PIPE,
|
|
@@ -183,21 +117,21 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
183
117
|
returncode = process.returncode
|
|
184
118
|
|
|
185
119
|
print(
|
|
186
|
-
"[DEBUG] 'jac create --
|
|
120
|
+
"[DEBUG] 'jac create --use client' completed "
|
|
187
121
|
f"returncode={returncode}\n"
|
|
188
122
|
f"STDOUT:\n{stdout}\n"
|
|
189
123
|
f"STDERR:\n{stderr}\n"
|
|
190
124
|
)
|
|
191
125
|
|
|
192
|
-
# If the currently installed `jac` CLI does not support `create --
|
|
126
|
+
# If the currently installed `jac` CLI does not support `create --use client`,
|
|
193
127
|
# fail the test instead of skipping it.
|
|
194
|
-
if returncode != 0 and "unrecognized arguments: --
|
|
128
|
+
if returncode != 0 and "unrecognized arguments: --use" in stderr:
|
|
195
129
|
pytest.fail(
|
|
196
|
-
"Test failed: installed `jac` CLI does not support `create --
|
|
130
|
+
"Test failed: installed `jac` CLI does not support `create --use client`."
|
|
197
131
|
)
|
|
198
132
|
|
|
199
133
|
assert returncode == 0, (
|
|
200
|
-
f"jac create --
|
|
134
|
+
f"jac create --use client failed\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}\n"
|
|
201
135
|
)
|
|
202
136
|
|
|
203
137
|
project_path = os.path.join(temp_dir, app_name)
|
|
@@ -217,17 +151,17 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
217
151
|
else:
|
|
218
152
|
shutil.copy2(src, dst)
|
|
219
153
|
|
|
220
|
-
# 3. Install packages from jac.toml using `jac add --
|
|
154
|
+
# 3. Install packages from jac.toml using `jac add --npm`
|
|
221
155
|
# This reads packages from jac.toml, generates package.json, and runs npm install
|
|
222
|
-
print("[DEBUG] Running 'jac add --
|
|
156
|
+
print("[DEBUG] Running 'jac add --npm' to install packages from jac.toml")
|
|
223
157
|
jac_add_result = run(
|
|
224
|
-
["jac", "add", "--
|
|
158
|
+
["jac", "add", "--npm"],
|
|
225
159
|
cwd=project_path,
|
|
226
160
|
capture_output=True,
|
|
227
161
|
text=True,
|
|
228
162
|
)
|
|
229
163
|
print(
|
|
230
|
-
"[DEBUG] 'jac add --
|
|
164
|
+
"[DEBUG] 'jac add --npm' completed "
|
|
231
165
|
f"returncode={jac_add_result.returncode}\n"
|
|
232
166
|
f"STDOUT (truncated to 2000 chars):\n{jac_add_result.stdout[:2000]}\n"
|
|
233
167
|
f"STDERR (truncated to 2000 chars):\n{jac_add_result.stderr[:2000]}\n"
|
|
@@ -235,28 +169,36 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
235
169
|
|
|
236
170
|
if jac_add_result.returncode != 0:
|
|
237
171
|
pytest.fail(
|
|
238
|
-
f"Test failed: jac add --
|
|
172
|
+
f"Test failed: jac add --npm failed or npm is not available in PATH.\n"
|
|
239
173
|
f"STDOUT:\n{jac_add_result.stdout}\n"
|
|
240
174
|
f"STDERR:\n{jac_add_result.stderr}\n"
|
|
241
175
|
)
|
|
242
176
|
|
|
243
|
-
app_jac_path = os.path.join(project_path, "
|
|
244
|
-
assert os.path.isfile(app_jac_path), "all-in-one
|
|
177
|
+
app_jac_path = os.path.join(project_path, "main.jac")
|
|
178
|
+
assert os.path.isfile(app_jac_path), "all-in-one main.jac file missing"
|
|
245
179
|
|
|
246
|
-
# 4. Start the server: `jac start
|
|
180
|
+
# 4. Start the server: `jac start main.jac`
|
|
247
181
|
# NOTE: We don't use text mode here, so `Popen` defaults to bytes.
|
|
248
182
|
# Use `Popen[bytes]` in the type annotation to keep mypy happy.
|
|
249
183
|
server: Popen[bytes] | None = None
|
|
184
|
+
# Use dynamic port allocation to avoid conflicts when running tests in parallel
|
|
185
|
+
server_port = get_free_port()
|
|
250
186
|
try:
|
|
251
|
-
print(
|
|
187
|
+
print(
|
|
188
|
+
f"[DEBUG] Starting server with 'jac start main.jac -p {server_port}'"
|
|
189
|
+
)
|
|
252
190
|
server = Popen(
|
|
253
|
-
["jac", "start", "
|
|
191
|
+
["jac", "start", "main.jac", "-p", str(server_port)],
|
|
254
192
|
cwd=project_path,
|
|
255
193
|
)
|
|
256
194
|
# Wait for localhost:8000 to become available
|
|
257
|
-
print(
|
|
258
|
-
|
|
259
|
-
|
|
195
|
+
print(
|
|
196
|
+
f"[DEBUG] Waiting for server to be available on 127.0.0.1:{server_port}"
|
|
197
|
+
)
|
|
198
|
+
wait_for_port("127.0.0.1", server_port, timeout=90.0)
|
|
199
|
+
print(
|
|
200
|
+
f"[DEBUG] Server is now accepting connections on 127.0.0.1:{server_port}"
|
|
201
|
+
)
|
|
260
202
|
|
|
261
203
|
# "/" – server up (serves client app HTML due to base_route_app="app")
|
|
262
204
|
# Note: The root endpoint may return 503 while the client bundle is building.
|
|
@@ -264,7 +206,7 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
264
206
|
try:
|
|
265
207
|
print("[DEBUG] Sending GET request to root endpoint / (with retry)")
|
|
266
208
|
root_bytes = _wait_for_endpoint(
|
|
267
|
-
"http://127.0.0.1:
|
|
209
|
+
f"http://127.0.0.1:{server_port}",
|
|
268
210
|
timeout=120.0,
|
|
269
211
|
poll_interval=2.0,
|
|
270
212
|
request_timeout=30.0,
|
|
@@ -290,7 +232,7 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
290
232
|
"[DEBUG] Sending GET request to /cl/app endpoint (with retry)"
|
|
291
233
|
)
|
|
292
234
|
page_bytes = _wait_for_endpoint(
|
|
293
|
-
"http://127.0.0.1:
|
|
235
|
+
f"http://127.0.0.1:{server_port}/cl/app",
|
|
294
236
|
timeout=120.0,
|
|
295
237
|
poll_interval=2.0,
|
|
296
238
|
request_timeout=30.0,
|
|
@@ -310,7 +252,7 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
310
252
|
try:
|
|
311
253
|
print("[DEBUG] Sending GET request to /cl/app#/nested endpoint")
|
|
312
254
|
with urlopen(
|
|
313
|
-
"http://127.0.0.1:
|
|
255
|
+
f"http://127.0.0.1:{server_port}/cl/app#/nested",
|
|
314
256
|
timeout=200,
|
|
315
257
|
) as resp_nested:
|
|
316
258
|
nested_body = resp_nested.read().decode(
|
|
@@ -336,7 +278,7 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
336
278
|
try:
|
|
337
279
|
print("[DEBUG] Sending GET request to /static/assets/burger.png")
|
|
338
280
|
with urlopen(
|
|
339
|
-
"http://127.0.0.1:
|
|
281
|
+
f"http://127.0.0.1:{server_port}/static/assets/burger.png",
|
|
340
282
|
timeout=20,
|
|
341
283
|
) as resp_png:
|
|
342
284
|
png_bytes = resp_png.read()
|
|
@@ -362,7 +304,7 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
362
304
|
"[DEBUG] Sending GET request to /workers/worker.js (with retry)"
|
|
363
305
|
)
|
|
364
306
|
worker_js_bytes = _wait_for_endpoint(
|
|
365
|
-
"http://127.0.0.1:
|
|
307
|
+
f"http://127.0.0.1:{server_port}/workers/worker.js",
|
|
366
308
|
timeout=60.0,
|
|
367
309
|
poll_interval=2.0,
|
|
368
310
|
request_timeout=20.0,
|
|
@@ -384,13 +326,18 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
384
326
|
f"Failed to GET /workers/worker.js after retries: {exc}"
|
|
385
327
|
)
|
|
386
328
|
|
|
387
|
-
#
|
|
329
|
+
# POST /walker/get_server_message – walkers are integrated and up and running
|
|
388
330
|
try:
|
|
389
|
-
print(
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
331
|
+
print(
|
|
332
|
+
"[DEBUG] Sending POST request to /walker/get_server_message endpoint"
|
|
333
|
+
)
|
|
334
|
+
req = Request(
|
|
335
|
+
f"http://127.0.0.1:{server_port}/walker/get_server_message",
|
|
336
|
+
data=json.dumps({}).encode("utf-8"),
|
|
337
|
+
headers={"Content-Type": "application/json"},
|
|
338
|
+
method="POST",
|
|
339
|
+
)
|
|
340
|
+
with urlopen(req, timeout=20) as resp_walker:
|
|
394
341
|
walker_body = resp_walker.read().decode(
|
|
395
342
|
"utf-8", errors="ignore"
|
|
396
343
|
)
|
|
@@ -400,12 +347,13 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
400
347
|
f"Body (truncated to 500 chars):\n{walker_body[:500]}"
|
|
401
348
|
)
|
|
402
349
|
assert resp_walker.status == 200
|
|
403
|
-
|
|
404
|
-
|
|
350
|
+
# The walker reports "hello from a basic walker!"
|
|
351
|
+
assert "hello from a basic walker" in walker_body.lower()
|
|
352
|
+
except (URLError, HTTPError, RemoteDisconnected) as exc:
|
|
405
353
|
print(
|
|
406
354
|
f"[DEBUG] Error while requesting /walker/get_server_message: {exc}"
|
|
407
355
|
)
|
|
408
|
-
pytest.fail("Failed to
|
|
356
|
+
pytest.fail("Failed to POST /walker/get_server_message")
|
|
409
357
|
|
|
410
358
|
# POST /walker/create_todo – create a Todo via walker HTTP API
|
|
411
359
|
try:
|
|
@@ -416,7 +364,7 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
416
364
|
"text": "Sample todo from all-in-one app",
|
|
417
365
|
}
|
|
418
366
|
req = Request(
|
|
419
|
-
"http://127.0.0.1:
|
|
367
|
+
f"http://127.0.0.1:{server_port}/walker/create_todo",
|
|
420
368
|
data=json.dumps(payload).encode("utf-8"),
|
|
421
369
|
headers={"Content-Type": "application/json"},
|
|
422
370
|
method="POST",
|
|
@@ -447,7 +395,7 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
447
395
|
"password": test_password,
|
|
448
396
|
}
|
|
449
397
|
req_register = Request(
|
|
450
|
-
"http://127.0.0.1:
|
|
398
|
+
f"http://127.0.0.1:{server_port}/user/register",
|
|
451
399
|
data=json.dumps(register_payload).encode("utf-8"),
|
|
452
400
|
headers={"Content-Type": "application/json"},
|
|
453
401
|
method="POST",
|
|
@@ -488,7 +436,7 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
488
436
|
"password": test_password,
|
|
489
437
|
}
|
|
490
438
|
req_login = Request(
|
|
491
|
-
"http://127.0.0.1:
|
|
439
|
+
f"http://127.0.0.1:{server_port}/user/login",
|
|
492
440
|
data=json.dumps(login_payload).encode("utf-8"),
|
|
493
441
|
headers={"Content-Type": "application/json"},
|
|
494
442
|
method="POST",
|
|
@@ -524,7 +472,7 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
524
472
|
"password": "wrong_password",
|
|
525
473
|
}
|
|
526
474
|
req_invalid_login = Request(
|
|
527
|
-
"http://127.0.0.1:
|
|
475
|
+
f"http://127.0.0.1:{server_port}/user/login",
|
|
528
476
|
data=json.dumps(invalid_login_payload).encode("utf-8"),
|
|
529
477
|
headers={"Content-Type": "application/json"},
|
|
530
478
|
method="POST",
|
|
@@ -611,10 +559,10 @@ def test_all_in_one_app_endpoints() -> None:
|
|
|
611
559
|
|
|
612
560
|
|
|
613
561
|
def test_default_client_app_renders() -> None:
|
|
614
|
-
"""Test that a default `jac create --
|
|
562
|
+
"""Test that a default `jac create --use client` app renders correctly when served.
|
|
615
563
|
|
|
616
564
|
This test validates the out-of-the-box experience:
|
|
617
|
-
1. Creates a new client app using `jac create --
|
|
565
|
+
1. Creates a new client app using `jac create --use client`
|
|
618
566
|
2. Installs packages
|
|
619
567
|
3. Starts the server
|
|
620
568
|
4. Validates that the default app renders with expected content
|
|
@@ -631,11 +579,13 @@ def test_default_client_app_renders() -> None:
|
|
|
631
579
|
print(f"[DEBUG] Changed working directory to {temp_dir}")
|
|
632
580
|
|
|
633
581
|
# 1. Create a new default Jac client app
|
|
634
|
-
jac_cmd =
|
|
635
|
-
env =
|
|
636
|
-
print(
|
|
582
|
+
jac_cmd = get_jac_command()
|
|
583
|
+
env = get_env_with_npm()
|
|
584
|
+
print(
|
|
585
|
+
f"[DEBUG] Running '{' '.join(jac_cmd)} create --use client {app_name}'"
|
|
586
|
+
)
|
|
637
587
|
process = Popen(
|
|
638
|
-
[*jac_cmd, "create", "--
|
|
588
|
+
[*jac_cmd, "create", "--use", "client", app_name],
|
|
639
589
|
stdin=PIPE,
|
|
640
590
|
stdout=PIPE,
|
|
641
591
|
stderr=PIPE,
|
|
@@ -646,18 +596,18 @@ def test_default_client_app_renders() -> None:
|
|
|
646
596
|
returncode = process.returncode
|
|
647
597
|
|
|
648
598
|
print(
|
|
649
|
-
f"[DEBUG] 'jac create --
|
|
599
|
+
f"[DEBUG] 'jac create --use client' completed returncode={returncode}\n"
|
|
650
600
|
f"STDOUT:\n{stdout}\n"
|
|
651
601
|
f"STDERR:\n{stderr}\n"
|
|
652
602
|
)
|
|
653
603
|
|
|
654
|
-
if returncode != 0 and "unrecognized arguments: --
|
|
604
|
+
if returncode != 0 and "unrecognized arguments: --use" in stderr:
|
|
655
605
|
pytest.fail(
|
|
656
|
-
"Test failed: installed `jac` CLI does not support `create --
|
|
606
|
+
"Test failed: installed `jac` CLI does not support `create --use client`."
|
|
657
607
|
)
|
|
658
608
|
|
|
659
609
|
assert returncode == 0, (
|
|
660
|
-
f"jac create --
|
|
610
|
+
f"jac create --use client failed\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}\n"
|
|
661
611
|
)
|
|
662
612
|
|
|
663
613
|
project_path = os.path.join(temp_dir, app_name)
|
|
@@ -679,46 +629,52 @@ def test_default_client_app_renders() -> None:
|
|
|
679
629
|
jac_toml_path = os.path.join(project_path, "jac.toml")
|
|
680
630
|
assert os.path.isfile(jac_toml_path), "jac.toml should exist"
|
|
681
631
|
|
|
682
|
-
# 2. Ensure packages are installed (jac create --
|
|
683
|
-
# If node_modules doesn't exist, run jac add --
|
|
632
|
+
# 2. Ensure packages are installed (jac create --use client should have done this)
|
|
633
|
+
# If node_modules doesn't exist, run jac add --npm
|
|
684
634
|
node_modules_path = os.path.join(
|
|
685
635
|
project_path, ".jac", "client", "node_modules"
|
|
686
636
|
)
|
|
687
637
|
if not os.path.isdir(node_modules_path):
|
|
688
|
-
print("[DEBUG] node_modules not found, running 'jac add --
|
|
638
|
+
print("[DEBUG] node_modules not found, running 'jac add --npm'")
|
|
689
639
|
jac_add_result = run(
|
|
690
|
-
[*jac_cmd, "add", "--
|
|
640
|
+
[*jac_cmd, "add", "--npm"],
|
|
691
641
|
cwd=project_path,
|
|
692
642
|
capture_output=True,
|
|
693
643
|
text=True,
|
|
694
644
|
env=env,
|
|
695
645
|
)
|
|
696
646
|
print(
|
|
697
|
-
f"[DEBUG] 'jac add --
|
|
647
|
+
f"[DEBUG] 'jac add --npm' completed returncode={jac_add_result.returncode}\n"
|
|
698
648
|
f"STDOUT (truncated):\n{jac_add_result.stdout[:1000]}\n"
|
|
699
649
|
f"STDERR (truncated):\n{jac_add_result.stderr[:1000]}\n"
|
|
700
650
|
)
|
|
701
651
|
if jac_add_result.returncode != 0:
|
|
702
652
|
pytest.fail(
|
|
703
|
-
f"jac add --
|
|
653
|
+
f"jac add --npm failed\n"
|
|
704
654
|
f"STDOUT:\n{jac_add_result.stdout}\n"
|
|
705
655
|
f"STDERR:\n{jac_add_result.stderr}\n"
|
|
706
656
|
)
|
|
707
657
|
|
|
708
658
|
# 3. Start the server (now uses main.jac at project root)
|
|
709
659
|
server: Popen[bytes] | None = None
|
|
660
|
+
# Use dynamic port allocation to avoid conflicts when running tests in parallel
|
|
661
|
+
server_port = get_free_port()
|
|
710
662
|
try:
|
|
711
|
-
print(
|
|
663
|
+
print(
|
|
664
|
+
f"[DEBUG] Starting server with 'jac start main.jac -p {server_port}'"
|
|
665
|
+
)
|
|
712
666
|
server = Popen(
|
|
713
|
-
[*jac_cmd, "start", "main.jac"],
|
|
667
|
+
[*jac_cmd, "start", "main.jac", "-p", str(server_port)],
|
|
714
668
|
cwd=project_path,
|
|
715
669
|
env=env,
|
|
716
670
|
)
|
|
717
671
|
|
|
718
672
|
# Wait for server to be ready
|
|
719
|
-
print("[DEBUG] Waiting for server on 127.0.0.1:
|
|
720
|
-
|
|
721
|
-
print(
|
|
673
|
+
print(f"[DEBUG] Waiting for server on 127.0.0.1:{server_port}")
|
|
674
|
+
wait_for_port("127.0.0.1", server_port, timeout=90.0)
|
|
675
|
+
print(
|
|
676
|
+
f"[DEBUG] Server is accepting connections on 127.0.0.1:{server_port}"
|
|
677
|
+
)
|
|
722
678
|
|
|
723
679
|
# 4. Test root endpoint - for client-only apps, root serves the HTML app
|
|
724
680
|
# Note: The root endpoint may return 503 while the client bundle is building.
|
|
@@ -726,7 +682,7 @@ def test_default_client_app_renders() -> None:
|
|
|
726
682
|
try:
|
|
727
683
|
print("[DEBUG] Testing root endpoint / (with retry)")
|
|
728
684
|
root_bytes = _wait_for_endpoint(
|
|
729
|
-
"http://127.0.0.1:
|
|
685
|
+
f"http://127.0.0.1:{server_port}",
|
|
730
686
|
timeout=120.0,
|
|
731
687
|
poll_interval=2.0,
|
|
732
688
|
request_timeout=30.0,
|
|
@@ -750,7 +706,7 @@ def test_default_client_app_renders() -> None:
|
|
|
750
706
|
try:
|
|
751
707
|
print("[DEBUG] Testing client app endpoint /cl/app")
|
|
752
708
|
page_bytes = _wait_for_endpoint(
|
|
753
|
-
"http://127.0.0.1:
|
|
709
|
+
f"http://127.0.0.1:{server_port}/cl/app",
|
|
754
710
|
timeout=120.0,
|
|
755
711
|
poll_interval=2.0,
|
|
756
712
|
request_timeout=30.0,
|
|
@@ -786,7 +742,7 @@ def test_default_client_app_renders() -> None:
|
|
|
786
742
|
)
|
|
787
743
|
if script_match:
|
|
788
744
|
js_path = script_match.group(1)
|
|
789
|
-
js_url = f"http://127.0.0.1:
|
|
745
|
+
js_url = f"http://127.0.0.1:{server_port}{js_path}"
|
|
790
746
|
print(f"[DEBUG] Fetching JS bundle from {js_url}")
|
|
791
747
|
with urlopen(js_url, timeout=30) as resp:
|
|
792
748
|
js_body = resp.read().decode("utf-8", errors="ignore")
|