diff --git a/package-lock.json b/package-lock.json index 13f3f32f2b..c4f335e75c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ }, "devDependencies": { "@types/chai": "^4.2.15", + "@types/chai-as-promised": "^7.1.5", "@types/glob": "^8.0.0", "@types/mocha": "^10.0.0", "@types/prompt": "^1.1.1", @@ -29,6 +30,7 @@ "@typescript-eslint/parser": "^5.36.1", "buffer": "^6.0.3", "chai": "^4.3.6", + "chai-as-promised": "^7.1.1", "cspell": "^6.2.2", "docsify-cli": "^4.3.0", "eslint": "^8.23.0", @@ -1189,6 +1191,15 @@ "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", "dev": true }, + "node_modules/@types/chai-as-promised": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.5.tgz", + "integrity": "sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ==", + "dev": true, + "dependencies": { + "@types/chai": "*" + } + }, "node_modules/@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -2865,6 +2876,18 @@ "node": ">=4" } }, + "node_modules/chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 5" + } + }, "node_modules/chainsaw": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", @@ -12547,6 +12570,15 @@ "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", "dev": true }, + "@types/chai-as-promised": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.5.tgz", + "integrity": "sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ==", + "dev": true, + "requires": { + "@types/chai": "*" + } + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -13778,6 +13810,15 @@ "type-detect": "^4.0.5" } }, + "chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "requires": { + "check-error": "^1.0.2" + } + }, "chainsaw": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", diff --git a/package.json b/package.json index c08a2678b2..621c6b9fb9 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "homepage": "https://github.com/dolanmiu/docx#readme", "devDependencies": { "@types/chai": "^4.2.15", + "@types/chai-as-promised": "^7.1.5", "@types/glob": "^8.0.0", "@types/mocha": "^10.0.0", "@types/prompt": "^1.1.1", @@ -76,6 +77,7 @@ "@typescript-eslint/parser": "^5.36.1", "buffer": "^6.0.3", "chai": "^4.3.6", + "chai-as-promised": "^7.1.1", "cspell": "^6.2.2", "docsify-cli": "^4.3.0", "eslint": "^8.23.0", diff --git a/src/patcher/from-docx.spec.ts b/src/patcher/from-docx.spec.ts index 9fa8b45119..296c3d93d7 100644 --- a/src/patcher/from-docx.spec.ts +++ b/src/patcher/from-docx.spec.ts @@ -1,11 +1,15 @@ -import { expect } from "chai"; +import * as chai from "chai"; import * as sinon from "sinon"; import * as JSZip from "jszip"; +import * as chaiAsPromised from "chai-as-promised"; import { ExternalHyperlink, ImageRun, Paragraph, TextRun } from "@file/paragraph"; import { patchDocument, PatchType } from "./from-docx"; +chai.use(chaiAsPromised); +const { expect } = chai; + const MOCK_XML = ` { describe("patchDocument", () => { - beforeEach(() => { - sinon.createStubInstance(JSZip, {}); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - sinon.stub(JSZip, "loadAsync").callsFake( - () => - new Promise((resolve) => { - const zip = new JSZip(); + describe("document.xml and [Content_Types].xml", () => { + before(() => { + sinon.createStubInstance(JSZip, {}); + sinon.stub(JSZip, "loadAsync").callsFake( + () => + new Promise((resolve) => { + const zip = new JSZip(); - zip.file("word/document.xml", MOCK_XML); - zip.file("[Content_Types].xml", ``); - resolve(zip); - }), - ); - }); - - afterEach(() => { - (JSZip.loadAsync as unknown as sinon.SinonStub).restore(); - }); - - it("should patch the document", async () => { - const output = await patchDocument(Buffer.from(""), { - patches: { - name: { - type: PatchType.PARAGRAPH, - children: [new TextRun("Sir. "), new TextRun("John Doe"), new TextRun("(The Conqueror)")], - }, - item_1: { - type: PatchType.PARAGRAPH, - children: [ - new TextRun("#657"), - new ExternalHyperlink({ - children: [ - new TextRun({ - text: "BBC News Link", - }), - ], - link: "https://www.bbc.co.uk/news", - }), - ], - }, - // eslint-disable-next-line @typescript-eslint/naming-convention - paragraph_replace: { - type: PatchType.DOCUMENT, - children: [ - new Paragraph({ - children: [ - new TextRun("This is a "), - new ExternalHyperlink({ - children: [ - new TextRun({ - text: "Google Link", - }), - ], - link: "https://www.google.co.uk", - }), - new ImageRun({ - data: Buffer.from(""), - transformation: { width: 100, height: 100 }, - }), - ], - }), - ], - }, - // eslint-disable-next-line @typescript-eslint/naming-convention - image_test: { - type: PatchType.PARAGRAPH, - children: [ - new ImageRun({ - data: Buffer.from(""), - transformation: { width: 100, height: 100 }, - }), - ], - }, - }, + zip.file("word/document.xml", MOCK_XML); + zip.file("[Content_Types].xml", ``); + resolve(zip); + }), + ); }); - expect(output).to.not.be.undefined; - }); - it("should patch the document", async () => { - const output = await patchDocument(Buffer.from(""), { - patches: {}, + after(() => { + (JSZip.loadAsync as unknown as sinon.SinonStub).restore(); }); - expect(output).to.not.be.undefined; - }); - it("should use the relationships file rather than create one", () => { - (JSZip.loadAsync as unknown as sinon.SinonStub).restore(); - sinon.createStubInstance(JSZip, {}); - sinon.stub(JSZip, "loadAsync").callsFake( - () => - new Promise((resolve) => { - const zip = new JSZip(); - - zip.file("word/document.xml", MOCK_XML); - zip.file("word/_rels/document.xml.rels", ``); - zip.file("[Content_Types].xml", ``); - resolve(zip); - }), - ); - - const output = patchDocument(Buffer.from(""), { - patches: { - // eslint-disable-next-line @typescript-eslint/naming-convention - image_test: { - type: PatchType.PARAGRAPH, - children: [ - new ImageRun({ - data: Buffer.from(""), - transformation: { width: 100, height: 100 }, - }), - ], + it("should patch the document", async () => { + const output = await patchDocument(Buffer.from(""), { + patches: { + name: { + type: PatchType.PARAGRAPH, + children: [new TextRun("Sir. "), new TextRun("John Doe"), new TextRun("(The Conqueror)")], + }, + item_1: { + type: PatchType.PARAGRAPH, + children: [ + new TextRun("#657"), + new ExternalHyperlink({ + children: [ + new TextRun({ + text: "BBC News Link", + }), + ], + link: "https://www.bbc.co.uk/news", + }), + ], + }, + // eslint-disable-next-line @typescript-eslint/naming-convention + paragraph_replace: { + type: PatchType.DOCUMENT, + children: [ + new Paragraph({ + children: [ + new TextRun("This is a "), + new ExternalHyperlink({ + children: [ + new TextRun({ + text: "Google Link", + }), + ], + link: "https://www.google.co.uk", + }), + new ImageRun({ + data: Buffer.from(""), + transformation: { width: 100, height: 100 }, + }), + ], + }), + ], + }, + // eslint-disable-next-line @typescript-eslint/naming-convention + image_test: { + type: PatchType.PARAGRAPH, + children: [ + new ImageRun({ + data: Buffer.from(""), + transformation: { width: 100, height: 100 }, + }), + ], + }, }, - }, + }); + expect(output).to.not.be.undefined; + }); + + it("should patch the document", async () => { + const output = await patchDocument(Buffer.from(""), { + patches: {}, + }); + expect(output).to.not.be.undefined; }); - expect(output).to.not.be.undefined; }); - it("should throw an error if the content types is not found", () => { - (JSZip.loadAsync as unknown as sinon.SinonStub).restore(); - sinon.createStubInstance(JSZip, {}); - sinon.stub(JSZip, "loadAsync").callsFake( - () => - new Promise((resolve) => { - const zip = new JSZip(); + describe("document.xml and [Content_Types].xml with relationships", () => { + before(() => { + sinon.createStubInstance(JSZip, {}); + sinon.stub(JSZip, "loadAsync").callsFake( + () => + new Promise((resolve) => { + const zip = new JSZip(); - zip.file("word/document.xml", MOCK_XML); - resolve(zip); - }), - ); + zip.file("word/document.xml", MOCK_XML); + zip.file("word/_rels/document.xml.rels", ``); + zip.file("[Content_Types].xml", ``); + resolve(zip); + }), + ); + }); - expect(() => - patchDocument(Buffer.from(""), { + after(() => { + (JSZip.loadAsync as unknown as sinon.SinonStub).restore(); + }); + + it("should use the relationships file rather than create one", async () => { + const output = await patchDocument(Buffer.from(""), { patches: { // eslint-disable-next-line @typescript-eslint/naming-convention image_test: { @@ -345,8 +325,46 @@ describe("from-docx", () => { ], }, }, - }), - ).to.throw(); + }); + expect(output).to.not.be.undefined; + }); + }); + + describe("document.xml", () => { + before(() => { + sinon.createStubInstance(JSZip, {}); + sinon.stub(JSZip, "loadAsync").callsFake( + () => + new Promise((resolve) => { + const zip = new JSZip(); + + zip.file("word/document.xml", MOCK_XML); + resolve(zip); + }), + ); + }); + + after(() => { + (JSZip.loadAsync as unknown as sinon.SinonStub).restore(); + }); + + it("should throw an error if the content types is not found", () => + expect( + patchDocument(Buffer.from(""), { + patches: { + // eslint-disable-next-line @typescript-eslint/naming-convention + image_test: { + type: PatchType.PARAGRAPH, + children: [ + new ImageRun({ + data: Buffer.from(""), + transformation: { width: 100, height: 100 }, + }), + ], + }, + }, + }), + ).to.eventually.be.rejected); }); }); });