349 lines
11 KiB
JavaScript
349 lines
11 KiB
JavaScript
const {
|
|
expectToThrow,
|
|
createDoc,
|
|
shouldBeSame,
|
|
isNode12,
|
|
createDocV4,
|
|
} = require("./utils");
|
|
const Errors = require("../errors.js");
|
|
const { expect } = require("chai");
|
|
const { xml2str, traits } = require("../doc-utils");
|
|
|
|
describe("Verify apiversion", function () {
|
|
it("should work with valid api version", function () {
|
|
const module = {
|
|
requiredAPIVersion: "3.23.0",
|
|
render(part) {
|
|
return part.value;
|
|
},
|
|
};
|
|
const doc = createDoc("loop-valid.docx");
|
|
doc.attachModule(module);
|
|
});
|
|
|
|
it("should fail with invalid api version", function () {
|
|
const module = {
|
|
requiredAPIVersion: "3.92.0",
|
|
render(part) {
|
|
return part.value;
|
|
},
|
|
};
|
|
const doc = createDoc("loop-valid.docx");
|
|
|
|
expectToThrow(() => doc.attachModule(module), Errors.XTAPIVersionError, {
|
|
message:
|
|
"The minor api version is not uptodate, you probably have to update docxtemplater with npm install --save docxtemplater",
|
|
name: "APIVersionError",
|
|
properties: {
|
|
id: "api_version_error",
|
|
currentModuleApiVersion: [3, 24, 0],
|
|
neededVersion: [3, 92, 0],
|
|
},
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Module attachment", function () {
|
|
it("should not allow to attach the same module twice", function () {
|
|
const module = {
|
|
name: "TestModule",
|
|
requiredAPIVersion: "3.0.0",
|
|
render(part) {
|
|
return part.value;
|
|
},
|
|
};
|
|
const doc1 = createDoc("loop-valid.docx");
|
|
doc1.attachModule(module);
|
|
const doc2 = createDoc("tag-example.docx");
|
|
|
|
let errMessage = null;
|
|
try {
|
|
doc2.attachModule(module);
|
|
} catch (e) {
|
|
errMessage = e.message;
|
|
}
|
|
expect(errMessage).to.equal(
|
|
'Cannot attach a module that was already attached : "TestModule". Maybe you are instantiating the module at the root level, and using it for multiple instances of Docxtemplater'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Module xml parse", function () {
|
|
it("should not mutate options (regression for issue #526)", function () {
|
|
const module = {
|
|
requiredAPIVersion: "3.0.0",
|
|
optionsTransformer(options, docxtemplater) {
|
|
const relsFiles = docxtemplater.zip
|
|
.file(/document.xml.rels/)
|
|
.map((file) => file.name);
|
|
options.xmlFileNames = options.xmlFileNames.concat(relsFiles);
|
|
return options;
|
|
},
|
|
};
|
|
const doc = createDoc("tag-example.docx");
|
|
const opts = {};
|
|
doc.setOptions(opts);
|
|
doc.attachModule(module);
|
|
doc.compile();
|
|
expect(opts).to.deep.equal({});
|
|
});
|
|
|
|
it("should be possible to parse xml files", function () {
|
|
let xmlDocuments;
|
|
|
|
const module = {
|
|
requiredAPIVersion: "3.0.0",
|
|
optionsTransformer(options, docxtemplater) {
|
|
const relsFiles = docxtemplater.zip
|
|
.file(/document.xml.rels/)
|
|
.map((file) => file.name);
|
|
options.xmlFileNames = options.xmlFileNames.concat(relsFiles);
|
|
return options;
|
|
},
|
|
set(options) {
|
|
if (options.xmlDocuments) {
|
|
xmlDocuments = options.xmlDocuments;
|
|
}
|
|
},
|
|
};
|
|
|
|
const doc = createDoc("tag-example.docx");
|
|
doc.attachModule(module);
|
|
doc.compile();
|
|
|
|
const xmlKeys = Object.keys(xmlDocuments);
|
|
expect(xmlKeys).to.deep.equal(["word/_rels/document.xml.rels"]);
|
|
const rels = xmlDocuments[
|
|
"word/_rels/document.xml.rels"
|
|
].getElementsByTagName("Relationship");
|
|
expect(rels.length).to.equal(10);
|
|
|
|
const str = xml2str(xmlDocuments["word/_rels/document.xml.rels"]);
|
|
if (isNode12()) {
|
|
expect(str).to
|
|
.equal(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
|
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId8" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" Target="footer1.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/><Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml"/><Relationship Id="rId2" Type="http://schemas.microsoft.com/office/2007/relationships/stylesWithEffects" Target="stylesWithEffects.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/><Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes" Target="endnotes.xml"/><Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes" Target="footnotes.xml"/><Relationship Id="rId10" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/><Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings" Target="webSettings.xml"/><Relationship Id="rId9" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Target="fontTable.xml"/></Relationships>`);
|
|
rels[5].setAttribute("Foobar", "Baz");
|
|
doc.render();
|
|
shouldBeSame({ doc, expectedName: "expected-module-change-rels.docx" });
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Module unique tags xml", function () {
|
|
it("should not cause an issue if tagsXmlLexedArray contains duplicates", function () {
|
|
const module = {
|
|
requiredAPIVersion: "3.0.0",
|
|
optionsTransformer(options, docxtemplater) {
|
|
docxtemplater.fileTypeConfig.tagsXmlLexedArray.push(
|
|
"w:p",
|
|
"w:r",
|
|
"w:p"
|
|
);
|
|
return options;
|
|
},
|
|
};
|
|
|
|
const doc = createDoc("tag-example.docx");
|
|
doc.attachModule(module);
|
|
doc.setData({
|
|
first_name: "Hipp",
|
|
last_name: "Edgar",
|
|
phone: "0652455478",
|
|
description: "New Website",
|
|
});
|
|
doc.compile();
|
|
doc.render();
|
|
shouldBeSame({ doc, expectedName: "expected-tag-example.docx" });
|
|
});
|
|
});
|
|
|
|
describe("Module traits", function () {
|
|
it("should not cause an issue if using traits.expandTo containing loop", function () {
|
|
const moduleName = "comment-module";
|
|
function getInner({ part, leftParts, rightParts, postparse }) {
|
|
part.subparsed = postparse([].concat(leftParts).concat(rightParts), {
|
|
basePart: part,
|
|
});
|
|
return part;
|
|
}
|
|
const module = {
|
|
name: "Test module",
|
|
requiredAPIVersion: "3.0.0",
|
|
parse(placeHolderContent) {
|
|
if (placeHolderContent[0] === "£") {
|
|
const type = "placeholder";
|
|
return {
|
|
type,
|
|
value: placeHolderContent.substr(1),
|
|
module: moduleName,
|
|
};
|
|
}
|
|
},
|
|
postparse(parsed, { postparse }) {
|
|
parsed = traits.expandToOne(parsed, {
|
|
moduleName,
|
|
getInner,
|
|
expandTo: ["w:p"],
|
|
postparse,
|
|
});
|
|
return parsed;
|
|
},
|
|
render(part) {
|
|
if (part.module === moduleName) {
|
|
return {
|
|
value: "",
|
|
};
|
|
}
|
|
},
|
|
};
|
|
|
|
const doc = createDoc("comment-with-loop.docx");
|
|
doc.attachModule(module);
|
|
doc.setData({}).compile().render();
|
|
shouldBeSame({ doc, expectedName: "expected-comment-example.docx" });
|
|
});
|
|
});
|
|
|
|
describe("Module errors", function () {
|
|
it("should work", function () {
|
|
const moduleName = "ErrorModule";
|
|
const module = {
|
|
name: "Error module",
|
|
requiredAPIVersion: "3.0.0",
|
|
parse(placeHolderContent) {
|
|
const type = "placeholder";
|
|
return {
|
|
type,
|
|
value: placeHolderContent,
|
|
module: moduleName,
|
|
};
|
|
},
|
|
render(part) {
|
|
if (part.module === moduleName) {
|
|
return {
|
|
errors: [new Error(`foobar ${part.value}`)],
|
|
};
|
|
}
|
|
},
|
|
};
|
|
|
|
let error = null;
|
|
const doc = createDoc("tag-example.docx");
|
|
doc.attachModule(module);
|
|
doc.setData({}).compile();
|
|
try {
|
|
doc.render();
|
|
} catch (e) {
|
|
error = e;
|
|
}
|
|
expect(error).to.be.an("object");
|
|
expect(error.message).to.equal("Multi error");
|
|
expect(error.properties.errors.length).to.equal(9);
|
|
expect(error.properties.errors[0].message).to.equal("foobar last_name");
|
|
expect(error.properties.errors[1].message).to.equal("foobar first_name");
|
|
expect(error.properties.errors[2].message).to.equal("foobar phone");
|
|
});
|
|
});
|
|
|
|
describe("Module should pass options to module.parse, module.postparse, module.render, module.postrender", function () {
|
|
it("should pass filePath and contentType options", function () {
|
|
const doc = createDoc("tag-example.docx");
|
|
const filePaths = [];
|
|
let renderFP = "",
|
|
renderCT = "",
|
|
postrenderFP = "",
|
|
postrenderCT = "",
|
|
postparseFP = "",
|
|
postparseCT = "";
|
|
const ct = [];
|
|
|
|
const module = {
|
|
name: "Test module",
|
|
requiredAPIVersion: "3.0.0",
|
|
parse(a, options) {
|
|
filePaths.push(options.filePath);
|
|
ct.push(options.contentType);
|
|
},
|
|
postparse(a, options) {
|
|
postparseFP = options.filePath;
|
|
postparseCT = options.contentType;
|
|
return a;
|
|
},
|
|
render(a, options) {
|
|
renderFP = options.filePath;
|
|
renderCT = options.contentType;
|
|
},
|
|
postrender(a, options) {
|
|
postrenderFP = options.filePath;
|
|
postrenderCT = options.contentType;
|
|
return a;
|
|
},
|
|
};
|
|
doc.attachModule(module);
|
|
doc.setData({}).compile();
|
|
doc.render();
|
|
expect(renderFP).to.equal("word/document.xml");
|
|
expect(renderCT).to.equal(
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"
|
|
);
|
|
expect(postparseFP).to.equal("word/document.xml");
|
|
expect(postparseCT).to.equal(
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"
|
|
);
|
|
expect(postrenderFP).to.equal("word/document.xml");
|
|
expect(postrenderCT).to.equal(
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"
|
|
);
|
|
|
|
expect(filePaths).to.deep.equal([
|
|
// Header appears 4 times because there are 4 tags in the header
|
|
"word/header1.xml",
|
|
"word/header1.xml",
|
|
"word/header1.xml",
|
|
"word/header1.xml",
|
|
// Footer appears 3 times because there are 3 tags in the header
|
|
"word/footer1.xml",
|
|
"word/footer1.xml",
|
|
"word/footer1.xml",
|
|
// Document appears 2 times because there are 2 tags in the header
|
|
"word/document.xml",
|
|
"word/document.xml",
|
|
]);
|
|
|
|
expect(ct).to.deep.equal([
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml",
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml",
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml",
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("Module detachment", function () {
|
|
it("should detach the module when the module does not support the document filetype", function () {
|
|
let isModuleCalled = false;
|
|
let isDetachedCalled = false;
|
|
const module = {
|
|
optionsTransformer(options) {
|
|
isModuleCalled = true;
|
|
return options;
|
|
},
|
|
on(eventName) {
|
|
if (eventName === "detached") {
|
|
isDetachedCalled = true;
|
|
}
|
|
},
|
|
supportedFileTypes: ["pptx"],
|
|
};
|
|
createDocV4("tag-example.docx", { modules: [module] });
|
|
expect(isDetachedCalled).to.equal(true);
|
|
expect(isModuleCalled).to.equal(false);
|
|
});
|
|
});
|