|
| 1 | +import { |
| 2 | + BlockNoteSchema, |
| 3 | + createBlockSpec, |
| 4 | + defaultBlockSpecs, |
| 5 | +} from '@blocknote/core'; |
1 | 6 | import { |
2 | 7 | CommentsExtension, |
3 | 8 | DefaultThreadStoreAuth, |
@@ -703,6 +708,57 @@ describe('Conversion Testing', () => { |
703 | 708 | }); |
704 | 709 | }); |
705 | 710 |
|
| 711 | + test('POST /api/convert keeps the docChildren block in JSON and leaves no trace of it in HTML or Markdown', async () => { |
| 712 | + const app = initApp(); |
| 713 | + // Written the way the frontend writes it, with its own docChildren spec, |
| 714 | + // so the test fails if the server schema drops the block when reading |
| 715 | + const frontendEditor = ServerBlockNoteEditor.create({ |
| 716 | + schema: BlockNoteSchema.create({ |
| 717 | + blockSpecs: { |
| 718 | + ...defaultBlockSpecs, |
| 719 | + docChildren: createBlockSpec( |
| 720 | + { type: 'docChildren', propSchema: {}, content: 'none' }, |
| 721 | + { render: () => ({ dom: document.createElement('div') }) }, |
| 722 | + )(), |
| 723 | + }, |
| 724 | + }), |
| 725 | + }); |
| 726 | + const yDocument = frontendEditor.blocksToYDoc( |
| 727 | + [ |
| 728 | + { type: 'paragraph' as const, content: 'Before' }, |
| 729 | + { type: 'docChildren' as const }, |
| 730 | + { type: 'paragraph' as const, content: 'After' }, |
| 731 | + ], |
| 732 | + 'document-store', |
| 733 | + ); |
| 734 | + const yjsUpdate = Buffer.from(Y.encodeStateAsUpdate(yDocument)); |
| 735 | + const convert = (accept: string) => |
| 736 | + request(app) |
| 737 | + .post('/api/convert') |
| 738 | + .set('origin', origin) |
| 739 | + .set('authorization', `Bearer ${apiKey}`) |
| 740 | + .set('content-type', 'application/vnd.yjs.doc') |
| 741 | + .set('accept', accept) |
| 742 | + .send(yjsUpdate); |
| 743 | + |
| 744 | + const jsonResponse = await convert('application/json'); |
| 745 | + expect(jsonResponse.status).toBe(200); |
| 746 | + expect( |
| 747 | + (jsonResponse.body as { type: string }[]).map((block) => block.type), |
| 748 | + ).toContain('docChildren'); |
| 749 | + |
| 750 | + const htmlResponse = await convert('text/html'); |
| 751 | + expect(htmlResponse.status).toBe(200); |
| 752 | + expect(htmlResponse.text).toContain('After'); |
| 753 | + expect(htmlResponse.text).not.toContain('\uFFFC'); |
| 754 | + |
| 755 | + const markdownResponse = await convert('text/markdown'); |
| 756 | + expect(markdownResponse.status).toBe(200); |
| 757 | + expect(markdownResponse.text).toContain('Before'); |
| 758 | + expect(markdownResponse.text).toContain('After'); |
| 759 | + expect(markdownResponse.text).not.toContain('\uFFFC'); |
| 760 | + }); |
| 761 | + |
706 | 762 | test('POST /api/convert with invalid Yjs content returns 400', async () => { |
707 | 763 | const destroySpy = vi.spyOn(Y.Doc.prototype, 'destroy'); |
708 | 764 | const app = initApp(); |
|
0 commit comments