fix(core): update stale registry + stair-opening tests to match behavior (#358)
Two unit-test groups had drifted from intentional implementation changes
and have been failing CI on main since before they were noticed:
- registry: re-registering a node kind is now HMR-aware — it warns and
replaces in dev/test and only throws in production (registry._register,
introduced in the in-world-selection work). `bun test` runs with
NODE_ENV=test, so the duplicate-kind tests took the dev (warn) path and
no longer threw. Pin NODE_ENV to 'production' for the throw-path
assertions via an `inProduction` helper, and add explicit dev/HMR
coverage for the warn-and-replace path.
- stair-opening-sync: the straight-flight opening geometry was
deliberately enlarged ("increase stair opening buffer constraints",
treadDepth*10 / length*0.8 / 3.0, openingOffset default 0.15). The
enlarged opening now spans nearly the full slab depth, so the manual
hole fixtures (which must *contain* the auto opening to suppress it) no
longer covered it. Enlarge the manual-opening fixtures to genuinely
cover the current opening, preserving each test's intent.
No production code changed — only test fixtures/assertions.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f7ff60561e
commit
96d6e0afdb
@@ -12,6 +12,20 @@ import {
|
|||||||
} from './registry'
|
} from './registry'
|
||||||
import type { AnyNodeDefinition, Plugin } from './types'
|
import type { AnyNodeDefinition, Plugin } from './types'
|
||||||
|
|
||||||
|
// Re-registering a kind warns + replaces in dev (HMR) but throws in
|
||||||
|
// production — see `registry._register`. `bun test` runs with
|
||||||
|
// NODE_ENV=test (dev path), so the throw-path tests pin NODE_ENV to
|
||||||
|
// 'production' for the duration of the call.
|
||||||
|
async function inProduction<T>(fn: () => T | Promise<T>): Promise<T> {
|
||||||
|
const prev = process.env.NODE_ENV
|
||||||
|
process.env.NODE_ENV = 'production'
|
||||||
|
try {
|
||||||
|
return await fn()
|
||||||
|
} finally {
|
||||||
|
process.env.NODE_ENV = prev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function makeDefinition(
|
function makeDefinition(
|
||||||
kind: string,
|
kind: string,
|
||||||
overrides: Partial<AnyNodeDefinition> = {},
|
overrides: Partial<AnyNodeDefinition> = {},
|
||||||
@@ -47,10 +61,21 @@ describe('nodeRegistry', () => {
|
|||||||
expect(nodeRegistry.get('column')).toBe(def)
|
expect(nodeRegistry.get('column')).toBe(def)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('registerNode throws on duplicate kind', () => {
|
test('registerNode throws on duplicate kind in production', async () => {
|
||||||
|
await inProduction(() => {
|
||||||
registerNode(makeDefinition('column'))
|
registerNode(makeDefinition('column'))
|
||||||
expect(() => registerNode(makeDefinition('column'))).toThrow(/duplicate node kind/)
|
expect(() => registerNode(makeDefinition('column'))).toThrow(/duplicate node kind/)
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('registerNode replaces on duplicate kind in dev (HMR)', () => {
|
||||||
|
const first = makeDefinition('column')
|
||||||
|
const second = makeDefinition('column')
|
||||||
|
registerNode(first)
|
||||||
|
registerNode(second)
|
||||||
|
expect(nodeRegistry.size).toBe(1)
|
||||||
|
expect(nodeRegistry.get('column')).toBe(second)
|
||||||
|
})
|
||||||
|
|
||||||
test('registerNode rejects empty kind', () => {
|
test('registerNode rejects empty kind', () => {
|
||||||
expect(() => registerNode(makeDefinition(''))).toThrow(/non-empty string/)
|
expect(() => registerNode(makeDefinition(''))).toThrow(/non-empty string/)
|
||||||
@@ -184,19 +209,21 @@ describe('loadPlugin', () => {
|
|||||||
await expect(loadPlugin(plugin)).rejects.toThrow(/apiVersion/)
|
await expect(loadPlugin(plugin)).rejects.toThrow(/apiVersion/)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('propagates duplicate-kind error from a single plugin', async () => {
|
test('propagates duplicate-kind error from a single plugin in production', async () => {
|
||||||
const plugin: Plugin = {
|
const plugin: Plugin = {
|
||||||
id: 'broken',
|
id: 'broken',
|
||||||
apiVersion: 1,
|
apiVersion: 1,
|
||||||
nodes: [makeDefinition('dup'), makeDefinition('dup')],
|
nodes: [makeDefinition('dup'), makeDefinition('dup')],
|
||||||
}
|
}
|
||||||
await expect(loadPlugin(plugin)).rejects.toThrow(/duplicate node kind/)
|
await inProduction(() => expect(loadPlugin(plugin)).rejects.toThrow(/duplicate node kind/))
|
||||||
})
|
})
|
||||||
|
|
||||||
test('propagates duplicate-kind error across plugins', async () => {
|
test('propagates duplicate-kind error across plugins in production', async () => {
|
||||||
|
await inProduction(async () => {
|
||||||
await loadPlugin({ id: 'a', apiVersion: 1, nodes: [makeDefinition('shared')] })
|
await loadPlugin({ id: 'a', apiVersion: 1, nodes: [makeDefinition('shared')] })
|
||||||
await expect(
|
await expect(
|
||||||
loadPlugin({ id: 'b', apiVersion: 1, nodes: [makeDefinition('shared')] }),
|
loadPlugin({ id: 'b', apiVersion: 1, nodes: [makeDefinition('shared')] }),
|
||||||
).rejects.toThrow(/duplicate node kind/)
|
).rejects.toThrow(/duplicate node kind/)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -79,10 +79,10 @@ describe('syncAutoStairOpenings', () => {
|
|||||||
const ground = LevelNode.parse({ name: 'Ground', level: 0, parentId: building.id })
|
const ground = LevelNode.parse({ name: 'Ground', level: 0, parentId: building.id })
|
||||||
const upper = LevelNode.parse({ name: 'Upper', level: 1, parentId: building.id })
|
const upper = LevelNode.parse({ name: 'Upper', level: 1, parentId: building.id })
|
||||||
const manualOpening: Array<[number, number]> = [
|
const manualOpening: Array<[number, number]> = [
|
||||||
[1.2, 0.8],
|
[1.0, 0.0],
|
||||||
[2.8, 0.8],
|
[3.0, 0.0],
|
||||||
[2.8, 2.9],
|
[3.0, 3.0],
|
||||||
[1.2, 2.9],
|
[1.0, 3.0],
|
||||||
]
|
]
|
||||||
const sourceCeiling = CeilingNode.parse({
|
const sourceCeiling = CeilingNode.parse({
|
||||||
name: 'Source Ceiling',
|
name: 'Source Ceiling',
|
||||||
@@ -206,10 +206,10 @@ describe('syncAutoStairOpenings', () => {
|
|||||||
const ground = LevelNode.parse({ name: 'Ground', level: 0, parentId: building.id })
|
const ground = LevelNode.parse({ name: 'Ground', level: 0, parentId: building.id })
|
||||||
const upper = LevelNode.parse({ name: 'Upper', level: 1, parentId: building.id })
|
const upper = LevelNode.parse({ name: 'Upper', level: 1, parentId: building.id })
|
||||||
const manualOpening: Array<[number, number]> = [
|
const manualOpening: Array<[number, number]> = [
|
||||||
[1.2, 0.8],
|
[1.0, 0.0],
|
||||||
[2.8, 0.8],
|
[3.0, 0.0],
|
||||||
[2.8, 2.9],
|
[3.0, 3.0],
|
||||||
[1.2, 2.9],
|
[1.0, 3.0],
|
||||||
]
|
]
|
||||||
const staleAutoOpening: Array<[number, number]> = [
|
const staleAutoOpening: Array<[number, number]> = [
|
||||||
[1.5, 1],
|
[1.5, 1],
|
||||||
|
|||||||
Reference in New Issue
Block a user