@ai-stack/payloadcms
Version:
<p align="center"> <img alt="Payload AI Plugin" src="assets/payload-ai-intro.gif" width="100%" /> </p>
140 lines (139 loc) • 5.08 kB
JavaScript
import { describe, expect, it } from 'vitest';
import { BLOCK_PLACEHOLDER_PREFIX, BLOCK_PLACEHOLDER_SUFFIX, withBlockPlaceholders } from '../lexicalToHTML.js';
import { reinsertPreservedBlocks } from '../setSafeLexicalState.js';
const paragraph = (text)=>({
type: 'paragraph',
children: [
{
type: 'text',
text
}
]
});
const block = (blockType)=>({
type: 'block',
fields: {
blockType
}
});
const marker = (index)=>`${BLOCK_PLACEHOLDER_PREFIX}${index}${BLOCK_PLACEHOLDER_SUFFIX}`;
describe('withBlockPlaceholders', ()=>{
it('replaces a top-level block node with a marker paragraph', ()=>{
const editorData = {
root: {
children: [
paragraph('before'),
block('image'),
paragraph('after')
]
}
};
const result = withBlockPlaceholders(editorData);
expect(result.root.children).toHaveLength(3);
expect(result.root.children[0]).toEqual(editorData.root.children[0]);
expect(result.root.children[1].type).toBe('paragraph');
expect(result.root.children[1].children[0].text).toBe(marker(0));
expect(result.root.children[2]).toEqual(editorData.root.children[2]);
});
it('numbers multiple blocks in document order', ()=>{
const editorData = {
root: {
children: [
block('image'),
paragraph('middle'),
block('gallery')
]
}
};
const result = withBlockPlaceholders(editorData);
expect(result.root.children[0].children[0].text).toBe(marker(0));
expect(result.root.children[2].children[0].text).toBe(marker(1));
});
it('returns the input unchanged when there are no blocks', ()=>{
const editorData = {
root: {
children: [
paragraph('only text')
]
}
};
const result = withBlockPlaceholders(editorData);
expect(result.root.children[0]).toEqual(editorData.root.children[0]);
});
});
describe('reinsertPreservedBlocks', ()=>{
it('swaps a marker paragraph back for the original block at the same position', ()=>{
const originalRoot = {
children: [
paragraph('before'),
block('image'),
paragraph('after')
]
};
// Model regenerated the surrounding text but echoed the marker back verbatim.
const nextChildren = [
paragraph('regenerated before'),
paragraph(marker(0)),
paragraph('regenerated after')
];
const merged = reinsertPreservedBlocks(originalRoot, nextChildren);
expect(merged).toHaveLength(3);
expect(merged[1]).toEqual(originalRoot.children[1]);
});
it('preserves multiple blocks matched by their own marker index', ()=>{
const originalRoot = {
children: [
block('image'),
paragraph('middle'),
block('gallery')
]
};
const nextChildren = [
paragraph(marker(0)),
paragraph('regenerated middle'),
paragraph(marker(1))
];
const merged = reinsertPreservedBlocks(originalRoot, nextChildren);
expect(merged[0]).toEqual(originalRoot.children[0]);
expect(merged[2]).toEqual(originalRoot.children[2]);
});
it('falls back to a proportional position when the marker is missing from the output', ()=>{
const originalRoot = {
children: [
paragraph('a'),
paragraph('b'),
block('image'),
paragraph('c')
]
};
// Model dropped the marker entirely - block must still be reinserted, not lost.
const nextChildren = [
paragraph('x'),
paragraph('y')
];
const merged = reinsertPreservedBlocks(originalRoot, nextChildren);
expect(merged).toHaveLength(3);
expect(merged.some((node)=>node.type === 'block')).toBe(true);
});
it('returns nextChildren unchanged when there were no blocks to preserve', ()=>{
const originalRoot = {
children: [
paragraph('a'),
paragraph('b')
]
};
const nextChildren = [
paragraph('regenerated')
];
const merged = reinsertPreservedBlocks(originalRoot, nextChildren);
expect(merged).toBe(nextChildren);
});
it('returns nextChildren unchanged when there is no original root snapshot', ()=>{
const nextChildren = [
paragraph('regenerated')
];
const merged = reinsertPreservedBlocks(null, nextChildren);
expect(merged).toBe(nextChildren);
});
});
//# sourceMappingURL=blockPreservation.test.js.map