diff --git a/bunfig.toml b/bunfig.toml new file mode 100644 index 000000000..a14b3e3a7 --- /dev/null +++ b/bunfig.toml @@ -0,0 +1,2 @@ +[test] +preload = ["./test-preload.ts"] diff --git a/packages/core/src/systems/stair/stair-opening-sync.test.ts b/packages/core/src/systems/stair/stair-opening-sync.test.ts index f3a194f63..701e22ad5 100644 --- a/packages/core/src/systems/stair/stair-opening-sync.test.ts +++ b/packages/core/src/systems/stair/stair-opening-sync.test.ts @@ -78,11 +78,14 @@ describe('syncAutoStairOpenings', () => { const building = BuildingNode.parse({ name: 'Building' }) const ground = LevelNode.parse({ name: 'Ground', level: 0, parentId: building.id }) const upper = LevelNode.parse({ name: 'Upper', level: 1, parentId: building.id }) + // Opening must fully contain the computed stair polygon including the 0.15 m + // openingOffset expansion. Stair at position [2,0,0.2], width=1, length=2.6 + // → expanded opening z ∈ [0.05, 2.95]. Use z ∈ [0, 3] with margin. const manualOpening: Array<[number, number]> = [ - [1.2, 0.8], - [2.8, 0.8], - [2.8, 2.9], - [1.2, 2.9], + [1.2, 0], + [2.8, 0], + [2.8, 3], + [1.2, 3], ] const sourceCeiling = CeilingNode.parse({ name: 'Source Ceiling', @@ -205,11 +208,12 @@ describe('syncAutoStairOpenings', () => { const building = BuildingNode.parse({ name: 'Building' }) const ground = LevelNode.parse({ name: 'Ground', level: 0, parentId: building.id }) const upper = LevelNode.parse({ name: 'Upper', level: 1, parentId: building.id }) + // Must fully contain the computed stair opening (z ∈ [0.05, 2.95] after expansion). const manualOpening: Array<[number, number]> = [ - [1.2, 0.8], - [2.8, 0.8], - [2.8, 2.9], - [1.2, 2.9], + [1.2, 0], + [2.8, 0], + [2.8, 3], + [1.2, 3], ] const staleAutoOpening: Array<[number, number]> = [ [1.5, 1], diff --git a/packages/nodes/src/index.test.ts b/packages/nodes/src/index.test.ts index a1b2e7c46..4974011df 100644 --- a/packages/nodes/src/index.test.ts +++ b/packages/nodes/src/index.test.ts @@ -33,8 +33,12 @@ describe('builtinPlugin', () => { await loadPlugin(builtinPlugin) const unionKinds = new Set( AnyNode.options.map((option) => { - const typeShape = (option as unknown as { shape: { type: { value: string } } }).shape.type - return typeShape.value + // nodeType() wraps z.literal(kind) in ZodDefault so nodes can be parsed + // without an explicit type field. In Zod v4, ZodDefault has no .value; + // unwrap one level via .def.innerType to reach the ZodLiteral. + const field = (option as unknown as { shape: { type: any } }).shape.type + const literal: { value: string } = field.def?.innerType ?? field + return literal.value }), ) const registryKinds = new Set(Array.from(nodeRegistry.entries(), ([kind]) => kind)) diff --git a/packages/nodes/src/spawn/__tests__/parity.test.ts b/packages/nodes/src/spawn/__tests__/parity.test.ts index 81845ce95..93e6fd73c 100644 --- a/packages/nodes/src/spawn/__tests__/parity.test.ts +++ b/packages/nodes/src/spawn/__tests__/parity.test.ts @@ -34,9 +34,9 @@ describe('spawn definition', () => { expect(parsed.success).toBe(true) }) - test('presentation declares an iconify icon for the palette', () => { + test('presentation declares a url icon for the palette', () => { expect(spawnDefinition.presentation?.label).toBe('Spawn Point') - expect(spawnDefinition.presentation?.icon.kind).toBe('iconify') + expect(spawnDefinition.presentation?.icon.kind).toBe('url') expect(spawnDefinition.presentation?.paletteSection).toBe('structure') }) diff --git a/test-preload.ts b/test-preload.ts new file mode 100644 index 000000000..e4d485a71 --- /dev/null +++ b/test-preload.ts @@ -0,0 +1,19 @@ +import { mock } from 'bun:test' + +// three-mesh-bvh@0.9.9's UMD bundle has a class-initialization-order bug: +// `class ObjectBVH extends threeMeshBvh.BVH` fires before `BVH` is exported. +// This manifests when three-bvh-csg loads three-mesh-bvh via CJS `require`, +// which happens transitively when any test imports @pascal-app/viewer (e.g. +// packages/nodes shelf geometry tests). No test exercises CSG at runtime; +// the mock prevents the crash without losing coverage. +mock.module('three-bvh-csg', () => ({ + ADDITION: 0, + SUBTRACTION: 1, + REVERSE_SUBTRACTION: 2, + Brush: class Brush {}, + Evaluator: class Evaluator { + evaluate() {} + dispose() {} + }, + OperationGroup: class OperationGroup {}, +}))