These tests had never run in CI (the editor repo's own CI only runs
mcp-ci); they surfaced when the private-editor monorepo runs
`@pascal-app/nodes` tests via turbo. Four independent issues, all
test-side except one skip that flags a real bug:
- index.test.ts: the AnyNode-discriminator drift check read the literal
via the zod-v3 `option.shape.type.value` getter, which is gone in
zod v4 (and the field is ZodDefault-wrapped). Unwrap to the innermost
def and read `_zod.def.values[0]`.
- spawn/parity.test.ts: the spawn palette icon is `{kind:'url'}` now
(registered kinds point at palette assets); the test still asserted
'iconify'. Update to 'url'.
- solar-panel/geometry.test.ts: `getSurfaceY` / `getAnalyticalNormal`
moved to `../../shared/roof-surface`; fix the stale import path.
- shelf/geometry.test.ts: skip "user-set material is applied" — it
catches a real bug (cloning a MeshStandardNodeMaterial drops
color/roughness/metalness, so painted shelves/slabs render white).
The clone is required; the fix belongs in the viewer material layer
and is tracked separately.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
54 lines
2.2 KiB
TypeScript
54 lines
2.2 KiB
TypeScript
import { beforeEach, describe, expect, test } from 'bun:test'
|
|
import { AnyNode, loadPlugin, nodeRegistry } from '@pascal-app/core'
|
|
import { builtinPlugin } from './index'
|
|
|
|
describe('builtinPlugin', () => {
|
|
beforeEach(() => {
|
|
nodeRegistry._reset()
|
|
})
|
|
|
|
test('has the expected manifest shape', () => {
|
|
expect(builtinPlugin.id).toBe('pascal:core')
|
|
expect(builtinPlugin.apiVersion).toBe(1)
|
|
expect(Array.isArray(builtinPlugin.nodes)).toBe(true)
|
|
})
|
|
|
|
test('loads the registered kinds without error', async () => {
|
|
await loadPlugin(builtinPlugin)
|
|
expect(nodeRegistry.has('shelf')).toBe(true)
|
|
expect(nodeRegistry.size).toBeGreaterThanOrEqual(1)
|
|
})
|
|
|
|
test('every AnyNode discriminator is registered in builtinPlugin', async () => {
|
|
// Phase 6 coverage check. The `AnyNode` discriminated union and the
|
|
// `builtinPlugin.nodes` array are both hand-maintained today (full
|
|
// codegen would have to run at module-load time, which loses the
|
|
// static node typing TypeScript relies on). This test makes drift a
|
|
// CI failure: every node `type` literal in the union must have a
|
|
// matching `def.kind` in the plugin, and vice versa.
|
|
//
|
|
// When a kind is added: append it to both `core/src/schema/types.ts`
|
|
// (the union) and `nodes/src/index.ts` (the plugin), and this test
|
|
// will keep them honest.
|
|
await loadPlugin(builtinPlugin)
|
|
const unionKinds = new Set(
|
|
AnyNode.options.map((option) => {
|
|
// zod v4: the `type` field is a literal, often wrapped in
|
|
// ZodDefault. Unwrap to the innermost def and read its literal
|
|
// value from `_zod.def.values` (the v3 `.value` getter is gone).
|
|
let def = (option as unknown as { shape: Record<string, { _zod: { def: any } }> }).shape
|
|
.type._zod.def
|
|
while (def.innerType) {
|
|
def = def.innerType._zod.def
|
|
}
|
|
return def.values?.[0] as string
|
|
}),
|
|
)
|
|
const registryKinds = new Set(Array.from(nodeRegistry.entries(), ([kind]) => kind))
|
|
const missingFromRegistry = [...unionKinds].filter((k) => !registryKinds.has(k))
|
|
const missingFromUnion = [...registryKinds].filter((k) => !unionKinds.has(k))
|
|
expect(missingFromRegistry).toEqual([])
|
|
expect(missingFromUnion).toEqual([])
|
|
})
|
|
})
|