diff --git a/printers/docx/test/full/.gitignore b/printers/docx/test/full/.gitignore new file mode 100644 index 0000000..c585e19 --- /dev/null +++ b/printers/docx/test/full/.gitignore @@ -0,0 +1 @@ +out \ No newline at end of file diff --git a/printers/docx/test/full/files/additional.mxd b/printers/docx/test/full/files/additional.mxd new file mode 100644 index 0000000..ae303c3 --- /dev/null +++ b/printers/docx/test/full/files/additional.mxd @@ -0,0 +1,9 @@ +## Additional file + +Formula: + +$$$math +y = bx + c +$$$ + +Image from main.mxd !PK[img]. diff --git a/printers/docx/test/full/files/main.mxd b/printers/docx/test/full/files/main.mxd new file mode 100644 index 0000000..7ae93a5 --- /dev/null +++ b/printers/docx/test/full/files/main.mxd @@ -0,0 +1,5 @@ +# Main file with content + +Image here + +![image-label](./nothing)(@h 4cm)(@n Image) diff --git a/printers/docx/test/full/files/unused.mxd b/printers/docx/test/full/files/unused.mxd new file mode 100644 index 0000000..b775196 --- /dev/null +++ b/printers/docx/test/full/files/unused.mxd @@ -0,0 +1,3 @@ +## Hidden content + +This content should not appear in the result file diff --git a/printers/docx/test/full/index.spec.ts b/printers/docx/test/full/index.spec.ts new file mode 100644 index 0000000..2171da6 --- /dev/null +++ b/printers/docx/test/full/index.spec.ts @@ -0,0 +1,104 @@ +import { convertYaxmFiles, diagnostic } from '@md-to-latex/converter'; +import * as fs from 'fs'; +import * as path from 'path'; +import yaml from 'js-yaml'; +import { buildConfig, createPrinterDocx } from '../../src'; + +describe('convertMarkdownFiles', function () { + const fullDiagnosticList: diagnostic.DiagnoseList = []; + + beforeAll(() => { + const convertResult = convertYaxmFiles({ + rootDir: __dirname, + buildConfig: yaml.load( + fs.readFileSync( + path.join(__dirname, 'yaxm-build.yml'), + 'utf-8', + ), + ) as any, + }); + fullDiagnosticList.push(...convertResult.diagnostic); + + const printer = createPrinterDocx(buildConfig()); + convertResult.result.forEach(data => { + const result = printer.processNode(printer, data.fileNode); + + const fullOutPath = path.join(__dirname, data.fileInfo.out); + + fs.mkdirSync(path.dirname(fullOutPath), { recursive: true }); + fs.writeFileSync(fullOutPath, result.result, 'utf-8'); + + fullDiagnosticList.push(...result.diagnostic); + }); + }); + + const fileParameters = { + main: { + pathTex: path.join(__dirname, 'out', 'main.tex'), + pathMd: path.join(__dirname, 'files', 'main.tex'), + emitted: true, + }, + another: { + pathTex: path.join(__dirname, 'out', 'another.tex'), + pathMd: path.join(__dirname, 'files', 'another.tex'), + emitted: true, + }, + unused: { + pathTex: path.join(__dirname, 'out', 'unused.tex'), + pathMd: path.join(__dirname, 'files', 'unused.tex'), + emitted: false, + }, + } as { + [Key: string]: { + pathTex: string; + pathMd: string; + emitted: boolean; + }; + }; + + Object.entries(fileParameters).forEach(entry => { + const emitted = entry[1].emitted; + test(`File ${entry[0]} should${ + emitted ? '' : ' not' + } be emitted`, () => { + if (emitted) { + expect(fs.existsSync(entry[1].pathTex)).toBeTruthy(); + } else { + expect(fs.existsSync(entry[1].pathTex)).not.toBeTruthy(); + } + }); + }); + + test('main.tex correct content', () => { + const content = fs.readFileSync(fileParameters.main.pathTex, 'utf8'); + + expect(content).toContain( + '\\section{\\uppercase{Main file with content}}', + ); + expect(content).toContain('\\setlength{\\belowcaptionskip}{-4ex}'); + expect(content).not.toContain( + '\\addtolength{\\belowcaptionskip}{-1em}', + ); + expect(content).toContain('\\begin{figure}[H]'); + expect(content).toContain('\\includegraphics[height=4cm]{./nothing}'); + expect(content).toContain('\\caption{Рисунок 1 -- Image}'); + expect(content).toContain('\\begin{figure}[H]'); + }); + + test('another.tex correct content', () => { + const content = fs.readFileSync(fileParameters.another.pathTex, 'utf8'); + + expect(content).toContain('\\subsection{Additional file}'); + expect(content).toContain('Formula:'); + expect(content).toContain('\\setlength{\\abovedisplayskip}{-0.9em}'); + expect(content).toContain('\\setlength{\\belowdisplayskip}{0pt}'); + expect(content).toContain('\\setlength{\\abovedisplayshortskip}{0pt}'); + expect(content).toContain('\\setlength{\\belowdisplayshortskip}{0pt}'); + }); + + test('another.tex correct link to image, defined in main.mxd', () => { + const content = fs.readFileSync(fileParameters.another.pathTex, 'utf8'); + + expect(content).toContain('Image from main.mxd 2'); + }); +}); diff --git a/printers/docx/test/full/yaxm-build.yml b/printers/docx/test/full/yaxm-build.yml new file mode 100644 index 0000000..75b52d6 --- /dev/null +++ b/printers/docx/test/full/yaxm-build.yml @@ -0,0 +1,5 @@ +files: + - path: files/main.mxd + out: out/main.tex + - path: files/additional.mxd + out: out/another.tex diff --git a/printers/docx/test/printer/__snapshots__/printer.spec.ts.snap b/printers/docx/test/printer/__snapshots__/printer.spec.ts.snap new file mode 100644 index 0000000..4083933 --- /dev/null +++ b/printers/docx/test/printer/__snapshots__/printer.spec.ts.snap @@ -0,0 +1,249 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`simple md to latex docs printer Header + Image + Code + Image 1`] = ` +Array [ + Object { + "errorType": 2, + "filePath": "[PATH]", + "message": "Unused picture label img-1", + "pos": Object { + "end": Object { + "absolute": 65, + "column": 55, + "line": 4, + }, + "start": Object { + "absolute": 11, + "column": 1, + "line": 4, + }, + }, + "severity": "WARNING", + }, + Object { + "errorType": 2, + "filePath": "[PATH]", + "message": "Unused picture label code-1", + "pos": Object { + "end": Object { + "absolute": 144, + "column": 4, + "line": 9, + }, + "start": Object { + "absolute": 67, + "column": 1, + "line": 6, + }, + }, + "severity": "WARNING", + }, + Object { + "errorType": 2, + "filePath": "[PATH]", + "message": "Unused picture label img-2", + "pos": Object { + "end": Object { + "absolute": 202, + "column": 57, + "line": 11, + }, + "start": Object { + "absolute": 146, + "column": 1, + "line": 11, + }, + }, + "severity": "WARNING", + }, + Object { + "errorType": 4, + "filePath": "[PATH]", + "message": "Unable to print node with type 'Heading' (TODO)", + "pos": Object { + "end": Object { + "absolute": 9, + "column": 9, + "line": 2, + }, + "start": Object { + "absolute": 1, + "column": 1, + "line": 2, + }, + }, + "severity": "WARNING", + }, + Object { + "errorType": 4, + "filePath": "[PATH]", + "message": "Unable to print node with type 'PictureProcessed' (TODO)", + "pos": Object { + "end": Object { + "absolute": 65, + "column": 55, + "line": 4, + }, + "start": Object { + "absolute": 11, + "column": 1, + "line": 4, + }, + }, + "severity": "WARNING", + }, + Object { + "errorType": 4, + "filePath": "[PATH]", + "message": "Unable to print node with type 'CodeProcessed' (TODO)", + "pos": Object { + "end": Object { + "absolute": 144, + "column": 4, + "line": 9, + }, + "start": Object { + "absolute": 67, + "column": 1, + "line": 6, + }, + }, + "severity": "WARNING", + }, + Object { + "errorType": 4, + "filePath": "[PATH]", + "message": "Unable to print node with type 'PictureProcessed' (TODO)", + "pos": Object { + "end": Object { + "absolute": 202, + "column": 57, + "line": 11, + }, + "start": Object { + "absolute": 146, + "column": 1, + "line": 11, + }, + }, + "severity": "WARNING", + }, +] +`; + +exports[`simple md to latex docs printer Header + Image + Code + Image 2`] = ` +Array [ + we { + "properties": pe { + "root": Array [], + "rootKey": "w:rPr", + }, + "root": Array [ + pe { + "root": Array [], + "rootKey": "w:rPr", + }, + fe { + "root": Array [ + V { + "root": Object { + "space": "preserve", + }, + "rootKey": "_attr", + "xmlKeys": Object { + "space": "xml:space", + }, + }, + "[TODO 'Heading']", + ], + "rootKey": "w:t", + }, + ], + "rootKey": "w:r", + }, + we { + "properties": pe { + "root": Array [], + "rootKey": "w:rPr", + }, + "root": Array [ + pe { + "root": Array [], + "rootKey": "w:rPr", + }, + fe { + "root": Array [ + V { + "root": Object { + "space": "preserve", + }, + "rootKey": "_attr", + "xmlKeys": Object { + "space": "xml:space", + }, + }, + "[TODO 'PictureProcessed']", + ], + "rootKey": "w:t", + }, + ], + "rootKey": "w:r", + }, + we { + "properties": pe { + "root": Array [], + "rootKey": "w:rPr", + }, + "root": Array [ + pe { + "root": Array [], + "rootKey": "w:rPr", + }, + fe { + "root": Array [ + V { + "root": Object { + "space": "preserve", + }, + "rootKey": "_attr", + "xmlKeys": Object { + "space": "xml:space", + }, + }, + "[TODO 'CodeProcessed']", + ], + "rootKey": "w:t", + }, + ], + "rootKey": "w:r", + }, + we { + "properties": pe { + "root": Array [], + "rootKey": "w:rPr", + }, + "root": Array [ + pe { + "root": Array [], + "rootKey": "w:rPr", + }, + fe { + "root": Array [ + V { + "root": Object { + "space": "preserve", + }, + "rootKey": "_attr", + "xmlKeys": Object { + "space": "xml:space", + }, + }, + "[TODO 'PictureProcessed']", + ], + "rootKey": "w:t", + }, + ], + "rootKey": "w:r", + }, +] +`; diff --git a/printers/docx/test/printer/__snapshots__/validation.spec.ts.snap b/printers/docx/test/printer/__snapshots__/validation.spec.ts.snap new file mode 100644 index 0000000..15f1272 --- /dev/null +++ b/printers/docx/test/printer/__snapshots__/validation.spec.ts.snap @@ -0,0 +1,47 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`validation test paragraph must be the root node 1`] = ` +Array [ + Object { + "errorType": 7, + "filePath": ".", + "message": "The docx root node is not a paragraph", + "pos": Object { + "end": Object { + "absolute": 0, + "column": 0, + "line": 0, + }, + "start": Object { + "absolute": 0, + "column": 0, + "line": 0, + }, + }, + "severity": "ERROR", + }, +] +`; + +exports[`validation test paragraph must not contain paragraphs 1`] = ` +Array [ + Object { + "errorType": 7, + "filePath": ".", + "message": "Docx Paragraph in paragraph detected", + "pos": Object { + "end": Object { + "absolute": 0, + "column": 0, + "line": 0, + }, + "start": Object { + "absolute": 0, + "column": 0, + "line": 0, + }, + }, + "severity": "ERROR", + }, +] +`; diff --git a/printers/docx/test/printer/printer.spec.ts b/printers/docx/test/printer/printer.spec.ts new file mode 100644 index 0000000..624f43b --- /dev/null +++ b/printers/docx/test/printer/printer.spec.ts @@ -0,0 +1,528 @@ +import { parseFile } from '@md-to-latex/converter/dist/ast/parsing'; +import { applyMacrosFull } from '@md-to-latex/converter/dist/macro'; +import { buildConfig, createPrinterDocx } from '../../src'; +import { DiagnoseList } from '@md-to-latex/converter/dist/diagnostic'; +import { YAXMDocxPrinterConfig } from '../../src/config'; +import { XmlComponent } from "docx"; + +function processingChain( + text: string, + config?: Partial, +): { + result: XmlComponent[]; + diagnostic: DiagnoseList; +} { + const { result: fileNode, diagnostic: fileDiagnostic } = parseFile( + text, + 'filepath', + ); + + const macroDiagnostic = applyMacrosFull(fileNode); + + const printer = createPrinterDocx(buildConfig(config)); + const { result, diagnostic: printerDiagnostic } = printer.processNode( + printer, + fileNode, + ); + + return { + result, + diagnostic: [ + ...fileDiagnostic, + ...macroDiagnostic, + ...printerDiagnostic, + ], + }; +} + +describe('simple md to latex docs printer', () => { + test('Paragraph', () => { + const result = processingChain(` +# Header + +Text +`); + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Subheader + List + Code Span', () => { + const result = processingChain(` +# Header + +- A +- B +- C + +## Subheader + +1. X +2. Y + 1. T + - 600 + - 700 + 2. \`Code_span\` +3. Z +`); + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Header + Image + Code + Image', () => { + const result = processingChain(` +# Header + +![img-1](./assets/img/dolphin.png)(Image name)(@h 5cm) + +\`\`\`python[code-1](Python Sample Code) +def main(): + print "Hello World" +\`\`\` + +![img-2](./assets/img/dolphin.png)(Image name 2)(@h 7cm) +`); + + expect(result.diagnostic).not.toHaveLength(0); + expect(result.diagnostic).toMatchSnapshot(); + expect(result.result).toMatchSnapshot(); + }); + + test('Del node', () => { + const result = processingChain(` +Test==node *what* hell==yeah we~ll. + `); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Code + Code', () => { + const result = processingChain(` +# Header + +Code in !PK[code-1] и !PK[code-2]. + + +\`\`\`python[code-1](Python Sample Code) +def main(): + print "Hello World" +\`\`\` + +\`\`\`python[code-2](Python Sample Code 2) +def hello_world(): + print "Hello World" +\`\`\` +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Table', () => { + const result = processingChain(` +Demonstrated in table !TK[table]. + +!T[table](Table with content) + +|a|b|c|d| +|---|---|---|---| +|1|2|3|4| +|t|r|e|z| +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Header + Formula', () => { + const result = processingChain(` +# Header + +$$$math + a = b + c +$$$ +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Inline formula must be wrapped with spaces', () => { + const result = processingChain(` +Inlined formula $\`\\sigma^2_w(t)=\\omega_0(t)\\sigma^2_0(t)+\\omega_1(t)\\sigma^2_1(t)\`$ +into the sentence. +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('bold and italic', () => { + const result = processingChain(`**Bold**: *testing*`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('ListItem + Br + Text must have 2 line breaks', () => { + const result = processingChain(`1. Item +New Line + +2. New Item`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('ListItem + MathLatex must have 2 line breaks', () => { + const result = processingChain(`1. Text +$$$math +Some text here +$$$`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); +}); + +describe('Applications', () => { + test('with list', () => { + const result = processingChain(`\ +!AC[code-full](@dir ./assets/code)(@file template-full.py)(@lang python) +!AC[code-full2](@dir ./assets/code)(@file template-full2.py)(@lang python) +!APR[picture-large](Large scheme)(./assets/img/circuit.png) + +# Header + +Code from application !AK[code-full2] describes image from application !AK[picture-large]. + +See application !AK[code-full]. + +# Applications + +!LAA[] +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('with multiple columns', () => { + const result = processingChain(` +!AC[code-full](@dir ./assets/code)(@file template-full.py)(@lang python)(@c 2) + +# Header + +See application !AK[code-full]. + +# Applications + +!LAA[] +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Unused application, should throw error', () => { + const result = processingChain(` +!AC[code-full](./assets/code)(template-full.py)(python) + +!LAA[] +`); + + expect(result.diagnostic).not.toHaveLength(0); + expect(result.diagnostic).toMatchSnapshot(); + expect(result.result).toMatchSnapshot(); + }); + + test('Undefined application, should throw error', () => { + const result = processingChain(` +!AK[nope] +`); + + expect(result.diagnostic).not.toHaveLength(0); + expect(result.diagnostic).toMatchSnapshot(); + expect(result.result).toMatchSnapshot(); + }); +}); + +describe('References', () => { + test('with list', () => { + const result = processingChain(` +!R[ref-1]( + H.~Y.~~Ignat. <> // Some Journal, 1867 +) + +!R[ref-2]( + H.~Y.~~Ignat. <> // Some Journal, 1867 +) + +# Header + +Code from reference !RK[ref-2] describes image from reference !RK[ref-1]. + +# References + +!LAR[] +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Unused reference, should throw error', () => { + const result = processingChain(` +!R[ref]( + A.~A.~~Amogus. <> // Steam library, 2021 +) + +!LAR[] +`); + + expect(result.diagnostic).not.toHaveLength(0); + expect(result.diagnostic).toMatchSnapshot(); + expect(result.result).toMatchSnapshot(); + }); + + test('Undefined reference, should throw error', () => { + const result = processingChain(` +!RK[nope] +`); + + expect(result.diagnostic).not.toHaveLength(0); + expect(result.diagnostic).toMatchSnapshot(); + expect(result.result).toMatchSnapshot(); + }); +}); + +describe('complex latex', function () { + test('Inline math', () => { + const result = processingChain(` +Text $\`a = b + \\sum_{i=0}^\\infty c_i\`$ ending. +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + + expect(result.result) + .toEqual(`Text $\\displaystyle a = b + \\sum_{i=0}^\\infty c_i$ ending. +`); + }); + + test('Text with percents', () => { + const result = processingChain(` +Text with 10% number. +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Text with escapes ("<" should be correct also)', () => { + const result = processingChain(` +Text with <<>assdasd. +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Tag
should break the page', () => { + const result = processingChain(` +The first page + +--------------------------------------- + +The second page +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Tag
should put additional break', () => { + const result = processingChain(` +The first line +The second line +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test("Text ' dereplacement", () => { + const result = processingChain(` +Otsu's method is a one-dimensional discrete analog of Fisher's +Discriminant Analysis, is related to Jenks optimization method. +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('CodeSpan dereplacement', () => { + const result = processingChain('`"sample & text"`'); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Inline latex math dereplacement', () => { + const result = processingChain(` +$\`a > b < c\`$ +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Table and picture key', () => { + const result = processingChain(` +Displayed in picture !PK[gray-square] (!PK[gray-square]) and table !TK[table]. + +![gray-square](./assets/img/example.png)(Gray square)(@h 5cm) + +!T[table](Table) + +|Key |Value | +|-------|------| +|Static number | 50 | +|Random number | $$ \\showcaserandomnumber $$ | +`); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); +}); + +describe('latex picture after table (#52)', function () { + // See https://github.com/markdown-to-latex/converter/issues/52 + test('Picture right after the table', () => { + const result = processingChain( + `!T[table](Table example) + +| Key | Value | +| ------------- | --------------------------- | +| Static number | 50 | + +![gray-square](./assets/img/example.png)(Gray square)(@h 5cm)`, + ); + + expect(result.diagnostic).not.toHaveLength(0); + expect(result.diagnostic).toMatchSnapshot(); + expect(result.result).toMatchSnapshot(); + }); + + test('Table + text + picture', () => { + const result = processingChain( + `!T[table](Table example) + +| Key | Value | +| ------------- | --------------------------- | +| Static number | 50 | + +Sample text line + +![gray-square](./assets/img/example.png)(Gray square)(@h 5cm)`, + ); + + expect(result.diagnostic).not.toHaveLength(0); + expect(result.diagnostic).toMatchSnapshot(); + expect(result.result).toMatchSnapshot(); + }); +}); + +describe('url variants', () => { + test('Default url', () => { + const result = processingChain( + '[](https://example.com/index_page.html?asd=asdasd&gege=gegege#header)', + ); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Bold url', () => { + const result = processingChain( + '[](https://example.com/index_page.html?asd=asdasd&gege=gegege#header)', + { + useLinkAs: 'bold', + }, + ); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Italic url', () => { + const result = processingChain( + '[](https://example.com/index_page.html?asd=asdasd&gege=gegege#header)', + { + useLinkAs: 'italic', + }, + ); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Underlined url', () => { + const result = processingChain( + '[](https://example.com/index_page.html?asd=asdasd&gege=gegege#header)', + { + useLinkAs: 'underline', + }, + ); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('No escape & code url', () => { + const result = processingChain( + '[](https://example.com/index_page.html?asd=asdasd&asdasd=gege#header)', + { + useLinkAs: 'monospace', + }, + ); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); +}); + +describe('Escapes', () => { + test('Default escapes', () => { + const result = processingChain(` +# Header + + + +The "definition" increased by 1% (more text more text). + `); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); +}); + +describe('CodeSpan', () => { + test('Monospace', () => { + const result = processingChain('CodeSpan `text & text`.', { + useCodeSpanAs: 'monospace', + }); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); + + test('Quote', () => { + const result = processingChain('CodeSpan `text & text`.', { + useCodeSpanAs: 'quotes', + }); + + expect(result.diagnostic).toHaveLength(0); + expect(result.result).toMatchSnapshot(); + }); +}); diff --git a/printers/docx/test/printer/validation.spec.ts b/printers/docx/test/printer/validation.spec.ts new file mode 100644 index 0000000..d2716ba --- /dev/null +++ b/printers/docx/test/printer/validation.spec.ts @@ -0,0 +1,21 @@ +import * as docx from "docx"; +import { validateDocxRootNode } from "../../src/validation"; + +describe("validation test", function() { + test("paragraph must be the root node", function() { + let diagnostic = validateDocxRootNode(new docx.TextRun({})); + expect(diagnostic).toMatchSnapshot(); + }); + + test("paragraph must not contain paragraphs", function() { + let node = new docx.Paragraph({ + children: [ + new docx.TextRun({ + children: [new docx.Paragraph({})] + }) + ] + }); + let diagnostic = validateDocxRootNode(node); + expect(diagnostic).toMatchSnapshot(); + }); +}); \ No newline at end of file