From d133063ae6718368762ea0728debc6dd71c1019b Mon Sep 17 00:00:00 2001 From: James Onnen Date: Thu, 30 Jul 2026 00:54:05 -0700 Subject: [PATCH] fix(nevermore-cli): tag only the script template as the batch test entry combine-test-places tagged every Script under ServerScriptService with `_BatchTest_`, and batch-test-runner executes `GetTagged(...)[1]`. With one script in a project those are the same script; with two, the runner loadstrings whichever the tag listed first and the package's real test bootstrap never runs. Nothing catches it downstream either -- a script that returns without erroring reports as a pass, so the batch reports 0ms and no jest output for a suite that was never asked to run. The `scriptPath` each triple already carries -- the target's `scriptTemplate`, and what the single-package path executes -- is now injected as a Script under ReplicatedStorage._BatchScripts and is the only thing tagged, which is what the file's own header said it did. The runner refuses an ambiguous tag rather than picking from it, so a project that reintroduces one gets told. Verified against a game with two server scripts: FAILED (0ms, no jest report) before, 645/707 passed after. Claude-Session: https://claude.ai/code/session_01Ei9RRAgYwL3MGtMkr6vyKE --- .../build-scripts/combine-test-places.luau | 35 ++++++++++++++----- .../templates/batch-test-runner.luau | 12 +++++-- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/tools/nevermore-cli/build-scripts/combine-test-places.luau b/tools/nevermore-cli/build-scripts/combine-test-places.luau index 2f894e1570f..e3ac74ad757 100644 --- a/tools/nevermore-cli/build-scripts/combine-test-places.luau +++ b/tools/nevermore-cli/build-scripts/combine-test-places.luau @@ -7,6 +7,11 @@ -- 1. Deserializes the .rbxl -- 2. Reparents ServerScriptService children (the package root) into the combined ServerScriptService -- 3. Reads the test script file and creates a Script under ReplicatedStorage._BatchScripts +-- +-- The injected script is the ONLY thing tagged `_BatchTest_`, because that tag is how +-- batch-test-runner picks what to execute and it can only execute one thing. This used to tag every +-- Script under ServerScriptService instead, which is the same script right up until a project has +-- two -- and then the runner ran whichever the tag happened to list first, silently testing nothing. local fs = require("@lune/fs") local process = require("@lune/process") @@ -40,17 +45,33 @@ local baseContents = fs.readFile(packages[1].rbxlPath) local game = roblox.deserializePlace(baseContents) local HttpService = game:GetService("HttpService") +local ReplicatedStorage = game:GetService("ReplicatedStorage") local ServerScriptService = game:GetService("ServerScriptService") ServerScriptService.LoadStringEnabled = true --- Process first package -for _, descendant in ServerScriptService:GetDescendants() do - if descendant:IsA("Script") then - descendant:AddTag("_BatchTest_" .. packages[1].slug) +local batchScripts = roblox.Instance.new("Folder") +batchScripts.Name = "_BatchScripts" +batchScripts.Parent = ReplicatedStorage + +-- Carries the package's entry point as source for the runner to loadstring. Never runs on its own: +-- a Script under ReplicatedStorage is inert, and the runner wants to choose when it runs anyway. +local function injectTestScript(pkg) + if not fs.isFile(pkg.scriptPath) then + print(`[CombinePlaces] No script template for {pkg.slug} at {pkg.scriptPath}`) + process.exit(1) end + + local testScript = roblox.Instance.new("Script") + testScript.Name = pkg.slug + testScript.Source = fs.readFile(pkg.scriptPath) + testScript:AddTag("_BatchTest_" .. pkg.slug) + testScript.Parent = batchScripts end +-- Process first package +injectTestScript(packages[1]) + -- Process remaining packages: deserialize each and reparent ServerScriptService children. -- NOTE: ObjectValues (links) within each package's subtree are preserved when the -- whole subtree is reparented as a unit. This works because all ObjectValue targets @@ -69,11 +90,7 @@ for idx = 2, #packages do HttpService.HttpEnabled = true end - for _, descendant in packageServerScriptService:GetDescendants() do - if descendant:IsA("Script") then - descendant:AddTag("_BatchTest_" .. pkg.slug) - end - end + injectTestScript(pkg) -- Reparent all ServerScriptService children (non-recursively, just move the roots) for _, child in packageServerScriptService:GetChildren() do diff --git a/tools/nevermore-cli/templates/batch-test-runner.luau b/tools/nevermore-cli/templates/batch-test-runner.luau index 2f66b85d95f..413aeeb1ecb 100644 --- a/tools/nevermore-cli/templates/batch-test-runner.luau +++ b/tools/nevermore-cli/templates/batch-test-runner.luau @@ -16,7 +16,15 @@ local scriptSources = {} for _, slug in packageSlugs do local tagged = CollectionService:GetTagged(`_BatchTest_{slug}`) local inst = tagged[1] - if inst then + if #tagged > 1 then + -- Refused rather than picked. Running whichever one the tag listed first is how this fails + -- quietly: a script that returns without erroring reports as a pass having tested nothing. + local fullNames = {} + for _, taggedInstance in tagged do + table.insert(fullNames, taggedInstance:GetFullName()) + end + warn(`[BatchTest] {slug}: {#tagged} instances tagged _BatchTest_{slug}: {table.concat(fullNames, ", ")}`) + elseif inst then scriptSources[slug] = inst.Source else warn(`[BatchTest] Failed to find script source for {slug}`) @@ -42,7 +50,7 @@ for _, slug in packageSlugs do local scriptSource = scriptSources[slug] if not scriptSource then print("===BATCH_TEST_BEGIN " .. slug .. "===") - warn(`[BatchTest] {slug}: No test script found for {slug}. Is it tagged with _BatchTest_{slug}?`) + warn(`[BatchTest] {slug}: No test script to run. Is exactly one instance tagged _BatchTest_{slug}?`) print("===BATCH_TEST_END " .. slug .. " FAIL 0===") table.insert(results, { slug = slug, success = false, durationMs = 0, error = "No test script found" }) continue