LearnNewsExamplesServices
Frontmatter
id19084
titleTreeStoreValueBanding registers its test class in beforeAll, so a second run in one worker collides
stateClosed
labels
bugaitesting
assigneesneo-opus-grace
createdAtSep 23, 2026, 3:53 AM
updatedAtSep 23, 2026, 12:24 PM
githubUrlhttps://github.com/neomjs/neo/issues/19084
authorneo-opus-grace
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 23, 2026, 12:24 PM

TreeStoreValueBanding registers its test class in beforeAll, so a second run in one worker collides

neo-opus-grace
neo-opus-grace commented on Sep 23, 2026, 3:53 AM

Context

data/TreeStoreValueBanding.spec.mjs:194 is one of the four intermittent arms #19039's instrument was built to measure. CI reported it as 1 flaky / 4259 passed on 2026-09-19. The instrument's first hosted probe on dev@526b65e0ee, --repeat-each=50 (35807579596), measured 1 flaky in 150:

Error: Namespace collision in unitTestMode for Test.Unit.Data.TreeStoreValueBanding.TestTreeModel

Locally, npm run test-unit -- …/TreeStoreValueBanding.spec.mjs --repeat-each=50 --workers=4 --retries=0 gives 3 failed / 147 passed, all three that same collision.

Sweeps: the latest 20 open issues at 2026-09-23T01:53:28Z hold no equivalent. There is no lane claim. The nearest prior art is #18776, a different unit-isolation leak, closed.

The Problem

The spec defines TestTreeModel inside its describe and registers it in test.beforeAll(() => { TestModel = Neo.setupClass(TestTreeModel); }), then never removes it. The unit config runs fullyParallel: true on 4 workers with 2 retries in CI. A worker can execute beforeAll more than once for this describe (repeats, or separate groups of its three tests). The second Neo.setupClass finds the namespace taken, and unitTestMode throws (src/Neo.mjs:875-882). The retry runs in a fresh worker and passes, so the report reads "flaky".

The Architectural Reality

  • Neo.setupClass in unitTestMode throws when a non-singleton re-registers a taken namespace. That is deliberate (src/Neo.mjs:869-874): two distinct classes sharing a name is a test-isolation leak.
  • 85 unit spec files register their test classes at module scope, which runs once per worker process because modules are cached. This spec is the only one that registers inside beforeAll.

The Fix

Register TestTreeModel at module scope, the idiom the other 85 files use: define the class and run Neo.setupClass once, outside beforeAll. No engine change.

Acceptance Criteria

  • --repeat-each=50 --workers=4 --retries=0 on the spec: 0 failed, 150 passed.
  • Mutation: moving the registration back into beforeAll restores the collision under the same command.
  • The three tests' assertions are unchanged.

Out of Scope

  • unitTestMode's collision rule. It is correct, and this spec broke it.
  • The other three intermittent arms (#19039).

Decision Record impact

None.

Related

#19039 · #19043 · #18776

Origin Session ID: 19051047-2f38-4bf0-be51-efd6b957564d

Retrieval Hint: "Namespace collision in unitTestMode beforeAll setupClass fullyParallel repeat-each"

tobiu referenced in commit 8ad391c - "test(data): TreeStoreValueBanding registers its test class once per worker process (#19084) (#19085) on Sep 23, 2026, 12:24 PM
tobiu closed this issue on Sep 23, 2026, 12:24 PM