import { BlockNoteSchema, createBlockSpec, createInlineContentSpec, createPageBreakBlockSpec, createStyleSpec, defaultBlockSpecs, defaultInlineContentSpecs, defaultStyleSpecs, } from "@blocknote/core"; import { ColumnBlock, ColumnListBlock } from "@blocknote/xl-multi-column"; import { Text } from "@react-pdf/renderer"; import { testDocument } from "@shared/testDocument.js"; import reactElementToJSXString from "react-element-to-jsx-string"; import { describe, expect, it } from "vitest"; import { pdfDefaultSchemaMappings } from "./defaultSchema/index.js"; import { PDFExporter } from "./pdfExporter.js"; import { partialBlocksToBlocksForTesting } from "@shared/formatConversionTestUtil.js"; // import * as ReactPDF from "@react-pdf/renderer"; // expect.extend({ toMatchImageSnapshot }); // import { toMatchImageSnapshot } from "jest-image-snapshot"; // import { pdf } from "pdf-to-img"; describe("exporter", () => { it("typescript: schema with extra block", async () => { // const exporter = createPdfExporterForDefaultSchema(); // const ps = exporter.transform(testDocument); const schema = BlockNoteSchema.create({ blockSpecs: { ...defaultBlockSpecs, pageBreak: createPageBreakBlockSpec(), column: ColumnBlock, columnList: ColumnListBlock, extraBlock: createBlockSpec( { content: "none", type: "extraBlock", propSchema: {}, }, {} as any, )(), }, }); new PDFExporter( schema, // @ts-expect-error pdfDefaultSchemaMappings, ); new PDFExporter(schema, { // @ts-expect-error blockMapping: pdfDefaultSchemaMappings.blockMapping, inlineContentMapping: pdfDefaultSchemaMappings.inlineContentMapping, styleMapping: pdfDefaultSchemaMappings.styleMapping, }); new PDFExporter(schema, { blockMapping: { ...pdfDefaultSchemaMappings.blockMapping, extraBlock: (_b, _t) => { throw new Error("sdf"); }, }, inlineContentMapping: pdfDefaultSchemaMappings.inlineContentMapping, styleMapping: pdfDefaultSchemaMappings.styleMapping, }); }); it("typescript: schema with extra inline content", async () => { const schema = BlockNoteSchema.create({ inlineContentSpecs: { ...defaultInlineContentSpecs, extraInlineContent: createInlineContentSpec( { type: "extraInlineContent", content: "styled", propSchema: {}, }, {} as any, ), }, }); new PDFExporter( schema, // @ts-expect-error pdfDefaultSchemaMappings, ); new PDFExporter(schema, { blockMapping: pdfDefaultSchemaMappings.blockMapping, // @ts-expect-error inlineContentMapping: pdfDefaultSchemaMappings.inlineContentMapping, styleMapping: pdfDefaultSchemaMappings.styleMapping, }); // no error new PDFExporter(schema, { blockMapping: pdfDefaultSchemaMappings.blockMapping, styleMapping: pdfDefaultSchemaMappings.styleMapping, inlineContentMapping: { ...pdfDefaultSchemaMappings.inlineContentMapping, extraInlineContent: () => { throw new Error("extraInlineContent not implemented"); }, }, }); }); it("typescript: schema with extra style", async () => { const schema = BlockNoteSchema.create({ styleSpecs: { ...defaultStyleSpecs, extraStyle: createStyleSpec( { type: "extraStyle", propSchema: "boolean", }, {} as any, ), }, }); new PDFExporter( schema, // @ts-expect-error pdfDefaultSchemaMappings, ); new PDFExporter(schema, { blockMapping: pdfDefaultSchemaMappings.blockMapping, inlineContentMapping: pdfDefaultSchemaMappings.inlineContentMapping, // @ts-expect-error styleMapping: pdfDefaultSchemaMappings.styleMapping, }); // no error new PDFExporter(schema, { blockMapping: pdfDefaultSchemaMappings.blockMapping, inlineContentMapping: pdfDefaultSchemaMappings.inlineContentMapping, styleMapping: { ...pdfDefaultSchemaMappings.styleMapping, extraStyle: () => { throw new Error("extraStyle not implemented"); }, }, }); }); it("typescript: schema with block and style removed", async () => { const schema = BlockNoteSchema.create({ blockSpecs: {}, styleSpecs: {}, }); // still works (no error) new PDFExporter(schema, pdfDefaultSchemaMappings); }); it("should export a document", async () => { const exporter = new PDFExporter( BlockNoteSchema.create({ blockSpecs: { ...defaultBlockSpecs, pageBreak: createPageBreakBlockSpec(), column: ColumnBlock, columnList: ColumnListBlock, }, }), pdfDefaultSchemaMappings, ); const transformed = await exporter.toReactPDFDocument(testDocument); const str = reactElementToJSXString(transformed); await expect(str).toMatchFileSnapshot("__snapshots__/example.jsx"); // would be nice to compare pdf images, but currently doesn't work on mac os (due to node canvas installation issue) // await ReactPDF.render(transformed, `${__dirname}/example.pdf`); // eslint-disable-next-line // const b = await ReactPDF(transformed); // await toMatchBinaryFileSnapshot(b, `__snapshots__/example.pdf`); // expect(b.toString("utf-8")).toMatchFileSnapshot( // `__snapshots__/example.pdf` // ); // const doc = await pdf(`${__dirname}/example.pdf`); // // expect(doc.length).toBe(2); // // expect(doc.metadata).toEqual({ ... }); // for await (const page of doc) { // expect(page).toMatchImageSnapshot(); // } }); it("should export a document with header and footer", async () => { const exporter = new PDFExporter( BlockNoteSchema.create({ blockSpecs: { ...defaultBlockSpecs, pageBreak: createPageBreakBlockSpec(), column: ColumnBlock, columnList: ColumnListBlock, }, }), pdfDefaultSchemaMappings, ); const transformed = await exporter.toReactPDFDocument(testDocument, { header: Header, footer: Footer, }); const str = reactElementToJSXString(transformed); await expect(str).toMatchFileSnapshot( "__snapshots__/exampleWithHeaderAndFooter.jsx", ); // await ReactPDF.render( // transformed, // `${__dirname}/exampleWithHeaderAndFooter.pdf` // ); }); it("should export a document with a multi-column block", async () => { const schema = BlockNoteSchema.create({ blockSpecs: { ...defaultBlockSpecs, pageBreak: createPageBreakBlockSpec(), column: ColumnBlock, columnList: ColumnListBlock, }, }); const exporter = new PDFExporter(schema, pdfDefaultSchemaMappings); const transformed = await exporter.toReactPDFDocument( partialBlocksToBlocksForTesting(schema, [ { type: "columnList", children: [ { type: "column", props: { width: 0.8, }, children: [ { type: "paragraph", content: "This paragraph is in a column!", }, ], }, { type: "column", props: { width: 1.4, }, children: [ { type: "heading", content: "So is this heading!", }, ], }, { type: "column", props: { width: 0.8, }, children: [ { type: "paragraph", content: "You can have multiple blocks in a column too", }, { type: "bulletListItem", content: "Block 1", }, { type: "bulletListItem", content: "Block 2", }, { type: "bulletListItem", content: "Block 3", }, ], }, ], }, ]), ); const str = reactElementToJSXString(transformed); await expect(str).toMatchFileSnapshot( "__snapshots__/exampleWithMultiColumn.jsx", ); }); });