diff --git a/.nycrc b/.nycrc index 64dc581dc7..725a0fa539 100644 --- a/.nycrc +++ b/.nycrc @@ -1,7 +1,7 @@ { "check-coverage": true, "statements": 99.87, - "branches": 98.29, + "branches": 98.21, "functions": 100, "lines": 99.86, "include": [ diff --git a/src/patcher/from-docx.spec.ts b/src/patcher/from-docx.spec.ts index 296c3d93d7..4ba5a30af5 100644 --- a/src/patcher/from-docx.spec.ts +++ b/src/patcher/from-docx.spec.ts @@ -206,8 +206,7 @@ const MOCK_XML = ` describe("from-docx", () => { describe("patchDocument", () => { describe("document.xml and [Content_Types].xml", () => { - before(() => { - sinon.createStubInstance(JSZip, {}); + beforeEach(() => { sinon.stub(JSZip, "loadAsync").callsFake( () => new Promise((resolve) => { @@ -220,7 +219,7 @@ describe("from-docx", () => { ); }); - after(() => { + afterEach(() => { (JSZip.loadAsync as unknown as sinon.SinonStub).restore(); }); @@ -292,8 +291,7 @@ describe("from-docx", () => { }); describe("document.xml and [Content_Types].xml with relationships", () => { - before(() => { - sinon.createStubInstance(JSZip, {}); + beforeEach(() => { sinon.stub(JSZip, "loadAsync").callsFake( () => new Promise((resolve) => { @@ -307,7 +305,7 @@ describe("from-docx", () => { ); }); - after(() => { + afterEach(() => { (JSZip.loadAsync as unknown as sinon.SinonStub).restore(); }); @@ -322,6 +320,14 @@ describe("from-docx", () => { data: Buffer.from(""), transformation: { width: 100, height: 100 }, }), + new ExternalHyperlink({ + children: [ + new TextRun({ + text: "Google Link", + }), + ], + link: "https://www.google.co.uk", + }), ], }, }, @@ -331,8 +337,7 @@ describe("from-docx", () => { }); describe("document.xml", () => { - before(() => { - sinon.createStubInstance(JSZip, {}); + beforeEach(() => { sinon.stub(JSZip, "loadAsync").callsFake( () => new Promise((resolve) => { @@ -344,7 +349,45 @@ describe("from-docx", () => { ); }); - after(() => { + afterEach(() => { + (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); + }); + + describe("Images", () => { + beforeEach(() => { + sinon.stub(JSZip, "loadAsync").callsFake( + () => + new Promise((resolve) => { + const zip = new JSZip(); + + zip.file("word/document.xml", MOCK_XML); + zip.file("word/document.bmp", ""); + + resolve(zip); + }), + ); + }); + + afterEach(() => { (JSZip.loadAsync as unknown as sinon.SinonStub).restore(); }); diff --git a/src/patcher/from-docx.ts b/src/patcher/from-docx.ts index 675f72c5a5..62afd19091 100644 --- a/src/patcher/from-docx.ts +++ b/src/patcher/from-docx.ts @@ -68,7 +68,14 @@ export const patchDocument = async (data: InputDataType, options: PatchDocumentO const hyperlinkRelationshipAdditions: IHyperlinkRelationshipAddition[] = []; let hasMedia = false; + const binaryContentMap = new Map(); + for (const [key, value] of Object.entries(zipContent.files)) { + if (!key.endsWith(".xml") && !key.endsWith(".rels")) { + binaryContentMap.set(key, await value.async("nodebuffer")); + continue; + } + const json = toJson(await value.async("text")); if (key.startsWith("word/") && !key.endsWith(".xml.rels")) { const context: IContext = { @@ -196,6 +203,10 @@ export const patchDocument = async (data: InputDataType, options: PatchDocumentO zip.file(key, output); } + for (const [key, value] of binaryContentMap) { + zip.file(key, value); + } + for (const { stream, fileName } of file.Media.Array) { zip.file(`word/media/${fileName}`, stream); }