From 6cdcc6268db8c29abe361f1886fa343dc601ddfc Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Fri, 13 Mar 2026 10:46:11 +0100 Subject: [PATCH 1/3] Prevent build tests from failing silently --- lib_dev/process.js | 20 +++++++++++++++++++ tests/build_tests/case3/input.js | 4 ++-- tests/build_tests/custom_namespace/input.js | 4 ++-- tests/build_tests/devonly/input.js | 4 ++-- tests/build_tests/exports/input.js | 4 ++-- tests/build_tests/hyphen2/input.js | 4 ++-- .../jsx_settings_inheritance/input.js | 4 ++-- tests/build_tests/nested/input.js | 4 ++-- tests/build_tests/nnest/input.js | 4 ++-- tests/build_tests/ns/input.js | 4 ++-- tests/build_tests/react_ppx/input.js | 4 ++-- .../transitive_dependency/input.js | 4 ++-- tests/build_tests/uncurried-always/input.js | 4 ++-- tests/build_tests/unicode/input.js | 4 ++-- tests/build_tests/x-y/input.js | 4 ++-- 15 files changed, 48 insertions(+), 28 deletions(-) diff --git a/lib_dev/process.js b/lib_dev/process.js index 469c653ffcf..6a7d0cfb0c4 100644 --- a/lib_dev/process.js +++ b/lib_dev/process.js @@ -32,6 +32,7 @@ export const { execBin, rescript, execBuild, + execBuildOrThrow, execClean, } = setup(); @@ -196,6 +197,25 @@ export function setup(cwd = process.cwd()) { return exec(rescript_exe, ["build", ...args], options); }, + /** + * Execute ReScript `build` command directly and throw on non-zero exit + * while preserving captured stdout/stderr for quiet successful tests. + * + * @param {string[]} [args] + * @param {ExecOptions} [options] + * @return {Promise} + */ + async execBuildOrThrow(args = [], options = {}) { + const out = await exec(rescript_exe, ["build", ...args], options); + if (out.status !== 0) { + const err = new Error("ReScript build failed"); + err.stack = out.stdout + out.stderr; + Object.assign(err, { execResult: out }); + throw err; + } + return out; + }, + /** * Execute ReScript `clean` command directly * diff --git a/tests/build_tests/case3/input.js b/tests/build_tests/case3/input.js index d2a494dc429..009ce15184b 100644 --- a/tests/build_tests/case3/input.js +++ b/tests/build_tests/case3/input.js @@ -5,10 +5,10 @@ import fs from "node:fs/promises"; import path from "node:path"; import { setup } from "#dev/process"; -const { execBuild, execClean } = setup(import.meta.dirname); +const { execBuildOrThrow, execClean } = setup(import.meta.dirname); await execClean(); -await execBuild(); +await execBuildOrThrow(); const o = await fs.readFile(path.join("src", "hello.res.js"), "ascii"); assert.ok(/HelloGen\.f/.test(o)); diff --git a/tests/build_tests/custom_namespace/input.js b/tests/build_tests/custom_namespace/input.js index 718d172356a..80893892e12 100644 --- a/tests/build_tests/custom_namespace/input.js +++ b/tests/build_tests/custom_namespace/input.js @@ -1,10 +1,10 @@ import * as assert from "node:assert"; import { setup } from "#dev/process"; -const { execClean, execBuild } = setup(import.meta.dirname); +const { execClean, execBuildOrThrow } = setup(import.meta.dirname); await execClean(); -await execBuild(); +await execBuildOrThrow(); const x = await import("./src/demo.res.js"); assert.equal(x.v, 42); diff --git a/tests/build_tests/devonly/input.js b/tests/build_tests/devonly/input.js index 50a4ceabd18..4df37430ada 100644 --- a/tests/build_tests/devonly/input.js +++ b/tests/build_tests/devonly/input.js @@ -2,6 +2,6 @@ import { setup } from "#dev/process"; -const { execBuild } = setup(import.meta.dirname); +const { execBuildOrThrow } = setup(import.meta.dirname); -await execBuild(); +await execBuildOrThrow(); diff --git a/tests/build_tests/exports/input.js b/tests/build_tests/exports/input.js index dd8449f36b2..209170d17dc 100644 --- a/tests/build_tests/exports/input.js +++ b/tests/build_tests/exports/input.js @@ -2,7 +2,7 @@ import { setup } from "#dev/process"; -const { execBuild, execClean } = setup(import.meta.dirname); +const { execBuildOrThrow, execClean } = setup(import.meta.dirname); -await execBuild(); +await execBuildOrThrow(); await execClean(); diff --git a/tests/build_tests/hyphen2/input.js b/tests/build_tests/hyphen2/input.js index dd8449f36b2..209170d17dc 100644 --- a/tests/build_tests/hyphen2/input.js +++ b/tests/build_tests/hyphen2/input.js @@ -2,7 +2,7 @@ import { setup } from "#dev/process"; -const { execBuild, execClean } = setup(import.meta.dirname); +const { execBuildOrThrow, execClean } = setup(import.meta.dirname); -await execBuild(); +await execBuildOrThrow(); await execClean(); diff --git a/tests/build_tests/jsx_settings_inheritance/input.js b/tests/build_tests/jsx_settings_inheritance/input.js index 6d8beddd227..87b4895e426 100644 --- a/tests/build_tests/jsx_settings_inheritance/input.js +++ b/tests/build_tests/jsx_settings_inheritance/input.js @@ -2,7 +2,7 @@ import { setup } from "#dev/process"; -const { execBuild, execClean } = setup(import.meta.dirname); +const { execBuildOrThrow, execClean } = setup(import.meta.dirname); await execClean(); -await execBuild(); +await execBuildOrThrow(); diff --git a/tests/build_tests/nested/input.js b/tests/build_tests/nested/input.js index 16b721cac26..0d5bc6809ce 100644 --- a/tests/build_tests/nested/input.js +++ b/tests/build_tests/nested/input.js @@ -5,9 +5,9 @@ import * as fs from "node:fs/promises"; import * as path from "node:path"; import { setup } from "#dev/process"; -const { execBuild, execClean } = setup(import.meta.dirname); +const { execBuildOrThrow, execClean } = setup(import.meta.dirname); -await execBuild(); +await execBuildOrThrow(); const content = await fs.readFile( path.join(import.meta.dirname, "src", "demo.js"), diff --git a/tests/build_tests/nnest/input.js b/tests/build_tests/nnest/input.js index bef91995b48..5ac0957f6a7 100644 --- a/tests/build_tests/nnest/input.js +++ b/tests/build_tests/nnest/input.js @@ -5,9 +5,9 @@ import * as fs from "node:fs/promises"; import * as path from "node:path"; import { setup } from "#dev/process"; -const { execBuild, execClean } = setup(import.meta.dirname); +const { execBuildOrThrow, execClean } = setup(import.meta.dirname); -await execBuild(); +await execBuildOrThrow(); const content = await fs.readFile( path.join(import.meta.dirname, "src", "demo.js"), diff --git a/tests/build_tests/ns/input.js b/tests/build_tests/ns/input.js index 50a4ceabd18..4df37430ada 100755 --- a/tests/build_tests/ns/input.js +++ b/tests/build_tests/ns/input.js @@ -2,6 +2,6 @@ import { setup } from "#dev/process"; -const { execBuild } = setup(import.meta.dirname); +const { execBuildOrThrow } = setup(import.meta.dirname); -await execBuild(); +await execBuildOrThrow(); diff --git a/tests/build_tests/react_ppx/input.js b/tests/build_tests/react_ppx/input.js index 50a4ceabd18..4df37430ada 100644 --- a/tests/build_tests/react_ppx/input.js +++ b/tests/build_tests/react_ppx/input.js @@ -2,6 +2,6 @@ import { setup } from "#dev/process"; -const { execBuild } = setup(import.meta.dirname); +const { execBuildOrThrow } = setup(import.meta.dirname); -await execBuild(); +await execBuildOrThrow(); diff --git a/tests/build_tests/transitive_dependency/input.js b/tests/build_tests/transitive_dependency/input.js index 765a1f4c7ad..0c81dc9bcc5 100644 --- a/tests/build_tests/transitive_dependency/input.js +++ b/tests/build_tests/transitive_dependency/input.js @@ -5,9 +5,9 @@ import { existsSync } from "node:fs"; import * as path from "node:path"; import { setup } from "#dev/process"; -const { execBuild, execClean } = setup(path.join(import.meta.dirname, "a")); +const { execBuildOrThrow, execClean } = setup(path.join(import.meta.dirname, "a")); await execClean(); -await execBuild(); +await execBuildOrThrow(); assert.ok( !existsSync( diff --git a/tests/build_tests/uncurried-always/input.js b/tests/build_tests/uncurried-always/input.js index dd8449f36b2..209170d17dc 100644 --- a/tests/build_tests/uncurried-always/input.js +++ b/tests/build_tests/uncurried-always/input.js @@ -2,7 +2,7 @@ import { setup } from "#dev/process"; -const { execBuild, execClean } = setup(import.meta.dirname); +const { execBuildOrThrow, execClean } = setup(import.meta.dirname); -await execBuild(); +await execBuildOrThrow(); await execClean(); diff --git a/tests/build_tests/unicode/input.js b/tests/build_tests/unicode/input.js index c6cdc701f83..7c68350b899 100644 --- a/tests/build_tests/unicode/input.js +++ b/tests/build_tests/unicode/input.js @@ -4,14 +4,14 @@ import * as fs from "node:fs/promises"; import * as path from "node:path"; import { setup } from "#dev/process"; -const { execBuild, execClean } = setup(import.meta.dirname); +const { execBuildOrThrow, execClean } = setup(import.meta.dirname); if (process.platform === "win32") { console.log("Skipping test on Windows"); process.exit(0); } -await execBuild(); +await execBuildOrThrow(); await fs.access( path.join(import.meta.dirname, "lib", "bs", "src", "đŸ“•annotation", "a.js"), diff --git a/tests/build_tests/x-y/input.js b/tests/build_tests/x-y/input.js index dd8449f36b2..209170d17dc 100644 --- a/tests/build_tests/x-y/input.js +++ b/tests/build_tests/x-y/input.js @@ -2,7 +2,7 @@ import { setup } from "#dev/process"; -const { execBuild, execClean } = setup(import.meta.dirname); +const { execBuildOrThrow, execClean } = setup(import.meta.dirname); -await execBuild(); +await execBuildOrThrow(); await execClean(); From f5018b0a9fe2320197be74f4b8d07fe99f3c44e9 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Fri, 13 Mar 2026 10:59:34 +0100 Subject: [PATCH 2/3] Fix failing build tests --- tests/build_tests/exports/input.js | 1 + tests/build_tests/react_ppx/src/gpr_3695_test.res | 2 +- tests/build_tests/transitive_dependency/a/tests/test.res | 2 +- tests/build_tests/transitive_dependency/input.js | 4 +++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/build_tests/exports/input.js b/tests/build_tests/exports/input.js index 209170d17dc..e5cbd070df4 100644 --- a/tests/build_tests/exports/input.js +++ b/tests/build_tests/exports/input.js @@ -4,5 +4,6 @@ import { setup } from "#dev/process"; const { execBuildOrThrow, execClean } = setup(import.meta.dirname); +await execClean(); await execBuildOrThrow(); await execClean(); diff --git a/tests/build_tests/react_ppx/src/gpr_3695_test.res b/tests/build_tests/react_ppx/src/gpr_3695_test.res index e190a476908..d089c2e36f9 100644 --- a/tests/build_tests/react_ppx/src/gpr_3695_test.res +++ b/tests/build_tests/react_ppx/src/gpr_3695_test.res @@ -1,6 +1,6 @@ module React = { type element - type componentLike<'props, 'return> = 'props => 'return + type component<'props> = 'props => element } module Test = { diff --git a/tests/build_tests/transitive_dependency/a/tests/test.res b/tests/build_tests/transitive_dependency/a/tests/test.res index aa7a48d65d5..6b797705d41 100644 --- a/tests/build_tests/transitive_dependency/a/tests/test.res +++ b/tests/build_tests/transitive_dependency/a/tests/test.res @@ -1 +1 @@ -Js.Console.log("test") +Console.log("test") diff --git a/tests/build_tests/transitive_dependency/input.js b/tests/build_tests/transitive_dependency/input.js index 0c81dc9bcc5..48f21ab2bee 100644 --- a/tests/build_tests/transitive_dependency/input.js +++ b/tests/build_tests/transitive_dependency/input.js @@ -5,7 +5,9 @@ import { existsSync } from "node:fs"; import * as path from "node:path"; import { setup } from "#dev/process"; -const { execBuildOrThrow, execClean } = setup(path.join(import.meta.dirname, "a")); +const { execBuildOrThrow, execClean } = setup( + path.join(import.meta.dirname, "a"), +); await execClean(); await execBuildOrThrow(); From d08b8fc37291fb77f6721bdc5bb903cda237d073 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Fri, 13 Mar 2026 11:06:20 +0100 Subject: [PATCH 3/3] CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4ff09d91bb..7ae7e25f5b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ #### :house: Internal - Reanalyze server: redesign incremental fixpoint with delete-then-rederive strategy and predecessor tracking, improving speed on deletions. https://github.com/rescript-lang/rescript/pull/8276 +- Fix build tests failing silently. https://github.com/rescript-lang/rescript/pull/8295 # 13.0.0-alpha.2