Upload 17 files
Browse files- tests/test_bucket_urls.py +29 -0
- tests/test_custom_ui_shell.py +77 -219
- tests/test_pass46_ui_regressions.py +6 -7
- tests/test_pass47_simple_spec_reset.py +18 -29
- tests/test_run_bundle_details.py +1 -1
tests/test_bucket_urls.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from src.bucket import summarize_run_bundle
|
| 2 |
+
from src.view_models import build_run_view_model
|
| 3 |
+
import app
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def test_bucket_artifact_tree_url_has_no_main_segment():
|
| 7 |
+
url = app._run_artifacts_url("gist-20260602-120645-a145824d", "fffiloni/space-factory-runs")
|
| 8 |
+
assert url == "https://huggingface.co/buckets/fffiloni/space-factory-runs/tree/runs/gist-20260602-120645-a145824d"
|
| 9 |
+
assert "/tree/main/runs/" not in url
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def test_run_summary_artifact_url_has_no_main_segment():
|
| 13 |
+
summary = summarize_run_bundle(
|
| 14 |
+
"run-launch",
|
| 15 |
+
{"state": {"status": "running"}, "launch": {}, "summary_file": {}},
|
| 16 |
+
bucket_source="user/space-factory-runs",
|
| 17 |
+
)
|
| 18 |
+
assert summary["artifacts_url"] == "https://huggingface.co/buckets/user/space-factory-runs/tree/runs/run-launch"
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def test_view_model_artifact_url_has_no_main_segment():
|
| 22 |
+
bundle = {
|
| 23 |
+
"summary": {"status": "running", "created_at": "2026-06-02T12:00:00+00:00"},
|
| 24 |
+
"state": {},
|
| 25 |
+
"launch": {"status": "running"},
|
| 26 |
+
"events": [],
|
| 27 |
+
}
|
| 28 |
+
view = build_run_view_model("run-launch", bundle, bucket_source="user/space-factory-runs")
|
| 29 |
+
assert view["links"]["artifacts_url"] == "https://huggingface.co/buckets/user/space-factory-runs/tree/runs/run-launch"
|
tests/test_custom_ui_shell.py
CHANGED
|
@@ -1,242 +1,100 @@
|
|
| 1 |
from pathlib import Path
|
| 2 |
|
| 3 |
|
| 4 |
-
def
|
| 5 |
-
|
| 6 |
-
assert (root / "web" / "index.html").exists()
|
| 7 |
-
assert (root / "web" / "static" / "app.css").exists()
|
| 8 |
-
assert (root / "web" / "static" / "app.js").exists()
|
| 9 |
-
assert (root / "web" / "static" / "progress.js").exists()
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
def test_app_registers_custom_routes():
|
| 13 |
-
root = Path(__file__).resolve().parents[1]
|
| 14 |
-
content = (root / "app.py").read_text()
|
| 15 |
-
assert "def register_custom_routes" in content
|
| 16 |
-
assert '"/custom"' in content
|
| 17 |
-
assert '"/api/progress/from-events"' in content
|
| 18 |
-
assert '"/api/runs"' in content
|
| 19 |
|
| 20 |
|
| 21 |
-
def
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
"Run storage",
|
| 29 |
-
"Live job progress",
|
| 30 |
-
"Run details",
|
| 31 |
-
"Validation & metrics",
|
| 32 |
-
"Latest events",
|
| 33 |
-
]:
|
| 34 |
-
assert text in html
|
| 35 |
|
| 36 |
|
| 37 |
-
def
|
| 38 |
-
|
| 39 |
-
|
| 40 |
for route in [
|
|
|
|
| 41 |
'"/api/me"',
|
| 42 |
'"/api/bucket/status"',
|
| 43 |
'"/api/bucket/create"',
|
| 44 |
'"/api/build"',
|
| 45 |
'"/api/validate"',
|
|
|
|
| 46 |
'"/api/runs/{run_id}/progress"',
|
|
|
|
|
|
|
| 47 |
]:
|
| 48 |
assert route in content
|
| 49 |
-
assert "_oauth_context_from_request" in content
|
| 50 |
|
| 51 |
|
| 52 |
-
def
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
def test_custom_ui_has_run_detail_explorer():
|
| 69 |
-
root = Path(__file__).resolve().parents[1]
|
| 70 |
-
html = (root / "web" / "index.html").read_text()
|
| 71 |
-
for element_id in ["selectedRunId", "selectedModelId", "artifactList", "reportPreview", "runDetailStatus"]:
|
| 72 |
-
assert element_id in html
|
| 73 |
-
js = (root / "web" / "static" / "runs.js").read_text()
|
| 74 |
-
assert "selectRun" in js
|
| 75 |
-
assert "renderRunDetail" in js
|
| 76 |
-
assert "/api/runs/" in js
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
def test_custom_ui_renders_metrics_from_progress():
|
| 80 |
-
root = Path(__file__).resolve().parents[1]
|
| 81 |
-
js = (root / "web" / "static" / "app.js").read_text()
|
| 82 |
-
assert "function renderMetrics" in js
|
| 83 |
-
assert "generation_smoke" in js
|
| 84 |
-
assert "recommended_zerogpu_duration" in js
|
| 85 |
|
| 86 |
-
def test_custom_ui_has_selected_run_actions_and_manual_hardware_panel():
|
| 87 |
-
root = Path(__file__).resolve().parents[1]
|
| 88 |
-
html = (root / "web" / "index.html").read_text()
|
| 89 |
-
for element_id in ["manualActionPanel", "manualOpenSettings", "manualGoValidate", "selectedValidateBtn", "selectedOpenSettings", "selectedBlockers"]:
|
| 90 |
-
assert element_id in html
|
| 91 |
-
app_js = (root / "web" / "static" / "app.js").read_text()
|
| 92 |
-
assert "prepareValidationFromActiveRun" in app_js
|
| 93 |
-
assert "renderManualAction" in app_js
|
| 94 |
-
runs_js = (root / "web" / "static" / "runs.js").read_text()
|
| 95 |
-
assert "renderSelectedLinks" in runs_js
|
| 96 |
-
assert "renderBlockers" in runs_js
|
| 97 |
|
| 98 |
-
def
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
assert element_id in html
|
| 106 |
-
assert "runStatusFilter" in js
|
| 107 |
-
assert "localStorage.setItem('asf.activeRun'" in js
|
| 108 |
-
assert "restoreActiveRun" in js
|
| 109 |
-
assert "Progress polling failed" in js
|
| 110 |
-
assert "renderRunsFromCache" in runs_js
|
| 111 |
-
assert "state.runsCache" in runs_js
|
| 112 |
-
assert ".run-row.selected" in css
|
| 113 |
-
|
| 114 |
-
def test_custom_ui_has_oauth_status_panel_and_login_link():
|
| 115 |
-
root = Path(__file__).resolve().parents[1]
|
| 116 |
-
html = (root / "web" / "index.html").read_text()
|
| 117 |
-
js = (root / "web" / "static" / "app.js").read_text()
|
| 118 |
-
app_py = (root / "app.py").read_text()
|
| 119 |
-
assert "authPanel" in html
|
| 120 |
-
assert "renderAuthWarnings" in js
|
| 121 |
-
assert "/oauth/huggingface/login" in js
|
| 122 |
-
assert '"/api/oauth/diagnostics"' in app_py
|
| 123 |
-
assert "public_oauth_context" in app_py
|
| 124 |
-
|
| 125 |
-
def test_custom_ui_v30_bucket_gate_and_zerogpu_toggle():
|
| 126 |
-
root = Path(__file__).resolve().parents[1]
|
| 127 |
-
html = (root / "web" / "index.html").read_text()
|
| 128 |
-
js = (root / "web" / "static" / "app.js").read_text()
|
| 129 |
-
assert 'id="tryZeroGpu"' in html
|
| 130 |
-
assert 'disabled /> Try ZeroGPU first' not in html
|
| 131 |
-
assert 'id="launchBuild" disabled' in html
|
| 132 |
-
assert 'buildGateText' in html
|
| 133 |
-
assert 'effectivePreferredHardware' in js
|
| 134 |
-
assert 'setBucketReady' in js
|
| 135 |
-
assert 'Create or check your private run bucket before launching a build' in js
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
def test_custom_ui_v30_css_has_overflow_and_duplicate_cleanup():
|
| 139 |
-
root = Path(__file__).resolve().parents[1]
|
| 140 |
-
css = (root / "web" / "static" / "app.css").read_text()
|
| 141 |
-
assert '.app-shell{min-height:100vh;max-width:1540px' in css
|
| 142 |
-
assert '.top-tabs{display:flex' in css
|
| 143 |
-
assert '.runs-table{border:1px solid var(--line);border-radius:14px;padding:0;overflow:hidden' in css
|
| 144 |
-
assert 'font-family:ui-monospace' in css
|
| 145 |
-
assert '.auth-panel,.operation-status{' in css
|
| 146 |
-
|
| 147 |
-
def test_custom_ui_v31_feedback_and_loading_states():
|
| 148 |
-
root = Path(__file__).resolve().parents[1]
|
| 149 |
-
html = (root / "web" / "index.html").read_text()
|
| 150 |
-
js = (root / "web" / "static" / "app.js").read_text()
|
| 151 |
-
css = (root / "web" / "static" / "app.css").read_text()
|
| 152 |
-
api_js = (root / "web" / "static" / "api.js").read_text()
|
| 153 |
-
progress_js = (root / "web" / "static" / "progress.js").read_text()
|
| 154 |
-
assert "operationStatus" in html
|
| 155 |
-
assert "lastPolled" in html
|
| 156 |
-
assert "setOperation" in js
|
| 157 |
-
assert "setBusy" in js
|
| 158 |
-
assert "validateBuildForm" in js
|
| 159 |
-
assert "validateValidationForm" in js
|
| 160 |
-
assert "TERMINAL_STATUSES" in js
|
| 161 |
-
assert "Run bucket is not ready" in Path(root / "app.py").read_text()
|
| 162 |
-
assert ".operation-status" in css
|
| 163 |
-
assert "parseApiError" in api_js
|
| 164 |
-
assert "lastPolled" in progress_js
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
def test_v33_root_custom_ui_not_iframe_preview():
|
| 168 |
-
root = Path(__file__).resolve().parents[1]
|
| 169 |
-
app_py = (root / "app.py").read_text()
|
| 170 |
-
readme = (root / "README.md").read_text()
|
| 171 |
-
assert '@fastapi_app.get("/", response_class=HTMLResponse)' in app_py
|
| 172 |
-
assert 'attach_huggingface_oauth(fastapi_app)' in app_py
|
| 173 |
-
assert '<iframe src="/custom"' not in app_py
|
| 174 |
-
assert 'Custom UI preview' not in app_py
|
| 175 |
-
assert 'The product root (`/`) is the custom dashboard' in readme
|
| 176 |
|
| 177 |
|
| 178 |
-
def
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
js = (root / "web" / "static" / "app.js").read_text()
|
| 202 |
-
runs_js = (root / "web" / "static" / "runs.js").read_text()
|
| 203 |
-
css = (root / "web" / "static" / "app.css").read_text()
|
| 204 |
-
assert "prepareNewBuild" in html
|
| 205 |
-
assert "buildModePanel" in html
|
| 206 |
-
assert "Preparing a new build" in html
|
| 207 |
-
assert "function prepareNewBuild" in js
|
| 208 |
-
assert "setBuildModeInspecting" in js
|
| 209 |
-
assert "filteredRuns" in runs_js
|
| 210 |
-
assert "apiGet(`/api/runs?limit=100" in runs_js
|
| 211 |
-
assert "status=${encodeURIComponent(status)}" not in runs_js
|
| 212 |
-
assert ".build-mode-panel" in css
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
def test_v40_tabbed_ui_logout_and_compact_progress():
|
| 216 |
-
root = Path(__file__).resolve().parents[1]
|
| 217 |
-
html = (root / "web" / "index.html").read_text()
|
| 218 |
-
css = (root / "web" / "static" / "app.css").read_text()
|
| 219 |
-
js = (root / "web" / "static" / "app.js").read_text()
|
| 220 |
-
runs_js = (root / "web" / "static" / "runs.js").read_text()
|
| 221 |
-
assert 'class="top-tabs"' in html
|
| 222 |
-
assert 'data-view="progress"' in html
|
| 223 |
-
assert 'id="logoutLink"' in html
|
| 224 |
-
assert 'class="sidebar"' not in html
|
| 225 |
-
assert 'max-height:330px' not in css
|
| 226 |
-
assert 'overflow:auto;padding-right' not in css
|
| 227 |
-
assert "switchView('progress')" in js
|
| 228 |
-
assert 'inferredJobUrl' in runs_js
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
def test_v43_run_view_model_contract_is_exposed_to_custom_ui():
|
| 232 |
-
root = Path(__file__).resolve().parents[1]
|
| 233 |
-
app_py = (root / "app.py").read_text()
|
| 234 |
-
html = (root / "web" / "index.html").read_text()
|
| 235 |
-
js = (root / "web" / "static" / "app.js").read_text() + (root / "web" / "static" / "progress.js").read_text()
|
| 236 |
-
assert '"/api/runs/resumable"' in app_py
|
| 237 |
-
assert '"/api/runs/{run_id}/view"' in app_py
|
| 238 |
-
assert "build_run_view_model" in app_py
|
| 239 |
-
for element_id in ["runSummaryCard", "activityFeed", "zeroGpuChecklist", "issueCard", "spaceTestPreview"]:
|
| 240 |
-
assert element_id in html
|
| 241 |
-
assert "bootstrapRunRecovery" in js
|
| 242 |
-
assert "renderRunViewModel" in js
|
|
|
|
| 1 |
from pathlib import Path
|
| 2 |
|
| 3 |
|
| 4 |
+
def root() -> Path:
|
| 5 |
+
return Path(__file__).resolve().parents[1]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
|
| 8 |
+
def test_custom_ui_assets_exist():
|
| 9 |
+
base = root()
|
| 10 |
+
assert (base / "web" / "index.html").exists()
|
| 11 |
+
assert (base / "web" / "static" / "app.css").exists()
|
| 12 |
+
assert (base / "web" / "static" / "app.js").exists()
|
| 13 |
+
assert (base / "web" / "static" / "progress.js").exists()
|
| 14 |
+
assert (base / "web" / "static" / "runs.js").exists()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
|
| 17 |
+
def test_app_registers_custom_routes_and_bridge_endpoints():
|
| 18 |
+
content = (root() / "app.py").read_text(encoding="utf-8")
|
| 19 |
+
assert "def register_custom_routes" in content
|
| 20 |
for route in [
|
| 21 |
+
'"/custom"',
|
| 22 |
'"/api/me"',
|
| 23 |
'"/api/bucket/status"',
|
| 24 |
'"/api/bucket/create"',
|
| 25 |
'"/api/build"',
|
| 26 |
'"/api/validate"',
|
| 27 |
+
'"/api/runs"',
|
| 28 |
'"/api/runs/{run_id}/progress"',
|
| 29 |
+
'"/api/runs/resumable"',
|
| 30 |
+
'"/api/runs/{run_id}/view"',
|
| 31 |
]:
|
| 32 |
assert route in content
|
|
|
|
| 33 |
|
| 34 |
|
| 35 |
+
def test_one_page_workspace_contains_core_sections():
|
| 36 |
+
html = (root() / "web" / "index.html").read_text(encoding="utf-8")
|
| 37 |
+
for text in [
|
| 38 |
+
"New Build",
|
| 39 |
+
"Active Run",
|
| 40 |
+
"Runs Explorer",
|
| 41 |
+
"Selected run",
|
| 42 |
+
"Space Test",
|
| 43 |
+
"Validation result",
|
| 44 |
+
"Raw events",
|
| 45 |
+
"Full report",
|
| 46 |
+
"Artifacts",
|
| 47 |
+
"Run storage",
|
| 48 |
+
]:
|
| 49 |
+
assert text in html
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
|
| 52 |
+
def test_one_page_workspace_keeps_required_ids_for_live_bridge():
|
| 53 |
+
html = (root() / "web" / "index.html").read_text(encoding="utf-8")
|
| 54 |
+
required_ids = [
|
| 55 |
+
"launchBuild",
|
| 56 |
+
"checkBucket",
|
| 57 |
+
"createBucket",
|
| 58 |
+
"launchValidate",
|
| 59 |
+
"progressStatus",
|
| 60 |
+
"timeline",
|
| 61 |
+
"activityFeed",
|
| 62 |
+
"runFilters",
|
| 63 |
+
"runsTable",
|
| 64 |
+
"selectedRunId",
|
| 65 |
+
"artifactList",
|
| 66 |
+
"reportPreview",
|
| 67 |
+
"eventsPanel",
|
| 68 |
+
"spaceTestPreview",
|
| 69 |
+
"metricsList",
|
| 70 |
+
"manualActionPanel",
|
| 71 |
+
"selectedValidateBtn",
|
| 72 |
+
"resumeLatestRun",
|
| 73 |
+
]
|
| 74 |
+
for element_id in required_ids:
|
| 75 |
assert element_id in html
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
|
| 78 |
+
def test_frontend_calls_real_bridge_endpoints_and_keeps_run_logic():
|
| 79 |
+
app_js = (root() / "web" / "static" / "app.js").read_text(encoding="utf-8")
|
| 80 |
+
runs_js = (root() / "web" / "static" / "runs.js").read_text(encoding="utf-8")
|
| 81 |
+
progress_js = (root() / "web" / "static" / "progress.js").read_text(encoding="utf-8")
|
| 82 |
+
for endpoint in ["/api/me", "/api/build", "/api/validate", "/api/bucket/status", "/api/bucket/create"]:
|
| 83 |
+
assert endpoint in app_js
|
| 84 |
+
assert "selectRun" in runs_js
|
| 85 |
+
assert "renderRunDetail" in runs_js
|
| 86 |
+
assert "renderRunViewModel" in progress_js
|
| 87 |
+
assert "renderActivityFeed" in progress_js
|
| 88 |
+
assert "renderDiagnostics" in progress_js
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def test_css_contains_one_page_responsive_layout():
|
| 92 |
+
css = (root() / "web" / "static" / "app.css").read_text(encoding="utf-8")
|
| 93 |
+
for snippet in [
|
| 94 |
+
".workspace-grid{display:grid;grid-template-columns:360px minmax(0,1fr) 340px",
|
| 95 |
+
".space-test-grid{display:grid;grid-template-columns:minmax(0,1.15fr) 360px",
|
| 96 |
+
"word-break:normal",
|
| 97 |
+
".run-row.selected",
|
| 98 |
+
"@media (max-width: 860px)",
|
| 99 |
+
]:
|
| 100 |
+
assert snippet in css.replace(" ", "") if "word-break:normal" == snippet else snippet in css
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tests/test_pass46_ui_regressions.py
CHANGED
|
@@ -1,16 +1,15 @@
|
|
| 1 |
from pathlib import Path
|
| 2 |
|
| 3 |
|
| 4 |
-
def
|
| 5 |
text = Path("web/static/runs.js").read_text(encoding="utf-8")
|
| 6 |
-
select_run = text.split("async function selectRun", 1)[1].split("function
|
| 7 |
assert "switchView(" not in select_run
|
| 8 |
assert "Keep the user on the current tab" in select_run
|
| 9 |
|
| 10 |
|
| 11 |
-
def
|
| 12 |
css = Path("web/static/app.css").read_text(encoding="utf-8")
|
| 13 |
-
assert "
|
| 14 |
-
assert "
|
| 15 |
-
assert "grid-template-columns:1fr
|
| 16 |
-
assert ".nav-item{flex:0 0 auto" in css
|
|
|
|
| 1 |
from pathlib import Path
|
| 2 |
|
| 3 |
|
| 4 |
+
def test_selecting_run_still_does_not_force_hidden_navigation():
|
| 5 |
text = Path("web/static/runs.js").read_text(encoding="utf-8")
|
| 6 |
+
select_run = text.split("async function selectRun", 1)[1].split("function renderSelectedLinks", 1)[0]
|
| 7 |
assert "switchView(" not in select_run
|
| 8 |
assert "Keep the user on the current tab" in select_run
|
| 9 |
|
| 10 |
|
| 11 |
+
def test_mobile_css_prevents_letter_by_letter_wrapping_in_one_page_layout():
|
| 12 |
css = Path("web/static/app.css").read_text(encoding="utf-8")
|
| 13 |
+
assert "word-break:normal" in css.replace(" ", "")
|
| 14 |
+
assert "@media (max-width: 860px)" in css
|
| 15 |
+
assert ".workspace-grid,.space-test-grid,.editor-grid,.two-cols,.summary-meta-grid,.diagnostic-list,.bottom-split,.three-way,.run-storage,.test-top-row{grid-template-columns:1fr}".replace(" ", "") in css.replace(" ", "")
|
|
|
tests/test_pass47_simple_spec_reset.py
CHANGED
|
@@ -1,41 +1,30 @@
|
|
| 1 |
from pathlib import Path
|
| 2 |
|
| 3 |
|
| 4 |
-
def
|
| 5 |
html = Path("web/index.html").read_text(encoding="utf-8")
|
| 6 |
-
assert 'data-view="build"' in html
|
| 7 |
-
assert 'data-view="progress"' in html
|
| 8 |
-
assert 'data-view="validate"' in html
|
| 9 |
-
assert
|
| 10 |
-
assert
|
| 11 |
|
| 12 |
|
| 13 |
-
def
|
| 14 |
html = Path("web/index.html").read_text(encoding="utf-8")
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
assert "Launch result" in build_section
|
| 19 |
-
assert "runsTableHome" not in build_section
|
| 20 |
-
assert "Run Explorer" not in build_section
|
| 21 |
|
| 22 |
|
| 23 |
-
def
|
| 24 |
html = Path("web/index.html").read_text(encoding="utf-8")
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
assert required in runs_section
|
| 28 |
|
| 29 |
|
| 30 |
-
def
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
assert "
|
| 34 |
-
assert "
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
def test_pass47_mobile_layout_is_single_column_safe():
|
| 38 |
-
css = Path("web/static/app.css").read_text(encoding="utf-8")
|
| 39 |
-
assert "Pass 47: deliberately simple three-tab interface" in css
|
| 40 |
-
assert ".simple-build-grid,.simple-runs-grid,.simple-validate-grid,.simple-storage-card{grid-template-columns:1fr!important}" in css
|
| 41 |
-
assert "word-break: normal" in css
|
|
|
|
| 1 |
from pathlib import Path
|
| 2 |
|
| 3 |
|
| 4 |
+
def test_one_page_workspace_has_no_public_tabs_anymore():
|
| 5 |
html = Path("web/index.html").read_text(encoding="utf-8")
|
| 6 |
+
assert 'data-view="build"' not in html
|
| 7 |
+
assert 'data-view="progress"' not in html
|
| 8 |
+
assert 'data-view="validate"' not in html
|
| 9 |
+
assert "Runs Explorer" in html
|
| 10 |
+
assert "Active Run" in html
|
| 11 |
|
| 12 |
|
| 13 |
+
def test_new_build_panel_is_left_column_and_launch_focused():
|
| 14 |
html = Path("web/index.html").read_text(encoding="utf-8")
|
| 15 |
+
assert 'id="newBuildCard"' in html
|
| 16 |
+
for text in ["Launch a private Space", "Run storage", "Build private Space", "Launch result"]:
|
| 17 |
+
assert text in html
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
|
| 20 |
+
def test_runs_explorer_and_selected_run_are_integrated_on_same_page():
|
| 21 |
html = Path("web/index.html").read_text(encoding="utf-8")
|
| 22 |
+
for text in ["Runs Explorer", "Search runs by ID, model, or space", "Selected run", "Prefill Space Test"]:
|
| 23 |
+
assert text in html
|
|
|
|
| 24 |
|
| 25 |
|
| 26 |
+
def test_space_test_panel_is_inline_not_tabbed():
|
| 27 |
+
html = Path("web/index.html").read_text(encoding="utf-8")
|
| 28 |
+
assert 'id="spaceTestSection"' in html
|
| 29 |
+
assert "Validate an existing Space" in html
|
| 30 |
+
assert "Launch validation" in html
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tests/test_run_bundle_details.py
CHANGED
|
@@ -42,7 +42,7 @@ def test_summarize_run_bundle_recovers_launch_only_running_job():
|
|
| 42 |
assert summary["target_space"] == "alice/z-image"
|
| 43 |
assert summary["job_id"] == "abc123"
|
| 44 |
assert summary["job_url"].endswith("/abc123")
|
| 45 |
-
assert summary["artifacts_url"].endswith("/tree/
|
| 46 |
|
| 47 |
|
| 48 |
def test_summarize_run_bundle_uses_summary_file_fallback():
|
|
|
|
| 42 |
assert summary["target_space"] == "alice/z-image"
|
| 43 |
assert summary["job_id"] == "abc123"
|
| 44 |
assert summary["job_url"].endswith("/abc123")
|
| 45 |
+
assert summary["artifacts_url"].endswith("/tree/runs/run-launch")
|
| 46 |
|
| 47 |
|
| 48 |
def test_summarize_run_bundle_uses_summary_file_fallback():
|