From b37ef59669b894745156cca8ccf0417193c29826 Mon Sep 17 00:00:00 2001 From: Adam Wildavsky Date: Mon, 8 Jun 2026 11:33:57 -0400 Subject: [PATCH 1/7] =?UTF-8?q?web/tests/test=5Fdds=5Fmvp=5Fjs.py=20?= =?UTF-8?q?=E2=80=94=20Resolves=20dds=5Fmvp.js=20via=20rlocation()=20and?= =?UTF-8?q?=20passes=20it=20to=20Node=20as=20DDS=5FMVP=5FJS=20(reliable=20?= =?UTF-8?q?under=20Bazel=20on=20Linux).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit web/tests/dds_mvp_test.mjs — Uses DDS_MVP_JS first, with fallbacks for direct node --test runs from the repo. --- web/tests/dds_mvp_test.mjs | 17 ++++++++++------- web/tests/test_dds_mvp_js.py | 4 ++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/web/tests/dds_mvp_test.mjs b/web/tests/dds_mvp_test.mjs index d19fba6c..779db510 100644 --- a/web/tests/dds_mvp_test.mjs +++ b/web/tests/dds_mvp_test.mjs @@ -16,10 +16,14 @@ import { createContext, runInContext } from "node:vm"; const DIRECTIONS = ["north", "east", "south", "west"]; const SUITS = ["spades", "hearts", "diamonds", "clubs"]; -function findWebRoot() { +function findDdsMvpJsPath() { + if (process.env.DDS_MVP_JS && existsSync(process.env.DDS_MVP_JS)) { + return process.env.DDS_MVP_JS; + } + const here = dirname(fileURLToPath(import.meta.url)); - const adjacent = join(here, ".."); - if (existsSync(join(adjacent, "dds_mvp.js"))) { + const adjacent = join(here, "..", "dds_mvp.js"); + if (existsSync(adjacent)) { return adjacent; } @@ -27,9 +31,9 @@ function findWebRoot() { if (!base) { continue; } - for (const sub of ["web", "_main/web"]) { + for (const sub of ["web/dds_mvp.js", "_main/web/dds_mvp.js"]) { const candidate = join(base, sub); - if (existsSync(join(candidate, "dds_mvp.js"))) { + if (existsSync(candidate)) { return candidate; } } @@ -92,8 +96,7 @@ function createMockDocument(initialValues = {}) { } function loadDdsMvp(document) { - const webRoot = findWebRoot(); - const code = readFileSync(join(webRoot, "dds_mvp.js"), "utf8"); + const code = readFileSync(findDdsMvpJsPath(), "utf8"); const sandbox = { document, console, diff --git a/web/tests/test_dds_mvp_js.py b/web/tests/test_dds_mvp_js.py index 32beed3c..ac2df6ae 100644 --- a/web/tests/test_dds_mvp_js.py +++ b/web/tests/test_dds_mvp_js.py @@ -38,11 +38,15 @@ def test_dds_mvp_js(self) -> None: assert node is not None test_script = rlocation("web/tests/dds_mvp_test.mjs") + dds_mvp_js = rlocation("web/dds_mvp.js") + env = os.environ.copy() + env["DDS_MVP_JS"] = str(dds_mvp_js) proc = subprocess.run( [node, "--test", str(test_script)], capture_output=True, text=True, check=False, + env=env, ) self.assertEqual( proc.returncode, From 6a7338054f1d863fbebe0063797d231affdb5a02 Mon Sep 17 00:00:00 2001 From: Adam Wildavsky Date: Mon, 8 Jun 2026 22:08:37 -0400 Subject: [PATCH 2/7] Trigger CI workflow From 7b2d49c5ad8f6f83b1f9d1f2500de79976981a61 Mon Sep 17 00:00:00 2001 From: Adam Wildavsky Date: Mon, 8 Jun 2026 21:47:42 -0400 Subject: [PATCH 3/7] Fix dds_mvp_js_test on Linux CI and with focusNorthSpades. Pass the resolved dds_mvp.js path via DDS_MVP_JS for Bazel runfiles, and add focus() to mock DOM elements so clearTestData and pageLoad work when merged with web changes. Co-authored-by: Cursor --- web/tests/dds_mvp_test.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/web/tests/dds_mvp_test.mjs b/web/tests/dds_mvp_test.mjs index 779db510..03908415 100644 --- a/web/tests/dds_mvp_test.mjs +++ b/web/tests/dds_mvp_test.mjs @@ -50,6 +50,7 @@ function createMockDocument(initialValues = {}) { id, value: initialValues[id] ?? "", innerHTML: "", + focus() {}, }; store.set(id, element); return element; From 8a2417fea74d4f72f1200ce57e856e10a4455205 Mon Sep 17 00:00:00 2001 From: Adam Wildavsky Date: Wed, 10 Jun 2026 19:15:57 +0100 Subject: [PATCH 4/7] Apply Copilot's suggestions Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- web/tests/test_dds_mvp_js.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/web/tests/test_dds_mvp_js.py b/web/tests/test_dds_mvp_js.py index ac2df6ae..199eb962 100644 --- a/web/tests/test_dds_mvp_js.py +++ b/web/tests/test_dds_mvp_js.py @@ -35,19 +35,24 @@ def rlocation(relpath: str) -> Path: class DdsMvpJsTest(unittest.TestCase): def test_dds_mvp_js(self) -> None: node = shutil.which("node") - assert node is not None + if not node: + raise unittest.SkipTest("node not found") test_script = rlocation("web/tests/dds_mvp_test.mjs") dds_mvp_js = rlocation("web/dds_mvp.js") env = os.environ.copy() env["DDS_MVP_JS"] = str(dds_mvp_js) - proc = subprocess.run( - [node, "--test", str(test_script)], - capture_output=True, - text=True, - check=False, - env=env, - ) + try: + proc = subprocess.run( + [node, "--test", str(test_script)], + capture_output=True, + text=True, + check=False, + env=env, + timeout=60, + ) + except subprocess.TimeoutExpired as exc: + self.fail(f"node --test timed out: {exc}") self.assertEqual( proc.returncode, 0, From 31bab8db385b559a43b362f02bab70a41bfa1537 Mon Sep 17 00:00:00 2001 From: Adam Wildavsky Date: Thu, 11 Jun 2026 16:59:19 -0400 Subject: [PATCH 5/7] Restore Node version gate lost in develop merge. Re-add SkipTest when Node is missing, too old for `node --test` (<18), or when `node --version` hangs. Lower the subprocess timeout to 55s so Python fails cleanly before Bazel's 60s short timeout. --- web/tests/test_dds_mvp_js.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/web/tests/test_dds_mvp_js.py b/web/tests/test_dds_mvp_js.py index 89a82b19..e0d247b4 100644 --- a/web/tests/test_dds_mvp_js.py +++ b/web/tests/test_dds_mvp_js.py @@ -37,6 +37,23 @@ def test_dds_mvp_js(self) -> None: if not node: raise unittest.SkipTest("node not found") + try: + version = subprocess.run( + [node, "--version"], + capture_output=True, + text=True, + check=False, + timeout=5, + ).stdout.strip() + except subprocess.TimeoutExpired: + raise unittest.SkipTest("node --version timed out") + try: + major = int(version.lstrip("v").split(".", 1)[0]) + except ValueError: + raise unittest.SkipTest(f"could not parse node version: {version!r}") + if major < 18: + raise unittest.SkipTest(f"node >= 18 required for `node --test` (found {version})") + test_script = rlocation("web/tests/dds_mvp_test.mjs") dds_mvp_js = rlocation("web/dds_mvp.js") env = os.environ.copy() @@ -48,7 +65,7 @@ def test_dds_mvp_js(self) -> None: text=True, check=False, env=env, - timeout=60, + timeout=55, ) except subprocess.TimeoutExpired as exc: self.fail(f"node --test timed out: {exc}") From a2c8376e99f453f942c65ff62456f94f19c1c843 Mon Sep 17 00:00:00 2001 From: Adam Wildavsky Date: Thu, 11 Jun 2026 20:01:30 -0400 Subject: [PATCH 6/7] Add code from develop lost during merge: Resolve dds_mvp.js via rlocation and DDS_MVP_JS so the test works under Bazel on Linux. Skip when Node is missing, too old for `node --test` (<18), or when `node --version` hangs. Add a 55s subprocess timeout so Python fails cleanly before Bazel's 60s short timeout. --- dds.code-workspace | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 dds.code-workspace diff --git a/dds.code-workspace b/dds.code-workspace new file mode 100644 index 00000000..876a1499 --- /dev/null +++ b/dds.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file From f75d4c4475ffc3dd4c8c16ef19d1a5cd0b99c67e Mon Sep 17 00:00:00 2001 From: Adam Wildavsky Date: Fri, 12 Jun 2026 01:14:47 +0100 Subject: [PATCH 7/7] Delete dds.code-workspace - should have been in .gitignore --- dds.code-workspace | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 dds.code-workspace diff --git a/dds.code-workspace b/dds.code-workspace deleted file mode 100644 index 876a1499..00000000 --- a/dds.code-workspace +++ /dev/null @@ -1,8 +0,0 @@ -{ - "folders": [ - { - "path": "." - } - ], - "settings": {} -} \ No newline at end of file