docs/plans/2026-03-10-phase-2-utility-ring-execution.md
Complete phase 2 for:
@platejs/utils@udecode/react-utils@udecode/utilsUse TDD for every new spec group. Keep this file as the live record for status, findings, verification, and learnings.
@platejs/utils@udecode/react-utils@udecode/utilstesting.mdc@platejs/slate:
@platejs/utils: 5 specs / 26 source files@udecode/react-utils: 4 specs / 18 source files@udecode/utils: 6 specs / 17 source files@platejs/core already has a much wider runtime base plus one compile-only type fixture, so deferring core until after the utility ring still makes sense.slate-react invariant that cleanly maps into phase 2 is use-slate-selector; the rest are phase-3 core material.@platejs/utils has real untested behavior in ExitBreakPlugin, selection hooks, fragment hooks, toolbar/remove hooks, and BlockPlaceholderPlugin.@udecode/react-utils has several branchy runtime helpers with no direct specs yet: primitive factories, useEffectOnce, useOnClickOutside, useStableFn, useStableMemo, PortalBody, and withRef.@udecode/utils mostly needs branch completion plus direct coverage for findHtmlParentElement.normalizeRoot(...) for normalize plugin behavior in @platejs/utilsrenderHook(...) with Plate context for selector-backed hooks@udecode/react-utils had two real runtime bugs, not just missing tests:
createPrimitiveComponent leaked setProps onto DOM nodescreatePrimitiveComponent merged hook and consumer styles, then overwrote the merged result with the raw consumer style prop@udecode/utils did not reveal new runtime bugs in scope; the remaining work was branch completion and one new direct helper suite.tdd, planning-with-files, and current testing policy.@platejs/utils.@platejs/utils red specs for ExitBreakPlugin and hook behavior.@platejs/utils coverage for:
ExitBreakPluginuseEditorStringuseMarkToolbarButtonuseRemoveNodeButtonBlockPlaceholderPlugin@udecode/react-utils coverage for:
createPrimitiveComponentcreatePrimitiveElementcreateSlotComponentuseEffectOnceuseOnClickOutsideuseStableFnuseStableMemoPortalBodywithRef@udecode/react-utils runtime bugs exposed by the new tests:
setProps to DOM elements in createPrimitiveComponentcreatePrimitiveComponent@udecode/utils coverage for:
findHtmlParentElementisUrl falsey/malformed branchessanitizeUrl internal-link and undefined-input branchesmergeProps precedence/query branchesbun test packages/utils/src passed.bun test packages/udecode/react-utils/src passed.bun test packages/udecode/utils/src passed.pnpm install passed.pnpm turbo build --filter=./packages/utils --filter=./packages/udecode/react-utils --filter=./packages/udecode/utils passed.pnpm turbo typecheck --filter=./packages/utils --filter=./packages/udecode/react-utils --filter=./packages/udecode/utils passed.bun lint:fix passed.bun typecheck passed.bun test packages/utils/src packages/udecode/react-utils/src packages/udecode/utils/srcdurable testing rule: mock and spyOn are already global via tooling/config/global.d.ts. Importing them from bun:test in new specs caused describe globals to disappear for those files. Phase-2 specs should use Bun globals only.durable testing rule: in this Bun + Testing Library setup, prefer render-returned queries over screen. Existing package tests already leaned that way, and new screen usage produced false harness failures.durable testing rule: avoid toHaveStyle in Bun specs here. Direct style property assertions are more reliable and avoid matcher internals that are currently broken in this setup.package reality: plugin configure({ options }) paths should omit unset keys in test helpers. Passing explicit undefined values clobbered BlockPlaceholderPlugin defaults and created fake failures.package reality: mergeProps({ handlerQuery: null }) does not disable handler merging. It means “no predicate gate,” so handler keys still merge.bug found: createPrimitiveComponent leaked setProps to DOM elements.bug found: createPrimitiveComponent dropped hook styles whenever the caller also passed style.