docxtemplater
Version:
.docx generator working with templates and data (like Mustache)
306 lines (292 loc) • 9.01 kB
JavaScript
;
var testUtils = require("./utils");
var expect = testUtils.expect;
var _ = require("lodash");
var expressions = require("angular-expressions");
function angularParser(tag) {
var expr = expressions.compile(tag);
return {
get: function get(scope) {
return expr(scope);
}
};
}
var Errors = require("../errors.js");
function expectToThrow(fn, type, expectedError) {
var e = null;
try {
fn();
} catch (error) {
e = error;
}
expect(e, "No error has been thrown").not.to.be.equal(null);
var toShowOnFail = e.stack;
expect(e, toShowOnFail).to.be.instanceOf(Error);
expect(e, toShowOnFail).to.be.instanceOf(type);
expect(e, toShowOnFail).to.be.an("object");
expect(e, toShowOnFail).to.have.property("properties");
expect(e.properties, toShowOnFail).to.be.an("object");
expect(e.properties, toShowOnFail).to.have.property("explanation");
expect(e.properties.explanation, toShowOnFail).to.be.a("string");
expect(e.properties, toShowOnFail).to.have.property("id");
expect(e.properties.id, toShowOnFail).to.be.a("string");
expect(e.properties.explanation, toShowOnFail).to.be.a("string");
delete e.properties.explanation;
e = _.omit(e, ["line", "sourceURL", "stack"]);
if (e.properties.rootError) {
expect(e.properties.rootError.message).to.equal(expectedError.properties.rootError.message);
delete e.properties.rootError;
delete expectedError.properties.rootError;
}
if (e.properties.paragraphParts) {
expect(e.properties.paragraphParts.length).to.equal(expectedError.properties.paragraphPartsLength);
delete e.properties.paragraphParts;
delete expectedError.properties.paragraphPartsLength;
}
if (e.stack) {
expect(e.stack).to.contain("Error: " + expectedError.message);
delete e.stack;
}
expect(JSON.parse(JSON.stringify(e))).to.be.deep.equal(expectedError);
}
describe("errors", function () {
it("should be thrown when unclosedtag", function () {
var content = "<w:t>{unclosedtag my text</w:t>";
var tags = {};
var expectedError = {
name: "TemplateError",
message: "Unclosed tag",
properties: {
context: "{unclosedtag my text",
id: "unclosed_tag",
xtag: "unclosedtag"
}
};
var create = testUtils.createXmlTemplaterDocx.bind(null, content, { tags: tags });
expectToThrow(create, Errors.XTTemplateError, expectedError);
});
it("should not be possible to close {#users} with {/foo}", function () {
var content = "<w:t>{#users}User {name}{/foo}</w:t>";
var tags = { users: [{ name: "John" }] };
var expectedError = {
name: "TemplateError",
message: "Closing tag does not match opening tag",
properties: {
id: "closing_tag_does_not_match_opening_tag",
openingtag: "users",
closingtag: "foo"
}
};
var create = testUtils.createXmlTemplaterDocx.bind(null, content, { tags: tags });
expectToThrow(create, Errors.XTTemplateError, expectedError);
});
it("should be thrown when unopenedloop", function () {
var content = "<w:t>{/loop} {foobar}</w:t>";
var scope = {};
var expectedError = {
name: "TemplateError",
message: "Unopened loop",
properties: {
id: "unopened_loop",
xtag: "loop"
}
};
var create = testUtils.createXmlTemplaterDocx.bind(null, content, { tags: scope });
expectToThrow(create, Errors.XTTemplateError, expectedError);
});
it("should be thrown when unclosedloop", function () {
var content = "<w:t>{#loop} {foobar}</w:t>";
var scope = {};
var expectedError = {
name: "TemplateError",
message: "Unclosed loop",
properties: {
id: "unclosed_loop",
xtag: "loop"
}
};
var create = testUtils.createXmlTemplaterDocx.bind(null, content, { tags: scope });
expectToThrow(create, Errors.XTTemplateError, expectedError);
});
it("should fail when rawtag not in paragraph", function () {
var content = "<w:t>{@myrawtag}</w:t>";
var scope = { myrawtag: "<w:p><w:t>foobar</w:t></w:p>" };
var expectedError = {
name: "TemplateError",
message: "Raw tag not in paragraph",
properties: {
expandTo: "w:p",
id: "raw_tag_outerxml_invalid",
index: 1,
postparsed: [{
position: "start",
text: true,
type: "tag",
value: "<w:t>"
}, {
module: "rawxml",
type: "placeholder",
value: "myrawtag"
}, {
position: "end",
text: true,
type: "tag",
value: "</w:t>"
}],
xtag: "myrawtag",
rootError: {
message: "No tag 'w:p' was found at the right"
}
}
};
var create = testUtils.createXmlTemplaterDocx.bind(null, content, { tags: scope });
expectToThrow(create, Errors.XTTemplateError, expectedError);
});
it("should fail when rawtag not in paragraph (in table)", function () {
var content = "<w:table><w:t>{@myrawtag}</w:t></w:p></w:table>";
var scope = { myrawtag: "<w:p><w:t>foobar</w:t></w:p>" };
var expectedError = {
name: "TemplateError",
message: "Raw tag not in paragraph",
properties: {
id: "raw_tag_outerxml_invalid",
xtag: "myrawtag",
postparsed: [{
type: "tag",
position: "start",
text: false,
value: "<w:table>"
}, {
type: "tag",
position: "start",
text: true,
value: "<w:t>"
}, {
type: "placeholder",
value: "myrawtag",
module: "rawxml"
}, {
type: "tag",
position: "end",
text: true,
value: "</w:t>"
}, {
type: "tag",
position: "end",
text: false,
value: "</w:p>"
}, {
type: "tag",
position: "end",
text: false,
value: "</w:table>"
}],
rootError: {
message: "No tag 'w:p' was found at the left"
},
expandTo: "w:p",
index: 2
}
};
var create = testUtils.createXmlTemplaterDocx.bind(null, content, { tags: scope });
expectToThrow(create, Errors.XTTemplateError, expectedError);
});
it("should fail when tag already opened", function () {
var content = "<w:t>{user {name}</w:t>";
var expectedError = {
name: "TemplateError",
message: "Unclosed tag",
properties: {
id: "unclosed_tag",
context: "{user ",
xtag: "user"
}
};
var create = testUtils.createXmlTemplaterDocx.bind(null, content);
expectToThrow(create, Errors.XTTemplateError, expectedError);
});
it("should fail when tag already closed", function () {
var content = "<w:t>foobar}age</w:t>";
var expectedError = {
name: "TemplateError",
message: "Unopened tag",
properties: {
id: "unopened_tag",
context: "foobar",
xtag: "foobar"
}
};
var create = testUtils.createXmlTemplaterDocx.bind(null, content);
expectToThrow(create, Errors.XTTemplateError, expectedError);
});
it("should fail when customparser fails to compile", function () {
var content = "<w:t>{name++}</w:t>";
var xmlTemplater = testUtils.createXmlTemplaterDocx(content, { tags: { name: 3 }, parser: angularParser });
var expectedError = {
name: "ScopeParserError",
message: "Scope parser compilation failed",
properties: {
id: "scopeparser_compilation_failed",
tag: "name++",
rootError: {
message: "Syntax Error: Token 'undefined' not a primary expression at column NaN of the expression [name++] starting at [name++]."
}
}
};
var create = xmlTemplater.render.bind(xmlTemplater);
expectToThrow(create, Errors.XTScopeParserError, expectedError);
});
it("should fail when customparser fails to execute", function () {
var content = "<w:t>{name|upper}</w:t>";
function errorParser() {
return {
get: function get() {
throw new Error("foo bar");
}
};
}
var xmlTemplater = testUtils.createXmlTemplaterDocx(content, { tags: { name: 3 }, parser: errorParser });
var expectedError = {
name: "ScopeParserError",
message: "Scope parser execution failed",
properties: {
id: "scopeparser_execution_failed",
tag: "name|upper",
scope: { name: 3 },
rootError: {
message: "foo bar"
}
}
};
var create = xmlTemplater.render.bind(xmlTemplater);
expectToThrow(create, Errors.XTScopeParserError, expectedError);
});
it("should fail when rawtag is not only text in paragraph", function () {
var content = "<w:p><w:t>{@myrawtag}</w:t><w:t>foobar</w:t></w:p>";
var scope = { myrawtag: "<w:p><w:t>foobar</w:t></w:p>" };
var expectedError = {
name: "TemplateError",
message: "Raw tag should be the only text in paragraph",
properties: {
id: "raw_xml_tag_should_be_only_text_in_paragraph",
xtag: "myrawtag",
paragraphPartsLength: 6
}
};
var create = testUtils.createXmlTemplaterDocx.bind(null, content, { tags: scope });
expectToThrow(create, Errors.XTTemplateError, expectedError);
});
describe("internal errors", function () {
it("should fail", function () {
var expectedError = {
name: "InternalError",
message: "Content must be a string",
properties: { id: "xmltemplater_content_must_be_string" }
};
function test() {
testUtils.createXmlTemplaterDocx(1);
}
expectToThrow(test, Errors.XTInternalError, expectedError);
});
});
});