diff --git a/craft/src/components/basic/Footer.editguard.test.tsx b/craft/src/components/basic/Footer.editguard.test.tsx new file mode 100644 index 0000000..95a03ff --- /dev/null +++ b/craft/src/components/basic/Footer.editguard.test.tsx @@ -0,0 +1,105 @@ +import { describe, test, expect, vi, beforeEach } from 'vitest'; +import React from 'react'; +import { createRoot, Root } from 'react-dom/client'; +import { act } from 'react-dom/test-utils'; + +/* Footer only needs useNode from @craftjs/core. Mock it following the + DOM-harness pattern in src/state/PageContext.slug.test.tsx (no + @testing-library/react in this repo) so we can drive `selected` across + re-renders and observe setProp calls without a real tree. */ +let mockSelected = false; +let lastCommittedProps: { text: string } = { text: '' }; +const setPropSpy = vi.fn((updater: (p: any) => void) => { + updater(lastCommittedProps); +}); + +vi.mock('@craftjs/core', () => ({ + useNode: (collect?: (node: any) => any) => { + const node = { events: { selected: mockSelected } }; + return { + connectors: { connect: (el: any) => el, drag: (el: any) => el }, + actions: { setProp: setPropSpy }, + ...(collect ? collect(node) : {}), + }; + }, +})); + +import { Footer } from './Footer'; + +let container: HTMLDivElement; +let root: Root; + +function render(ui: React.ReactElement) { + container = document.createElement('div'); + document.body.appendChild(container); + act(() => { + root = createRoot(container); + root.render(ui); + }); +} + +function rerender(ui: React.ReactElement) { + act(() => { + root.render(ui); + }); +} + +beforeEach(() => { + mockSelected = false; + lastCommittedProps = { text: 'Original' }; + setPropSpy.mockClear(); +}); + +describe('Footer edit-guard (mirrors Heading.tsx mechanism)', () => { + test('deselecting without a real blur still commits the in-progress edit', () => { + mockSelected = true; + render(