summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-08-28 19:55:24 +0100
committerMichael Williamson <mike@zwobble.org>2016-08-28 19:55:38 +0100
commitb1ae23f544c479d2b71347bbf67df7baac40d78f (patch)
tree383e694dae42ba544f690c3b0ab388a7931c0793
parent7dba15069f9a606b9e248d7e4cd024ddaa6ac3e3 (diff)
parentc42714e5f4b643de27b106a084601e39b7e5d04c (diff)
Merge branch 'master' into image-errors
Conflicts: test/mammoth.tests.js
-rw-r--r--.github/ISSUE_TEMPLATE.md12
-rw-r--r--NEWS8
-rw-r--r--README.md23
-rw-r--r--lib/document-matchers.js2
-rw-r--r--lib/document-to-html.js162
-rw-r--r--lib/documents.js9
-rw-r--r--lib/docx/body-reader.js2
-rw-r--r--lib/docx/document-xml-reader.js5
-rw-r--r--lib/docx/docx-reader.js27
-rw-r--r--lib/html-paths.js31
-rw-r--r--lib/html/index.js9
-rw-r--r--lib/options-reader.js2
-rw-r--r--lib/style-reader.js28
-rw-r--r--package.json2
-rw-r--r--test/document-matchers.tests.js80
-rw-r--r--test/document-to-html.tests.js1039
-rw-r--r--test/docx/body-reader.tests.js1230
-rw-r--r--test/docx/content-types-reader.tests.js78
-rw-r--r--test/docx/docx-reader.tests.js54
-rw-r--r--test/docx/files.tests.js50
-rw-r--r--test/docx/notes-reader.tests.js42
-rw-r--r--test/docx/numbering-xml.tests.js42
-rw-r--r--test/docx/office-xml-reader.tests.js36
-rw-r--r--test/docx/style-map.tests.js115
-rw-r--r--test/docx/styles-reader.tests.js127
-rw-r--r--test/html-paths.tests.js28
-rw-r--r--test/html/simplify.tests.js189
-rw-r--r--test/html/write.tests.js60
-rw-r--r--test/images.tests.js9
-rw-r--r--test/main.tests.js96
-rw-r--r--test/mammoth.tests.js631
-rw-r--r--test/options-reader.tests.js71
-rw-r--r--test/results.tests.js18
-rw-r--r--test/style-reader.tests.js108
-rwxr-xr-xtest/test-data/comments.docxbin0 -> 15526 bytes
-rw-r--r--test/test-data/empty.zipbin0 -> 22 bytes
-rw-r--r--test/testing.js10
-rw-r--r--test/unzip.tests.js54
-rw-r--r--test/writers/html-writer.tests.js220
-rw-r--r--test/writers/markdown-writer.tests.js600
-rw-r--r--test/xml/reader.tests.js132
-rw-r--r--test/xml/writer.tests.js136
-rw-r--r--test/zipfile.tests.js22
43 files changed, 2896 insertions, 2703 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..00044b5
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,12 @@
+If you're reporting a bug or requesting a feature, it's handy to have:
+* a minimal example document
+* the HTML output that you'd expect
+
+If you're reporting a bug, it's also useful to know what platform you're
+running on, including:
+
+* the operating system and version
+* if running in the browser:
+ * the browser and version
+ * whether you get the same issue in other browsers
+* if running on node.js, the version you're using
diff --git a/NEWS b/NEWS
index ea86620..3c3a715 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+# 1.2.0
+
+* Throw more informative error when word/document.xml cannot be found.
+
+# 1.1.0
+
+* Add support for comments.
+
# 1.0.4
* Add support for w:sdt elements. This allows the bodies of content controls,
diff --git a/README.md b/README.md
index 2b6bac2..4f310a0 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,8 @@ The following features are currently supported:
* Text boxes. The contents of the text box are treated as a separate paragraph
that appears after the paragraph containing the text box.
+* Comments.
+
## Web demo
The easiest way to try out mammoth is to use the web demo:
@@ -295,6 +297,27 @@ var options = {
mammoth.convertToHtml({path: "path/to/document.docx"}, options);
```
+#### Comments
+
+By default, comments are ignored.
+To include comments in the generated HTML,
+add a style mapping for `comment-reference`.
+For instance:
+
+```javascript
+var mammoth = require("mammoth");
+
+var options = {
+ styleMap: [
+ "comment-reference => sup"
+ ]
+};
+mammoth.convertToHtml({path: "path/to/document.docx"}, options);
+```
+
+Comments will be appended to the end of the document,
+with links to the comments wrapped using the specified style mapping.
+
### API
#### `mammoth.convertToHtml(input, options)`
diff --git a/lib/document-matchers.js b/lib/document-matchers.js
index 60bc65f..bdc213c 100644
--- a/lib/document-matchers.js
+++ b/lib/document-matchers.js
@@ -4,7 +4,7 @@ exports.bold = new Matcher("bold");
exports.italic = new Matcher("italic");
exports.underline = new Matcher("underline");
exports.strikethrough = new Matcher("strikethrough");
-exports.commentReference = new Matcher("comment-reference");
+exports.commentReference = new Matcher("commentReference");
function paragraph(options) {
diff --git a/lib/document-to-html.js b/lib/document-to-html.js
index 6aa7a9c..e022946 100644
--- a/lib/document-to-html.js
+++ b/lib/document-to-html.js
@@ -13,18 +13,24 @@ exports.DocumentConverter = DocumentConverter;
function DocumentConverter(options) {
return {
- convertToHtml: function() {
- var conversion = new DocumentConversion(options);
- return conversion.convertToHtml.apply(this, arguments);
+ convertToHtml: function(element) {
+ var comments = _.indexBy(
+ element.type === documents.types.document ? element.comments : [],
+ "commentId"
+ );
+ var conversion = new DocumentConversion(options, comments);
+ return conversion.convertToHtml(element);
}
};
}
-function DocumentConversion(options) {
+function DocumentConversion(options, comments) {
var noteNumber = 1;
var noteReferences = [];
+ var referencedComments = [];
+
options = _.extend({ignoreEmptyParagraphs: true}, options);
var idPrefix = options.idPrefix === undefined ? "" : options.idPrefix;
@@ -89,16 +95,17 @@ function DocumentConversion(options) {
}
function convertParagraph(element, messages) {
- var style = styleForParagraph(element, messages);
-
- var children = convertElements(element.children, messages);
- if (!options.ignoreEmptyParagraphs) {
- children = [Html.forceWrite].concat(children);
- }
- return Html.pathToNodes(style, children);
+ return htmlPathForParagraph(element, messages).wrap(function() {
+ var content = convertElements(element.children, messages);
+ if (options.ignoreEmptyParagraphs) {
+ return content;
+ } else {
+ return [Html.forceWrite].concat(content);
+ }
+ });
}
- function styleForParagraph(element, messages) {
+ function htmlPathForParagraph(element, messages) {
var style = findStyle(element);
if (style) {
@@ -112,58 +119,60 @@ function DocumentConversion(options) {
}
function convertRun(run, messages) {
- var style;
- if (run.styleId) {
- style = findStyle(run);
- if (!style) {
- messages.push(unrecognisedStyleWarning("run", run));
- }
- }
- var result = convertElements(run.children, messages);
+ var nodes = function() {
+ return convertElements(run.children, messages);
+ };
+ var paths = [];
if (run.isStrikethrough) {
- result = convertRunProperty(result, "strikethrough", "s");
+ paths.push(findHtmlPathForRunProperty("strikethrough", "s"));
}
if (run.isUnderline) {
- result = convertUnderline(result);
+ paths.push(findHtmlPathForRunProperty("underline"));
}
if (run.verticalAlignment === documents.verticalAlignment.subscript) {
- result = wrapInNonFreshElement(result, "sub");
+ paths.push(htmlPaths.element("sub", {}, {fresh: false}));
}
if (run.verticalAlignment === documents.verticalAlignment.superscript) {
- result = wrapInNonFreshElement(result, "sup");
+ paths.push(htmlPaths.element("sup", {}, {fresh: false}));
}
if (run.isItalic) {
- result = convertRunProperty(result, "italic", "em");
+ paths.push(findHtmlPathForRunProperty("italic", "em"));
}
if (run.isBold) {
- result = convertRunProperty(result, "bold", "strong");
+ paths.push(findHtmlPathForRunProperty("bold", "strong"));
}
- if (style) {
- result = Html.pathToNodes(style.to, result);
+ var stylePath = htmlPaths.empty;
+ if (run.styleId) {
+ var style = findStyle(run);
+ if (style) {
+ stylePath = style.to;
+ } else {
+ messages.push(unrecognisedStyleWarning("run", run));
+ }
}
- return result;
- }
-
- function wrapInNonFreshElement(nodes, tagName) {
- return [Html.nonFreshElement(tagName, {}, nodes)];
+ paths.push(stylePath);
+
+ paths.forEach(function(path) {
+ nodes = path.wrap.bind(path, nodes);
+ });
+
+ return nodes();
}
- function convertUnderline(runHtml) {
- var style = findStyle({type: "underline"});
- if (style) {
- return Html.pathToNodes(style.to, runHtml);
+ function findHtmlPathForRunProperty(elementType, defaultTagName) {
+ var path = findHtmlPath({type: elementType});
+ if (path) {
+ return path;
+ } else if (defaultTagName) {
+ return htmlPaths.element(defaultTagName, {}, {fresh: false});
} else {
- return runHtml;
+ return htmlPaths.empty;
}
}
- function convertRunProperty(result, elementType, defaultTagName) {
- var style = findStyle({type: elementType});
- if (style) {
- return Html.pathToNodes(style.to, result);
- } else {
- return wrapInNonFreshElement(result, defaultTagName);
- }
+ function findHtmlPath(element, defaultPath) {
+ var style = findStyle(element);
+ return style ? style.to : defaultPath;
}
function findStyle(element) {
@@ -192,11 +201,19 @@ function DocumentConversion(options) {
}
function noteHtmlId(note) {
- return htmlId(note.noteType + "-" + note.noteId);
+ return referentHtmlId(note.noteType, note.noteId);
}
function noteRefHtmlId(note) {
- return htmlId(note.noteType + "-ref-" + note.noteId);
+ return referenceHtmlId(note.noteType, note.noteId);
+ }
+
+ function referentHtmlId(referenceType, referenceId) {
+ return htmlId(referenceType + "-" + referenceId);
+ }
+
+ function referenceHtmlId(referenceType, referenceId) {
+ return htmlId(referenceType + "-ref-" + referenceId);
}
function htmlId(suffix) {
@@ -226,6 +243,46 @@ function DocumentConversion(options) {
];
}
+ function convertCommentReference(reference, messages) {
+ return findHtmlPath(reference, htmlPaths.ignore).wrap(function() {
+ var comment = comments[reference.commentId];
+ var count = referencedComments.length + 1;
+ var label = "[" + commentAuthorLabel(comment) + count + "]";
+ referencedComments.push({label: label, comment: comment});
+ // TODO: remove duplication with note references
+ return [
+ Html.freshElement("a", {
+ href: "#" + referentHtmlId("comment", reference.commentId),
+ id: referenceHtmlId("comment", reference.commentId)
+ }, [Html.text(label)])
+ ];
+ });
+ }
+
+ function convertComment(referencedComment, messages) {
+ // TODO: remove duplication with note references
+
+ var label = referencedComment.label;
+ var comment = referencedComment.comment;
+ var body = convertElements(comment.body).concat([
+ Html.nonFreshElement("p", {}, [
+ Html.text(" "),
+ Html.freshElement("a", {"href": "#" + referenceHtmlId("comment", comment.commentId)}, [
+ Html.text("↑")
+ ])
+ ])
+ ]);
+
+ return [
+ Html.freshElement(
+ "dt",
+ {"id": referentHtmlId("comment", comment.commentId)},
+ [Html.text("Comment " + label)]
+ ),
+ Html.freshElement("dd", {}, body)
+ ];
+ }
+
function wrapChildrenInFreshElement(element, wrapElementName, messages) {
var children = convertElements(element.children, messages);
return [
@@ -241,7 +298,10 @@ function DocumentConversion(options) {
});
var notesNodes = convertElements(notes, messages);
return children.concat([
- Html.freshElement("ol", {}, notesNodes)
+ Html.freshElement("ol", {}, notesNodes),
+ Html.freshElement("dl", {}, flatMap(referencedComments, function(referencedComment) {
+ return convertComment(referencedComment, messages);
+ }))
]);
},
"paragraph": convertParagraph,
@@ -283,6 +343,8 @@ function DocumentConversion(options) {
return Html.freshElement("li", {id: noteHtmlId(element)}, body);
},
+ "commentReference": convertCommentReference,
+ "comment": convertComment,
"image": deferredConversion(recoveringConvertImage(options.convertImage || defaultConvertImage)),
"table": convertTable,
"tableRow": convertTableRow,
@@ -331,3 +393,7 @@ function walkHtml(nodes, callback) {
}
});
}
+
+var commentAuthorLabel = exports.commentAuthorLabel = function commentAuthorLabel(comment) {
+ return comment.authorInitials || "";
+};
diff --git a/lib/documents.js b/lib/documents.js
index d4a28af..428dc09 100644
--- a/lib/documents.js
+++ b/lib/documents.js
@@ -24,7 +24,8 @@ function Document(children, options) {
return {
type: types.document,
children: children,
- notes: options.notes || new Notes({})
+ notes: options.notes || new Notes({}),
+ comments: options.comments || []
};
}
@@ -181,9 +182,9 @@ function BookmarkStart(options) {
};
}
-exports.Document = Document;
-exports.Paragraph = Paragraph;
-exports.Run = Run;
+exports.document = exports.Document = Document;
+exports.paragraph = exports.Paragraph = Paragraph;
+exports.run = exports.Run = Run;
exports.Text = Text;
exports.Tab = Tab;
exports.Hyperlink = Hyperlink;
diff --git a/lib/docx/body-reader.js b/lib/docx/body-reader.js
index b514363..7b3120d 100644
--- a/lib/docx/body-reader.js
+++ b/lib/docx/body-reader.js
@@ -379,13 +379,13 @@ var ignoreElements = {
"office-word:wrap": true,
"v:shadow": true,
"v:shapetype": true,
+ "w:annotationRef": true,
"w:bookmarkEnd": true,
"w:sectPr": true,
"w:proofErr": true,
"w:lastRenderedPageBreak": true,
"w:commentRangeStart": true,
"w:commentRangeEnd": true,
- "w:commentReference": true,
"w:del": true,
"w:footnoteRef": true,
"w:endnoteRef": true,
diff --git a/lib/docx/document-xml-reader.js b/lib/docx/document-xml-reader.js
index 12ca19e..bb912e4 100644
--- a/lib/docx/document-xml-reader.js
+++ b/lib/docx/document-xml-reader.js
@@ -12,7 +12,10 @@ function DocumentXmlReader(options) {
var result = bodyReader.readXmlElements(body.children)
.map(function(children) {
- return new documents.Document(children, {notes: options.notes});
+ return new documents.Document(children, {
+ notes: options.notes,
+ comments: options.comments
+ });
});
return new Result(result.value, result.messages);
}
diff --git a/lib/docx/docx-reader.js b/lib/docx/docx-reader.js
index 6ad63ab..0c7d57f 100644
--- a/lib/docx/docx-reader.js
+++ b/lib/docx/docx-reader.js
@@ -14,6 +14,7 @@ var contentTypesReader = require("./content-types-reader");
var numberingXml = require("./numbering-xml");
var stylesReader = require("./styles-reader");
var notesReader = require("./notes-reader");
+var commentsReader = require("./comments-reader");
var Files = require("./files").Files;
@@ -40,6 +41,13 @@ function read(docxFile, input) {
} else {
return new Result([]);
}
+ }),
+ comments: readXmlFileWithBody("comments", result, function(bodyReader, xml) {
+ if (xml) {
+ return commentsReader.createCommentsReader(bodyReader)(xml);
+ } else {
+ return new Result([]);
+ }
})
};
}).also(function(result) {
@@ -52,13 +60,20 @@ function read(docxFile, input) {
};
}).then(function(result) {
return readXmlFileWithBody("document", result, function(bodyReader, xml) {
- return result.notes.flatMap(function(notes) {
- var reader = new DocumentXmlReader({
- bodyReader: bodyReader,
- notes: notes
+ if (xml) {
+ return result.notes.flatMap(function(notes) {
+ return result.comments.flatMap(function(comments) {
+ var reader = new DocumentXmlReader({
+ bodyReader: bodyReader,
+ notes: notes,
+ comments: comments
+ });
+ return reader.convertXmlToDocument(xml);
+ });
});
- return reader.convertXmlToDocument(xml);
- });
+ } else {
+ throw new Error("Could not find word/document.xml in ZIP file. Are you sure this is a valid .docx file?");
+ }
});
});
}
diff --git a/lib/html-paths.js b/lib/html-paths.js
index 04bc655..5a00cd8 100644
--- a/lib/html-paths.js
+++ b/lib/html-paths.js
@@ -1,5 +1,7 @@
var _ = require("underscore");
+var html = require("./html");
+
exports.topLevelElement = topLevelElement;
exports.elements = elements;
exports.element = element;
@@ -9,15 +11,27 @@ function topLevelElement(tagName, attributes) {
}
function elements(elementStyles) {
- return elementStyles.map(function(elementStyle) {
+ return new HtmlPath(elementStyles.map(function(elementStyle) {
if (_.isString(elementStyle)) {
return element(elementStyle);
} else {
return elementStyle;
}
- });
+ }));
+}
+
+function HtmlPath(elements) {
+ this._elements = elements;
}
+HtmlPath.prototype.wrap = function wrap(children) {
+ var result = children();
+ for (var index = this._elements.length - 1; index >= 0; index--) {
+ result = this._elements[index].wrapNodes(result);
+ }
+ return result;
+};
+
function element(tagName, attributes, options) {
options = options || {};
return new Element(tagName, attributes, options);
@@ -44,4 +58,17 @@ Element.prototype.matchesElement = function(element) {
return this.tagNames[element.tagName] && _.isEqual(this.attributes || {}, element.attributes || {});
};
+Element.prototype.wrap = function wrap(generateNodes) {
+ return this.wrapNodes(generateNodes());
+};
+
+Element.prototype.wrapNodes = function wrapNodes(nodes) {
+ return [html.elementWithTag(this, nodes)];
+};
+
exports.empty = elements([]);
+exports.ignore = {
+ wrap: function() {
+ return [];
+ }
+};
diff --git a/lib/html/index.js b/lib/html/index.js
index edc8256..600d783 100644
--- a/lib/html/index.js
+++ b/lib/html/index.js
@@ -7,15 +7,6 @@ exports.selfClosingElement = ast.selfClosingElement;
exports.text = ast.text;
exports.forceWrite = ast.forceWrite;
-function pathToNodes(path, children) {
- var result = children;
- for (var index = path.length - 1; index >= 0; index--) {
- result = [ast.elementWithTag(path[index], result)];
- }
- return result;
-}
-
-exports.pathToNodes = pathToNodes;
exports.simplify = require("./simplify");
function write(writer, nodes) {
diff --git a/lib/options-reader.js b/lib/options-reader.js
index 19934d8..3765fd3 100644
--- a/lib/options-reader.js
+++ b/lib/options-reader.js
@@ -26,6 +26,8 @@ var standardOptions = exports._standardOptions = {
"r[style-name='footnote reference'] =>",
"p[style-name='endnote text'] => p",
"r[style-name='endnote reference'] =>",
+ "p[style-name='annotation text'] => p",
+ "r[style-name='annotation reference'] =>",
// LibreOffice
"p[style-name='Footnote'] => p",
diff --git a/lib/style-reader.js b/lib/style-reader.js
index ab9a171..fe60930 100644
--- a/lib/style-reader.js
+++ b/lib/style-reader.js
@@ -177,16 +177,21 @@ function htmlPathRule() {
return htmlPaths.element(tagName, attributes, options);
});
- return lop.rules.then(
- lop.rules.zeroOrMoreWithSeparator(
- styleElementRule,
- lop.rules.sequence(
- whitespaceRule,
- lop.rules.tokenOfType("gt"),
- whitespaceRule
- )
- ),
- htmlPaths.elements
+ return lop.rules.firstOf("html path",
+ lop.rules.then(lop.rules.tokenOfType("bang"), function() {
+ return htmlPaths.ignore;
+ }),
+ lop.rules.then(
+ lop.rules.zeroOrMoreWithSeparator(
+ styleElementRule,
+ lop.rules.sequence(
+ whitespaceRule,
+ lop.rules.tokenOfType("gt"),
+ whitespaceRule
+ )
+ ),
+ htmlPaths.elements
+ )
);
}
@@ -234,7 +239,8 @@ function tokenise(string) {
{name: "close-square-bracket", regex: /\]/},
{name: "string", regex: /'([^']*)'/},
{name: "integer", regex: /([0-9]+)/},
- {name: "choice", regex: /\|/}
+ {name: "choice", regex: /\|/},
+ {name: "bang", regex: /(!)/}
]);
return tokeniser.tokenise(string);
}
diff --git a/package.json b/package.json
index 7ca400e..74d3644 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mammoth",
- "version": "1.0.4",
+ "version": "1.1.0",
"author": "Michael Williamson <mike@zwobble.org>",
"description": "Convert Word documents from docx to simple HTML and Markdown",
"keywords": [
diff --git a/test/document-matchers.tests.js b/test/document-matchers.tests.js
index 58dbf80..b989b2d 100644
--- a/test/document-matchers.tests.js
+++ b/test/document-matchers.tests.js
@@ -1,50 +1,48 @@
var assert = require("assert");
-var test = require("./testing").test;
+var test = require("./test")(module);
var documentMatchers = require("../lib/document-matchers");
var documents = require("../lib/documents");
var Paragraph = documents.Paragraph;
-describe("document-matchers", function() {
- test("paragraph with no options matches any paragraph", function() {
- var matcher = documentMatchers.paragraph();
- assert.ok(matcher.matches(new Paragraph()));
- assert.ok(matcher.matches(paragraphWithStyle("Heading1", "Heading 1")));
- });
-
- test("paragraph style ID only matches paragraphs with that style ID", function() {
- var matcher = documentMatchers.paragraph({styleId: "Heading1"});
- assert.ok(!matcher.matches(new Paragraph()));
- assert.ok(matcher.matches(paragraphWithStyle("Heading1", "Heading 1")));
- assert.ok(!matcher.matches(paragraphWithStyle("Heading2", "Heading 2")));
- });
-
- test("paragraph style name only matches paragraphs with that style name", function() {
- var matcher = documentMatchers.paragraph({styleName: "Heading 1"});
- assert.ok(!matcher.matches(new Paragraph()));
- assert.ok(matcher.matches(paragraphWithStyle("Heading1", "Heading 1")));
- assert.ok(!matcher.matches(paragraphWithStyle("Heading2", "Heading 2")));
- });
-
- test("ordered-list(index) matches an ordered list with specified level index", function() {
- var matcher = documentMatchers.paragraph({list: {isOrdered: true, levelIndex: 1}});
- assert.ok(!matcher.matches(new Paragraph()));
- assert.ok(matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: true}})));
- assert.ok(!matcher.matches(new Paragraph([], {numbering: {level: 0, isOrdered: true}})));
- assert.ok(!matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: false}})));
- });
-
- test("unordered-list(index) matches an unordered list with specified level index", function() {
- var matcher = documentMatchers.paragraph({list: {isOrdered: false, levelIndex: 1}});
- assert.ok(!matcher.matches(new Paragraph()));
- assert.ok(matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: false}})));
- assert.ok(!matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: true}})));
- });
-
- test("matchers for lists with index 0 do not match elements that are not lists", function() {
- var matcher = documentMatchers.paragraph({list: {isOrdered: true, levelIndex: 0}});
- assert.ok(!matcher.matches(new Paragraph()));
- });
+test("paragraph with no options matches any paragraph", function() {
+ var matcher = documentMatchers.paragraph();
+ assert.ok(matcher.matches(new Paragraph()));
+ assert.ok(matcher.matches(paragraphWithStyle("Heading1", "Heading 1")));
+});
+
+test("paragraph style ID only matches paragraphs with that style ID", function() {
+ var matcher = documentMatchers.paragraph({styleId: "Heading1"});
+ assert.ok(!matcher.matches(new Paragraph()));
+ assert.ok(matcher.matches(paragraphWithStyle("Heading1", "Heading 1")));
+ assert.ok(!matcher.matches(paragraphWithStyle("Heading2", "Heading 2")));
+});
+
+test("paragraph style name only matches paragraphs with that style name", function() {
+ var matcher = documentMatchers.paragraph({styleName: "Heading 1"});
+ assert.ok(!matcher.matches(new Paragraph()));
+ assert.ok(matcher.matches(paragraphWithStyle("Heading1", "Heading 1")));
+ assert.ok(!matcher.matches(paragraphWithStyle("Heading2", "Heading 2")));
+});
+
+test("ordered-list(index) matches an ordered list with specified level index", function() {
+ var matcher = documentMatchers.paragraph({list: {isOrdered: true, levelIndex: 1}});
+ assert.ok(!matcher.matches(new Paragraph()));
+ assert.ok(matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: true}})));
+ assert.ok(!matcher.matches(new Paragraph([], {numbering: {level: 0, isOrdered: true}})));
+ assert.ok(!matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: false}})));
+});
+
+test("unordered-list(index) matches an unordered list with specified level index", function() {
+ var matcher = documentMatchers.paragraph({list: {isOrdered: false, levelIndex: 1}});
+ assert.ok(!matcher.matches(new Paragraph()));
+ assert.ok(matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: false}})));
+ assert.ok(!matcher.matches(new Paragraph([], {numbering: {level: 1, isOrdered: true}})));
+});
+
+test("matchers for lists with index 0 do not match elements that are not lists", function() {
+ var matcher = documentMatchers.paragraph({list: {isOrdered: true, levelIndex: 0}});
+ assert.ok(!matcher.matches(new Paragraph()));
});
function paragraphWithStyle(styleId, styleName) {
diff --git a/test/document-to-html.tests.js b/test/document-to-html.tests.js
index 0b4f905..cc8aff5 100644
--- a/test/document-to-html.tests.js
+++ b/test/document-to-html.tests.js
@@ -2,8 +2,10 @@ var assert = require("assert");
var promises = require("../lib/promises");
var documents = require("../lib/documents");
-var DocumentConverter = require("../lib/document-to-html").DocumentConverter;
-var test = require("./testing").test;
+var documentToHtml = require("../lib/document-to-html");
+var DocumentConverter = documentToHtml.DocumentConverter;
+var commentAuthorLabel = documentToHtml.commentAuthorLabel;
+var test = require("./test")(module);
var htmlPaths = require("../lib/html-paths");
var xml = require("../lib/xml");
var results = require("../lib/results");
@@ -11,543 +13,592 @@ var documentMatchers = require("../lib/document-matchers");
var Html = require("../lib/html");
-describe('DocumentConverter', function() {
- test('should empty document to empty string', function() {
- var document = new documents.Document([]);
- var converter = new DocumentConverter();
- return converter.convertToHtml(document).then(function(result) {
- assert.equal(result.value, "");
- });
+test('should empty document to empty string', function() {
+ var document = new documents.Document([]);
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(document).then(function(result) {
+ assert.equal(result.value, "");
});
-
- test('should convert document containing one paragraph to single p element', function() {
- var document = new documents.Document([
- paragraphOfText("Hello.")
- ]);
- var converter = new DocumentConverter();
- return converter.convertToHtml(document).then(function(result) {
- assert.equal(result.value, "<p>Hello.</p>");
- });
+});
+
+test('should convert document containing one paragraph to single p element', function() {
+ var document = new documents.Document([
+ paragraphOfText("Hello.")
+ ]);
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(document).then(function(result) {
+ assert.equal(result.value, "<p>Hello.</p>");
});
-
- test('ignores empty paragraphs', function() {
- var document = new documents.Document([
- paragraphOfText("")
- ]);
- var converter = new DocumentConverter();
- return converter.convertToHtml(document).then(function(result) {
- assert.equal(result.value, "");
- });
+});
+
+test('ignores empty paragraphs', function() {
+ var document = new documents.Document([
+ paragraphOfText("")
+ ]);
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(document).then(function(result) {
+ assert.equal(result.value, "");
});
-
- test('text is HTML-escaped', function() {
- var document = new documents.Document([
- paragraphOfText("1 < 2")
- ]);
- var converter = new DocumentConverter();
- return converter.convertToHtml(document).then(function(result) {
- assert.equal(result.value, "<p>1 &lt; 2</p>");
- });
+});
+
+test('text is HTML-escaped', function() {
+ var document = new documents.Document([
+ paragraphOfText("1 < 2")
+ ]);
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(document).then(function(result) {
+ assert.equal(result.value, "<p>1 &lt; 2</p>");
});
-
- test('should convert document containing multiple paragraphs to multiple p elements', function() {
- var document = new documents.Document([
- paragraphOfText("Hello."),
- paragraphOfText("Goodbye.")
- ]);
- var converter = new DocumentConverter();
- return converter.convertToHtml(document).then(function(result) {
- assert.equal(result.value, "<p>Hello.</p><p>Goodbye.</p>");
- });
+});
+
+test('should convert document containing multiple paragraphs to multiple p elements', function() {
+ var document = new documents.Document([
+ paragraphOfText("Hello."),
+ paragraphOfText("Goodbye.")
+ ]);
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(document).then(function(result) {
+ assert.equal(result.value, "<p>Hello.</p><p>Goodbye.</p>");
});
-
- test('uses style mappings to pick HTML element for docx paragraph', function() {
- var document = new documents.Document([
- paragraphOfText("Hello.", "Heading1", "Heading 1")
- ]);
- var converter = new DocumentConverter({
- styleMap: [
- {
- from: documentMatchers.paragraph({styleName: "Heading 1"}),
- to: htmlPaths.topLevelElement("h1")
- }
- ]
- });
- return converter.convertToHtml(document).then(function(result) {
- assert.equal(result.value, "<h1>Hello.</h1>");
- });
+});
+
+test('uses style mappings to pick HTML element for docx paragraph', function() {
+ var document = new documents.Document([
+ paragraphOfText("Hello.", "Heading1", "Heading 1")
+ ]);
+ var converter = new DocumentConverter({
+ styleMap: [
+ {
+ from: documentMatchers.paragraph({styleName: "Heading 1"}),
+ to: htmlPaths.topLevelElement("h1")
+ }
+ ]
});
-
- test('mappings for style names are case insensitive', function() {
- var document = new documents.Document([
- paragraphOfText("Hello.", "Heading1", "heading 1")
- ]);
- var converter = new DocumentConverter({
- styleMap: [
- {
- from: documentMatchers.paragraph({styleName: "Heading 1"}),
- to: htmlPaths.topLevelElement("h1")
- }
- ]
- });
- return converter.convertToHtml(document).then(function(result) {
- assert.equal(result.value, "<h1>Hello.</h1>");
- });
+ return converter.convertToHtml(document).then(function(result) {
+ assert.equal(result.value, "<h1>Hello.</h1>");
});
-
- test('can use non-default HTML element for unstyled paragraphs', function() {
- var document = new documents.Document([
- paragraphOfText("Hello.")
- ]);
- var converter = new DocumentConverter({
- styleMap: [
- {
- from: documentMatchers.paragraph(),
- to: htmlPaths.topLevelElement("h1")
- }
- ]
- });
- return converter.convertToHtml(document).then(function(result) {
- assert.equal(result.value, "<h1>Hello.</h1>");
- });
+});
+
+test('mappings for style names are case insensitive', function() {
+ var document = new documents.Document([
+ paragraphOfText("Hello.", "Heading1", "heading 1")
+ ]);
+ var converter = new DocumentConverter({
+ styleMap: [
+ {
+ from: documentMatchers.paragraph({styleName: "Heading 1"}),
+ to: htmlPaths.topLevelElement("h1")
+ }
+ ]
});
-
- test('warning is emitted if paragraph style is unrecognised', function() {
- var document = new documents.Document([
- paragraphOfText("Hello.", "Heading1", "Heading 1")
- ]);
- var converter = new DocumentConverter();
- return converter.convertToHtml(document).then(function(result) {
- assert.deepEqual(result.messages, [results.warning("Unrecognised paragraph style: 'Heading 1' (Style ID: Heading1)")]);
- });
+ return converter.convertToHtml(document).then(function(result) {
+ assert.equal(result.value, "<h1>Hello.</h1>");
});
-
- test('can use stacked styles to generate nested HTML elements', function() {
- var document = new documents.Document([
- paragraphOfText("Hello.")
- ]);
- var converter = new DocumentConverter({
- styleMap: [
- {
- from: documentMatchers.paragraph(),
- to: htmlPaths.elements(["h1", "span"])
- }
- ]
- });
- return converter.convertToHtml(document).then(function(result) {
- assert.equal(result.value, "<h1><span>Hello.</span></h1>");
- });
+});
+
+test('can use non-default HTML element for unstyled paragraphs', function() {
+ var document = new documents.Document([
+ paragraphOfText("Hello.")
+ ]);
+ var converter = new DocumentConverter({
+ styleMap: [
+ {
+ from: documentMatchers.paragraph(),
+ to: htmlPaths.topLevelElement("h1")
+ }
+ ]
});
-
- test('bold runs are wrapped in <strong> tags by default', function() {
- var run = runOfText("Hello.", {isBold: true});
- var converter = new DocumentConverter();
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<strong>Hello.</strong>");
- });
+ return converter.convertToHtml(document).then(function(result) {
+ assert.equal(result.value, "<h1>Hello.</h1>");
});
-
- test('bold runs can be configured with style mapping', function() {
- var run = runOfText("Hello.", {isBold: true});
- var converter = new DocumentConverter({
- styleMap: [
- {
- from: documentMatchers.bold,
- to: htmlPaths.elements([htmlPaths.element("em")])
- }
- ]
- });
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<em>Hello.</em>");
- });
+});
+
+test('warning is emitted if paragraph style is unrecognised', function() {
+ var document = new documents.Document([
+ paragraphOfText("Hello.", "Heading1", "Heading 1")
+ ]);
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(document).then(function(result) {
+ assert.deepEqual(result.messages, [results.warning("Unrecognised paragraph style: 'Heading 1' (Style ID: Heading1)")]);
});
-
- test('bold runs can exist inside other tags', function() {
- var run = new documents.Paragraph([
- runOfText("Hello.", {isBold: true})
- ]);
- var converter = new DocumentConverter();
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<p><strong>Hello.</strong></p>");
- });
+});
+
+test('can use stacked styles to generate nested HTML elements', function() {
+ var document = new documents.Document([
+ paragraphOfText("Hello.")
+ ]);
+ var converter = new DocumentConverter({
+ styleMap: [
+ {
+ from: documentMatchers.paragraph(),
+ to: htmlPaths.elements(["h1", "span"])
+ }
+ ]
});
-
- test('consecutive bold runs are wrapped in a single <strong> element', function() {
- var paragraph = new documents.Paragraph([
- runOfText("Hello", {isBold: true}),
- runOfText(".", {isBold: true})
- ]);
- var converter = new DocumentConverter();
- return converter.convertToHtml(paragraph).then(function(result) {
- assert.equal(result.value, "<p><strong>Hello.</strong></p>");
- });
+ return converter.convertToHtml(document).then(function(result) {
+ assert.equal(result.value, "<h1><span>Hello.</span></h1>");
});
-
- test('underline runs are ignored by default', function() {
- var run = runOfText("Hello.", {isUnderline: true});
- var converter = new DocumentConverter();
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "Hello.");
- });
+});
+
+test('bold runs are wrapped in <strong> tags by default', function() {
+ var run = runOfText("Hello.", {isBold: true});
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<strong>Hello.</strong>");
});
-
- test('underline runs can be mapped using style mapping', function() {
- var run = runOfText("Hello.", {isUnderline: true});
- var converter = new DocumentConverter({
- styleMap: [
- {
- from: documentMatchers.underline,
- to: htmlPaths.elements([htmlPaths.element("u")])
- }
- ]
- });
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<u>Hello.</u>");
- });
+});
+
+test('bold runs can be configured with style mapping', function() {
+ var run = runOfText("Hello.", {isBold: true});
+ var converter = new DocumentConverter({
+ styleMap: [
+ {
+ from: documentMatchers.bold,
+ to: htmlPaths.elements([htmlPaths.element("em")])
+ }
+ ]
});
-
- test('style mapping for underline runs does not close parent elements', function() {
- var run = runOfText("Hello.", {isUnderline: true, isBold: true});
- var converter = new DocumentConverter({
- styleMap: [
- {
- from: documentMatchers.underline,
- to: htmlPaths.elements([htmlPaths.element("u")])
- }
- ]
- });
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<strong><u>Hello.</u></strong>");
- });
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<em>Hello.</em>");
});
-
- test('strikethrough runs are wrapped in <s> tags by default', function() {
- var run = runOfText("Hello.", {isStrikethrough: true});
- var converter = new DocumentConverter();
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<s>Hello.</s>");
- });
+});
+
+test('bold runs can exist inside other tags', function() {
+ var run = new documents.Paragraph([
+ runOfText("Hello.", {isBold: true})
+ ]);
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<p><strong>Hello.</strong></p>");
});
-
- test('strikethrough runs can be configured with style mapping', function() {
- var run = runOfText("Hello.", {isStrikethrough: true});
- var converter = new DocumentConverter({
- styleMap: [
- {
- from: documentMatchers.strikethrough,
- to: htmlPaths.elements([htmlPaths.element("del")])
- }
- ]
- });
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<del>Hello.</del>");
- });
+});
+
+test('consecutive bold runs are wrapped in a single <strong> element', function() {
+ var paragraph = new documents.Paragraph([
+ runOfText("Hello", {isBold: true}),
+ runOfText(".", {isBold: true})
+ ]);
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(paragraph).then(function(result) {
+ assert.equal(result.value, "<p><strong>Hello.</strong></p>");
});
+});
- test('italic runs are wrapped in <em> tags', function() {
- var run = runOfText("Hello.", {isItalic: true});
- var converter = new DocumentConverter();
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<em>Hello.</em>");
- });
+test('underline runs are ignored by default', function() {
+ var run = runOfText("Hello.", {isUnderline: true});
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "Hello.");
});
-
- test('italic runs can be configured with style mapping', function() {
- var run = runOfText("Hello.", {isItalic: true});
- var converter = new DocumentConverter({
- styleMap: [
- {
- from: documentMatchers.italic,
- to: htmlPaths.elements([htmlPaths.element("strong")])
- }
- ]
- });
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<strong>Hello.</strong>");
- });
+});
+
+test('underline runs can be mapped using style mapping', function() {
+ var run = runOfText("Hello.", {isUnderline: true});
+ var converter = new DocumentConverter({
+ styleMap: [
+ {
+ from: documentMatchers.underline,
+ to: htmlPaths.elements([htmlPaths.element("u")])
+ }
+ ]
});
-
- test('run can be both bold and italic', function() {
- var run = runOfText("Hello.", {isBold: true, isItalic: true});
- var converter = new DocumentConverter();
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<strong><em>Hello.</em></strong>");
- });
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<u>Hello.</u>");
});
-
- test('superscript runs are wrapped in <sup> tags', function() {
- var run = runOfText("Hello.", {
- verticalAlignment: documents.verticalAlignment.superscript
- });
- var converter = new DocumentConverter();
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<sup>Hello.</sup>");
- });
+});
+
+test('style mapping for underline runs does not close parent elements', function() {
+ var run = runOfText("Hello.", {isUnderline: true, isBold: true});
+ var converter = new DocumentConverter({
+ styleMap: [
+ {
+ from: documentMatchers.underline,
+ to: htmlPaths.elements([htmlPaths.element("u")])
+ }
+ ]
});
-
- test('subscript runs are wrapped in <sub> tags', function() {
- var run = runOfText("Hello.", {
- verticalAlignment: documents.verticalAlignment.subscript
- });
- var converter = new DocumentConverter();
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<sub>Hello.</sub>");
- });
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<strong><u>Hello.</u></strong>");
});
-
- test('run styles are converted to HTML if mapping exists', function() {
- var run = runOfText("Hello.", {styleId: "Heading1Char", styleName: "Heading 1 Char"});
- var converter = new DocumentConverter({
- styleMap: [
- {
- from: documentMatchers.run({styleName: "Heading 1 Char"}),
- to: htmlPaths.elements(["strong"])
- }
- ]
- });
- return converter.convertToHtml(run).then(function(result) {
- assert.equal(result.value, "<strong>Hello.</strong>");
- });
+});
+
+test('strikethrough runs are wrapped in <s> tags by default', function() {
+ var run = runOfText("Hello.", {isStrikethrough: true});
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<s>Hello.</s>");
});
-
- test('warning is emitted if run style is unrecognised', function() {
- var run = runOfText("Hello.", {styleId: "Heading1Char", styleName: "Heading 1 Char"});
- var converter = new DocumentConverter();
- return converter.convertToHtml(run).then(function(result) {
- assert.deepEqual(result.messages, [results.warning("Unrecognised run style: 'Heading 1 Char' (Style ID: Heading1Char)")]);
- });
+});
+
+test('strikethrough runs can be configured with style mapping', function() {
+ var run = runOfText("Hello.", {isStrikethrough: true});
+ var converter = new DocumentConverter({
+ styleMap: [
+ {
+ from: documentMatchers.strikethrough,
+ to: htmlPaths.elements([htmlPaths.element("del")])
+ }
+ ]
});
-
- test('docx hyperlink is converted to <a>', function() {
- var hyperlink = new documents.Hyperlink(
- [runOfText("Hello.")],
- {href: "http://www.example.com"}
- );
- var converter = new DocumentConverter();
- return converter.convertToHtml(hyperlink).then(function(result) {
- assert.equal(result.value, '<a href="http://www.example.com">Hello.</a>');
- });
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<del>Hello.</del>");
});
+});
- test('docx hyperlink with anchor is converted to <a>', function() {
- var hyperlink = new documents.Hyperlink(
- [runOfText("Hello.")],
- {anchor: "_Peter"}
- );
- var converter = new DocumentConverter({
- idPrefix: "doc-42-"
- });
- return converter.convertToHtml(hyperlink).then(function(result) {
- assert.equal(result.value, '<a href="#doc-42-_Peter">Hello.</a>');
- });
+test('italic runs are wrapped in <em> tags', function() {
+ var run = runOfText("Hello.", {isItalic: true});
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<em>Hello.</em>");
});
+});
- test('bookmarks are converted to anchors', function() {
- var bookmarkStart = new documents.BookmarkStart({name: "_Peter"});
- var converter = new DocumentConverter({
- idPrefix: "doc-42-"
- });
- var document = new documents.Document([bookmarkStart]);
- return converter.convertToHtml(document).then(function(result) {
- assert.equal(result.value, '<a id="doc-42-_Peter"></a>');
- });
+test('italic runs can be configured with style mapping', function() {
+ var run = runOfText("Hello.", {isItalic: true});
+ var converter = new DocumentConverter({
+ styleMap: [
+ {
+ from: documentMatchers.italic,
+ to: htmlPaths.elements([htmlPaths.element("strong")])
+ }
+ ]
+ });
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<strong>Hello.</strong>");
});
+});
- test('docx tab is converted to tab in HTML', function() {
- var tab = new documents.Tab();
- var converter = new DocumentConverter();
- return converter.convertToHtml(tab).then(function(result) {
- assert.equal(result.value, "\t");
- });
+test('run can be both bold and italic', function() {
+ var run = runOfText("Hello.", {isBold: true, isItalic: true});
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<strong><em>Hello.</em></strong>");
});
-
- test('docx table is converted to table in HTML', function() {
- var table = new documents.Table([
- new documents.TableRow([
- new documents.TableCell([paragraphOfText("Top left")]),
- new documents.TableCell([paragraphOfText("Top right")])
- ]),
- new documents.TableRow([
- new documents.TableCell([paragraphOfText("Bottom left")]),
- new documents.TableCell([paragraphOfText("Bottom right")])
- ])
- ]);
- var converter = new DocumentConverter();
-
- return converter.convertToHtml(table).then(function(result) {
- var expectedHtml = "<table>" +
- "<tr><td><p>Top left</p></td><td><p>Top right</p></td></tr>" +
- "<tr><td><p>Bottom left</p></td><td><p>Bottom right</p></td></tr>" +
- "</table>";
- assert.equal(result.value, expectedHtml);
- });
+});
+
+test('superscript runs are wrapped in <sup> tags', function() {
+ var run = runOfText("Hello.", {
+ verticalAlignment: documents.verticalAlignment.superscript
});
-
- test('empty cells are preserved in table', function() {
- var table = new documents.Table([
- new documents.TableRow([
- new documents.TableCell([paragraphOfText("")]),
- new documents.TableCell([paragraphOfText("Top right")])
- ])
- ]);
- var converter = new DocumentConverter();
-
- return converter.convertToHtml(table).then(function(result) {
- var expectedHtml = "<table>" +
- "<tr><td></td><td><p>Top right</p></td></tr>" +
- "</table>";
- assert.equal(result.value, expectedHtml);
- });
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<sup>Hello.</sup>");
});
-
- test('table cells are written with colSpan if not equal to one', function() {
- var table = new documents.Table([
- new documents.TableRow([
- new documents.TableCell([paragraphOfText("Top left")], {colSpan: 2}),
- new documents.TableCell([paragraphOfText("Top right")])
- ])
- ]);
- var converter = new DocumentConverter();
-
- return converter.convertToHtml(table).then(function(result) {
- var expectedHtml = "<table>" +
- "<tr><td colspan=\"2\"><p>Top left</p></td><td><p>Top right</p></td></tr>" +
- "</table>";
- assert.equal(result.value, expectedHtml);
- });
+});
+
+test('subscript runs are wrapped in <sub> tags', function() {
+ var run = runOfText("Hello.", {
+ verticalAlignment: documents.verticalAlignment.subscript
});
-
- test('table cells are written with rowSpan if not equal to one', function() {
- var table = new documents.Table([
- new documents.TableRow([
- new documents.TableCell([], {rowSpan: 2})
- ])
- ]);
- var converter = new DocumentConverter();
-
- return converter.convertToHtml(table).then(function(result) {
- var expectedHtml = "<table>" +
- "<tr><td rowspan=\"2\"></td></tr>" +
- "</table>";
- assert.equal(result.value, expectedHtml);
- });
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<sub>Hello.</sub>");
+ });
+});
+
+test('run styles are converted to HTML if mapping exists', function() {
+ var run = runOfText("Hello.", {styleId: "Heading1Char", styleName: "Heading 1 Char"});
+ var converter = new DocumentConverter({
+ styleMap: [
+ {
+ from: documentMatchers.run({styleName: "Heading 1 Char"}),
+ to: htmlPaths.elements(["strong"])
+ }
+ ]
+ });
+ return converter.convertToHtml(run).then(function(result) {
+ assert.equal(result.value, "<strong>Hello.</strong>");
+ });
+});
+
+test('warning is emitted if run style is unrecognised', function() {
+ var run = runOfText("Hello.", {styleId: "Heading1Char", styleName: "Heading 1 Char"});
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(run).then(function(result) {
+ assert.deepEqual(result.messages, [results.warning("Unrecognised run style: 'Heading 1 Char' (Style ID: Heading1Char)")]);
+ });
+});
+
+test('docx hyperlink is converted to <a>', function() {
+ var hyperlink = new documents.Hyperlink(
+ [runOfText("Hello.")],
+ {href: "http://www.example.com"}
+ );
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(hyperlink).then(function(result) {
+ assert.equal(result.value, '<a href="http://www.example.com">Hello.</a>');
+ });
+});
+
+test('docx hyperlink with anchor is converted to <a>', function() {
+ var hyperlink = new documents.Hyperlink(
+ [runOfText("Hello.")],
+ {anchor: "_Peter"}
+ );
+ var converter = new DocumentConverter({
+ idPrefix: "doc-42-"
+ });
+ return converter.convertToHtml(hyperlink).then(function(result) {
+ assert.equal(result.value, '<a href="#doc-42-_Peter">Hello.</a>');
+ });
+});
+
+test('bookmarks are converted to anchors', function() {
+ var bookmarkStart = new documents.BookmarkStart({name: "_Peter"});
+ var converter = new DocumentConverter({
+ idPrefix: "doc-42-"
+ });
+ var document = new documents.Document([bookmarkStart]);
+ return converter.convertToHtml(document).then(function(result) {
+ assert.equal(result.value, '<a id="doc-42-_Peter"></a>');
+ });
+});
+
+test('docx tab is converted to tab in HTML', function() {
+ var tab = new documents.Tab();
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(tab).then(function(result) {
+ assert.equal(result.value, "\t");
+ });
+});
+
+test('docx table is converted to table in HTML', function() {
+ var table = new documents.Table([
+ new documents.TableRow([
+ new documents.TableCell([paragraphOfText("Top left")]),
+ new documents.TableCell([paragraphOfText("Top right")])
+ ]),
+ new documents.TableRow([
+ new documents.TableCell([paragraphOfText("Bottom left")]),
+ new documents.TableCell([paragraphOfText("Bottom right")])
+ ])
+ ]);
+ var converter = new DocumentConverter();
+
+ return converter.convertToHtml(table).then(function(result) {
+ var expectedHtml = "<table>" +
+ "<tr><td><p>Top left</p></td><td><p>Top right</p></td></tr>" +
+ "<tr><td><p>Bottom left</p></td><td><p>Bottom right</p></td></tr>" +
+ "</table>";
+ assert.equal(result.value, expectedHtml);
+ });
+});
+
+test('empty cells are preserved in table', function() {
+ var table = new documents.Table([
+ new documents.TableRow([
+ new documents.TableCell([paragraphOfText("")]),
+ new documents.TableCell([paragraphOfText("Top right")])
+ ])
+ ]);
+ var converter = new DocumentConverter();
+
+ return converter.convertToHtml(table).then(function(result) {
+ var expectedHtml = "<table>" +
+ "<tr><td></td><td><p>Top right</p></td></tr>" +
+ "</table>";
+ assert.equal(result.value, expectedHtml);
+ });
+});
+
+test('table cells are written with colSpan if not equal to one', function() {
+ var table = new documents.Table([
+ new documents.TableRow([
+ new documents.TableCell([paragraphOfText("Top left")], {colSpan: 2}),
+ new documents.TableCell([paragraphOfText("Top right")])
+ ])
+ ]);
+ var converter = new DocumentConverter();
+
+ return converter.convertToHtml(table).then(function(result) {
+ var expectedHtml = "<table>" +
+ "<tr><td colspan=\"2\"><p>Top left</p></td><td><p>Top right</p></td></tr>" +
+ "</table>";
+ assert.equal(result.value, expectedHtml);
+ });
+});
+
+test('table cells are written with rowSpan if not equal to one', function() {
+ var table = new documents.Table([
+ new documents.TableRow([
+ new documents.TableCell([], {rowSpan: 2})
+ ])
+ ]);
+ var converter = new DocumentConverter();
+
+ return converter.convertToHtml(table).then(function(result) {
+ var expectedHtml = "<table>" +
+ "<tr><td rowspan=\"2\"></td></tr>" +
+ "</table>";
+ assert.equal(result.value, expectedHtml);
});
+});
+
+test('line break is converted to <br>', function() {
+ var lineBreak = new documents.LineBreak();
+ var converter = new DocumentConverter();
- test('line break is converted to <br>', function() {
- var lineBreak = new documents.LineBreak();
- var converter = new DocumentConverter();
-
- return converter.convertToHtml(lineBreak).then(function(result) {
- assert.equal(result.value, "<br />");
- });
+ return converter.convertToHtml(lineBreak).then(function(result) {
+ assert.equal(result.value, "<br />");
});
+});
+
+test('footnote reference is converted to superscript intra-page link', function() {
+ var footnoteReference = new documents.NoteReference({
+ noteType: "footnote",
+ noteId: "4"
+ });
+ var converter = new DocumentConverter({
+ idPrefix: "doc-42-"
+ });
+ return converter.convertToHtml(footnoteReference).then(function(result) {
+ assert.equal(result.value, '<sup><a href="#doc-42-footnote-4" id="doc-42-footnote-ref-4">[1]</a></sup>');
+ });
+});
+
+test('footnotes are included after the main body', function() {
+ var footnoteReference = new documents.NoteReference({
+ noteType: "footnote",
+ noteId: "4"
+ });
+ var document = new documents.Document(
+ [new documents.Paragraph([
+ runOfText("Knock knock"),
+ new documents.Run([footnoteReference])
+ ])],
+ {
+ notes: new documents.Notes({
+ 4: new documents.Note({
+ noteType: "footnote",
+ noteId: "4",
+ body: [paragraphOfText("Who's there?")]
+ })
+ })
+ }
+ );
- test('footnote reference is converted to superscript intra-page link', function() {
- var footnoteReference = new documents.NoteReference({
- noteType: "footnote",
- noteId: "4"
- });
- var converter = new DocumentConverter({
- idPrefix: "doc-42-"
- });
- return converter.convertToHtml(footnoteReference).then(function(result) {
- assert.equal(result.value, '<sup><a href="#doc-42-footnote-4" id="doc-42-footnote-ref-4">[1]</a></sup>');
- });
+ var converter = new DocumentConverter({
+ idPrefix: "doc-42-"
+ });
+ return converter.convertToHtml(document).then(function(result) {
+ var expectedOutput = '<p>Knock knock<sup><a href="#doc-42-footnote-4" id="doc-42-footnote-ref-4">[1]</a></sup></p>' +
+ '<ol><li id="doc-42-footnote-4"><p>Who\'s there? <a href="#doc-42-footnote-ref-4">↑</a></p></li></ol>';
+ assert.equal(result.value, expectedOutput);
+ });
+});
+
+test('comments are ignored by default', function() {
+ var reference = documents.commentReference({commentId: "4"});
+ var comment = documents.comment({
+ commentId: "4",
+ body: [paragraphOfText("Who's there?")]
+ });
+ var document = documents.document([
+ documents.paragraph([
+ runOfText("Knock knock"),
+ documents.run([reference])
+ ])
+ ], {comments: [comment]});
+
+ var converter = new DocumentConverter({});
+ return converter.convertToHtml(document).then(function(result) {
+ assert.equal(result.value, '<p>Knock knock</p>');
+ assert.deepEqual(result.messages, []);
});
+});
- test('footnotes are included after the main body', function() {
- var footnoteReference = new documents.NoteReference({
- noteType: "footnote",
- noteId: "4"
- });
- var document = new documents.Document(
- [new documents.Paragraph([
- runOfText("Knock knock"),
- new documents.Run([footnoteReference])
- ])],
- {
- notes: new documents.Notes({
- 4: new documents.Note({
- noteType: "footnote",
- noteId: "4",
- body: [paragraphOfText("Who's there?")]
- })
- })
- }
+test('comment references are linked to comment after main body', function() {
+ var reference = documents.commentReference({commentId: "4"});
+ var comment = documents.comment({
+ commentId: "4",
+ body: [paragraphOfText("Who's there?")],
+ authorName: "The Piemaker",
+ authorInitials: "TP"
+ });
+ var document = documents.document([
+ documents.paragraph([
+ runOfText("Knock knock"),
+ documents.run([reference])
+ ])
+ ], {comments: [comment]});
+
+ var converter = new DocumentConverter({
+ idPrefix: "doc-42-",
+ styleMap: [
+ {from: documentMatchers.commentReference, to: htmlPaths.element("sup")}
+ ]
+ });
+ return converter.convertToHtml(document).then(function(result) {
+ var expectedHtml = (
+ '<p>Knock knock<sup><a href="#doc-42-comment-4" id="doc-42-comment-ref-4">[TP1]</a></sup></p>' +
+ '<dl><dt id="doc-42-comment-4">Comment [TP1]</dt><dd><p>Who\'s there? <a href="#doc-42-comment-ref-4">↑</a></p></dd></dl>'
);
-
- var converter = new DocumentConverter({
- idPrefix: "doc-42-"
- });
- return converter.convertToHtml(document).then(function(result) {
- var expectedOutput = '<p>Knock knock<sup><a href="#doc-42-footnote-4" id="doc-42-footnote-ref-4">[1]</a></sup></p>' +
- '<ol><li id="doc-42-footnote-4"><p>Who\'s there? <a href="#doc-42-footnote-ref-4">↑</a></p></li></ol>';
- assert.equal(result.value, expectedOutput);
- });
+ assert.equal(result.value, expectedHtml);
+ assert.deepEqual(result.messages, []);
});
-
- test('images are written with data URIs', function() {
- var imageBuffer = new Buffer("Not an image at all!");
- var image = new documents.Image({
- readImage: function(encoding) {
- return promises.when(imageBuffer.toString(encoding));
- },
- contentType: "image/png"
- });
- var converter = new DocumentConverter();
- return converter.convertToHtml(image).then(function(result) {
- assert.equal(result.value, '<img src="data:image/png;base64,' + imageBuffer.toString("base64") + '" />');
- });
+});
+
+test('images are written with data URIs', function() {
+ var imageBuffer = new Buffer("Not an image at all!");
+ var image = new documents.Image({
+ readImage: function(encoding) {
+ return promises.when(imageBuffer.toString(encoding));
+ },
+ contentType: "image/png"
+ });
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(image).then(function(result) {
+ assert.equal(result.value, '<img src="data:image/png;base64,' + imageBuffer.toString("base64") + '" />');
});
-
- test('images have alt attribute if available', function() {
- var imageBuffer = new Buffer("Not an image at all!");
- var image = new documents.Image({
- readImage: function() {
- return promises.when(imageBuffer);
- },
- altText: "It's a hat"
+});
+
+test('images have alt attribute if available', function() {
+ var imageBuffer = new Buffer("Not an image at all!");
+ var image = new documents.Image({
+ readImage: function() {
+ return promises.when(imageBuffer);
+ },
+ altText: "It's a hat"
+ });
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(image)
+ .then(function(result) {
+ return xml.readString(result.value);
+ })
+ .then(function(htmlImageElement) {
+ assert.equal(htmlImageElement.attributes.alt, "It's a hat");
});
- var converter = new DocumentConverter();
- return converter.convertToHtml(image)
- .then(function(result) {
- return xml.readString(result.value);
- })
- .then(function(htmlImageElement) {
- assert.equal(htmlImageElement.attributes.alt, "It's a hat");
+});
+
+test('can add custom handler for images', function() {
+ var imageBuffer = new Buffer("Not an image at all!");
+ var image = new documents.Image({
+ readImage: function(encoding) {
+ return promises.when(imageBuffer.toString(encoding));
+ },
+ contentType: "image/png"
+ });
+ var converter = new DocumentConverter({
+ convertImage: function(element, messages) {
+ return element.read("utf8").then(function(altText) {
+ return [Html.selfClosingElement("img", {alt: altText})];
});
+ }
});
-
- test('can add custom handler for images', function() {
- var imageBuffer = new Buffer("Not an image at all!");
- var image = new documents.Image({
- readImage: function(encoding) {
- return promises.when(imageBuffer.toString(encoding));
- },
- contentType: "image/png"
- });
- var converter = new DocumentConverter({
- convertImage: function(element, messages) {
- return element.read("utf8").then(function(altText) {
- return [Html.selfClosingElement("img", {alt: altText})];
- });
- }
- });
- return converter.convertToHtml(image).then(function(result) {
- assert.equal(result.value, '<img alt="Not an image at all!" />');
- });
+ return converter.convertToHtml(image).then(function(result) {
+ assert.equal(result.value, '<img alt="Not an image at all!" />');
});
-
- test('long documents do not cause stack overflow', function() {
- var paragraphs = [];
- for (var i = 0; i < 1000; i++) {
- paragraphs.push(paragraphOfText("Hello."));
- }
- var document = new documents.Document(paragraphs);
- var converter = new DocumentConverter();
- return converter.convertToHtml(document).then(function(result) {
- assert.equal(result.value.indexOf("<p>Hello.</p>"), 0);
- });
+});
+
+test('long documents do not cause stack overflow', function() {
+ var paragraphs = [];
+ for (var i = 0; i < 1000; i++) {
+ paragraphs.push(paragraphOfText("Hello."));
+ }
+ var document = new documents.Document(paragraphs);
+ var converter = new DocumentConverter();
+ return converter.convertToHtml(document).then(function(result) {
+ assert.equal(result.value.indexOf("<p>Hello.</p>"), 0);
});
});
@@ -563,3 +614,13 @@ function runOfText(text, properties) {
var textElement = new documents.Text(text);
return new documents.Run([textElement], properties);
}
+
+test('when initials are not blank then comment author label is initials', function() {
+ assert.equal(commentAuthorLabel({authorInitials: "TP"}), "TP")
+});
+
+test('when initials are blank then comment author label is blank', function() {
+ assert.equal(commentAuthorLabel({authorInitials: ""}), "")
+ assert.equal(commentAuthorLabel({authorInitials: undefined}), "")
+ assert.equal(commentAuthorLabel({authorInitials: null}), "")
+});
diff --git a/test/docx/body-reader.tests.js b/test/docx/body-reader.tests.js
index 24c2d8d..34463f7 100644
--- a/test/docx/body-reader.tests.js
+++ b/test/docx/body-reader.tests.js
@@ -10,7 +10,7 @@ var Styles = require("../../lib/docx/styles-reader").Styles;
var warning = require("../../lib/results").warning;
var testing = require("../testing");
-var test = testing.test;
+var test = require("../test")(module);
var createFakeDocxFile = testing.createFakeDocxFile;
function readXmlElement(element, options) {
@@ -35,664 +35,662 @@ var fakeContentTypes = {
}
};
-describe("readXmlElement: ", function() {
- test("paragraph has no style if it has no properties", function() {
- var paragraphXml = new XmlElement("w:p", {}, []);
- var paragraph = readXmlElementValue(paragraphXml);
- assert.deepEqual(paragraph.styleId, null);
- });
+test("paragraph has no style if it has no properties", function() {
+ var paragraphXml = new XmlElement("w:p", {}, []);
+ var paragraph = readXmlElementValue(paragraphXml);
+ assert.deepEqual(paragraph.styleId, null);
+});
+
+test("paragraph has style ID and name read from paragraph properties if present", function() {
+ var styleXml = new XmlElement("w:pStyle", {"w:val": "Heading1"}, []);
+ var propertiesXml = new XmlElement("w:pPr", {}, [styleXml]);
+ var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
- test("paragraph has style ID and name read from paragraph properties if present", function() {
- var styleXml = new XmlElement("w:pStyle", {"w:val": "Heading1"}, []);
- var propertiesXml = new XmlElement("w:pPr", {}, [styleXml]);
- var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
-
- var styles = new Styles({"Heading1": {name: "Heading 1"}}, {});
-
- var paragraph = readXmlElementValue(paragraphXml, {styles: styles});
- assert.deepEqual(paragraph.styleId, "Heading1");
- assert.deepEqual(paragraph.styleName, "Heading 1");
- });
+ var styles = new Styles({"Heading1": {name: "Heading 1"}}, {});
- test("warning is emitted when paragraph style cannot be found", function() {
- var styleXml = new XmlElement("w:pStyle", {"w:val": "Heading1"}, []);
- var propertiesXml = new XmlElement("w:pPr", {}, [styleXml]);
- var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
-
- var styles = new Styles({}, {});
-
- var result = readXmlElement(paragraphXml, {styles: styles});
- var paragraph = result.value;
- assert.deepEqual(paragraph.styleId, "Heading1");
- assert.deepEqual(paragraph.styleName, null);
- assert.deepEqual(result.messages, [warning("Paragraph style with ID Heading1 was referenced but not defined in the document")]);
- });
+ var paragraph = readXmlElementValue(paragraphXml, {styles: styles});
+ assert.deepEqual(paragraph.styleId, "Heading1");
+ assert.deepEqual(paragraph.styleName, "Heading 1");
+});
+
+test("warning is emitted when paragraph style cannot be found", function() {
+ var styleXml = new XmlElement("w:pStyle", {"w:val": "Heading1"}, []);
+ var propertiesXml = new XmlElement("w:pPr", {}, [styleXml]);
+ var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
+
+ var styles = new Styles({}, {});
+
+ var result = readXmlElement(paragraphXml, {styles: styles});
+ var paragraph = result.value;
+ assert.deepEqual(paragraph.styleId, "Heading1");
+ assert.deepEqual(paragraph.styleName, null);
+ assert.deepEqual(result.messages, [warning("Paragraph style with ID Heading1 was referenced but not defined in the document")]);
+});
+
+test("paragraph has justification read from paragraph properties if present", function() {
+ var justificationXml = new XmlElement("w:jc", {"w:val": "center"}, []);
+ var propertiesXml = new XmlElement("w:pPr", {}, [justificationXml]);
+ var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
+ var paragraph = readXmlElementValue(paragraphXml);
+ assert.deepEqual(paragraph.alignment, "center");
+});
+
+test("paragraph has numbering properties from paragraph properties if present", function() {
+ var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
+ new XmlElement("w:ilvl", {"w:val": "1"}),
+ new XmlElement("w:numId", {"w:val": "42"})
+ ]);
+ var propertiesXml = new XmlElement("w:pPr", {}, [numberingPropertiesXml]);
+ var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
- test("paragraph has justification read from paragraph properties if present", function() {
- var justificationXml = new XmlElement("w:jc", {"w:val": "center"}, []);
- var propertiesXml = new XmlElement("w:pPr", {}, [justificationXml]);
- var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
- var paragraph = readXmlElementValue(paragraphXml);
- assert.deepEqual(paragraph.alignment, "center");
- });
+ var numbering = new Numbering({"42": {"1": {isOrdered: true, level: "1"}}});
- test("paragraph has numbering properties from paragraph properties if present", function() {
- var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
- new XmlElement("w:ilvl", {"w:val": "1"}),
- new XmlElement("w:numId", {"w:val": "42"})
- ]);
- var propertiesXml = new XmlElement("w:pPr", {}, [numberingPropertiesXml]);
- var paragraphXml = new XmlElement("w:p", {}, [propertiesXml]);
-
- var numbering = new Numbering({"42": {"1": {isOrdered: true, level: "1"}}});
-
- var paragraph = readXmlElementValue(paragraphXml, {numbering: numbering});
- assert.deepEqual(paragraph.numbering, {level: "1", isOrdered: true});
- });
+ var paragraph = readXmlElementValue(paragraphXml, {numbering: numbering});
+ assert.deepEqual(paragraph.numbering, {level: "1", isOrdered: true});
+});
+
+test("numbering properties are converted to numbering at specified level", function() {
+ var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
+ new XmlElement("w:ilvl", {"w:val": "1"}),
+ new XmlElement("w:numId", {"w:val": "42"})
+ ]);
- test("numbering properties are converted to numbering at specified level", function() {
- var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
- new XmlElement("w:ilvl", {"w:val": "1"}),
- new XmlElement("w:numId", {"w:val": "42"})
- ]);
-
- var numbering = new Numbering({"42": {"1": {isOrdered: true, level: "1"}}});
-
- var reader = new BodyReader({
- numbering: numbering
- });
- var numberingLevel = reader._readNumberingProperties(numberingPropertiesXml);
- assert.deepEqual(numberingLevel, {level: "1", isOrdered: true});
- });
+ var numbering = new Numbering({"42": {"1": {isOrdered: true, level: "1"}}});
- test("numbering properties are ignored if w:ilvl is missing", function() {
- var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
- new XmlElement("w:numId", {"w:val": "42"})
- ]);
-
- var numbering = new Numbering({"42": {"1": {isOrdered: true, level: "1"}}});
-
- var reader = new BodyReader({
- numbering: numbering
- });
- var numberingLevel = reader._readNumberingProperties(numberingPropertiesXml);
- assert.equal(numberingLevel, null);
+ var reader = new BodyReader({
+ numbering: numbering
});
+ var numberingLevel = reader._readNumberingProperties(numberingPropertiesXml);
+ assert.deepEqual(numberingLevel, {level: "1", isOrdered: true});
+});
+
+test("numbering properties are ignored if w:ilvl is missing", function() {
+ var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
+ new XmlElement("w:numId", {"w:val": "42"})
+ ]);
- test("numbering properties are ignored if w:numId is missing", function() {
- var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
- new XmlElement("w:ilvl", {"w:val": "1"})
- ]);
-
- var numbering = new Numbering({"42": {"1": {isOrdered: true, level: "1"}}});
-
- var reader = new BodyReader({
- numbering: numbering
- });
- var numberingLevel = reader._readNumberingProperties(numberingPropertiesXml);
- assert.equal(numberingLevel, null);
- });
+ var numbering = new Numbering({"42": {"1": {isOrdered: true, level: "1"}}});
- test("run has no style if it has no properties", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.styleId, null);
+ var reader = new BodyReader({
+ numbering: numbering
});
+ var numberingLevel = reader._readNumberingProperties(numberingPropertiesXml);
+ assert.equal(numberingLevel, null);
+});
+
+test("numbering properties are ignored if w:numId is missing", function() {
+ var numberingPropertiesXml = new XmlElement("w:numPr", {}, [
+ new XmlElement("w:ilvl", {"w:val": "1"})
+ ]);
- test("run has style ID and name read from run properties if present", function() {
- var runStyleXml = new XmlElement("w:rStyle", {"w:val": "Heading1Char"});
- var runXml = runWithProperties([runStyleXml]);
-
- var styles = new Styles({}, {"Heading1Char": {name: "Heading 1 Char"}});
-
- var run = readXmlElementValue(runXml, {styles: styles});
- assert.deepEqual(run.styleId, "Heading1Char");
- assert.deepEqual(run.styleName, "Heading 1 Char");
- });
+ var numbering = new Numbering({"42": {"1": {isOrdered: true, level: "1"}}});
- test("warning is emitted when run style cannot be found", function() {
- var runStyleXml = new XmlElement("w:rStyle", {"w:val": "Heading1Char"});
- var runXml = runWithProperties([runStyleXml]);
-
- var styles = new Styles({}, {});
-
- var result = readXmlElement(runXml, {styles: styles});
- var run = result.value;
- assert.deepEqual(run.styleId, "Heading1Char");
- assert.deepEqual(run.styleName, null);
- assert.deepEqual(result.messages, [warning("Run style with ID Heading1Char was referenced but not defined in the document")]);
+ var reader = new BodyReader({
+ numbering: numbering
});
+ var numberingLevel = reader._readNumberingProperties(numberingPropertiesXml);
+ assert.equal(numberingLevel, null);
+});
+
+test("run has no style if it has no properties", function() {
+ var runXml = runWithProperties([]);
+ var run = readXmlElementValue(runXml);
+ assert.deepEqual(run.styleId, null);
+});
+
+test("run has style ID and name read from run properties if present", function() {
+ var runStyleXml = new XmlElement("w:rStyle", {"w:val": "Heading1Char"});
+ var runXml = runWithProperties([runStyleXml]);
- test("isBold is false if bold element is not present", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.isBold, false);
- });
+ var styles = new Styles({}, {"Heading1Char": {name: "Heading 1 Char"}});
- test("isBold is true if bold element is present", function() {
- var boldXml = new XmlElement("w:b");
- var runXml = runWithProperties([boldXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isBold, true);
- });
+ var run = readXmlElementValue(runXml, {styles: styles});
+ assert.deepEqual(run.styleId, "Heading1Char");
+ assert.deepEqual(run.styleName, "Heading 1 Char");
+});
- test("isUnderline is false if underline element is not present", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.isUnderline, false);
- });
+test("warning is emitted when run style cannot be found", function() {
+ var runStyleXml = new XmlElement("w:rStyle", {"w:val": "Heading1Char"});
+ var runXml = runWithProperties([runStyleXml]);
+
+ var styles = new Styles({}, {});
+
+ var result = readXmlElement(runXml, {styles: styles});
+ var run = result.value;
+ assert.deepEqual(run.styleId, "Heading1Char");
+ assert.deepEqual(run.styleName, null);
+ assert.deepEqual(result.messages, [warning("Run style with ID Heading1Char was referenced but not defined in the document")]);
+});
- test("isUnderline is true if underline element is present", function() {
- var underlineXml = new XmlElement("w:u");
- var runXml = runWithProperties([underlineXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isUnderline, true);
- });
+test("isBold is false if bold element is not present", function() {
+ var runXml = runWithProperties([]);
+ var run = readXmlElementValue(runXml);
+ assert.deepEqual(run.isBold, false);
+});
- test("isStrikethrough is false if strikethrough element is not present", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.isStrikethrough, false);
- });
+test("isBold is true if bold element is present", function() {
+ var boldXml = new XmlElement("w:b");
+ var runXml = runWithProperties([boldXml]);
+ var run = readXmlElementValue(runXml);
+ assert.equal(run.isBold, true);
+});
- test("isStrikethrough is true if strikethrough element is present", function() {
- var strikethroughXml = new XmlElement("w:strike");
- var runXml = runWithProperties([strikethroughXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isStrikethrough, true);
- });
+test("isUnderline is false if underline element is not present", function() {
+ var runXml = runWithProperties([]);
+ var run = readXmlElementValue(runXml);
+ assert.deepEqual(run.isUnderline, false);
+});
- test("isItalic is false if bold element is not present", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.isItalic, false);
- });
-
- test("isItalic is true if bold element is present", function() {
- var italicXml = new XmlElement("w:i");
- var runXml = runWithProperties([italicXml]);
- var run = readXmlElementValue(runXml);
- assert.equal(run.isItalic, true);
- });
-
- test("run has baseline vertical alignment by default", function() {
- var runXml = runWithProperties([]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.verticalAlignment, documents.verticalAlignment.baseline);
- });
-
- test("run has vertical alignment read from properties", function() {
- var verticalAlignmentXml = new XmlElement("w:vertAlign", {"w:val": "superscript"});
- var runXml = runWithProperties([verticalAlignmentXml]);
-
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run.verticalAlignment, documents.verticalAlignment.superscript);
- });
-
- test("run properties not included as child of run", function() {
- var runStyleXml = new XmlElement("w:rStyle");
- var runPropertiesXml = new XmlElement("w:rPr", {}, [runStyleXml]);
- var runXml = new XmlElement("w:r", {}, [runPropertiesXml]);
- var result = readXmlElement(runXml);
- assert.deepEqual(result.value.children, []);
- });
-
- test("w:tab is read as document tab element", function() {
- var tabXml = new XmlElement("w:tab");
- var result = readXmlElement(tabXml);
- assert.deepEqual(result.value, new documents.Tab());
- });
+test("isUnderline is true if underline element is present", function() {
+ var underlineXml = new XmlElement("w:u");
+ var runXml = runWithProperties([underlineXml]);
+ var run = readXmlElementValue(runXml);
+ assert.equal(run.isUnderline, true);
+});
+
+test("isStrikethrough is false if strikethrough element is not present", function() {
+ var runXml = runWithProperties([]);
+ var run = readXmlElementValue(runXml);
+ assert.deepEqual(run.isStrikethrough, false);
+});
+
+test("isStrikethrough is true if strikethrough element is present", function() {
+ var strikethroughXml = new XmlElement("w:strike");
+ var runXml = runWithProperties([strikethroughXml]);
+ var run = readXmlElementValue(runXml);
+ assert.equal(run.isStrikethrough, true);
+});
+
+test("isItalic is false if bold element is not present", function() {
+ var runXml = runWithProperties([]);
+ var run = readXmlElementValue(runXml);
+ assert.deepEqual(run.isItalic, false);
+});
+
+test("isItalic is true if bold element is present", function() {
+ var italicXml = new XmlElement("w:i");
+ var runXml = runWithProperties([italicXml]);
+ var run = readXmlElementValue(runXml);
+ assert.equal(run.isItalic, true);
+});
+
+test("run has baseline vertical alignment by default", function() {
+ var runXml = runWithProperties([]);
+ var run = readXmlElementValue(runXml);
+ assert.deepEqual(run.verticalAlignment, documents.verticalAlignment.baseline);
+});
+
+test("run has vertical alignment read from properties", function() {
+ var verticalAlignmentXml = new XmlElement("w:vertAlign", {"w:val": "superscript"});
+ var runXml = runWithProperties([verticalAlignmentXml]);
- test("w:tbl is read as document table element", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- new XmlElement("w:tr", {}, [
- new XmlElement("w:tc", {}, [
- new XmlElement("w:p", {}, [])
- ])
- ])
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.value, new documents.Table([
- new documents.TableRow([
- new documents.TableCell([
- new documents.Paragraph([])
- ])
+ var run = readXmlElementValue(runXml);
+ assert.deepEqual(run.verticalAlignment, documents.verticalAlignment.superscript);
+});
+
+test("run properties not included as child of run", function() {
+ var runStyleXml = new XmlElement("w:rStyle");
+ var runPropertiesXml = new XmlElement("w:rPr", {}, [runStyleXml]);
+ var runXml = new XmlElement("w:r", {}, [runPropertiesXml]);
+ var result = readXmlElement(runXml);
+ assert.deepEqual(result.value.children, []);
+});
+
+test("w:tab is read as document tab element", function() {
+ var tabXml = new XmlElement("w:tab");
+ var result = readXmlElement(tabXml);
+ assert.deepEqual(result.value, new documents.Tab());
+});
+
+test("w:tbl is read as document table element", function() {
+ var tableXml = new XmlElement("w:tbl", {}, [
+ new XmlElement("w:tr", {}, [
+ new XmlElement("w:tc", {}, [
+ new XmlElement("w:p", {}, [])
])
- ]));
- });
-
- test("w:gridSpan is read as colSpan for table cell", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- new XmlElement("w:tr", {}, [
- new XmlElement("w:tc", {}, [
- new XmlElement("w:tcPr", {}, [
- new XmlElement("w:gridSpan", {"w:val": "2"})
- ]),
- new XmlElement("w:p", {}, [])
- ])
+ ])
+ ]);
+ var result = readXmlElement(tableXml);
+ assert.deepEqual(result.value, new documents.Table([
+ new documents.TableRow([
+ new documents.TableCell([
+ new documents.Paragraph([])
])
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.value, new documents.Table([
- new documents.TableRow([
- new documents.TableCell([
- new documents.Paragraph([])
- ], {colSpan: 2})
+ ])
+ ]));
+});
+
+test("w:gridSpan is read as colSpan for table cell", function() {
+ var tableXml = new XmlElement("w:tbl", {}, [
+ new XmlElement("w:tr", {}, [
+ new XmlElement("w:tc", {}, [
+ new XmlElement("w:tcPr", {}, [
+ new XmlElement("w:gridSpan", {"w:val": "2"})
+ ]),
+ new XmlElement("w:p", {}, [])
])
- ]));
- });
-
- test("w:vMerge is read as rowSpan for table cell", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- row(emptyCell()),
- row(emptyCell(vMerge("restart"))),
- row(emptyCell(vMerge("continue"))),
- row(emptyCell(vMerge("continue"))),
- row(emptyCell())
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.value, new documents.Table([
- docRow([docEmptyCell()]),
- docRow([docEmptyCell({rowSpan: 3})]),
- docRow([]),
- docRow([]),
- docRow([docEmptyCell()])
- ]));
- });
-
- test("w:vMerge without val is treated as continue", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- row(emptyCell(vMerge("restart"))),
- row(emptyCell(vMerge()))
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.value, new documents.Table([
- docRow([docEmptyCell({rowSpan: 2})]),
- docRow([])
- ]));
- });
-
- test("w:vMerge accounts for cells spanning columns", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- row(emptyCell(), emptyCell(), emptyCell(vMerge("restart"))),
- row(emptyCell(gridSpan("2")), emptyCell(vMerge("continue"))),
- row(emptyCell(), emptyCell(), emptyCell(vMerge("continue"))),
- row(emptyCell(), emptyCell(), emptyCell())
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.value, new documents.Table([
- docRow([docEmptyCell(), docEmptyCell(), docEmptyCell({rowSpan: 3})]),
- docRow([docEmptyCell({colSpan: 2})]),
- docRow([docEmptyCell(), docEmptyCell()]),
- docRow([docEmptyCell(), docEmptyCell(), docEmptyCell()])
- ]));
- });
-
- test("no vertical cell merging if merged cells do not line up", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- row(emptyCell(gridSpan("2"), vMerge("restart"))),
- row(emptyCell(), emptyCell(vMerge("continue")))
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.value, new documents.Table([
- docRow([docEmptyCell({colSpan: 2})]),
- docRow([docEmptyCell(), docEmptyCell()])
- ]));
- });
-
- test("warning if non-row in table", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- new XmlElement("w:p")
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.messages, [warning("unexpected non-row element in table, cell merging may be incorrect")]);
- });
-
- test("warning if non-cell in table row", function() {
- var tableXml = new XmlElement("w:tbl", {}, [
- row(new XmlElement("w:p"))
- ]);
- var result = readXmlElement(tableXml);
- assert.deepEqual(result.messages, [warning("unexpected non-cell element in table row, cell merging may be incorrect")]);
- });
-
- function row() {
- return new XmlElement("w:tr", {}, Array.prototype.slice.call(arguments));
- }
-
- function emptyCell() {
- return new XmlElement("w:tc", {}, [
- new XmlElement("w:tcPr", {}, Array.prototype.slice.call(arguments))
- ]);
- }
-
- function vMerge(val) {
- return new XmlElement("w:vMerge", {"w:val": val}, []);
- }
-
- function gridSpan(val) {
- return new XmlElement("w:gridSpan", {"w:val": val});
- }
-
- function docRow(children) {
- return new documents.TableRow(children);
- }
-
- function docEmptyCell(properties) {
- return new documents.TableCell([], properties);
- }
+ ])
+ ]);
+ var result = readXmlElement(tableXml);
+ assert.deepEqual(result.value, new documents.Table([
+ new documents.TableRow([
+ new documents.TableCell([
+ new documents.Paragraph([])
+ ], {colSpan: 2})
+ ])
+ ]));
+});
- test("w:bookmarkStart is read as a bookmarkStart", function() {
- var bookmarkStart = new XmlElement("w:bookmarkStart", {"w:name": "_Peter", "w:id": "42"});
- var result = readXmlElement(bookmarkStart);
- assert.deepEqual(result.value.name, "_Peter");
- assert.deepEqual(result.value.type, "bookmarkStart");
- });
-
- test('_GoBack bookmark is ignored', function() {
- var bookmarkStart = new XmlElement("w:bookmarkStart", {"w:name": "_GoBack"});
- var result = readXmlElement(bookmarkStart);
- assert.deepEqual(result.value, []);
- });
-
- test("can read imagedata elements with r:id attribute", function() {
- var imagedataElement = new XmlElement("v:imagedata", {"r:id": "rId5", "o:title": "It's a hat"});
-
- var imageBuffer = new Buffer("Not an image at all!");
- var reader = new BodyReader({
- relationships: {
- "rId5": {target: "media/hat.png"}
- },
- contentTypes: fakeContentTypes,
- docxFile: createFakeDocxFile({
- "word/media/hat.png": imageBuffer
- })
- });
- var result = reader.readXmlElement(imagedataElement);
- assert.deepEqual(result.messages, []);
- var element = result.value;
- assert.equal("image", element.type);
- assert.equal(element.altText, "It's a hat");
- assert.equal(element.contentType, "image/png");
- return element.read()
- .then(function(readValue) {
- assert.equal(readValue, imageBuffer);
- });
- });
-
- test("can read inline pictures", function() {
- var drawing = createInlineImage({
- blip: createEmbeddedBlip("rId5"),
- description: "It's a hat"
+test("w:vMerge is read as rowSpan for table cell", function() {
+ var tableXml = new XmlElement("w:tbl", {}, [
+ row(emptyCell()),
+ row(emptyCell(vMerge("restart"))),
+ row(emptyCell(vMerge("continue"))),
+ row(emptyCell(vMerge("continue"))),
+ row(emptyCell())
+ ]);
+ var result = readXmlElement(tableXml);
+ assert.deepEqual(result.value, new documents.Table([
+ docRow([docEmptyCell()]),
+ docRow([docEmptyCell({rowSpan: 3})]),
+ docRow([]),
+ docRow([]),
+ docRow([docEmptyCell()])
+ ]));
+});
+
+test("w:vMerge without val is treated as continue", function() {
+ var tableXml = new XmlElement("w:tbl", {}, [
+ row(emptyCell(vMerge("restart"))),
+ row(emptyCell(vMerge()))
+ ]);
+ var result = readXmlElement(tableXml);
+ assert.deepEqual(result.value, new documents.Table([
+ docRow([docEmptyCell({rowSpan: 2})]),
+ docRow([])
+ ]));
+});
+
+test("w:vMerge accounts for cells spanning columns", function() {
+ var tableXml = new XmlElement("w:tbl", {}, [
+ row(emptyCell(), emptyCell(), emptyCell(vMerge("restart"))),
+ row(emptyCell(gridSpan("2")), emptyCell(vMerge("continue"))),
+ row(emptyCell(), emptyCell(), emptyCell(vMerge("continue"))),
+ row(emptyCell(), emptyCell(), emptyCell())
+ ]);
+ var result = readXmlElement(tableXml);
+ assert.deepEqual(result.value, new documents.Table([
+ docRow([docEmptyCell(), docEmptyCell(), docEmptyCell({rowSpan: 3})]),
+ docRow([docEmptyCell({colSpan: 2})]),
+ docRow([docEmptyCell(), docEmptyCell()]),
+ docRow([docEmptyCell(), docEmptyCell(), docEmptyCell()])
+ ]));
+});
+
+test("no vertical cell merging if merged cells do not line up", function() {
+ var tableXml = new XmlElement("w:tbl", {}, [
+ row(emptyCell(gridSpan("2"), vMerge("restart"))),
+ row(emptyCell(), emptyCell(vMerge("continue")))
+ ]);
+ var result = readXmlElement(tableXml);
+ assert.deepEqual(result.value, new documents.Table([
+ docRow([docEmptyCell({colSpan: 2})]),
+ docRow([docEmptyCell(), docEmptyCell()])
+ ]));
+});
+
+test("warning if non-row in table", function() {
+ var tableXml = new XmlElement("w:tbl", {}, [
+ new XmlElement("w:p")
+ ]);
+ var result = readXmlElement(tableXml);
+ assert.deepEqual(result.messages, [warning("unexpected non-row element in table, cell merging may be incorrect")]);
+});
+
+test("warning if non-cell in table row", function() {
+ var tableXml = new XmlElement("w:tbl", {}, [
+ row(new XmlElement("w:p"))
+ ]);
+ var result = readXmlElement(tableXml);
+ assert.deepEqual(result.messages, [warning("unexpected non-cell element in table row, cell merging may be incorrect")]);
+});
+
+function row() {
+ return new XmlElement("w:tr", {}, Array.prototype.slice.call(arguments));
+}
+
+function emptyCell() {
+ return new XmlElement("w:tc", {}, [
+ new XmlElement("w:tcPr", {}, Array.prototype.slice.call(arguments))
+ ]);
+}
+
+function vMerge(val) {
+ return new XmlElement("w:vMerge", {"w:val": val}, []);
+}
+
+function gridSpan(val) {
+ return new XmlElement("w:gridSpan", {"w:val": val});
+}
+
+function docRow(children) {
+ return new documents.TableRow(children);
+}
+
+function docEmptyCell(properties) {
+ return new documents.TableCell([], properties);
+}
+
+test("w:bookmarkStart is read as a bookmarkStart", function() {
+ var bookmarkStart = new XmlElement("w:bookmarkStart", {"w:name": "_Peter", "w:id": "42"});
+ var result = readXmlElement(bookmarkStart);
+ assert.deepEqual(result.value.name, "_Peter");
+ assert.deepEqual(result.value.type, "bookmarkStart");
+});
+
+test('_GoBack bookmark is ignored', function() {
+ var bookmarkStart = new XmlElement("w:bookmarkStart", {"w:name": "_GoBack"});
+ var result = readXmlElement(bookmarkStart);
+ assert.deepEqual(result.value, []);
+});
+
+test("can read imagedata elements with r:id attribute", function() {
+ var imagedataElement = new XmlElement("v:imagedata", {"r:id": "rId5", "o:title": "It's a hat"});
+
+ var imageBuffer = new Buffer("Not an image at all!");
+ var reader = new BodyReader({
+ relationships: {
+ "rId5": {target: "media/hat.png"}
+ },
+ contentTypes: fakeContentTypes,
+ docxFile: createFakeDocxFile({
+ "word/media/hat.png": imageBuffer
+ })
+ });
+ var result = reader.readXmlElement(imagedataElement);
+ assert.deepEqual(result.messages, []);
+ var element = result.value;
+ assert.equal("image", element.type);
+ assert.equal(element.altText, "It's a hat");
+ assert.equal(element.contentType, "image/png");
+ return element.read()
+ .then(function(readValue) {
+ assert.equal(readValue, imageBuffer);
});
-
- var imageBuffer = new Buffer("Not an image at all!");
- var reader = new BodyReader({
- relationships: {
- "rId5": {target: "media/hat.png"}
- },
- contentTypes: fakeContentTypes,
- docxFile: createFakeDocxFile({
- "word/media/hat.png": imageBuffer
- })
+});
+
+test("can read inline pictures", function() {
+ var drawing = createInlineImage({
+ blip: createEmbeddedBlip("rId5"),
+ description: "It's a hat"
+ });
+
+ var imageBuffer = new Buffer("Not an image at all!");
+ var reader = new BodyReader({
+ relationships: {
+ "rId5": {target: "media/hat.png"}
+ },
+ contentTypes: fakeContentTypes,
+ docxFile: createFakeDocxFile({
+ "word/media/hat.png": imageBuffer
+ })
+ });
+ var result = reader.readXmlElement(drawing);
+ assert.deepEqual(result.messages, []);
+ var element = single(result.value);
+ assert.equal("image", element.type);
+ assert.equal(element.altText, "It's a hat");
+ assert.equal(element.contentType, "image/png");
+ return element.read()
+ .then(function(readValue) {
+ assert.equal(readValue, imageBuffer);
});
- var result = reader.readXmlElement(drawing);
- assert.deepEqual(result.messages, []);
- var element = single(result.value);
- assert.equal("image", element.type);
- assert.equal(element.altText, "It's a hat");
- assert.equal(element.contentType, "image/png");
- return element.read()
- .then(function(readValue) {
- assert.equal(readValue, imageBuffer);
- });
- });
-
- test("can read anchored pictures", function() {
- var drawing = new XmlElement("w:drawing", {}, [
- new XmlElement("wp:anchor", {}, [
- new XmlElement("wp:docPr", {descr: "It's a hat"}),
- new XmlElement("a:graphic", {}, [
- new XmlElement("a:graphicData", {}, [
- new XmlElement("pic:pic", {}, [
- new XmlElement("pic:blipFill", {}, [
- new XmlElement("a:blip", {"r:embed": "rId5"})
- ])
+});
+
+test("can read anchored pictures", function() {
+ var drawing = new XmlElement("w:drawing", {}, [
+ new XmlElement("wp:anchor", {}, [
+ new XmlElement("wp:docPr", {descr: "It's a hat"}),
+ new XmlElement("a:graphic", {}, [
+ new XmlElement("a:graphicData", {}, [
+ new XmlElement("pic:pic", {}, [
+ new XmlElement("pic:blipFill", {}, [
+ new XmlElement("a:blip", {"r:embed": "rId5"})
])
])
])
])
- ]);
-
- var imageBuffer = new Buffer("Not an image at all!");
- var reader = new BodyReader({
- relationships: {
- "rId5": {target: "media/hat.png"}
- },
- contentTypes: fakeContentTypes,
- docxFile: createFakeDocxFile({
- "word/media/hat.png": imageBuffer
- })
- });
- var result = reader.readXmlElement(drawing);
- assert.deepEqual(result.messages, []);
- var element = single(result.value);
- assert.equal("image", element.type);
- assert.equal(element.altText, "It's a hat");
- return element.read()
- .then(function(readValue) {
- assert.equal(readValue, imageBuffer);
- });
- });
-
- test("can read linked pictures", function() {
- var drawing = createInlineImage({
- blip: createLinkedBlip("rId5"),
- description: "It's a hat"
- });
-
- var imageBuffer = new Buffer("Not an image at all!");
- var reader = new BodyReader({
- relationships: {
- "rId5": {target: "file:///media/hat.png"}
- },
- contentTypes: fakeContentTypes,
- files: testing.createFakeFiles({
- "file:///media/hat.png": imageBuffer
- })
- });
- var result = reader.readXmlElement(drawing);
- assert.deepEqual(result.messages, []);
- var element = single(result.value);
- assert.equal("image", element.type);
- assert.equal(element.altText, "It's a hat");
- assert.equal(element.contentType, "image/png");
- return element.read()
- .then(function(readValue) {
- assert.equal(readValue, imageBuffer);
- });
- });
+ ])
+ ]);
- test("warning if unsupported image type", function() {
- var drawing = createInlineImage({
- blip: createEmbeddedBlip("rId5"),
- description: "It's a hat"
+ var imageBuffer = new Buffer("Not an image at all!");
+ var reader = new BodyReader({
+ relationships: {
+ "rId5": {target: "media/hat.png"}
+ },
+ contentTypes: fakeContentTypes,
+ docxFile: createFakeDocxFile({
+ "word/media/hat.png": imageBuffer
+ })
+ });
+ var result = reader.readXmlElement(drawing);
+ assert.deepEqual(result.messages, []);
+ var element = single(result.value);
+ assert.equal("image", element.type);
+ assert.equal(element.altText, "It's a hat");
+ return element.read()
+ .then(function(readValue) {
+ assert.equal(readValue, imageBuffer);
});
-
- var imageBuffer = new Buffer("Not an image at all!");
- var reader = new BodyReader({
- relationships: {
- "rId5": {target: "media/hat.emf"}
- },
- contentTypes: fakeContentTypes,
- docxFile: createFakeDocxFile({
- "word/media/hat.emf": imageBuffer
- })
+});
+
+test("can read linked pictures", function() {
+ var drawing = createInlineImage({
+ blip: createLinkedBlip("rId5"),
+ description: "It's a hat"
+ });
+
+ var imageBuffer = new Buffer("Not an image at all!");
+ var reader = new BodyReader({
+ relationships: {
+ "rId5": {target: "file:///media/hat.png"}
+ },
+ contentTypes: fakeContentTypes,
+ files: testing.createFakeFiles({
+ "file:///media/hat.png": imageBuffer
+ })
+ });
+ var result = reader.readXmlElement(drawing);
+ assert.deepEqual(result.messages, []);
+ var element = single(result.value);
+ assert.equal("image", element.type);
+ assert.equal(element.altText, "It's a hat");
+ assert.equal(element.contentType, "image/png");
+ return element.read()
+ .then(function(readValue) {
+ assert.equal(readValue, imageBuffer);
});
- var result = reader.readXmlElement(drawing);
- assert.deepEqual(result.messages, [warning("Image of type image/x-emf is unlikely to display in web browsers")]);
- var element = single(result.value);
- assert.equal(element.contentType, "image/x-emf");
- });
-
- test("no elements created if image cannot be found in w:drawing", function() {
- var drawing = new XmlElement("w:drawing", {}, []);
-
- var reader = new BodyReader({});
- var result = reader.readXmlElement(drawing);
- assert.deepEqual(result.messages, []);
- assert.deepEqual(result.value, []);
- });
-
- test("no elements created if image cannot be found in wp:inline", function() {
- var drawing = new XmlElement("wp:inline", {}, []);
-
- var reader = new BodyReader({});
- var result = reader.readXmlElement(drawing);
- assert.deepEqual(result.messages, []);
- assert.deepEqual(result.value, []);
- });
-
- test("children of w:ins are converted normally", function() {
- var runXml = new XmlElement("w:r", {}, []);
- var insXml = new XmlElement("w:ins", {}, [runXml]);
- var result = readXmlElement(insXml);
- assert.deepEqual(result.value[0].type, "run");
- });
-
- test("children of w:smartTag are converted normally", function() {
- var runXml = new XmlElement("w:r", {}, []);
- var smartTagXml = new XmlElement("w:smartTag", {}, [runXml]);
- var result = readXmlElement(smartTagXml);
- assert.deepEqual(result.value[0].type, "run");
- });
-
- test("w:hyperlink is read as document hyperlink if it has a relationship ID", function() {
- var runXml = new XmlElement("w:r", {}, []);
- var hyperlinkXml = new XmlElement("w:hyperlink", {"r:id": "r42"}, [runXml]);
- var relationships = {
- "r42": {target: "http://example.com"}
- };
- var result = readXmlElement(hyperlinkXml, {relationships: relationships});
- assert.deepEqual(result.value.href, "http://example.com");
- assert.deepEqual(result.value.children[0].type, "run");
- });
+});
- test("w:hyperlink is read as document hyperlink if it has an anchor", function() {
- var runXml = new XmlElement("w:r", {}, []);
- var hyperlinkXml = new XmlElement("w:hyperlink", {"w:anchor": "_Peter"}, [runXml]);
- var result = readXmlElement(hyperlinkXml);
- assert.deepEqual(result.value.anchor, "_Peter");
- assert.deepEqual(result.value.children[0].type, "run");
- });
+test("warning if unsupported image type", function() {
+ var drawing = createInlineImage({
+ blip: createEmbeddedBlip("rId5"),
+ description: "It's a hat"
+ });
+
+ var imageBuffer = new Buffer("Not an image at all!");
+ var reader = new BodyReader({
+ relationships: {
+ "rId5": {target: "media/hat.emf"}
+ },
+ contentTypes: fakeContentTypes,
+ docxFile: createFakeDocxFile({
+ "word/media/hat.emf": imageBuffer
+ })
+ });
+ var result = reader.readXmlElement(drawing);
+ assert.deepEqual(result.messages, [warning("Image of type image/x-emf is unlikely to display in web browsers")]);
+ var element = single(result.value);
+ assert.equal(element.contentType, "image/x-emf");
+});
- test("w:hyperlink is ignored if it does not have a relationship ID nor anchor", function() {
- var runXml = new XmlElement("w:r", {}, []);
- var hyperlinkXml = new XmlElement("w:hyperlink", {}, [runXml]);
- var result = readXmlElement(hyperlinkXml);
- assert.deepEqual(result.value[0].type, "run");
- });
-
- test("w:br is read as line break", function() {
- var breakXml = new XmlElement("w:br", {}, []);
- var result = readXmlElement(breakXml);
- assert.deepEqual(result.value.type, "lineBreak");
- assert.deepEqual(result.messages, []);
- });
-
- test("warning on breaks that aren't line breaks", function() {
- var breakXml = new XmlElement("w:br", {"w:type": "page"}, []);
- var result = readXmlElement(breakXml);
- assert.deepEqual(result.value, []);
- assert.deepEqual(result.messages, [warning("Unsupported break type: page")]);
- });
+test("no elements created if image cannot be found in w:drawing", function() {
+ var drawing = new XmlElement("w:drawing", {}, []);
- test("w:footnoteReference has ID read", function() {
- var referenceXml = new XmlElement("w:footnoteReference", {"w:id": "4"});
- var result = readXmlElement(referenceXml);
- assert.deepEqual(
- result.value,
- documents.noteReference({noteType: "footnote", noteId: "4"})
- );
- assert.deepEqual(result.messages, []);
- });
-
- test("w:commentReference has ID read", function() {
- var referenceXml = new XmlElement("w:commentReference", {"w:id": "4"});
- var result = readXmlElement(referenceXml);
- assert.deepEqual(
- result.value,
- documents.commentReference({commentId: "4"})
- );
- assert.deepEqual(result.messages, []);
- });
-
- test("emits warning on unrecognised element", function() {
- var unrecognisedElement = new XmlElement("w:not-an-element");
- var result = readXmlElement(unrecognisedElement);
- assert.deepEqual(
- result.messages,
- [{
- type: "warning",
- message: "An unrecognised element was ignored: w:not-an-element"
- }]
- );
- assert.deepEqual(result.value, []);
- });
+ var reader = new BodyReader({});
+ var result = reader.readXmlElement(drawing);
+ assert.deepEqual(result.messages, []);
+ assert.deepEqual(result.value, []);
+});
+
+test("no elements created if image cannot be found in wp:inline", function() {
+ var drawing = new XmlElement("wp:inline", {}, []);
- test("w:bookmarkEnd is ignored without warning", function() {
- var ignoredElement = new XmlElement("w:bookmarkEnd");
- var result = readXmlElement(ignoredElement);
- assert.deepEqual(result.messages, []);
- assert.deepEqual([], result.value);
- });
+ var reader = new BodyReader({});
+ var result = reader.readXmlElement(drawing);
+ assert.deepEqual(result.messages, []);
+ assert.deepEqual(result.value, []);
+});
- test("text boxes have content appended after containing paragraph", function() {
- var textbox = new XmlElement("w:pict", {}, [
- new XmlElement("v:shape", {}, [
- new XmlElement("v:textbox", {}, [
- new XmlElement("w:txbxContent", {}, [
- paragraphWithStyleId("textbox-content")
- ])
+test("children of w:ins are converted normally", function() {
+ var runXml = new XmlElement("w:r", {}, []);
+ var insXml = new XmlElement("w:ins", {}, [runXml]);
+ var result = readXmlElement(insXml);
+ assert.deepEqual(result.value[0].type, "run");
+});
+
+test("children of w:smartTag are converted normally", function() {
+ var runXml = new XmlElement("w:r", {}, []);
+ var smartTagXml = new XmlElement("w:smartTag", {}, [runXml]);
+ var result = readXmlElement(smartTagXml);
+ assert.deepEqual(result.value[0].type, "run");
+});
+
+test("w:hyperlink is read as document hyperlink if it has a relationship ID", function() {
+ var runXml = new XmlElement("w:r", {}, []);
+ var hyperlinkXml = new XmlElement("w:hyperlink", {"r:id": "r42"}, [runXml]);
+ var relationships = {
+ "r42": {target: "http://example.com"}
+ };
+ var result = readXmlElement(hyperlinkXml, {relationships: relationships});
+ assert.deepEqual(result.value.href, "http://example.com");
+ assert.deepEqual(result.value.children[0].type, "run");
+});
+
+test("w:hyperlink is read as document hyperlink if it has an anchor", function() {
+ var runXml = new XmlElement("w:r", {}, []);
+ var hyperlinkXml = new XmlElement("w:hyperlink", {"w:anchor": "_Peter"}, [runXml]);
+ var result = readXmlElement(hyperlinkXml);
+ assert.deepEqual(result.value.anchor, "_Peter");
+ assert.deepEqual(result.value.children[0].type, "run");
+});
+
+test("w:hyperlink is ignored if it does not have a relationship ID nor anchor", function() {
+ var runXml = new XmlElement("w:r", {}, []);
+ var hyperlinkXml = new XmlElement("w:hyperlink", {}, [runXml]);
+ var result = readXmlElement(hyperlinkXml);
+ assert.deepEqual(result.value[0].type, "run");
+});
+
+test("w:br is read as line break", function() {
+ var breakXml = new XmlElement("w:br", {}, []);
+ var result = readXmlElement(breakXml);
+ assert.deepEqual(result.value.type, "lineBreak");
+ assert.deepEqual(result.messages, []);
+});
+
+test("warning on breaks that aren't line breaks", function() {
+ var breakXml = new XmlElement("w:br", {"w:type": "page"}, []);
+ var result = readXmlElement(breakXml);
+ assert.deepEqual(result.value, []);
+ assert.deepEqual(result.messages, [warning("Unsupported break type: page")]);
+});
+
+test("w:footnoteReference has ID read", function() {
+ var referenceXml = new XmlElement("w:footnoteReference", {"w:id": "4"});
+ var result = readXmlElement(referenceXml);
+ assert.deepEqual(
+ result.value,
+ documents.noteReference({noteType: "footnote", noteId: "4"})
+ );
+ assert.deepEqual(result.messages, []);
+});
+
+test("w:commentReference has ID read", function() {
+ var referenceXml = new XmlElement("w:commentReference", {"w:id": "4"});
+ var result = readXmlElement(referenceXml);
+ assert.deepEqual(
+ result.value,
+ documents.commentReference({commentId: "4"})
+ );
+ assert.deepEqual(result.messages, []);
+});
+
+test("emits warning on unrecognised element", function() {
+ var unrecognisedElement = new XmlElement("w:not-an-element");
+ var result = readXmlElement(unrecognisedElement);
+ assert.deepEqual(
+ result.messages,
+ [{
+ type: "warning",
+ message: "An unrecognised element was ignored: w:not-an-element"
+ }]
+ );
+ assert.deepEqual(result.value, []);
+});
+
+test("w:bookmarkEnd is ignored without warning", function() {
+ var ignoredElement = new XmlElement("w:bookmarkEnd");
+ var result = readXmlElement(ignoredElement);
+ assert.deepEqual(result.messages, []);
+ assert.deepEqual([], result.value);
+});
+
+test("text boxes have content appended after containing paragraph", function() {
+ var textbox = new XmlElement("w:pict", {}, [
+ new XmlElement("v:shape", {}, [
+ new XmlElement("v:textbox", {}, [
+ new XmlElement("w:txbxContent", {}, [
+ paragraphWithStyleId("textbox-content")
])
])
- ]);
- var paragraph = new XmlElement("w:p", {}, [
- new XmlElement("w:r", {}, [textbox])
- ]);
- var result = readXmlElement(paragraph);
- assert.deepEqual(result.value[1].styleId, "textbox-content");
- });
+ ])
+ ]);
+ var paragraph = new XmlElement("w:p", {}, [
+ new XmlElement("w:r", {}, [textbox])
+ ]);
+ var result = readXmlElement(paragraph);
+ assert.deepEqual(result.value[1].styleId, "textbox-content");
+});
- test("mc:Fallback is used when mc:AlternateContent is read", function() {
- var styles = new Styles({"first": {name: "First"}, "second": {name: "Second"}}, {});
- var textbox = new XmlElement("mc:AlternateContent", {}, [
- new XmlElement("mc:Choice", {"Requires": "wps"}, [
- paragraphWithStyleId("first")
- ]),
- new XmlElement("mc:Fallback", {}, [
- paragraphWithStyleId("second")
- ])
- ]);
- var result = readXmlElement(textbox, {styles: styles});
- assert.deepEqual(result.value[0].styleId, "second");
- });
+test("mc:Fallback is used when mc:AlternateContent is read", function() {
+ var styles = new Styles({"first": {name: "First"}, "second": {name: "Second"}}, {});
+ var textbox = new XmlElement("mc:AlternateContent", {}, [
+ new XmlElement("mc:Choice", {"Requires": "wps"}, [
+ paragraphWithStyleId("first")
+ ]),
+ new XmlElement("mc:Fallback", {}, [
+ paragraphWithStyleId("second")
+ ])
+ ]);
+ var result = readXmlElement(textbox, {styles: styles});
+ assert.deepEqual(result.value[0].styleId, "second");
+});
- test("w:sdtContent is used when w:sdt is read", function() {
- var element = xml.element("w:sdt", {}, [
- xml.element("w:sdtContent", {}, [
- xml.element("w:t", {}, [xml.text("Blackdown")])
- ])
- ]);
- var result = readXmlElement(element);
- assert.deepEqual(result.value, [new documents.Text("Blackdown")]);
- });
-
- test("text nodes are ignored when reading children", function() {
- var runXml = new XmlElement("w:r", {}, [xml.text("[text]")]);
- var run = readXmlElementValue(runXml);
- assert.deepEqual(run, new documents.Run([]));
- });
+test("w:sdtContent is used when w:sdt is read", function() {
+ var element = xml.element("w:sdt", {}, [
+ xml.element("w:sdtContent", {}, [
+ xml.element("w:t", {}, [xml.text("Blackdown")])
+ ])
+ ]);
+ var result = readXmlElement(element);
+ assert.deepEqual(result.value, [new documents.Text("Blackdown")]);
+});
+
+test("text nodes are ignored when reading children", function() {
+ var runXml = new XmlElement("w:r", {}, [xml.text("[text]")]);
+ var run = readXmlElementValue(runXml);
+ assert.deepEqual(run, new documents.Run([]));
});
function paragraphWithStyleId(styleId) {
diff --git a/test/docx/content-types-reader.tests.js b/test/docx/content-types-reader.tests.js
index 5ea93ec..0c83dd2 100644
--- a/test/docx/content-types-reader.tests.js
+++ b/test/docx/content-types-reader.tests.js
@@ -2,46 +2,44 @@ var assert = require("assert");
var readContentTypesFromXml = require("../../lib/docx/content-types-reader").readContentTypesFromXml;
var XmlElement = require("../../lib/xml").Element;
-var test = require("../testing").test;
+var test = require("../test")(module);
-describe('readContentTypesFromXml', function() {
- test('reads default-per-extension from XML', function() {
- var contentTypes = readContentTypesFromXml(
- new XmlElement("content-types:Types", {}, [
- new XmlElement("content-types:Default", {Extension: "png", ContentType: "image/png"})
- ])
- );
- assert.equal(contentTypes.findContentType("word/media/hat.png"), "image/png");
- });
-
- test('reads overrides in preference to defaults', function() {
- var contentTypes = readContentTypesFromXml(
- new XmlElement("content-types:Types", {}, [
- new XmlElement("content-types:Default", {Extension: "png", ContentType: "image/png"}),
- new XmlElement("content-types:Override", {PartName: "/word/media/hat.png", ContentType: "image/hat"})
- ])
- );
- assert.equal(contentTypes.findContentType("word/media/hat.png"), "image/hat");
- });
-
- test('fallback content types have common image types', function() {
- var contentTypes = readContentTypesFromXml(
- new XmlElement("content-types:Types", {}, [])
- );
- assert.equal(contentTypes.findContentType("word/media/hat.png"), "image/png");
- assert.equal(contentTypes.findContentType("word/media/hat.gif"), "image/gif");
- assert.equal(contentTypes.findContentType("word/media/hat.jpg"), "image/jpeg");
- assert.equal(contentTypes.findContentType("word/media/hat.jpeg"), "image/jpeg");
- assert.equal(contentTypes.findContentType("word/media/hat.bmp"), "image/bmp");
- assert.equal(contentTypes.findContentType("word/media/hat.tif"), "image/tiff");
- assert.equal(contentTypes.findContentType("word/media/hat.tiff"), "image/tiff");
- });
-
- test('fallback content types are case insensitive on extension', function() {
- var contentTypes = readContentTypesFromXml(
- new XmlElement("content-types:Types", {}, [])
- );
- assert.equal(contentTypes.findContentType("word/media/hat.PnG"), "image/png");
- });
+test('reads default-per-extension from XML', function() {
+ var contentTypes = readContentTypesFromXml(
+ new XmlElement("content-types:Types", {}, [
+ new XmlElement("content-types:Default", {Extension: "png", ContentType: "image/png"})
+ ])
+ );
+ assert.equal(contentTypes.findContentType("word/media/hat.png"), "image/png");
+});
+
+test('reads overrides in preference to defaults', function() {
+ var contentTypes = readContentTypesFromXml(
+ new XmlElement("content-types:Types", {}, [
+ new XmlElement("content-types:Default", {Extension: "png", ContentType: "image/png"}),
+ new XmlElement("content-types:Override", {PartName: "/word/media/hat.png", ContentType: "image/hat"})
+ ])
+ );
+ assert.equal(contentTypes.findContentType("word/media/hat.png"), "image/hat");
+});
+
+test('fallback content types have common image types', function() {
+ var contentTypes = readContentTypesFromXml(
+ new XmlElement("content-types:Types", {}, [])
+ );
+ assert.equal(contentTypes.findContentType("word/media/hat.png"), "image/png");
+ assert.equal(contentTypes.findContentType("word/media/hat.gif"), "image/gif");
+ assert.equal(contentTypes.findContentType("word/media/hat.jpg"), "image/jpeg");
+ assert.equal(contentTypes.findContentType("word/media/hat.jpeg"), "image/jpeg");
+ assert.equal(contentTypes.findContentType("word/media/hat.bmp"), "image/bmp");
+ assert.equal(contentTypes.findContentType("word/media/hat.tif"), "image/tiff");
+ assert.equal(contentTypes.findContentType("word/media/hat.tiff"), "image/tiff");
+});
+
+test('fallback content types are case insensitive on extension', function() {
+ var contentTypes = readContentTypesFromXml(
+ new XmlElement("content-types:Types", {}, [])
+ );
+ assert.equal(contentTypes.findContentType("word/media/hat.PnG"), "image/png");
});
diff --git a/test/docx/docx-reader.tests.js b/test/docx/docx-reader.tests.js
index 69ade7e..283d03a 100644
--- a/test/docx/docx-reader.tests.js
+++ b/test/docx/docx-reader.tests.js
@@ -4,39 +4,37 @@ var docxReader = require("../../lib/docx/docx-reader");
var documents = require("../../lib/documents");
var testing = require("../testing");
-var test = testing.test;
+var test = require("../test")(module);
var testData = testing.testData;
var createFakeDocxFile = testing.createFakeDocxFile;
-describe("docx-reader", function() {
- test("can read document with single paragraph with single run of text", function() {
- var expectedDocument = documents.Document([
- documents.Paragraph([
- documents.Run([
- documents.Text("Hello.")
- ])
+test("can read document with single paragraph with single run of text", function() {
+ var expectedDocument = documents.Document([
+ documents.Paragraph([
+ documents.Run([
+ documents.Text("Hello.")
])
- ]);
- var docxFile = createFakeDocxFile({
- "word/document.xml": testData("simple/word/document.xml")
- });
- return docxReader.read(docxFile).then(function(result) {
- assert.deepEqual(expectedDocument, result.value);
- });
+ ])
+ ]);
+ var docxFile = createFakeDocxFile({
+ "word/document.xml": testData("simple/word/document.xml")
});
-
- test("hyperlink hrefs are read from relationships file", function() {
- var docxFile = createFakeDocxFile({
- "word/document.xml": testData("hyperlinks/word/document.xml"),
- "word/_rels/document.xml.rels": testData("hyperlinks/word/_rels/document.xml.rels")
- });
- return docxReader.read(docxFile).then(function(result) {
- var paragraph = result.value.children[0];
- assert.equal(1, paragraph.children.length);
- var hyperlink = paragraph.children[0];
- assert.equal(hyperlink.href, "http://www.example.com");
- assert.equal(hyperlink.children.length, 1);
- });
+ return docxReader.read(docxFile).then(function(result) {
+ assert.deepEqual(expectedDocument, result.value);
+ });
+});
+
+test("hyperlink hrefs are read from relationships file", function() {
+ var docxFile = createFakeDocxFile({
+ "word/document.xml": testData("hyperlinks/word/document.xml"),
+ "word/_rels/document.xml.rels": testData("hyperlinks/word/_rels/document.xml.rels")
+ });
+ return docxReader.read(docxFile).then(function(result) {
+ var paragraph = result.value.children[0];
+ assert.equal(1, paragraph.children.length);
+ var hyperlink = paragraph.children[0];
+ assert.equal(hyperlink.href, "http://www.example.com");
+ assert.equal(hyperlink.children.length, 1);
});
});
diff --git a/test/docx/files.tests.js b/test/docx/files.tests.js
index 2a0919c..75999aa 100644
--- a/test/docx/files.tests.js
+++ b/test/docx/files.tests.js
@@ -7,13 +7,13 @@ var Files = require("../../lib/docx/files").Files;
var uriToPath = require("../../lib/docx/files").uriToPath;
var testing = require("../testing");
-var test = testing.test;
+var test = require("../test")(module);
var readFile = promises.promisify(fs.readFile.bind(fs));
-describe("Files", function() {
- test("can open files with file URI", function() {
+test("Files", {
+ "can open files with file URI": function() {
var filePath = path.resolve(testing.testPath("tiny-picture.png"));
var files = new Files(null);
return files.read("file:///" + filePath.replace(/^\//, ""), "base64").then(function(contents) {
@@ -21,9 +21,9 @@ describe("Files", function() {
assert.deepEqual(contents, expectedContents);
});
});
- });
+ },
- test("can open files with relative URI", function() {
+ "can open files with relative URI": function() {
var filePath = path.resolve(testing.testPath("tiny-picture.png"));
var files = new Files(testing.testPath("."));
return files.read("tiny-picture.png", "base64").then(function(contents) {
@@ -31,21 +31,21 @@ describe("Files", function() {
assert.deepEqual(contents, expectedContents);
});
});
- });
+ },
- test("given base is not set when opening relative uri then error is raised", function() {
+ "given base is not set when opening relative uri then error is raised": function() {
var files = new Files(null);
return assertError(files.read("not-a-real-file.png", "base64"), function(err) {
assert.equal(err.message, "could not find external image 'not-a-real-file.png', path of input document is unknown");
});
- });
+ },
- test("error if relative uri cannot be opened", function() {
+ "error if relative uri cannot be opened": function() {
var files = new Files("/tmp");
return assertError(files.read("not-a-real-file.png", "base64"), function(err) {
assertRegex(err.message, /could not open external image: 'not-a-real-file.png' \(document directory: '\/tmp'\)\nENOENT.*\/tmp\/not-a-real-file.png.*/);
});
- });
+ }
});
function assertError(promise, func) {
@@ -59,36 +59,36 @@ function assertRegex(actual, expected) {
}
-describe("uriToPath", function() {
- test("leading slash is retained on non-Windows file URIs", function() {
+test("uriToPath", {
+ "leading slash is retained on non-Windows file URIs": function() {
assert.equal(uriToPath("file:///a/b/c", "linux"), "/a/b/c");
assert.equal(uriToPath("file:///a/b/c", "win32"), "/a/b/c");
- });
+ },
- test("URI is unquoted", function() {
+ "URI is unquoted": function() {
assert.equal(uriToPath("file:///a%20b"), "/a b");
- });
+ },
- test("when host is set to localhost then path can be found", function() {
+ "when host is set to localhost then path can be found": function() {
assert.equal(uriToPath("file://localhost/a/b/c"), "/a/b/c");
- });
+ },
- test("when host is set but not localhost then path cannot be found", function() {
+ "when host is set but not localhost then path cannot be found": function() {
assert.throws(function() {
uriToPath("file://example/a/b/c");
}, /Could not convert URI to path: file:\/\/example\/a\/b\/c/);
- });
+ },
- test("leading slash is not dropped on Windows file URIs when platform is not Windows", function() {
+ "leading slash is not dropped on Windows file URIs when platform is not Windows": function() {
assert.equal(uriToPath("file:///c:/a", "linux"), "/c:/a");
- });
+ },
- test("leading slash is dropped on Windows file URIs when platform is Windows", function() {
+ "leading slash is dropped on Windows file URIs when platform is Windows": function() {
assert.equal(uriToPath("file:///c:/a", "win32"), "c:/a");
assert.equal(uriToPath("file:///C:/a", "win32"), "C:/a");
- });
+ },
- test("relative URI is unquoted", function() {
+ "relative URI is unquoted": function() {
assert.equal(uriToPath("a%20b/c"), "a b/c");
- });
+ }
});
diff --git a/test/docx/notes-reader.tests.js b/test/docx/notes-reader.tests.js
index 85a49f5..1d4cf9c 100644
--- a/test/docx/notes-reader.tests.js
+++ b/test/docx/notes-reader.tests.js
@@ -4,36 +4,32 @@ var createFootnotesReader = require("../../lib/docx/notes-reader").createFootnot
var BodyReader = require("../../lib/docx/body-reader").BodyReader;
var documents = require("../../lib/documents");
var XmlElement = require("../../lib/xml").Element;
-var test = require("../testing").test;
+var test = require("../test")(module);
-describe('readFootnotesXml', function() {
- test('ID and body of footnote are read', function() {
- var bodyReader = new BodyReader({});
- var footnoteBody = [new XmlElement("w:p", {}, [])];
- var footnotes = createFootnotesReader(bodyReader)(
- new XmlElement("w:footnotes", {}, [
- new XmlElement("w:footnote", {"w:id": "1"}, footnoteBody)
- ])
- );
- assert.equal(footnotes.value.length, 1);
- assert.deepEqual(footnotes.value[0].body, [new documents.Paragraph([])]);
- assert.deepEqual(footnotes.value[0].noteId, "1");
- });
+test('ID and body of footnote are read', function() {
+ var bodyReader = new BodyReader({});
+ var footnoteBody = [new XmlElement("w:p", {}, [])];
+ var footnotes = createFootnotesReader(bodyReader)(
+ new XmlElement("w:footnotes", {}, [
+ new XmlElement("w:footnote", {"w:id": "1"}, footnoteBody)
+ ])
+ );
+ assert.equal(footnotes.value.length, 1);
+ assert.deepEqual(footnotes.value[0].body, [new documents.Paragraph([])]);
+ assert.deepEqual(footnotes.value[0].noteId, "1");
});
footnoteTypeIsIgnored('continuationSeparator');
footnoteTypeIsIgnored('separator');
function footnoteTypeIsIgnored(type) {
- describe('footnotes of type ' + type + ' are ignored', function() {
- test('ID and body of footnote are read', function() {
- var footnotes = createFootnotesReader()(
- new XmlElement("w:footnotes", {}, [
- new XmlElement("w:footnote", {"w:id": "1", "w:type": type}, [])
- ])
- );
- assert.equal(footnotes.value.length, 0);
- });
+ test('footnotes of type ' + type + ' are ignored', function() {
+ var footnotes = createFootnotesReader()(
+ new XmlElement("w:footnotes", {}, [
+ new XmlElement("w:footnote", {"w:id": "1", "w:type": type}, [])
+ ])
+ );
+ assert.equal(footnotes.value.length, 0);
});
}
diff --git a/test/docx/numbering-xml.tests.js b/test/docx/numbering-xml.tests.js
index fb28cb8..7ecacc2 100644
--- a/test/docx/numbering-xml.tests.js
+++ b/test/docx/numbering-xml.tests.js
@@ -2,31 +2,29 @@ var duck = require("duck");
var readNumberingXml = require("../../lib/docx/numbering-xml").readNumberingXml;
var XmlElement = require("../../lib/xml").Element;
-var test = require("../testing").test;
+var test = require("../test")(module);
-describe('readNumberingXml', function() {
- test('w:num element inherits levels from w:abstractNum', function() {
- var numbering = readNumberingXml(
- new XmlElement("w:numbering", {}, [
- new XmlElement("w:abstractNum", {"w:abstractNumId": "42"}, [
- new XmlElement("w:lvl", {"w:ilvl": "0"}, [
- new XmlElement("w:numFmt", {"w:val": "bullet"})
- ]),
- new XmlElement("w:lvl", {"w:ilvl": "1"}, [
- new XmlElement("w:numFmt", {"w:val": "decimal"})
- ])
+test('w:num element inherits levels from w:abstractNum', function() {
+ var numbering = readNumberingXml(
+ new XmlElement("w:numbering", {}, [
+ new XmlElement("w:abstractNum", {"w:abstractNumId": "42"}, [
+ new XmlElement("w:lvl", {"w:ilvl": "0"}, [
+ new XmlElement("w:numFmt", {"w:val": "bullet"})
]),
- new XmlElement("w:num", {"w:numId": "47"}, [
- new XmlElement("w:abstractNumId", {"w:val": "42"})
+ new XmlElement("w:lvl", {"w:ilvl": "1"}, [
+ new XmlElement("w:numFmt", {"w:val": "decimal"})
])
+ ]),
+ new XmlElement("w:num", {"w:numId": "47"}, [
+ new XmlElement("w:abstractNumId", {"w:val": "42"})
])
- );
- duck.assertThat(numbering.findLevel("47", "0"), duck.hasProperties({
- isOrdered: false
- }));
- duck.assertThat(numbering.findLevel("47", "1"), duck.hasProperties({
- isOrdered: true
- }));
- });
+ ])
+ );
+ duck.assertThat(numbering.findLevel("47", "0"), duck.hasProperties({
+ isOrdered: false
+ }));
+ duck.assertThat(numbering.findLevel("47", "1"), duck.hasProperties({
+ isOrdered: true
+ }));
});
diff --git a/test/docx/office-xml-reader.tests.js b/test/docx/office-xml-reader.tests.js
index f28c4f3..6cd9d7d 100644
--- a/test/docx/office-xml-reader.tests.js
+++ b/test/docx/office-xml-reader.tests.js
@@ -2,25 +2,23 @@ var assert = require("assert");
var xml = require("../../lib/xml");
var officeXmlReader = require("../../lib/docx/office-xml-reader");
-var test = require("../testing").test;
+var test = require("../test")(module);
-describe("office-xml-reader", function() {
- test("mc:AlternateContent is replaced by contents of mc:Fallback", function() {
- var xmlString =
- '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
- '<numbering xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">' +
- '<mc:AlternateContent>' +
- '<mc:Choice Requires="w14">' +
- '<choice/>' +
- '</mc:Choice>' +
- '<mc:Fallback>' +
- '<fallback/>' +
- '</mc:Fallback>' +
- '</mc:AlternateContent>' +
- '</numbering>';
- return officeXmlReader.read(xmlString).then(function(element) {
- assert.deepEqual(element.children, [xml.element("fallback")]);
- });
- });
+test("mc:AlternateContent is replaced by contents of mc:Fallback", function() {
+ var xmlString =
+ '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
+ '<numbering xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">' +
+ '<mc:AlternateContent>' +
+ '<mc:Choice Requires="w14">' +
+ '<choice/>' +
+ '</mc:Choice>' +
+ '<mc:Fallback>' +
+ '<fallback/>' +
+ '</mc:Fallback>' +
+ '</mc:AlternateContent>' +
+ '</numbering>';
+ return officeXmlReader.read(xmlString).then(function(element) {
+ assert.deepEqual(element.children, [xml.element("fallback")]);
+ });
});
diff --git a/test/docx/style-map.tests.js b/test/docx/style-map.tests.js
index 55171f8..4ddb127 100644
--- a/test/docx/style-map.tests.js
+++ b/test/docx/style-map.tests.js
@@ -4,85 +4,82 @@ var JSZip = require("jszip");
var zipfile = require("../../lib/zipfile");
var styleMap = require("../../lib/docx/style-map");
-var test = require("../testing").test;
+var test = require("../test")(module);
-describe("style-map", function() {
- test('reading embedded style map on document without embedded style map returns null', function() {
- var zip = normalDocx();
-
- return styleMap.readStyleMap(zip).then(function(contents) {
- assert.equal(contents, null);
- });
+test('reading embedded style map on document without embedded style map returns null', function() {
+ var zip = normalDocx();
+
+ return styleMap.readStyleMap(zip).then(function(contents) {
+ assert.equal(contents, null);
});
+});
+
+test('embedded style map can be read after being written', function() {
+ var zip = normalDocx();
- test('embedded style map can be read after being written', function() {
- var zip = normalDocx();
-
- return styleMap.writeStyleMap(zip, "p => h1").then(function() {
- return styleMap.readStyleMap(zip).then(function(contents) {
- assert.equal(contents, "p => h1");
- });
+ return styleMap.writeStyleMap(zip, "p => h1").then(function() {
+ return styleMap.readStyleMap(zip).then(function(contents) {
+ assert.equal(contents, "p => h1");
});
});
+});
+
+test('embedded style map is written to separate file', function() {
+ var zip = normalDocx();
- test('embedded style map is written to separate file', function() {
- var zip = normalDocx();
-
- return styleMap.writeStyleMap(zip, "p => h1").then(function() {
- return zip.read("mammoth/style-map", "utf8").then(function(contents) {
- assert.equal(contents, "p => h1");
- });
+ return styleMap.writeStyleMap(zip, "p => h1").then(function() {
+ return zip.read("mammoth/style-map", "utf8").then(function(contents) {
+ assert.equal(contents, "p => h1");
});
});
+});
+
+test('embedded style map is referenced in relationships', function() {
+ var zip = normalDocx();
- test('embedded style map is referenced in relationships', function() {
- var zip = normalDocx();
-
- return styleMap.writeStyleMap(zip, "p => h1").then(function() {
- return zip.read("word/_rels/document.xml.rels", "utf8").then(function(contents) {
- assert.equal(contents, expectedRelationshipsXml);
- });
+ return styleMap.writeStyleMap(zip, "p => h1").then(function() {
+ return zip.read("word/_rels/document.xml.rels", "utf8").then(function(contents) {
+ assert.equal(contents, expectedRelationshipsXml);
});
});
+});
+
+test('re-embedding style map replaces original', function() {
+ var zip = normalDocx();
- test('re-embedding style map replaces original', function() {
- var zip = normalDocx();
-
- return styleMap.writeStyleMap(zip, "p => h1").then(function() {
- return styleMap.writeStyleMap(zip, "p => h2");
- }).then(function() {
- return zip.read("word/_rels/document.xml.rels", "utf8").then(function(contents) {
- assert.equal(contents, expectedRelationshipsXml);
- });
- }).then(function() {
- return styleMap.readStyleMap(zip).then(function(contents) {
- assert.equal(contents, "p => h2");
- });
+ return styleMap.writeStyleMap(zip, "p => h1").then(function() {
+ return styleMap.writeStyleMap(zip, "p => h2");
+ }).then(function() {
+ return zip.read("word/_rels/document.xml.rels", "utf8").then(function(contents) {
+ assert.equal(contents, expectedRelationshipsXml);
+ });
+ }).then(function() {
+ return styleMap.readStyleMap(zip).then(function(contents) {
+ assert.equal(contents, "p => h2");
});
});
+});
+
+test('embedded style map has override content type in [Content_Types].xml', function() {
+ var zip = normalDocx();
- test('embedded style map has override content type in [Content_Types].xml', function() {
- var zip = normalDocx();
-
- return styleMap.writeStyleMap(zip, "p => h1").then(function() {
- return zip.read("[Content_Types].xml", "utf8").then(function(contents) {
- assert.equal(contents, expectedContentTypesXml);
- });
+ return styleMap.writeStyleMap(zip, "p => h1").then(function() {
+ return zip.read("[Content_Types].xml", "utf8").then(function(contents) {
+ assert.equal(contents, expectedContentTypesXml);
});
});
+});
+
+test('replacing style map keeps content type', function() {
+ var zip = normalDocx();
- test('replacing style map keeps content type', function() {
- var zip = normalDocx();
-
- return styleMap.writeStyleMap(zip, "p => h1").then(function() {
- return styleMap.writeStyleMap(zip, "p => h2");
- }).then(function() {
- return zip.read("[Content_Types].xml", "utf8").then(function(contents) {
- assert.equal(contents, expectedContentTypesXml);
- });
+ return styleMap.writeStyleMap(zip, "p => h1").then(function() {
+ return styleMap.writeStyleMap(zip, "p => h2");
+ }).then(function() {
+ return zip.read("[Content_Types].xml", "utf8").then(function(contents) {
+ assert.equal(contents, expectedContentTypesXml);
});
});
-
});
var expectedRelationshipsXml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
diff --git a/test/docx/styles-reader.tests.js b/test/docx/styles-reader.tests.js
index 8de53ef..4c5da7e 100644
--- a/test/docx/styles-reader.tests.js
+++ b/test/docx/styles-reader.tests.js
@@ -2,75 +2,72 @@ var assert = require("assert");
var readStylesXml = require("../../lib/docx/styles-reader").readStylesXml;
var XmlElement = require("../../lib/xml").Element;
-var test = require("../testing").test;
+var test = require("../test")(module);
-describe('readStylesXml', function() {
- test('paragraph style is null if no style with that ID exists', function() {
- var styles = readStylesXml(
- new XmlElement("w:styles", {}, [])
- );
- assert.equal(styles.findParagraphStyleById("Heading1"), null);
- });
-
- test('paragraph style can be found by ID', function() {
- var styles = readStylesXml(
- new XmlElement("w:styles", {}, [
- paragraphStyleElement("Heading1", "Heading 1")
- ])
- );
- assert.equal(styles.findParagraphStyleById("Heading1").styleId, "Heading1");
- });
-
- test('character style can be found by ID', function() {
- var styles = readStylesXml(
- new XmlElement("w:styles", {}, [
- characterStyleElement("Heading1Char", "Heading 1 Char")
- ])
- );
- assert.equal(styles.findCharacterStyleById("Heading1Char").styleId, "Heading1Char");
- });
-
- test('paragraph and character styles are distinct', function() {
- var styles = readStylesXml(
- new XmlElement("w:styles", {}, [
- paragraphStyleElement("Heading1", "Heading 1"),
- characterStyleElement("Heading1Char", "Heading 1 Char")
- ])
- );
- assert.equal(styles.findCharacterStyleById("Heading1"), null);
- assert.equal(styles.findParagraphStyleById("Heading1Char"), null);
- });
-
- test('character and table styles are distinct', function() {
- var styles = readStylesXml(
- new XmlElement("w:styles", {}, [
- styleElement("table", "Heading1", "Heading 1")
- ])
- );
- assert.equal(styles.findCharacterStyleById("Heading1"), null);
- });
-
- test('styles include names', function() {
- var styles = readStylesXml(
- new XmlElement("w:styles", {}, [
- paragraphStyleElement("Heading1", "Heading 1")
- ])
- );
- assert.equal(styles.findParagraphStyleById("Heading1").name, "Heading 1");
- });
+test('paragraph style is null if no style with that ID exists', function() {
+ var styles = readStylesXml(
+ new XmlElement("w:styles", {}, [])
+ );
+ assert.equal(styles.findParagraphStyleById("Heading1"), null);
+});
+
+test('paragraph style can be found by ID', function() {
+ var styles = readStylesXml(
+ new XmlElement("w:styles", {}, [
+ paragraphStyleElement("Heading1", "Heading 1")
+ ])
+ );
+ assert.equal(styles.findParagraphStyleById("Heading1").styleId, "Heading1");
+});
+
+test('character style can be found by ID', function() {
+ var styles = readStylesXml(
+ new XmlElement("w:styles", {}, [
+ characterStyleElement("Heading1Char", "Heading 1 Char")
+ ])
+ );
+ assert.equal(styles.findCharacterStyleById("Heading1Char").styleId, "Heading1Char");
+});
- test('style name is null if w:name element does not exist', function() {
- var styles = readStylesXml(
- new XmlElement("w:styles", {}, [
- styleWithoutWNameElement("paragraph", "Heading1"),
- styleWithoutWNameElement("character", "Heading1Char")
- ])
- );
- assert.equal(styles.findParagraphStyleById("Heading1").name, null);
- assert.equal(styles.findCharacterStyleById("Heading1Char").name, null);
- });
+test('paragraph and character styles are distinct', function() {
+ var styles = readStylesXml(
+ new XmlElement("w:styles", {}, [
+ paragraphStyleElement("Heading1", "Heading 1"),
+ characterStyleElement("Heading1Char", "Heading 1 Char")
+ ])
+ );
+ assert.equal(styles.findCharacterStyleById("Heading1"), null);
+ assert.equal(styles.findParagraphStyleById("Heading1Char"), null);
+});
+
+test('character and table styles are distinct', function() {
+ var styles = readStylesXml(
+ new XmlElement("w:styles", {}, [
+ styleElement("table", "Heading1", "Heading 1")
+ ])
+ );
+ assert.equal(styles.findCharacterStyleById("Heading1"), null);
+});
+
+test('styles include names', function() {
+ var styles = readStylesXml(
+ new XmlElement("w:styles", {}, [
+ paragraphStyleElement("Heading1", "Heading 1")
+ ])
+ );
+ assert.equal(styles.findParagraphStyleById("Heading1").name, "Heading 1");
+});
+test('style name is null if w:name element does not exist', function() {
+ var styles = readStylesXml(
+ new XmlElement("w:styles", {}, [
+ styleWithoutWNameElement("paragraph", "Heading1"),
+ styleWithoutWNameElement("character", "Heading1Char")
+ ])
+ );
+ assert.equal(styles.findParagraphStyleById("Heading1").name, null);
+ assert.equal(styles.findCharacterStyleById("Heading1Char").name, null);
});
function paragraphStyleElement(id, name) {
diff --git a/test/html-paths.tests.js b/test/html-paths.tests.js
index 76a77ef..8d75b7c 100644
--- a/test/html-paths.tests.js
+++ b/test/html-paths.tests.js
@@ -1,22 +1,20 @@
var assert = require("assert");
-var test = require("./testing").test;
+var test = require("./test")(module);
var htmlPaths = require("../lib/html-paths");
-describe("html-paths", function() {
- test("element can match multiple tag names", function() {
- var pathPart = htmlPaths.element(["ul", "ol"]);
- assert.ok(pathPart.matchesElement({tagName: "ul"}));
- assert.ok(pathPart.matchesElement({tagName: "ol"}));
- assert.ok(!pathPart.matchesElement({tagName: "p"}));
- });
-
- test("element matches if attributes are the same", function() {
- var pathPart = htmlPaths.element(["p"], {"class": "tip"});
- assert.ok(!pathPart.matchesElement({tagName: "p"}));
- assert.ok(!pathPart.matchesElement({tagName: "p", attributes: {"class": "tip help"}}));
- assert.ok(pathPart.matchesElement({tagName: "p", attributes: {"class": "tip"}}));
- });
+test("element can match multiple tag names", function() {
+ var pathPart = htmlPaths.element(["ul", "ol"]);
+ assert.ok(pathPart.matchesElement({tagName: "ul"}));
+ assert.ok(pathPart.matchesElement({tagName: "ol"}));
+ assert.ok(!pathPart.matchesElement({tagName: "p"}));
+});
+
+test("element matches if attributes are the same", function() {
+ var pathPart = htmlPaths.element(["p"], {"class": "tip"});
+ assert.ok(!pathPart.matchesElement({tagName: "p"}));
+ assert.ok(!pathPart.matchesElement({tagName: "p", attributes: {"class": "tip help"}}));
+ assert.ok(pathPart.matchesElement({tagName: "p", attributes: {"class": "tip"}}));
});
diff --git a/test/html/simplify.tests.js b/test/html/simplify.tests.js
index ccc5610..50593ee 100644
--- a/test/html/simplify.tests.js
+++ b/test/html/simplify.tests.js
@@ -2,108 +2,105 @@ var assert = require("assert");
var _ = require("underscore");
-var test = require("../testing").test;
+var test = require("../test")(module);
var html = require("../../lib/html");
var htmlPaths = require("../../lib/html-paths");
var nonFreshElement = html.nonFreshElement;
var text = html.text;
-var pathToNodes = html.pathToNodes;
-describe("simplify", function() {
- test("empty text nodes are removed", function() {
- assert.deepEqual(
- simplifyNode(text("")),
- []
- );
- });
-
- test("elements with no children are removed", function() {
- assert.deepEqual(
- simplifyNode(nonFreshElement("p", {}, [])),
- []
- );
- });
-
- test("elements only containing empty nodes are removed", function() {
- assert.deepEqual(
- simplifyNode(nonFreshElement("p", {}, [text("")])),
- []
- );
- });
-
- test("empty children of element are removed", function() {
- assert.deepEqual(
- simplifyNode(nonFreshElement("p", {}, [text("Hello"), text("")])),
- [nonFreshElement("p", {}, [text("Hello")])]
- );
- });
+test("empty text nodes are removed", function() {
+ assert.deepEqual(
+ simplifyNode(text("")),
+ []
+ );
+});
+
+test("elements with no children are removed", function() {
+ assert.deepEqual(
+ simplifyNode(nonFreshElement("p", {}, [])),
+ []
+ );
+});
+
+test("elements only containing empty nodes are removed", function() {
+ assert.deepEqual(
+ simplifyNode(nonFreshElement("p", {}, [text("")])),
+ []
+ );
+});
+
+test("empty children of element are removed", function() {
+ assert.deepEqual(
+ simplifyNode(nonFreshElement("p", {}, [text("Hello"), text("")])),
+ [nonFreshElement("p", {}, [text("Hello")])]
+ );
+});
+
+test("successive fresh elements are not collapsed", function() {
+ var path = htmlPaths.elements([
+ htmlPaths.element("p", {}, {fresh: true})
+ ]);
+ var original = concat(
+ pathToNodes(path, [text("Hello")]),
+ pathToNodes(path, [text(" there")])
+ );
- test("successive fresh elements are not collapsed", function() {
- var path = htmlPaths.elements([
- htmlPaths.element("p", {}, {fresh: true})
- ]);
- var original = concat(
+ assert.deepEqual(
+ html.simplify(original),
+ original);
+});
+
+test("successive plain non-fresh elements are collapsed if they have the same tag name", function() {
+ var path = htmlPaths.elements([
+ htmlPaths.element("p", {}, {fresh: false})
+ ]);
+ assert.deepEqual(
+ html.simplify(concat(
pathToNodes(path, [text("Hello")]),
pathToNodes(path, [text(" there")])
- );
-
- assert.deepEqual(
- html.simplify(original),
- original);
- });
-
- test("successive plain non-fresh elements are collapsed if they have the same tag name", function() {
- var path = htmlPaths.elements([
- htmlPaths.element("p", {}, {fresh: false})
- ]);
- assert.deepEqual(
- html.simplify(concat(
- pathToNodes(path, [text("Hello")]),
- pathToNodes(path, [text(" there")])
- )),
- pathToNodes(path, [text("Hello"), text(" there")])
- );
- });
-
- test("non-fresh can collapse into preceding fresh element", function() {
- var freshPath = htmlPaths.elements([
- htmlPaths.element("p", {}, {fresh: true})]);
- var nonFreshPath = htmlPaths.elements([
- htmlPaths.element("p", {}, {fresh: false})]);
- assert.deepEqual(
- html.simplify(concat(
- pathToNodes(freshPath, [text("Hello")]),
- pathToNodes(nonFreshPath, [text(" there")])
- )),
- pathToNodes(freshPath, [text("Hello"), text(" there")])
- );
- });
-
- test("children of collapsed element can collapse with children of another collapsed element", function() {
- assert.deepEqual(
- html.simplify([
- nonFreshElement("blockquote", {}, [nonFreshElement("p", {}, [text("Hello")])]),
- nonFreshElement("blockquote", {}, [nonFreshElement("p", {}, [text("there")])])
- ]),
- [nonFreshElement("blockquote", {}, [nonFreshElement("p", {}, [text("Hello"), text("there")])])]
- );
- });
-
- test("empty elements are removed before collapsing", function() {
- var freshPath = htmlPaths.elements([
- htmlPaths.element("p", {}, {fresh: true})]);
- var nonFreshPath = htmlPaths.elements([
- htmlPaths.element("p", {}, {fresh: false})]);
- assert.deepEqual(
- html.simplify(concat(
- pathToNodes(nonFreshPath, [text("Hello")]),
- pathToNodes(freshPath, []),
- pathToNodes(nonFreshPath, [text(" there")])
- )),
- pathToNodes(nonFreshPath, [text("Hello"), text(" there")])
- );
- });
+ )),
+ pathToNodes(path, [text("Hello"), text(" there")])
+ );
+});
+
+test("non-fresh can collapse into preceding fresh element", function() {
+ var freshPath = htmlPaths.elements([
+ htmlPaths.element("p", {}, {fresh: true})]);
+ var nonFreshPath = htmlPaths.elements([
+ htmlPaths.element("p", {}, {fresh: false})]);
+ assert.deepEqual(
+ html.simplify(concat(
+ pathToNodes(freshPath, [text("Hello")]),
+ pathToNodes(nonFreshPath, [text(" there")])
+ )),
+ pathToNodes(freshPath, [text("Hello"), text(" there")])
+ );
+});
+
+test("children of collapsed element can collapse with children of another collapsed element", function() {
+ assert.deepEqual(
+ html.simplify([
+ nonFreshElement("blockquote", {}, [nonFreshElement("p", {}, [text("Hello")])]),
+ nonFreshElement("blockquote", {}, [nonFreshElement("p", {}, [text("there")])])
+ ]),
+ [nonFreshElement("blockquote", {}, [nonFreshElement("p", {}, [text("Hello"), text("there")])])]
+ );
+});
+
+test("empty elements are removed before collapsing", function() {
+ var freshPath = htmlPaths.elements([
+ htmlPaths.element("p", {}, {fresh: true})]);
+ var nonFreshPath = htmlPaths.elements([
+ htmlPaths.element("p", {}, {fresh: false})]);
+ assert.deepEqual(
+ html.simplify(concat(
+ pathToNodes(nonFreshPath, [text("Hello")]),
+ pathToNodes(freshPath, []),
+ pathToNodes(nonFreshPath, [text(" there")])
+ )),
+ pathToNodes(nonFreshPath, [text("Hello"), text(" there")])
+ );
});
function simplifyNode(node) {
@@ -113,3 +110,9 @@ function simplifyNode(node) {
function concat() {
return _.flatten(arguments, true);
}
+
+function pathToNodes(path, nodes) {
+ return path.wrap(function() {
+ return nodes;
+ });
+}
diff --git a/test/html/write.tests.js b/test/html/write.tests.js
index 531995f..9db8c79 100644
--- a/test/html/write.tests.js
+++ b/test/html/write.tests.js
@@ -1,40 +1,38 @@
var assert = require("assert");
-var test = require("../testing").test;
+var test = require("../test")(module);
var html = require("../../lib/html");
var writers = require("../../lib/writers");
-describe("HTML write", function() {
- test("text is HTML escaped", function() {
- assert.equal(
- generateString(html.text("<>&")),
- "&lt;&gt;&amp;");
- });
-
- test("double quotes outside of attributes are not escaped", function() {
- assert.equal(
- generateString(html.text('"')),
- '"');
- });
-
- test("element attributes are HTML escaped", function() {
- assert.equal(
- generateString(html.freshElement("p", {"x": "<"})),
- '<p x="&lt;"></p>');
- });
-
- test("double quotes inside attributes are escaped", function() {
- assert.equal(
- generateString(html.freshElement("p", {"x": '"'})),
- '<p x="&quot;"></p>');
- });
-
- test("element children are written", function() {
- assert.equal(
- generateString(html.freshElement("p", {}, [html.text("Hello")])),
- '<p>Hello</p>');
- });
+test("text is HTML escaped", function() {
+ assert.equal(
+ generateString(html.text("<>&")),
+ "&lt;&gt;&amp;");
+});
+
+test("double quotes outside of attributes are not escaped", function() {
+ assert.equal(
+ generateString(html.text('"')),
+ '"');
+});
+
+test("element attributes are HTML escaped", function() {
+ assert.equal(
+ generateString(html.freshElement("p", {"x": "<"})),
+ '<p x="&lt;"></p>');
+});
+
+test("double quotes inside attributes are escaped", function() {
+ assert.equal(
+ generateString(html.freshElement("p", {"x": '"'})),
+ '<p x="&quot;"></p>');
+});
+
+test("element children are written", function() {
+ assert.equal(
+ generateString(html.freshElement("p", {}, [html.text("Hello")])),
+ '<p>Hello</p>');
});
function generateString(node) {
diff --git a/test/images.tests.js b/test/images.tests.js
index 7aac5a2..7ba3ec9 100644
--- a/test/images.tests.js
+++ b/test/images.tests.js
@@ -2,12 +2,9 @@ var assert = require("assert");
var mammoth = require("../");
-var testing = require("./testing");
-var test = testing.test;
+var test = require("./test")(module);
-describe('images', function() {
- test('mammoth.images.inline() should be an alias of mammoth.images.imgElement()', function() {
- assert.ok(mammoth.images.inline === mammoth.images.imgElement);
- });
+test('mammoth.images.inline() should be an alias of mammoth.images.imgElement()', function() {
+ assert.ok(mammoth.images.inline === mammoth.images.imgElement);
});
diff --git a/test/main.tests.js b/test/main.tests.js
index d603626..505c31f 100644
--- a/test/main.tests.js
+++ b/test/main.tests.js
@@ -6,69 +6,67 @@ var fs = require("fs");
var temp = require('temp').track();
var promises = require("../lib/promises");
-var test = require("./testing").test;
+var test = require("./test")(module);
var testPath = require("./testing").testPath;
-describe("CLI", function() {
- test("HTML is printed to stdout if output file is not set", function() {
- return runMammoth(testPath("single-paragraph.docx")).then(function(result) {
- assert.equal(result.stderrOutput, "");
- assert.equal(result.output, "<p>Walking on imported air</p>");
- });
- });
-
- test("HTML is written to file if output file is set", function() {
- return createTempDir().then(function(tempDir) {
- var outputPath = path.join(tempDir, "output.html");
- return runMammoth(testPath("single-paragraph.docx"), outputPath).then(function(result) {
- assert.equal(result.stderrOutput, "");
- assert.equal(result.output, "");
- assert.equal(fs.readFileSync(outputPath, "utf8"), "<p>Walking on imported air</p>");
- });
- });
+test("HTML is printed to stdout if output file is not set", function() {
+ return runMammoth(testPath("single-paragraph.docx")).then(function(result) {
+ assert.equal(result.stderrOutput, "");
+ assert.equal(result.output, "<p>Walking on imported air</p>");
});
-
- var imageBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAOvgAADr4B6kKxwAAAABNJREFUKFNj/M+ADzDhlWUYqdIAQSwBE8U+X40AAAAASUVORK5CYII=";
-
- test("inline images are included in output if writing to single file", function() {
- return runMammoth(testPath("tiny-picture.docx")).then(function(result) {
+});
+
+test("HTML is written to file if output file is set", function() {
+ return createTempDir().then(function(tempDir) {
+ var outputPath = path.join(tempDir, "output.html");
+ return runMammoth(testPath("single-paragraph.docx"), outputPath).then(function(result) {
assert.equal(result.stderrOutput, "");
- assert.equal(result.output, '<p><img src="data:image/png;base64,' + imageBase64 + '" /></p>');
+ assert.equal(result.output, "");
+ assert.equal(fs.readFileSync(outputPath, "utf8"), "<p>Walking on imported air</p>");
});
});
-
- test("images are written to separate files if output dir is set", function() {
- return createTempDir().then(function(tempDir) {
- var outputPath = path.join(tempDir, "tiny-picture.html");
- var imagePath = path.join(tempDir, "1.png");
- return runMammoth(testPath("tiny-picture.docx"), "--output-dir", tempDir).then(function(result) {
- assert.equal(result.stderrOutput, "");
- assert.equal(result.output, "");
- assert.equal(fs.readFileSync(outputPath, "utf8"), '<p><img src="1.png" /></p>');
- assert.equal(fs.readFileSync(imagePath, "base64"), imageBase64);
- });
- });
+});
+
+var imageBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAOvgAADr4B6kKxwAAAABNJREFUKFNj/M+ADzDhlWUYqdIAQSwBE8U+X40AAAAASUVORK5CYII=";
+
+test("inline images are included in output if writing to single file", function() {
+ return runMammoth(testPath("tiny-picture.docx")).then(function(result) {
+ assert.equal(result.stderrOutput, "");
+ assert.equal(result.output, '<p><img src="data:image/png;base64,' + imageBase64 + '" /></p>');
});
-
- test("style map is used if set", function() {
- return createTempDir().then(function(tempDir) {
- var styleMapPath = path.join(tempDir, "style-map");
- fs.writeFileSync(styleMapPath, "p => span:fresh");
- return runMammoth(testPath("single-paragraph.docx"), "--style-map", styleMapPath).then(function(result) {
- assert.equal(result.stderrOutput, "");
- assert.equal(result.output, "<span>Walking on imported air</span>");
- });
+});
+
+test("images are written to separate files if output dir is set", function() {
+ return createTempDir().then(function(tempDir) {
+ var outputPath = path.join(tempDir, "tiny-picture.html");
+ var imagePath = path.join(tempDir, "1.png");
+ return runMammoth(testPath("tiny-picture.docx"), "--output-dir", tempDir).then(function(result) {
+ assert.equal(result.stderrOutput, "");
+ assert.equal(result.output, "");
+ assert.equal(fs.readFileSync(outputPath, "utf8"), '<p><img src="1.png" /></p>');
+ assert.equal(fs.readFileSync(imagePath, "base64"), imageBase64);
});
});
-
- test("--output-format=markdown option generate markdown output", function() {
- return runMammoth(testPath("single-paragraph.docx"), "--output-format=markdown").then(function(result) {
+});
+
+test("style map is used if set", function() {
+ return createTempDir().then(function(tempDir) {
+ var styleMapPath = path.join(tempDir, "style-map");
+ fs.writeFileSync(styleMapPath, "p => span:fresh");
+ return runMammoth(testPath("single-paragraph.docx"), "--style-map", styleMapPath).then(function(result) {
assert.equal(result.stderrOutput, "");
- assert.equal(result.output, "Walking on imported air\n\n");
+ assert.equal(result.output, "<span>Walking on imported air</span>");
});
});
});
+test("--output-format=markdown option generate markdown output", function() {
+ return runMammoth(testPath("single-paragraph.docx"), "--output-format=markdown").then(function(result) {
+ assert.equal(result.stderrOutput, "");
+ assert.equal(result.output, "Walking on imported air\n\n");
+ });
+});
+
function runMammoth() {
var args = Array.prototype.slice.call(arguments, 0);
diff --git a/test/mammoth.tests.js b/test/mammoth.tests.js
index b01b65d..73e6a0f 100644
--- a/test/mammoth.tests.js
+++ b/test/mammoth.tests.js
@@ -8,347 +8,374 @@ var promises = require("../lib/promises");
var results = require("../lib/results");
var testing = require("./testing");
-var test = testing.test;
+var test = require("./test")(module);
var testData = testing.testData;
var createFakeDocxFile = testing.createFakeDocxFile;
-describe('mammoth', function() {
- test('should convert docx containing one paragraph to single p element', function() {
- var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
- return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+test('should convert docx containing one paragraph to single p element', function() {
+ var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
+ return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+ assert.equal(result.value, "<p>Walking on imported air</p>");
+ assert.deepEqual(result.messages, []);
+ });
+});
+
+test('should convert docx represented by a Buffer', function() {
+ var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
+ return promises.nfcall(fs.readFile, docxPath)
+ .then(function(buffer) {
+ return mammoth.convertToHtml({buffer: buffer});
+ })
+ .then(function(result) {
assert.equal(result.value, "<p>Walking on imported air</p>");
assert.deepEqual(result.messages, []);
});
+});
+
+test('should read docx xml files with unicode byte order mark', function() {
+ var docxPath = path.join(__dirname, "test-data/utf8-bom.docx");
+ return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+ assert.equal(result.value, "<p>This XML has a byte order mark.</p>");
+ assert.deepEqual(result.messages, []);
});
-
- test('should convert docx represented by a Buffer', function() {
- var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
- return promises.nfcall(fs.readFile, docxPath)
- .then(function(buffer) {
- return mammoth.convertToHtml({buffer: buffer});
- })
- .then(function(result) {
- assert.equal(result.value, "<p>Walking on imported air</p>");
- assert.deepEqual(result.messages, []);
- });
- });
-
- test('should read docx xml files with unicode byte order mark', function() {
- var docxPath = path.join(__dirname, "test-data/utf8-bom.docx");
- return mammoth.convertToHtml({path: docxPath}).then(function(result) {
- assert.equal(result.value, "<p>This XML has a byte order mark.</p>");
- assert.deepEqual(result.messages, []);
- });
+});
+
+test('empty paragraphs are ignored by default', function() {
+ var docxPath = path.join(__dirname, "test-data/empty.docx");
+ return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+ assert.equal(result.value, "");
+ assert.deepEqual(result.messages, []);
});
-
- test('empty paragraphs are ignored by default', function() {
- var docxPath = path.join(__dirname, "test-data/empty.docx");
- return mammoth.convertToHtml({path: docxPath}).then(function(result) {
- assert.equal(result.value, "");
- assert.deepEqual(result.messages, []);
- });
+});
+
+test('empty paragraphs are preserved if ignoreEmptyParagraphs is false', function() {
+ var docxPath = path.join(__dirname, "test-data/empty.docx");
+ return mammoth.convertToHtml({path: docxPath}, {ignoreEmptyParagraphs: false}).then(function(result) {
+ assert.equal(result.value, "<p></p>");
+ assert.deepEqual(result.messages, []);
});
-
- test('empty paragraphs are preserved if ignoreEmptyParagraphs is false', function() {
- var docxPath = path.join(__dirname, "test-data/empty.docx");
- return mammoth.convertToHtml({path: docxPath}, {ignoreEmptyParagraphs: false}).then(function(result) {
- assert.equal(result.value, "<p></p>");
- assert.deepEqual(result.messages, []);
- });
+});
+
+test('style map can be expressed as string', function() {
+ var docxFile = createFakeDocxFile({
+ "word/document.xml": testData("simple/word/document.xml")
});
-
- test('style map can be expressed as string', function() {
- var docxFile = createFakeDocxFile({
- "word/document.xml": testData("simple/word/document.xml")
- });
- var options = {
- styleMap: "p => h1"
- };
- return mammoth.convertToHtml({file: docxFile}, options).then(function(result) {
- assert.equal("<h1>Hello.</h1>", result.value);
- });
+ var options = {
+ styleMap: "p => h1"
+ };
+ return mammoth.convertToHtml({file: docxFile}, options).then(function(result) {
+ assert.equal("<h1>Hello.</h1>", result.value);
});
-
- test('style map can be expressed as array of style mappings', function() {
- var docxFile = createFakeDocxFile({
- "word/document.xml": testData("simple/word/document.xml")
- });
- var options = {
- styleMap: ["p => h1"]
- };
- return mammoth.convertToHtml({file: docxFile}, options).then(function(result) {
- assert.equal("<h1>Hello.</h1>", result.value);
- });
+});
+
+test('style map can be expressed as array of style mappings', function() {
+ var docxFile = createFakeDocxFile({
+ "word/document.xml": testData("simple/word/document.xml")
});
-
- test('embedded style map is used if present', function() {
- var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
- return promises.nfcall(fs.readFile, docxPath)
- .then(function(buffer) {
- return mammoth.embedStyleMap({buffer: buffer}, "p => h1");
- })
- .then(function(docx) {
- return mammoth.convertToHtml({buffer: docx.toBuffer()});
- })
- .then(function(result) {
- assert.equal(result.value, "<h1>Walking on imported air</h1>");
- assert.deepEqual(result.messages, []);
- });
- });
-
- test('embedded style map can be retrieved', function() {
- var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
- return promises.nfcall(fs.readFile, docxPath)
- .then(function(buffer) {
- return mammoth.embedStyleMap({buffer: buffer}, "p => h1");
- })
- .then(function(docx) {
- return mammoth.readEmbeddedStyleMap({buffer: docx.toBuffer()});
- })
- .then(function(styleMap) {
- assert.equal(styleMap, "p => h1");
- });
- });
-
- test('warning if style mapping is not understood', function() {
- var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
- var options = {
- styleMap: "!!!!\np => h1"
- };
- return mammoth.convertToHtml({path: docxPath}, options).then(function(result) {
- assert.equal("<h1>Walking on imported air</h1>", result.value);
- var warning = "Did not understand this style mapping, so ignored it: !!!!\n" +
- 'Error was at character number 1: Expected element type but got unrecognisedCharacter "!"';
- assert.deepEqual(result.messages, [results.warning(warning)]);
- });
+ var options = {
+ styleMap: ["p => h1"]
+ };
+ return mammoth.convertToHtml({file: docxFile}, options).then(function(result) {
+ assert.equal("<h1>Hello.</h1>", result.value);
});
-
- test('options are passed to document converter when calling mammoth.convertToHtml', function() {
- var docxFile = createFakeDocxFile({
- "word/document.xml": testData("simple/word/document.xml")
+});
+
+test('embedded style map is used if present', function() {
+ var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
+ return promises.nfcall(fs.readFile, docxPath)
+ .then(function(buffer) {
+ return mammoth.embedStyleMap({buffer: buffer}, "p => h1");
+ })
+ .then(function(docx) {
+ return mammoth.convertToHtml({buffer: docx.toBuffer()});
+ })
+ .then(function(result) {
+ assert.equal(result.value, "<h1>Walking on imported air</h1>");
+ assert.deepEqual(result.messages, []);
});
- var options = {
- styleMap: "p => h1"
- };
- return mammoth.convertToHtml({file: docxFile}, options).then(function(result) {
- assert.equal("<h1>Hello.</h1>", result.value);
+});
+
+test('embedded style map can be retrieved', function() {
+ var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
+ return promises.nfcall(fs.readFile, docxPath)
+ .then(function(buffer) {
+ return mammoth.embedStyleMap({buffer: buffer}, "p => h1");
+ })
+ .then(function(docx) {
+ return mammoth.readEmbeddedStyleMap({buffer: docx.toBuffer()});
+ })
+ .then(function(styleMap) {
+ assert.equal(styleMap, "p => h1");
});
+});
+
+test('warning if style mapping is not understood', function() {
+ var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
+ var options = {
+ styleMap: "????\np => h1"
+ };
+ return mammoth.convertToHtml({path: docxPath}, options).then(function(result) {
+ assert.equal("<h1>Walking on imported air</h1>", result.value);
+ var warning = "Did not understand this style mapping, so ignored it: ????\n" +
+ 'Error was at character number 1: Expected element type but got unrecognisedCharacter "?"';
+ assert.deepEqual(result.messages, [results.warning(warning)]);
});
-
- test('options.transformDocument is used to transform document if set', function() {
- var docxFile = createFakeDocxFile({
- "word/document.xml": testData("simple/word/document.xml")
- });
- var options = {
- transformDocument: function(document) {
- document.children[0].styleId = "Heading1";
- return document;
- }
- };
- return mammoth.convertToHtml({file: docxFile}, options).then(function(result) {
- assert.equal("<h1>Hello.</h1>", result.value);
- });
+});
+
+test('options are passed to document converter when calling mammoth.convertToHtml', function() {
+ var docxFile = createFakeDocxFile({
+ "word/document.xml": testData("simple/word/document.xml")
});
-
- test('mammoth.transforms.paragraph only transforms paragraphs', function() {
- var docxFile = createFakeDocxFile({
- "word/document.xml": testData("simple/word/document.xml")
- });
- var options = {
- transformDocument: mammoth.transforms.paragraph(function(paragraph) {
- return _.extend(paragraph, {styleId: "Heading1"});
- })
- };
- return mammoth.convertToHtml({file: docxFile}, options).then(function(result) {
- assert.equal("<h1>Hello.</h1>", result.value);
- });
+ var options = {
+ styleMap: "p => h1"
+ };
+ return mammoth.convertToHtml({file: docxFile}, options).then(function(result) {
+ assert.equal("<h1>Hello.</h1>", result.value);
});
-
- test('inline images are included in output', function() {
- var docxPath = path.join(__dirname, "test-data/tiny-picture.docx");
- return mammoth.convertToHtml({path: docxPath}).then(function(result) {
- assert.equal(result.value, '<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAOvgAADr4B6kKxwAAAABNJREFUKFNj/M+ADzDhlWUYqdIAQSwBE8U+X40AAAAASUVORK5CYII=" /></p>');
- });
+});
+
+test('options.transformDocument is used to transform document if set', function() {
+ var docxFile = createFakeDocxFile({
+ "word/document.xml": testData("simple/word/document.xml")
+ });
+ var options = {
+ transformDocument: function(document) {
+ document.children[0].styleId = "Heading1";
+ return document;
+ }
+ };
+ return mammoth.convertToHtml({file: docxFile}, options).then(function(result) {
+ assert.equal("<h1>Hello.</h1>", result.value);
});
-
- test('src of inline images can be changed', function() {
- var docxPath = path.join(__dirname, "test-data/tiny-picture.docx");
- var convertImage = mammoth.images.imgElement(function(element) {
- return element.read("base64").then(function(encodedImage) {
- return {src: encodedImage.substring(0, 2) + "," + element.contentType};
- });
- });
- return mammoth.convertToHtml({path: docxPath}, {convertImage: convertImage}).then(function(result) {
- assert.equal(result.value, '<p><img src="iV,image/png" /></p>');
- });
+});
+
+test('mammoth.transforms.paragraph only transforms paragraphs', function() {
+ var docxFile = createFakeDocxFile({
+ "word/document.xml": testData("simple/word/document.xml")
+ });
+ var options = {
+ transformDocument: mammoth.transforms.paragraph(function(paragraph) {
+ return _.extend(paragraph, {styleId: "Heading1"});
+ })
+ };
+ return mammoth.convertToHtml({file: docxFile}, options).then(function(result) {
+ assert.equal("<h1>Hello.</h1>", result.value);
});
-
- test('images stored outside of document are included in output', function() {
- var docxPath = path.join(__dirname, "test-data/external-picture.docx");
- return mammoth.convertToHtml({path: docxPath}).then(function(result) {
- assert.equal(result.value, '<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAOvgAADr4B6kKxwAAAABNJREFUKFNj/M+ADzDhlWUYqdIAQSwBE8U+X40AAAAASUVORK5CYII=" /></p>');
- assert.deepEqual(result.messages, []);
- });
+});
+
+test('inline images are included in output', function() {
+ var docxPath = path.join(__dirname, "test-data/tiny-picture.docx");
+ return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+ assert.equal(result.value, '<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAOvgAADr4B6kKxwAAAABNJREFUKFNj/M+ADzDhlWUYqdIAQSwBE8U+X40AAAAASUVORK5CYII=" /></p>');
});
-
- test('error if images stored outside of document are specified when passing file without path', function() {
- var docxPath = path.join(__dirname, "test-data/external-picture.docx");
- var buffer = fs.readFileSync(docxPath);
- return mammoth.convertToHtml({buffer: buffer}).then(function(result) {
- assert.equal(result.value, '');
- assert.equal(result.messages[0].message, "could not find external image 'tiny-picture.png', path of input document is unknown");
- assert.equal(result.messages[0].type, "error");
+});
+
+test('src of inline images can be changed', function() {
+ var docxPath = path.join(__dirname, "test-data/tiny-picture.docx");
+ var convertImage = mammoth.images.imgElement(function(element) {
+ return element.read("base64").then(function(encodedImage) {
+ return {src: encodedImage.substring(0, 2) + "," + element.contentType};
});
});
-
- test('simple list is converted to list elements', function() {
- var docxPath = path.join(__dirname, "test-data/simple-list.docx");
- return mammoth.convertToHtml({path: docxPath}).then(function(result) {
- assert.equal(result.value, '<ul><li>Apple</li><li>Banana</li></ul>');
- });
+ return mammoth.convertToHtml({path: docxPath}, {convertImage: convertImage}).then(function(result) {
+ assert.equal(result.value, '<p><img src="iV,image/png" /></p>');
});
-
- test('word tables are converted to html tables', function() {
- var docxPath = path.join(__dirname, "test-data/tables.docx");
- return mammoth.convertToHtml({path: docxPath}).then(function(result) {
- var expectedHtml = "<p>Above</p>" +
- "<table>" +
- "<tr><td><p>Top left</p></td><td><p>Top right</p></td></tr>" +
- "<tr><td><p>Bottom left</p></td><td><p>Bottom right</p></td></tr>" +
- "</table>" +
- "<p>Below</p>";
- assert.equal(result.value, expectedHtml);
- assert.deepEqual(result.messages, []);
- });
+});
+
+test('images stored outside of document are included in output', function() {
+ var docxPath = path.join(__dirname, "test-data/external-picture.docx");
+ return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+ assert.equal(result.value, '<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAOvgAADr4B6kKxwAAAABNJREFUKFNj/M+ADzDhlWUYqdIAQSwBE8U+X40AAAAASUVORK5CYII=" /></p>');
+ assert.deepEqual(result.messages, []);
});
-
- test('footnotes are appended to text', function() {
- // TODO: don't duplicate footnotes with multiple references
- var docxPath = path.join(__dirname, "test-data/footnotes.docx");
- var options = {
- idPrefix: "doc-42-"
- };
- return mammoth.convertToHtml({path: docxPath}, options).then(function(result) {
- var expectedOutput = '<p>Ouch' +
- '<sup><a href="#doc-42-footnote-1" id="doc-42-footnote-ref-1">[1]</a></sup>.' +
- '<sup><a href="#doc-42-footnote-2" id="doc-42-footnote-ref-2">[2]</a></sup></p>' +
- '<ol><li id="doc-42-footnote-1"><p> A tachyon walks into a bar. <a href="#doc-42-footnote-ref-1">↑</a></p></li>' +
- '<li id="doc-42-footnote-2"><p> Fin. <a href="#doc-42-footnote-ref-2">↑</a></p></li></ol>';
- assert.equal(result.value, expectedOutput);
- assert.deepEqual(result.messages, []);
- });
+});
+
+test('error if images stored outside of document are specified when passing file without path', function() {
+ var docxPath = path.join(__dirname, "test-data/external-picture.docx");
+ var buffer = fs.readFileSync(docxPath);
+ return mammoth.convertToHtml({buffer: buffer}).then(function(result) {
+ assert.equal(result.value, '');
+ assert.equal(result.messages[0].message, "could not find external image 'tiny-picture.png', path of input document is unknown");
+ assert.equal(result.messages[0].type, "error");
});
-
- test('endnotes are appended to text', function() {
- var docxPath = path.join(__dirname, "test-data/endnotes.docx");
- var options = {
- idPrefix: "doc-42-"
- };
- return mammoth.convertToHtml({path: docxPath}, options).then(function(result) {
- var expectedOutput = '<p>Ouch' +
- '<sup><a href="#doc-42-endnote-2" id="doc-42-endnote-ref-2">[1]</a></sup>.' +
- '<sup><a href="#doc-42-endnote-3" id="doc-42-endnote-ref-3">[2]</a></sup></p>' +
- '<ol><li id="doc-42-endnote-2"><p> A tachyon walks into a bar. <a href="#doc-42-endnote-ref-2">↑</a></p></li>' +
- '<li id="doc-42-endnote-3"><p> Fin. <a href="#doc-42-endnote-ref-3">↑</a></p></li></ol>';
- assert.equal(result.value, expectedOutput);
- assert.deepEqual(result.messages, []);
- });
+});
+
+test('simple list is converted to list elements', function() {
+ var docxPath = path.join(__dirname, "test-data/simple-list.docx");
+ return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+ assert.equal(result.value, '<ul><li>Apple</li><li>Banana</li></ul>');
});
-
- test('relationships are handled properly in footnotes', function() {
- var docxPath = path.join(__dirname, "test-data/footnote-hyperlink.docx");
- var options = {
- idPrefix: "doc-42-"
- };
- return mammoth.convertToHtml({path: docxPath}, options).then(function(result) {
- var expectedOutput =
- '<p><sup><a href="#doc-42-footnote-1" id="doc-42-footnote-ref-1">[1]</a></sup></p>' +
- '<ol><li id="doc-42-footnote-1"><p> <a href="http://www.example.com">Example</a> <a href="#doc-42-footnote-ref-1">↑</a></p></li></ol>';
- assert.equal(result.value, expectedOutput);
- assert.deepEqual(result.messages, []);
- });
+});
+
+test('word tables are converted to html tables', function() {
+ var docxPath = path.join(__dirname, "test-data/tables.docx");
+ return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+ var expectedHtml = "<p>Above</p>" +
+ "<table>" +
+ "<tr><td><p>Top left</p></td><td><p>Top right</p></td></tr>" +
+ "<tr><td><p>Bottom left</p></td><td><p>Bottom right</p></td></tr>" +
+ "</table>" +
+ "<p>Below</p>";
+ assert.equal(result.value, expectedHtml);
+ assert.deepEqual(result.messages, []);
});
-
- test('textboxes are read', function() {
- var docxPath = path.join(__dirname, "test-data/text-box.docx");
- return mammoth.convertToHtml({path: docxPath}).then(function(result) {
- var expectedOutput = '<p>Datum plane</p>';
- assert.equal(result.value, expectedOutput);
- });
+});
+
+test('footnotes are appended to text', function() {
+ // TODO: don't duplicate footnotes with multiple references
+ var docxPath = path.join(__dirname, "test-data/footnotes.docx");
+ var options = {
+ idPrefix: "doc-42-"
+ };
+ return mammoth.convertToHtml({path: docxPath}, options).then(function(result) {
+ var expectedOutput = '<p>Ouch' +
+ '<sup><a href="#doc-42-footnote-1" id="doc-42-footnote-ref-1">[1]</a></sup>.' +
+ '<sup><a href="#doc-42-footnote-2" id="doc-42-footnote-ref-2">[2]</a></sup></p>' +
+ '<ol><li id="doc-42-footnote-1"><p> A tachyon walks into a bar. <a href="#doc-42-footnote-ref-1">↑</a></p></li>' +
+ '<li id="doc-42-footnote-2"><p> Fin. <a href="#doc-42-footnote-ref-2">↑</a></p></li></ol>';
+ assert.equal(result.value, expectedOutput);
+ assert.deepEqual(result.messages, []);
});
-
- test('underline is ignored by default', function() {
- var docxPath = path.join(__dirname, "test-data/underline.docx");
- return mammoth.convertToHtml({path: docxPath}).then(function(result) {
- assert.equal(result.value, '<p><strong>The Sunset Tree</strong></p>');
- });
+});
+
+test('endnotes are appended to text', function() {
+ var docxPath = path.join(__dirname, "test-data/endnotes.docx");
+ var options = {
+ idPrefix: "doc-42-"
+ };
+ return mammoth.convertToHtml({path: docxPath}, options).then(function(result) {
+ var expectedOutput = '<p>Ouch' +
+ '<sup><a href="#doc-42-endnote-2" id="doc-42-endnote-ref-2">[1]</a></sup>.' +
+ '<sup><a href="#doc-42-endnote-3" id="doc-42-endnote-ref-3">[2]</a></sup></p>' +
+ '<ol><li id="doc-42-endnote-2"><p> A tachyon walks into a bar. <a href="#doc-42-endnote-ref-2">↑</a></p></li>' +
+ '<li id="doc-42-endnote-3"><p> Fin. <a href="#doc-42-endnote-ref-3">↑</a></p></li></ol>';
+ assert.equal(result.value, expectedOutput);
+ assert.deepEqual(result.messages, []);
});
-
- test('underline can be configured with style mapping', function() {
- var docxPath = path.join(__dirname, "test-data/underline.docx");
- return mammoth.convertToHtml({path: docxPath}, {styleMap: "u => em"}).then(function(result) {
- assert.equal(result.value, '<p><strong>The <em>Sunset</em> Tree</strong></p>');
- });
+});
+
+test('relationships are handled properly in footnotes', function() {
+ var docxPath = path.join(__dirname, "test-data/footnote-hyperlink.docx");
+ var options = {
+ idPrefix: "doc-42-"
+ };
+ return mammoth.convertToHtml({path: docxPath}, options).then(function(result) {
+ var expectedOutput =
+ '<p><sup><a href="#doc-42-footnote-1" id="doc-42-footnote-ref-1">[1]</a></sup></p>' +
+ '<ol><li id="doc-42-footnote-1"><p> <a href="http://www.example.com">Example</a> <a href="#doc-42-footnote-ref-1">↑</a></p></li></ol>';
+ assert.equal(result.value, expectedOutput);
+ assert.deepEqual(result.messages, []);
});
-
- test('strikethrough is converted to <s> by default', function() {
- var docxPath = path.join(__dirname, "test-data/strikethrough.docx");
- return mammoth.convertToHtml({path: docxPath}).then(function(result) {
- assert.equal(result.value, "<p><s>Today's Special: Salmon</s> Sold out</p>");
- });
+});
+
+test('when style mapping is defined for comment references then comments are included', function() {
+ var docxPath = path.join(__dirname, "test-data/comments.docx");
+ var options = {
+ idPrefix: "doc-42-",
+ styleMap: "comment-reference => sup"
+ };
+ return mammoth.convertToHtml({path: docxPath}, options).then(function(result) {
+ var expectedOutput = (
+ '<p>Ouch' +
+ '<sup><a href="#doc-42-comment-0" id="doc-42-comment-ref-0">[MW1]</a></sup>.' +
+ '<sup><a href="#doc-42-comment-2" id="doc-42-comment-ref-2">[MW2]</a></sup></p>' +
+ '<dl><dt id="doc-42-comment-0">Comment [MW1]</dt><dd><p>A tachyon walks into a bar. <a href="#doc-42-comment-ref-0">↑</a></p></dd>' +
+ '<dt id="doc-42-comment-2">Comment [MW2]</dt><dd><p>Fin. <a href="#doc-42-comment-ref-2">↑</a></p></dd></dl>'
+ );
+ assert.equal(result.value, expectedOutput);
+ assert.deepEqual(result.messages, []);
});
-
- test('strikethrough conversion can be configured with style mappings', function() {
- var docxPath = path.join(__dirname, "test-data/strikethrough.docx");
- return mammoth.convertToHtml({path: docxPath}, {styleMap: "strike => del"}).then(function(result) {
- assert.equal(result.value, "<p><del>Today's Special: Salmon</del> Sold out</p>");
- });
+});
+
+test('textboxes are read', function() {
+ var docxPath = path.join(__dirname, "test-data/text-box.docx");
+ return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+ var expectedOutput = '<p>Datum plane</p>';
+ assert.equal(result.value, expectedOutput);
});
-
- test('indentation is used if prettyPrint is true', function() {
- var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
- return mammoth.convertToHtml({path: docxPath}, {prettyPrint: true}).then(function(result) {
- assert.equal(result.value, "<p>\n Walking on imported air\n</p>");
- assert.deepEqual(result.messages, []);
- });
+});
+
+test('underline is ignored by default', function() {
+ var docxPath = path.join(__dirname, "test-data/underline.docx");
+ return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+ assert.equal(result.value, '<p><strong>The Sunset Tree</strong></p>');
});
-
- test('using styleMapping throws error', function() {
- try {
- mammoth.styleMapping();
- } catch (error) {
- assert.equal(
- error.message,
- 'Use a raw string instead of mammoth.styleMapping e.g. "p[style-name=\'Title\'] => h1" instead of mammoth.styleMapping("p[style-name=\'Title\'] => h1")'
- );
- }
+});
+
+test('underline can be configured with style mapping', function() {
+ var docxPath = path.join(__dirname, "test-data/underline.docx");
+ return mammoth.convertToHtml({path: docxPath}, {styleMap: "u => em"}).then(function(result) {
+ assert.equal(result.value, '<p><strong>The <em>Sunset</em> Tree</strong></p>');
+ });
+});
+
+test('strikethrough is converted to <s> by default', function() {
+ var docxPath = path.join(__dirname, "test-data/strikethrough.docx");
+ return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+ assert.equal(result.value, "<p><s>Today's Special: Salmon</s> Sold out</p>");
+ });
+});
+
+test('strikethrough conversion can be configured with style mappings', function() {
+ var docxPath = path.join(__dirname, "test-data/strikethrough.docx");
+ return mammoth.convertToHtml({path: docxPath}, {styleMap: "strike => del"}).then(function(result) {
+ assert.equal(result.value, "<p><del>Today's Special: Salmon</del> Sold out</p>");
+ });
+});
+
+test('indentation is used if prettyPrint is true', function() {
+ var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
+ return mammoth.convertToHtml({path: docxPath}, {prettyPrint: true}).then(function(result) {
+ assert.equal(result.value, "<p>\n Walking on imported air\n</p>");
+ assert.deepEqual(result.messages, []);
+ });
+});
+
+test('using styleMapping throws error', function() {
+ try {
+ mammoth.styleMapping();
+ } catch (error) {
+ assert.equal(
+ error.message,
+ 'Use a raw string instead of mammoth.styleMapping e.g. "p[style-name=\'Title\'] => h1" instead of mammoth.styleMapping("p[style-name=\'Title\'] => h1")'
+ );
+ }
+});
+
+test('can convert single paragraph to markdown', function() {
+ var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
+ return mammoth.convertToMarkdown({path: docxPath}).then(function(result) {
+ assert.equal(result.value, "Walking on imported air\n\n");
+ assert.deepEqual(result.messages, []);
+ });
+});
+
+test('extractRawText only retains raw text', function() {
+ var docxPath = path.join(__dirname, "test-data/simple-list.docx");
+ return mammoth.extractRawText({path: docxPath}).then(function(result) {
+ assert.equal(result.value, 'Apple\n\nBanana\n\n');
});
-
- test('can convert single paragraph to markdown', function() {
- var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
- return mammoth.convertToMarkdown({path: docxPath}).then(function(result) {
+});
+
+test('extractRawText can use .docx files represented by a Buffer', function() {
+ var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
+ return promises.nfcall(fs.readFile, docxPath)
+ .then(function(buffer) {
+ return mammoth.extractRawText({buffer: buffer});
+ })
+ .then(function(result) {
assert.equal(result.value, "Walking on imported air\n\n");
assert.deepEqual(result.messages, []);
});
- });
+});
- test('extractRawText only retains raw text', function() {
- var docxPath = path.join(__dirname, "test-data/simple-list.docx");
- return mammoth.extractRawText({path: docxPath}).then(function(result) {
- assert.equal(result.value, 'Apple\n\nBanana\n\n');
- });
- });
-
- test('extractRawText can use .docx files represented by a Buffer', function() {
- var docxPath = path.join(__dirname, "test-data/single-paragraph.docx");
- return promises.nfcall(fs.readFile, docxPath)
- .then(function(buffer) {
- return mammoth.extractRawText({buffer: buffer});
- })
- .then(function(result) {
- assert.equal(result.value, "Walking on imported air\n\n");
- assert.deepEqual(result.messages, []);
- });
+
+test('should throw error if file is not a valid docx document', function() {
+ var docxPath = path.join(__dirname, "test-data/empty.zip");
+ return mammoth.convertToHtml({path: docxPath}).then(function(result) {
+ assert.ok(false, "Expected error");
+ }, function(error) {
+ assert.equal(error.message, "Could not find word/document.xml in ZIP file. Are you sure this is a valid .docx file?");
});
});
diff --git a/test/options-reader.tests.js b/test/options-reader.tests.js
index 94c864c..06e0764 100644
--- a/test/options-reader.tests.js
+++ b/test/options-reader.tests.js
@@ -3,46 +3,45 @@ var assert = require("assert");
var optionsReader = require("../lib/options-reader");
var standardOptions = optionsReader._standardOptions;
var readOptions = optionsReader.readOptions;
+var test = require("./test")(module);
-describe('readOptions', function() {
- it('standard options are used if options is undefined', function() {
- assert.deepEqual(standardOptions, readOptions(undefined));
- });
-
- it('standard options are used if options is empty', function() {
- assert.deepEqual(standardOptions, readOptions({}));
- });
-
- it('custom style map as string is prepended to standard style map', function() {
- var options = readOptions({
- styleMap: "p.SectionTitle => h2"
- });
- assert.deepEqual("p.SectionTitle => h2", options.styleMap[0]);
- assert.deepEqual(standardOptions.styleMap, options.styleMap.slice(1));
+test('standard options are used if options is undefined', function() {
+ assert.deepEqual(standardOptions, readOptions(undefined));
+});
+
+test('standard options are used if options is empty', function() {
+ assert.deepEqual(standardOptions, readOptions({}));
+});
+
+test('custom style map as string is prepended to standard style map', function() {
+ var options = readOptions({
+ styleMap: "p.SectionTitle => h2"
});
-
- it('custom style map as array is prepended to standard style map', function() {
- var options = readOptions({
- styleMap: ["p.SectionTitle => h2"]
- });
- assert.deepEqual("p.SectionTitle => h2", options.styleMap[0]);
- assert.deepEqual(standardOptions.styleMap, options.styleMap.slice(1));
+ assert.deepEqual("p.SectionTitle => h2", options.styleMap[0]);
+ assert.deepEqual(standardOptions.styleMap, options.styleMap.slice(1));
+});
+
+test('custom style map as array is prepended to standard style map', function() {
+ var options = readOptions({
+ styleMap: ["p.SectionTitle => h2"]
});
-
- it('lines starting with # in custom style map are ignored', function() {
- var options = readOptions({
- styleMap: "# p.SectionTitle => h3\np.SectionTitle => h2"
- });
- assert.deepEqual("p.SectionTitle => h2", options.styleMap[0]);
- assert.deepEqual(standardOptions.styleMap, options.styleMap.slice(1));
+ assert.deepEqual("p.SectionTitle => h2", options.styleMap[0]);
+ assert.deepEqual(standardOptions.styleMap, options.styleMap.slice(1));
+});
+
+test('lines starting with # in custom style map are ignored', function() {
+ var options = readOptions({
+ styleMap: "# p.SectionTitle => h3\np.SectionTitle => h2"
});
-
- it('default style mappings are ignored if includeDefaultStyleMap is false', function() {
- var options = readOptions({
- styleMap: "p.SectionTitle => h2",
- includeDefaultStyleMap: false
- });
- assert.deepEqual(["p.SectionTitle => h2"], options.styleMap);
+ assert.deepEqual("p.SectionTitle => h2", options.styleMap[0]);
+ assert.deepEqual(standardOptions.styleMap, options.styleMap.slice(1));
+});
+
+test('default style mappings are ignored if includeDefaultStyleMap is false', function() {
+ var options = readOptions({
+ styleMap: "p.SectionTitle => h2",
+ includeDefaultStyleMap: false
});
+ assert.deepEqual(["p.SectionTitle => h2"], options.styleMap);
});
diff --git a/test/results.tests.js b/test/results.tests.js
index 3c0df78..2ce470b 100644
--- a/test/results.tests.js
+++ b/test/results.tests.js
@@ -2,16 +2,14 @@ var assert = require("assert");
var results = require("../lib/results");
var Result = results.Result;
-var test = require("./testing").test;
+var test = require("./test")(module);
-describe("Result.combine", function() {
- test("removes any duplicate messages", function() {
- var first = new Result(null, [results.warning("Warning...")]);
- var second = new Result(null, [results.warning("Warning...")]);
-
- var combined = Result.combine([first, second]);
-
- assert.deepEqual(combined.messages, [results.warning("Warning...")]);
- });
+test("Result.combine removes any duplicate messages", function() {
+ var first = new Result(null, [results.warning("Warning...")]);
+ var second = new Result(null, [results.warning("Warning...")]);
+
+ var combined = Result.combine([first, second]);
+
+ assert.deepEqual(combined.messages, [results.warning("Warning...")]);
});
diff --git a/test/style-reader.tests.js b/test/style-reader.tests.js
index 7265e8f..19f9c00 100644
--- a/test/style-reader.tests.js
+++ b/test/style-reader.tests.js
@@ -3,7 +3,7 @@ var htmlPaths = require("../lib/html-paths");
var documentMatchers = require("../lib/document-matchers");
var styleReader = require("../lib/style-reader");
var results = require("../lib/results");
-var test = require("./testing").test;
+var test = require("./test")(module);
var readHtmlPath = styleReader.readHtmlPath;
@@ -11,136 +11,140 @@ var readDocumentMatcher = styleReader.readDocumentMatcher;
var readStyle = styleReader.readStyle;
-describe('styleReader.readHtmlPath', function() {
- test('reads empty path', function() {
+test('styleReader.readHtmlPath', {
+ 'reads empty path': function() {
assertHtmlPath("", htmlPaths.empty);
- });
+ },
- test('reads single element', function() {
+ 'reads single element': function() {
assertHtmlPath("p", htmlPaths.elements(["p"]));
- });
+ },
- test('reads choice of elements', function() {
+ 'reads choice of elements': function() {
assertHtmlPath(
"ul|ol",
htmlPaths.elements([
htmlPaths.element(["ul", "ol"])
])
);
- });
+ },
- test('reads nested elements', function() {
+ 'reads nested elements': function() {
assertHtmlPath("ul > li", htmlPaths.elements(["ul", "li"]));
- });
+ },
- test('reads class on element', function() {
+ 'reads class on element': function() {
var expected = htmlPaths.elements([
htmlPaths.element("p", {"class": "tip"})
]);
assertHtmlPath("p.tip", expected);
- });
+ },
- test('reads multiple classes on element', function() {
+ 'reads multiple classes on element': function() {
var expected = htmlPaths.elements([
htmlPaths.element("p", {"class": "tip help"})
]);
assertHtmlPath("p.tip.help", expected);
- });
+ },
- test('reads when element must be fresh', function() {
+ 'reads when element must be fresh': function() {
var expected = htmlPaths.elements([
htmlPaths.element("p", {}, {"fresh": true})
]);
assertHtmlPath("p:fresh", expected);
- });
+ },
- function assertHtmlPath(input, expected) {
- assert.deepEqual(readHtmlPath(input), results.success(expected));
+ 'reads ignore element': function() {
+ assertHtmlPath("!", htmlPaths.ignore);
}
});
-describe("styleReader.readDocumentMatcher", function() {
- test("reads plain paragraph", function() {
+function assertHtmlPath(input, expected) {
+ assert.deepEqual(readHtmlPath(input), results.success(expected));
+}
+
+test("styleReader.readDocumentMatcher", {
+ "reads plain paragraph": function() {
assertDocumentMatcher("p", documentMatchers.paragraph());
- });
+ },
- test("reads paragraph with style ID", function() {
+ "reads paragraph with style ID": function() {
assertDocumentMatcher(
"p.Heading1",
documentMatchers.paragraph({styleId: "Heading1"})
);
- });
+ },
- test("reads paragraph with style name", function() {
+ "reads paragraph with style name": function() {
assertDocumentMatcher(
"p[style-name='Heading 1']",
documentMatchers.paragraph({styleName: "Heading 1"})
);
- });
+ },
- test("reads p:ordered-list(1) as ordered list with index of 0", function() {
+ "reads p:ordered-list(1) as ordered list with index of 0": function() {
assertDocumentMatcher(
"p:ordered-list(1)",
documentMatchers.paragraph({list: {isOrdered: true, levelIndex: 0}})
);
- });
+ },
- test("reads p:unordered-list(1) as unordered list with index of 0", function() {
+ "reads p:unordered-list(1) as unordered list with index of 0": function() {
assertDocumentMatcher(
"p:unordered-list(1)",
documentMatchers.paragraph({list: {isOrdered: false, levelIndex: 0}})
);
- });
+ },
- test("reads plain run", function() {
+ "reads plain run": function() {
assertDocumentMatcher(
"r",
documentMatchers.run()
);
- });
+ },
- test("reads bold", function() {
+ "reads bold": function() {
assertDocumentMatcher(
"b",
documentMatchers.bold
);
- });
+ },
- test("reads italic", function() {
+ "reads italic": function() {
assertDocumentMatcher(
"i",
documentMatchers.italic
);
- });
+ },
- test("reads underline", function() {
+ "reads underline": function() {
assertDocumentMatcher(
"u",
documentMatchers.underline
);
- });
+ },
- test("reads strikethrough", function() {
+ "reads strikethrough": function() {
assertDocumentMatcher(
"strike",
documentMatchers.strikethrough
);
- });
+ },
- test("reads comment-reference", function() {
+ "reads comment-reference": function() {
assertDocumentMatcher(
"comment-reference",
documentMatchers.commentReference
);
- });
-
- function assertDocumentMatcher(input, expected) {
- assert.deepEqual(readDocumentMatcher(input), results.success(expected));
}
});
+
+function assertDocumentMatcher(input, expected) {
+ assert.deepEqual(readDocumentMatcher(input), results.success(expected));
+}
-describe("styleReader.read", function() {
- test("document matcher is mapped to HTML path using arrow", function() {
+test("styleReader.read", {
+ "document matcher is mapped to HTML path using arrow": function() {
assertStyleMapping(
"p => h1",
{
@@ -148,9 +152,9 @@ describe("styleReader.read", function() {
to: htmlPaths.elements(["h1"])
}
);
- });
+ },
- test("reads style mapping with no HTML path", function() {
+ "reads style mapping with no HTML path": function() {
assertStyleMapping(
"r =>",
{
@@ -158,9 +162,9 @@ describe("styleReader.read", function() {
to: htmlPaths.empty
}
);
- });
-
- function assertStyleMapping(input, expected) {
- assert.deepEqual(readStyle(input), results.success(expected));
}
});
+
+function assertStyleMapping(input, expected) {
+ assert.deepEqual(readStyle(input), results.success(expected));
+}
diff --git a/test/test-data/comments.docx b/test/test-data/comments.docx
new file mode 100755
index 0000000..32cdae1
--- /dev/null
+++ b/test/test-data/comments.docx
Binary files differ
diff --git a/test/test-data/empty.zip b/test/test-data/empty.zip
new file mode 100644
index 0000000..15cb0ec
--- /dev/null
+++ b/test/test-data/empty.zip
Binary files differ
diff --git a/test/testing.js b/test/testing.js
index d70f86e..cb37777 100644
--- a/test/testing.js
+++ b/test/testing.js
@@ -3,22 +3,12 @@ var fs = require("fs");
var promises = require("../lib/promises");
var _ = require("underscore");
-exports.test = test;
exports.testPath = testPath;
exports.testData = testData;
exports.createFakeDocxFile = createFakeDocxFile;
exports.createFakeFiles = createFakeFiles;
-function test(name, func) {
- it(name, function(done) {
- var result = func();
- promises.when(result).then(function() {
- done();
- }).done();
- });
-}
-
function testPath(filename) {
return path.join(__dirname, "test-data", filename);
}
diff --git a/test/unzip.tests.js b/test/unzip.tests.js
index 994fb68..4e1bd61 100644
--- a/test/unzip.tests.js
+++ b/test/unzip.tests.js
@@ -2,39 +2,37 @@ var fs = require("fs");
var assert = require("assert");
var path = require("path");
-var test = require("./testing").test;
+var test = require("./test")(module);
var unzip = require("../lib/unzip");
var promises = require("../lib/promises");
-describe("unzip", function() {
- test("unzip fails if given empty object", function() {
- return unzip.openZip({}).then(function() {
- assert.ok(false, "Expected failure");
- }, function(error) {
- assert.equal("Could not find file in options", error.message);
- });
+test("unzip fails if given empty object", function() {
+ return unzip.openZip({}).then(function() {
+ assert.ok(false, "Expected failure");
+ }, function(error) {
+ assert.equal("Could not find file in options", error.message);
+ });
+});
+
+test("unzip can open local zip file", function() {
+ var zipPath = path.join(__dirname, "test-data/hello.zip");
+ return unzip.openZip({path: zipPath}).then(function(zipFile) {
+ return zipFile.read("hello", "utf8");
+ }).then(function(contents) {
+ assert.equal(contents, "Hello world\n");
});
-
- test("unzip can open local zip file", function() {
- var zipPath = path.join(__dirname, "test-data/hello.zip");
- return unzip.openZip({path: zipPath}).then(function(zipFile) {
+});
+
+test('unzip can open Buffer', function() {
+ var zipPath = path.join(__dirname, "test-data/hello.zip");
+ return promises.nfcall(fs.readFile, zipPath)
+ .then(function(buffer) {
+ return unzip.openZip({buffer: buffer});
+ })
+ .then(function(zipFile) {
return zipFile.read("hello", "utf8");
- }).then(function(contents) {
+ })
+ .then(function(contents) {
assert.equal(contents, "Hello world\n");
});
- });
-
- test('unzip can open Buffer', function() {
- var zipPath = path.join(__dirname, "test-data/hello.zip");
- return promises.nfcall(fs.readFile, zipPath)
- .then(function(buffer) {
- return unzip.openZip({buffer: buffer});
- })
- .then(function(zipFile) {
- return zipFile.read("hello", "utf8");
- })
- .then(function(contents) {
- assert.equal(contents, "Hello world\n");
- });
- });
});
diff --git a/test/writers/html-writer.tests.js b/test/writers/html-writer.tests.js
index 41d8839..b5cdf4e 100644
--- a/test/writers/html-writer.tests.js
+++ b/test/writers/html-writer.tests.js
@@ -1,117 +1,115 @@
var assert = require("assert");
-var test = require("../testing").test;
+var test = require("../test")(module);
var htmlWriter = require("../../lib/writers/html-writer");
-describe('html-writer', function() {
- test('can generate simple paragraph', function() {
- var writer = htmlWriter.writer();
- writer.open("p");
- writer.text("Hello");
- writer.close("p");
- return assert.equal(writer.asString(), "<p>Hello</p>");
- });
-
- test('can nest elements', function() {
- var writer = htmlWriter.writer();
- writer.open("ul");
- writer.open("li");
- writer.text("One");
- writer.close("li");
- writer.open("li");
- writer.text("Two");
- writer.close("li");
- writer.close("ul");
- return assert.equal(writer.asString(), "<ul><li>One</li><li>Two</li></ul>");
- });
-
- test('indents text if prettyPrint is true', function() {
- var writer = htmlWriter.writer({prettyPrint: true});
- writer.open("p");
- writer.text("One");
- writer.close("p");
- writer.open("p");
- writer.text("Two");
- writer.close("p");
- return assert.equal(writer.asString(), "<p>\n One\n</p>\n<p>\n Two\n</p>");
- });
-
- test('indents element if prettyPrint is true', function() {
- var writer = htmlWriter.writer({prettyPrint: true});
- writer.open("ul");
- writer.open("li");
- writer.text("One");
- writer.close("li");
- writer.open("li");
- writer.text("Two");
- writer.close("li");
- writer.close("ul");
- return assert.equal(writer.asString(), "<ul>\n <li>\n One\n </li>\n <li>\n Two\n </li>\n</ul>");
- });
-
- test('when prettyPrint is true inner elements do not have new lines', function() {
- var writer = htmlWriter.writer({prettyPrint: true});
- writer.open("p");
- writer.text("One");
- writer.open("em");
- writer.text("Two");
- writer.close("em");
- writer.close("p");
- return assert.equal(writer.asString(), "<p>\n One<em>Two</em>\n</p>");
- });
-
- test('indents closing element correctly when nested inside another indented element', function() {
- var writer = htmlWriter.writer({prettyPrint: true});
- writer.open("div");
- writer.open("div");
- writer.open("div");
- writer.text("Hello");
- writer.close("div");
- writer.close("div");
- writer.close("div");
- return assert.equal(writer.asString(), "<div>\n <div>\n <div>\n Hello\n </div>\n </div>\n</div>");
- });
-
- test('newlines in text are indented', function() {
- var writer = htmlWriter.writer({prettyPrint: true});
- writer.open("p");
- writer.text("One\nTwo");
- writer.close("p");
- return assert.equal(writer.asString(), "<p>\n One\n Two\n</p>");
- });
-
- test('run of text has only one new line', function() {
- var writer = htmlWriter.writer({prettyPrint: true});
- writer.open("p");
- writer.text("One");
- writer.text("Two");
- writer.close("p");
- return assert.equal(writer.asString(), "<p>\n OneTwo\n</p>");
- });
-
- test('run of html has only one new line', function() {
- var writer = htmlWriter.writer({prettyPrint: true});
- writer.open("p");
- writer.append("One");
- writer.append("Two");
- writer.close("p");
- return assert.equal(writer.asString(), "<p>\n OneTwo\n</p>");
- });
-
- test('self closing elements are indented', function() {
- var writer = htmlWriter.writer({prettyPrint: true});
- writer.open("p");
- writer.selfClosing("br");
- writer.close("p");
- return assert.equal(writer.asString(), "<p>\n <br />\n</p>");
- });
-
- test('newlines in appended HTML are indented', function() {
- var writer = htmlWriter.writer({prettyPrint: true});
- writer.open("p");
- writer.append("One\nTwo");
- writer.close("p");
- return assert.equal(writer.asString(), "<p>\n One\n Two\n</p>");
- });
+test('can generate simple paragraph', function() {
+ var writer = htmlWriter.writer();
+ writer.open("p");
+ writer.text("Hello");
+ writer.close("p");
+ return assert.equal(writer.asString(), "<p>Hello</p>");
+});
+
+test('can nest elements', function() {
+ var writer = htmlWriter.writer();
+ writer.open("ul");
+ writer.open("li");
+ writer.text("One");
+ writer.close("li");
+ writer.open("li");
+ writer.text("Two");
+ writer.close("li");
+ writer.close("ul");
+ return assert.equal(writer.asString(), "<ul><li>One</li><li>Two</li></ul>");
+});
+
+test('indents text if prettyPrint is true', function() {
+ var writer = htmlWriter.writer({prettyPrint: true});
+ writer.open("p");
+ writer.text("One");
+ writer.close("p");
+ writer.open("p");
+ writer.text("Two");
+ writer.close("p");
+ return assert.equal(writer.asString(), "<p>\n One\n</p>\n<p>\n Two\n</p>");
+});
+
+test('indents element if prettyPrint is true', function() {
+ var writer = htmlWriter.writer({prettyPrint: true});
+ writer.open("ul");
+ writer.open("li");
+ writer.text("One");
+ writer.close("li");
+ writer.open("li");
+ writer.text("Two");
+ writer.close("li");
+ writer.close("ul");
+ return assert.equal(writer.asString(), "<ul>\n <li>\n One\n </li>\n <li>\n Two\n </li>\n</ul>");
+});
+
+test('when prettyPrint is true inner elements do not have new lines', function() {
+ var writer = htmlWriter.writer({prettyPrint: true});
+ writer.open("p");
+ writer.text("One");
+ writer.open("em");
+ writer.text("Two");
+ writer.close("em");
+ writer.close("p");
+ return assert.equal(writer.asString(), "<p>\n One<em>Two</em>\n</p>");
+});
+
+test('indents closing element correctly when nested inside another indented element', function() {
+ var writer = htmlWriter.writer({prettyPrint: true});
+ writer.open("div");
+ writer.open("div");
+ writer.open("div");
+ writer.text("Hello");
+ writer.close("div");
+ writer.close("div");
+ writer.close("div");
+ return assert.equal(writer.asString(), "<div>\n <div>\n <div>\n Hello\n </div>\n </div>\n</div>");
+});
+
+test('newlines in text are indented', function() {
+ var writer = htmlWriter.writer({prettyPrint: true});
+ writer.open("p");
+ writer.text("One\nTwo");
+ writer.close("p");
+ return assert.equal(writer.asString(), "<p>\n One\n Two\n</p>");
+});
+
+test('run of text has only one new line', function() {
+ var writer = htmlWriter.writer({prettyPrint: true});
+ writer.open("p");
+ writer.text("One");
+ writer.text("Two");
+ writer.close("p");
+ return assert.equal(writer.asString(), "<p>\n OneTwo\n</p>");
+});
+
+test('run of html has only one new line', function() {
+ var writer = htmlWriter.writer({prettyPrint: true});
+ writer.open("p");
+ writer.append("One");
+ writer.append("Two");
+ writer.close("p");
+ return assert.equal(writer.asString(), "<p>\n OneTwo\n</p>");
+});
+
+test('self closing elements are indented', function() {
+ var writer = htmlWriter.writer({prettyPrint: true});
+ writer.open("p");
+ writer.selfClosing("br");
+ writer.close("p");
+ return assert.equal(writer.asString(), "<p>\n <br />\n</p>");
+});
+
+test('newlines in appended HTML are indented', function() {
+ var writer = htmlWriter.writer({prettyPrint: true});
+ writer.open("p");
+ writer.append("One\nTwo");
+ writer.close("p");
+ return assert.equal(writer.asString(), "<p>\n One\n Two\n</p>");
});
diff --git a/test/writers/markdown-writer.tests.js b/test/writers/markdown-writer.tests.js
index 38d2afe..6d078c5 100644
--- a/test/writers/markdown-writer.tests.js
+++ b/test/writers/markdown-writer.tests.js
@@ -1,306 +1,304 @@
var assert = require("assert");
-var test = require("../testing").test;
+var test = require("../test")(module);
var mdWriter = require("../../lib/writers/markdown-writer");
-describe('markdown-writer', function() {
- test('special markdown characters are escaped', function() {
- var writer = mdWriter.writer();
- writer.text("\\*");
- return assert.equal(writer.asString(), "\\\\\\*");
- });
-
- test('unrecognised elements are treated as normal text', function() {
- var writer = mdWriter.writer();
- writer.open("blah");
- writer.text("Hello");
- writer.close("blah");
- return assert.equal(writer.asString(), "Hello");
- });
-
- test('paragraphs are terminated with double new line', function() {
- var writer = mdWriter.writer();
- writer.open("p");
- writer.text("Hello");
- writer.close("p");
- return assert.equal(writer.asString(), "Hello\n\n");
- });
-
- test('h1 elements are converted to heading with leading hash', function() {
- var writer = mdWriter.writer();
- writer.open("h1");
- writer.text("Hello");
- writer.close("h1");
- return assert.equal(writer.asString(), "# Hello\n\n");
- });
-
- test('h6 elements are converted to heading with six leading hashes', function() {
- var writer = mdWriter.writer();
- writer.open("h6");
- writer.text("Hello");
- writer.close("h6");
- return assert.equal(writer.asString(), "###### Hello\n\n");
- });
-
- test('br is written as two spaces followed by new line', function() {
- var writer = mdWriter.writer();
- writer.text("Hello World");
- writer.selfClosing("br");
- return assert.equal(writer.asString(), "Hello World \n");
- });
-
- test('strong text is surrounded by two underscores', function() {
- var writer = mdWriter.writer();
- writer.text("Hello ");
- writer.open("strong");
- writer.text("World");
- writer.close("strong");
- return assert.equal(writer.asString(), "Hello __World__");
- });
-
- test('emphasised text is surrounded by one asterix', function() {
- var writer = mdWriter.writer();
- writer.text("Hello ");
- writer.open("em");
- writer.text("World");
- writer.close("em");
- return assert.equal(writer.asString(), "Hello *World*");
- });
-
- test('anchor tags are written as hyperlinks', function() {
- var writer = mdWriter.writer();
- writer.open("a", {"href": "http://example.com"});
- writer.text("Hello");
- writer.close("a");
- return assert.equal(writer.asString(), "[Hello](http://example.com)");
- });
-
- test('anchor tags without href attribute are treated as ordinary text', function() {
- var writer = mdWriter.writer();
- writer.open("a");
- writer.text("Hello");
- writer.close("a");
- return assert.equal(writer.asString(), "Hello");
- });
-
- test('elements with IDs have anchor tags with IDs appended to start of markdown element', function() {
- var writer = mdWriter.writer();
- writer.open("h1", {id: "start"});
- writer.text("Hello");
- writer.close("h1");
- return assert.equal(writer.asString(), '# <a id="start"></a>Hello\n\n');
- });
-
- test('links have anchors before opening square bracket', function() {
- var writer = mdWriter.writer();
- writer.open("a", {href: "http://example.com", id: "start"});
- writer.text("Hello");
- writer.close("a");
- return assert.equal(writer.asString(), '<a id="start"></a>[Hello](http://example.com)');
- });
-
- test('can generate images', function() {
- var writer = mdWriter.writer();
- writer.selfClosing("img", {"src": "http://example.com/image.jpg", "alt": "Alt Text"});
- return assert.equal(writer.asString(), "![Alt Text](http://example.com/image.jpg)");
- });
-
- test('can generate images with missing alt attribute', function() {
- var writer = mdWriter.writer();
- writer.selfClosing("img", {"src": "http://example.com/image.jpg"});
- return assert.equal(writer.asString(), "![](http://example.com/image.jpg)");
- });
-
- test('can generate images with missing src attribute', function() {
- var writer = mdWriter.writer();
- writer.selfClosing("img", {"alt": "Alt Text"});
- return assert.equal(writer.asString(), "![Alt Text]()");
- });
-
- test("doesn't display empty images", function() {
- var writer = mdWriter.writer();
- writer.selfClosing("img");
- return assert.equal(writer.asString(), "");
- });
-
- test('list item outside of list is treated as unordered list', function() {
- var writer = mdWriter.writer();
- writer.open("li");
- writer.text("Hello");
- writer.close("li");
- return assert.equal(writer.asString(), "- Hello\n");
- });
-
- test('can generate an ordered list', function() {
- var writer = mdWriter.writer();
- writer.open("ol");
- writer.open("li");
- writer.text("Hello");
- writer.close("li");
- writer.open("li");
- writer.text("World");
- writer.close("li");
- writer.close("ol");
- return assert.equal(writer.asString(), "1. Hello\n2. World\n\n");
- });
-
- test('can generate an unordered list', function() {
- var writer = mdWriter.writer();
- writer.open("ul");
- writer.open("li");
- writer.text("Hello");
- writer.close("li");
- writer.open("li");
- writer.text("World");
- writer.close("li");
- writer.close("ul");
- return assert.equal(writer.asString(), "- Hello\n- World\n\n");
- });
-
- test('can generate a nested ordered list with correct numbering', function() {
- var writer = mdWriter.writer();
- writer.open("ol");
- writer.open("li");
- writer.text("Outer One");
-
- writer.open("ol");
- writer.open("li");
- writer.text("Nested One");
- writer.close("li");
- writer.open("li");
- writer.text("Nested Two");
- writer.close("li");
- writer.close("ol");
-
- writer.close("li");
- writer.open("li");
- writer.text("Outer Two");
- writer.close("li");
- writer.close("ol");
- return assert.equal(writer.asString(), "1. Outer One\n\t1. Nested One\n\t2. Nested Two\n2. Outer Two\n\n");
- });
-
- test('can generate a multi-level nested ordered list', function() {
- var writer = mdWriter.writer();
- writer.open("ol");
- writer.open("li");
- writer.text("Outer One");
-
- writer.open("ol");
- writer.open("li");
- writer.text("Nested One");
-
- writer.open("ol");
- writer.open("li");
- writer.text("Inner One");
- writer.close("li");
- writer.close("ol");
-
- writer.close("li");
- writer.close("ol");
-
- writer.close("li");
- writer.close("ol");
- return assert.equal(writer.asString(), "1. Outer One\n\t1. Nested One\n\t\t1. Inner One\n\n");
- });
-
- test('new ordered list resets numbering', function() {
- var writer = mdWriter.writer();
- writer.open("ol");
- writer.open("li");
- writer.text("First");
- writer.close("li");
- writer.close("ol");
-
- writer.open("p");
- writer.text("Hello");
- writer.close("p");
-
- writer.open("ol");
- writer.open("li");
- writer.text("Second");
- writer.close("li");
- writer.close("ol");
-
- return assert.equal(writer.asString(), "1. First\n\nHello\n\n1. Second\n\n");
- });
-
- test('can generate a nested unordered list', function() {
- var writer = mdWriter.writer();
- writer.open("ul");
- writer.open("li");
- writer.text("Outer One");
-
- writer.open("ul");
- writer.open("li");
- writer.text("Nested One");
- writer.close("li");
- writer.open("li");
- writer.text("Nested Two");
- writer.close("li");
- writer.close("ul");
-
- writer.close("li");
- writer.open("li");
- writer.text("Outer Two");
- writer.close("li");
- writer.close("ul");
- return assert.equal(writer.asString(), "- Outer One\n\t- Nested One\n\t- Nested Two\n- Outer Two\n\n");
- });
-
- test('can nest inline elements', function() {
- var writer = mdWriter.writer();
- writer.open("p");
- writer.text("Lorem ");
- writer.open("strong");
- writer.text("ipsum ");
- writer.open("em");
- writer.text("dolor");
- writer.close("em");
- writer.text(" sit");
- writer.close("strong");
- writer.text(" amet");
- writer.close("p");
- return assert.equal(writer.asString(), "Lorem __ipsum *dolor* sit__ amet\n\n");
- });
-
- test('can emphasise list text', function() {
- var writer = mdWriter.writer();
- writer.open("ol");
- writer.open("li");
- writer.text("Hello ");
- writer.open("strong");
- writer.text("Strong");
- writer.close("strong");
- writer.text(" World");
- writer.close("li");
- writer.open("li");
- writer.text("Hello ");
- writer.open("em");
- writer.text("Emphasis");
- writer.close("em");
- writer.text(" World");
- writer.close("li");
- writer.close("ol");
- return assert.equal(writer.asString(), "1. Hello __Strong__ World\n2. Hello *Emphasis* World\n\n");
- });
-
- test('generates correct spacing between paragraphs and lists', function() {
- var writer = mdWriter.writer();
- writer.open("p");
- writer.text("Hello World");
- writer.close("p");
- writer.open("ul");
- writer.open("li");
- writer.text("First Item");
- writer.close("li");
- writer.open("li");
- writer.text("Second Item");
- writer.close("li");
- writer.close("ul");
- writer.open("p");
- writer.text("Hello World");
- writer.close("p");
- return assert.equal(writer.asString(), "Hello World\n\n- First Item\n- Second Item\n\nHello World\n\n");
- });
+test('special markdown characters are escaped', function() {
+ var writer = mdWriter.writer();
+ writer.text("\\*");
+ return assert.equal(writer.asString(), "\\\\\\*");
+});
+
+test('unrecognised elements are treated as normal text', function() {
+ var writer = mdWriter.writer();
+ writer.open("blah");
+ writer.text("Hello");
+ writer.close("blah");
+ return assert.equal(writer.asString(), "Hello");
+});
+
+test('paragraphs are terminated with double new line', function() {
+ var writer = mdWriter.writer();
+ writer.open("p");
+ writer.text("Hello");
+ writer.close("p");
+ return assert.equal(writer.asString(), "Hello\n\n");
+});
+
+test('h1 elements are converted to heading with leading hash', function() {
+ var writer = mdWriter.writer();
+ writer.open("h1");
+ writer.text("Hello");
+ writer.close("h1");
+ return assert.equal(writer.asString(), "# Hello\n\n");
+});
+
+test('h6 elements are converted to heading with six leading hashes', function() {
+ var writer = mdWriter.writer();
+ writer.open("h6");
+ writer.text("Hello");
+ writer.close("h6");
+ return assert.equal(writer.asString(), "###### Hello\n\n");
+});
+
+test('br is written as two spaces followed by new line', function() {
+ var writer = mdWriter.writer();
+ writer.text("Hello World");
+ writer.selfClosing("br");
+ return assert.equal(writer.asString(), "Hello World \n");
+});
+
+test('strong text is surrounded by two underscores', function() {
+ var writer = mdWriter.writer();
+ writer.text("Hello ");
+ writer.open("strong");
+ writer.text("World");
+ writer.close("strong");
+ return assert.equal(writer.asString(), "Hello __World__");
+});
+
+test('emphasised text is surrounded by one asterix', function() {
+ var writer = mdWriter.writer();
+ writer.text("Hello ");
+ writer.open("em");
+ writer.text("World");
+ writer.close("em");
+ return assert.equal(writer.asString(), "Hello *World*");
+});
+
+test('anchor tags are written as hyperlinks', function() {
+ var writer = mdWriter.writer();
+ writer.open("a", {"href": "http://example.com"});
+ writer.text("Hello");
+ writer.close("a");
+ return assert.equal(writer.asString(), "[Hello](http://example.com)");
+});
+
+test('anchor tags without href attribute are treated as ordinary text', function() {
+ var writer = mdWriter.writer();
+ writer.open("a");
+ writer.text("Hello");
+ writer.close("a");
+ return assert.equal(writer.asString(), "Hello");
+});
+
+test('elements with IDs have anchor tags with IDs appended to start of markdown element', function() {
+ var writer = mdWriter.writer();
+ writer.open("h1", {id: "start"});
+ writer.text("Hello");
+ writer.close("h1");
+ return assert.equal(writer.asString(), '# <a id="start"></a>Hello\n\n');
+});
+
+test('links have anchors before opening square bracket', function() {
+ var writer = mdWriter.writer();
+ writer.open("a", {href: "http://example.com", id: "start"});
+ writer.text("Hello");
+ writer.close("a");
+ return assert.equal(writer.asString(), '<a id="start"></a>[Hello](http://example.com)');
+});
+
+test('can generate images', function() {
+ var writer = mdWriter.writer();
+ writer.selfClosing("img", {"src": "http://example.com/image.jpg", "alt": "Alt Text"});
+ return assert.equal(writer.asString(), "![Alt Text](http://example.com/image.jpg)");
+});
+
+test('can generate images with missing alt attribute', function() {
+ var writer = mdWriter.writer();
+ writer.selfClosing("img", {"src": "http://example.com/image.jpg"});
+ return assert.equal(writer.asString(), "![](http://example.com/image.jpg)");
+});
+
+test('can generate images with missing src attribute', function() {
+ var writer = mdWriter.writer();
+ writer.selfClosing("img", {"alt": "Alt Text"});
+ return assert.equal(writer.asString(), "![Alt Text]()");
+});
+
+test("doesn't display empty images", function() {
+ var writer = mdWriter.writer();
+ writer.selfClosing("img");
+ return assert.equal(writer.asString(), "");
+});
+
+test('list item outside of list is treated as unordered list', function() {
+ var writer = mdWriter.writer();
+ writer.open("li");
+ writer.text("Hello");
+ writer.close("li");
+ return assert.equal(writer.asString(), "- Hello\n");
+});
+
+test('can generate an ordered list', function() {
+ var writer = mdWriter.writer();
+ writer.open("ol");
+ writer.open("li");
+ writer.text("Hello");
+ writer.close("li");
+ writer.open("li");
+ writer.text("World");
+ writer.close("li");
+ writer.close("ol");
+ return assert.equal(writer.asString(), "1. Hello\n2. World\n\n");
+});
+
+test('can generate an unordered list', function() {
+ var writer = mdWriter.writer();
+ writer.open("ul");
+ writer.open("li");
+ writer.text("Hello");
+ writer.close("li");
+ writer.open("li");
+ writer.text("World");
+ writer.close("li");
+ writer.close("ul");
+ return assert.equal(writer.asString(), "- Hello\n- World\n\n");
+});
+
+test('can generate a nested ordered list with correct numbering', function() {
+ var writer = mdWriter.writer();
+ writer.open("ol");
+ writer.open("li");
+ writer.text("Outer One");
+
+ writer.open("ol");
+ writer.open("li");
+ writer.text("Nested One");
+ writer.close("li");
+ writer.open("li");
+ writer.text("Nested Two");
+ writer.close("li");
+ writer.close("ol");
+
+ writer.close("li");
+ writer.open("li");
+ writer.text("Outer Two");
+ writer.close("li");
+ writer.close("ol");
+ return assert.equal(writer.asString(), "1. Outer One\n\t1. Nested One\n\t2. Nested Two\n2. Outer Two\n\n");
+});
+
+test('can generate a multi-level nested ordered list', function() {
+ var writer = mdWriter.writer();
+ writer.open("ol");
+ writer.open("li");
+ writer.text("Outer One");
+
+ writer.open("ol");
+ writer.open("li");
+ writer.text("Nested One");
+
+ writer.open("ol");
+ writer.open("li");
+ writer.text("Inner One");
+ writer.close("li");
+ writer.close("ol");
+
+ writer.close("li");
+ writer.close("ol");
+
+ writer.close("li");
+ writer.close("ol");
+ return assert.equal(writer.asString(), "1. Outer One\n\t1. Nested One\n\t\t1. Inner One\n\n");
+});
+
+test('new ordered list resets numbering', function() {
+ var writer = mdWriter.writer();
+ writer.open("ol");
+ writer.open("li");
+ writer.text("First");
+ writer.close("li");
+ writer.close("ol");
+
+ writer.open("p");
+ writer.text("Hello");
+ writer.close("p");
+
+ writer.open("ol");
+ writer.open("li");
+ writer.text("Second");
+ writer.close("li");
+ writer.close("ol");
+
+ return assert.equal(writer.asString(), "1. First\n\nHello\n\n1. Second\n\n");
+});
+
+test('can generate a nested unordered list', function() {
+ var writer = mdWriter.writer();
+ writer.open("ul");
+ writer.open("li");
+ writer.text("Outer One");
+
+ writer.open("ul");
+ writer.open("li");
+ writer.text("Nested One");
+ writer.close("li");
+ writer.open("li");
+ writer.text("Nested Two");
+ writer.close("li");
+ writer.close("ul");
+
+ writer.close("li");
+ writer.open("li");
+ writer.text("Outer Two");
+ writer.close("li");
+ writer.close("ul");
+ return assert.equal(writer.asString(), "- Outer One\n\t- Nested One\n\t- Nested Two\n- Outer Two\n\n");
+});
+
+test('can nest inline elements', function() {
+ var writer = mdWriter.writer();
+ writer.open("p");
+ writer.text("Lorem ");
+ writer.open("strong");
+ writer.text("ipsum ");
+ writer.open("em");
+ writer.text("dolor");
+ writer.close("em");
+ writer.text(" sit");
+ writer.close("strong");
+ writer.text(" amet");
+ writer.close("p");
+ return assert.equal(writer.asString(), "Lorem __ipsum *dolor* sit__ amet\n\n");
+});
+
+test('can emphasise list text', function() {
+ var writer = mdWriter.writer();
+ writer.open("ol");
+ writer.open("li");
+ writer.text("Hello ");
+ writer.open("strong");
+ writer.text("Strong");
+ writer.close("strong");
+ writer.text(" World");
+ writer.close("li");
+ writer.open("li");
+ writer.text("Hello ");
+ writer.open("em");
+ writer.text("Emphasis");
+ writer.close("em");
+ writer.text(" World");
+ writer.close("li");
+ writer.close("ol");
+ return assert.equal(writer.asString(), "1. Hello __Strong__ World\n2. Hello *Emphasis* World\n\n");
+});
+
+test('generates correct spacing between paragraphs and lists', function() {
+ var writer = mdWriter.writer();
+ writer.open("p");
+ writer.text("Hello World");
+ writer.close("p");
+ writer.open("ul");
+ writer.open("li");
+ writer.text("First Item");
+ writer.close("li");
+ writer.open("li");
+ writer.text("Second Item");
+ writer.close("li");
+ writer.close("ul");
+ writer.open("p");
+ writer.text("Hello World");
+ writer.close("p");
+ return assert.equal(writer.asString(), "Hello World\n\n- First Item\n- Second Item\n\nHello World\n\n");
});
diff --git a/test/xml/reader.tests.js b/test/xml/reader.tests.js
index 005753c..6b7d3a0 100644
--- a/test/xml/reader.tests.js
+++ b/test/xml/reader.tests.js
@@ -1,87 +1,85 @@
var assert = require("assert");
var xmlreader = require("../../lib/xml/reader");
-var test = require("../testing").test;
+var test = require("../test")(module);
-describe('xmlreader.readString', function() {
- test('should read self-closing element', function() {
- return xmlreader.readString("<body/>").then(function(result) {
- assert.deepEqual({type: "element", name: "body", attributes: {}, children: []}, result);
- });
+test('should read self-closing element', function() {
+ return xmlreader.readString("<body/>").then(function(result) {
+ assert.deepEqual({type: "element", name: "body", attributes: {}, children: []}, result);
});
-
- test('should read empty element with separate closing tag', function() {
- return xmlreader.readString("<body></body>").then(function(result) {
- assert.deepEqual({type: "element", name: "body", attributes: {}, children: []}, result);
- });
+});
+
+test('should read empty element with separate closing tag', function() {
+ return xmlreader.readString("<body></body>").then(function(result) {
+ assert.deepEqual({type: "element", name: "body", attributes: {}, children: []}, result);
});
-
- test('should read attributes of tags', function() {
- return xmlreader.readString('<body name="bob"/>').then(function(result) {
- assert.deepEqual({name: "bob"}, result.attributes);
- });
+});
+
+test('should read attributes of tags', function() {
+ return xmlreader.readString('<body name="bob"/>').then(function(result) {
+ assert.deepEqual({name: "bob"}, result.attributes);
});
-
- test('can read text element', function() {
- return xmlreader.readString('<body>Hello!</body>').then(function(result) {
- assert.deepEqual({type: "text", value: "Hello!"}, result.children[0]);
- });
+});
+
+test('can read text element', function() {
+ return xmlreader.readString('<body>Hello!</body>').then(function(result) {
+ assert.deepEqual({type: "text", value: "Hello!"}, result.children[0]);
});
-
- test('should read element with children', function() {
- return xmlreader.readString("<body><a/><b/></body>").then(function(root) {
- assert.equal(2, root.children.length);
- assert.equal("a", root.children[0].name);
- assert.equal("b", root.children[1].name);
- });
+});
+
+test('should read element with children', function() {
+ return xmlreader.readString("<body><a/><b/></body>").then(function(root) {
+ assert.equal(2, root.children.length);
+ assert.equal("a", root.children[0].name);
+ assert.equal("b", root.children[1].name);
});
+});
- test('unmapped namespaces URIs are included in braces as prefix', function() {
- return xmlreader.readString('<w:body xmlns:w="word"/>').then(function(result) {
- assert.deepEqual(result.name, "{word}body");
- });
+test('unmapped namespaces URIs are included in braces as prefix', function() {
+ return xmlreader.readString('<w:body xmlns:w="word"/>').then(function(result) {
+ assert.deepEqual(result.name, "{word}body");
});
+});
- test('mapped namespaces URIs are translated using map', function() {
- var namespaceMap = {
- "word": "x"
- };
-
- return xmlreader.readString('<w:body xmlns:w="word"/>', namespaceMap).then(function(result) {
- assert.deepEqual(result.name, "x:body");
- });
+test('mapped namespaces URIs are translated using map', function() {
+ var namespaceMap = {
+ "word": "x"
+ };
+
+ return xmlreader.readString('<w:body xmlns:w="word"/>', namespaceMap).then(function(result) {
+ assert.deepEqual(result.name, "x:body");
});
+});
- test('namespace of attributes is mapped to prefix', function() {
- var namespaceMap = {
- "word": "x"
- };
- var xmlString = '<w:body xmlns:w="word" w:val="Hello!"/>';
- return xmlreader.readString(xmlString, namespaceMap).then(function(result) {
- assert.deepEqual(result.attributes["x:val"], "Hello!");
- });
+test('namespace of attributes is mapped to prefix', function() {
+ var namespaceMap = {
+ "word": "x"
+ };
+ var xmlString = '<w:body xmlns:w="word" w:val="Hello!"/>';
+ return xmlreader.readString(xmlString, namespaceMap).then(function(result) {
+ assert.deepEqual(result.attributes["x:val"], "Hello!");
});
-
- test('can find first element with name', function() {
- return xmlreader.readString('<body><a/><b index="1"/><b index="2"/></body>').then(function(result) {
- var first = result.first("b");
- assert.equal("1", first.attributes.index);
- });
+});
+
+test('can find first element with name', function() {
+ return xmlreader.readString('<body><a/><b index="1"/><b index="2"/></body>').then(function(result) {
+ var first = result.first("b");
+ assert.equal("1", first.attributes.index);
});
-
- test('whitespace between xml declaration and root tag is ignored', function() {
- return xmlreader.readString('<?xml version="1.0" ?>\n<body/>').then(function(result) {
- assert.deepEqual("body", result.name);
- });
+});
+
+test('whitespace between xml declaration and root tag is ignored', function() {
+ return xmlreader.readString('<?xml version="1.0" ?>\n<body/>').then(function(result) {
+ assert.deepEqual("body", result.name);
});
-
- test('error if XML is badly formed', function() {
- return xmlreader.readString("<bo").then(function(result) {
- throw new Error("Expected failure");
- }, function(error) {
- assert.ok(error);
- return 1;
- });
+});
+
+test('error if XML is badly formed', function() {
+ return xmlreader.readString("<bo").then(function(result) {
+ throw new Error("Expected failure");
+ }, function(error) {
+ assert.ok(error);
+ return 1;
});
});
diff --git a/test/xml/writer.tests.js b/test/xml/writer.tests.js
index d41ddc1..0d87cae 100644
--- a/test/xml/writer.tests.js
+++ b/test/xml/writer.tests.js
@@ -2,77 +2,75 @@ var assert = require("assert");
var xml = require("../../lib/xml");
var writer = require("../../lib/xml/writer");
-var test = require("../testing").test;
+var test = require("../test")(module);
-describe('xml.writer', function() {
- test('writing empty root element writes out xml declaration and empty root element', function() {
- assertXmlString(xml.element("root"), {}, '<root/>');
- });
-
- test('can write empty child elements', function() {
- assertXmlString(xml.element("root", {}, [xml.element("album"), xml.element("single")]), {},
- '<root><album/><single/></root>');
- });
-
- test('can write empty descendant elements', function() {
- var element = xml.element("root", {}, [
- xml.element("album", {}, [
- xml.element("year"),
- xml.element("song")
- ])
- ]);
- assertXmlString(element, {},
- '<root><album><year/><song/></album></root>');
- });
-
- test('can write element attributes', function() {
- var element = xml.element("root", {}, [
- xml.element("album", {"title": "Everything in Transit"})
- ]);
- assertXmlString(element, {},
- '<root><album title="Everything in Transit"/></root>');
- });
-
- test('can write text nodes', function() {
- var element = xml.element("root", {}, [
- xml.element("album", {}, [
- xml.text("Everything in Transit")
- ])
- ]);
- assertXmlString(element, {},
- '<root><album>Everything in Transit</album></root>');
- });
-
- test('can write root element with long-form prefix when URI is namespace', function() {
- var element = xml.element("{music}root");
- assertXmlString(element, {"m": "music"},
- '<m:root xmlns:m="music"/>');
- });
-
- test('can write child elements with long-form prefix when URI is namespace', function() {
- var element = xml.element("root", {}, [
- xml.element("{music}album")
- ]);
- assertXmlString(element, {"m": "music"},
- '<root xmlns:m="music"><m:album/></root>');
- });
-
- test('can write child elements with short-form prefix when URI is namespace', function() {
- var element = xml.element("root", {}, [
- xml.element("m:album")
- ]);
- assertXmlString(element, {"m": "music"},
- '<root xmlns:m="music"><m:album/></root>');
- });
-
- test('default namespace has key of empty string', function() {
- var element = xml.element("root", {}, [
- xml.element("{music}album")
- ]);
- assertXmlString(element, {"": "music"},
- '<root xmlns="music"><album/></root>');
- });
+test('writing empty root element writes out xml declaration and empty root element', function() {
+ assertXmlString(xml.element("root"), {}, '<root/>');
+});
+
+test('can write empty child elements', function() {
+ assertXmlString(xml.element("root", {}, [xml.element("album"), xml.element("single")]), {},
+ '<root><album/><single/></root>');
+});
+
+test('can write empty descendant elements', function() {
+ var element = xml.element("root", {}, [
+ xml.element("album", {}, [
+ xml.element("year"),
+ xml.element("song")
+ ])
+ ]);
+ assertXmlString(element, {},
+ '<root><album><year/><song/></album></root>');
+});
+
+test('can write element attributes', function() {
+ var element = xml.element("root", {}, [
+ xml.element("album", {"title": "Everything in Transit"})
+ ]);
+ assertXmlString(element, {},
+ '<root><album title="Everything in Transit"/></root>');
+});
+
+test('can write text nodes', function() {
+ var element = xml.element("root", {}, [
+ xml.element("album", {}, [
+ xml.text("Everything in Transit")
+ ])
+ ]);
+ assertXmlString(element, {},
+ '<root><album>Everything in Transit</album></root>');
+});
+
+test('can write root element with long-form prefix when URI is namespace', function() {
+ var element = xml.element("{music}root");
+ assertXmlString(element, {"m": "music"},
+ '<m:root xmlns:m="music"/>');
+});
+
+test('can write child elements with long-form prefix when URI is namespace', function() {
+ var element = xml.element("root", {}, [
+ xml.element("{music}album")
+ ]);
+ assertXmlString(element, {"m": "music"},
+ '<root xmlns:m="music"><m:album/></root>');
+});
+
+test('can write child elements with short-form prefix when URI is namespace', function() {
+ var element = xml.element("root", {}, [
+ xml.element("m:album")
+ ]);
+ assertXmlString(element, {"m": "music"},
+ '<root xmlns:m="music"><m:album/></root>');
+});
+
+test('default namespace has key of empty string', function() {
+ var element = xml.element("root", {}, [
+ xml.element("{music}album")
+ ]);
+ assertXmlString(element, {"": "music"},
+ '<root xmlns="music"><album/></root>');
});
diff --git a/test/zipfile.tests.js b/test/zipfile.tests.js
index 1a0ab99..c838548 100644
--- a/test/zipfile.tests.js
+++ b/test/zipfile.tests.js
@@ -2,20 +2,18 @@ var assert = require("assert");
var JSZip = require("jszip");
-var test = require("./testing").test;
+var test = require("./test")(module);
var zipfile = require("../lib/zipfile");
-describe("zipfile", function() {
- test('file in zip can be read after being written', function() {
- var zip = emptyZipFile();
- assert(!zip.exists("song/title"));
-
- zip.write("song/title", "Dark Blue");
-
- assert(zip.exists("song/title"));
- return zip.read("song/title", "utf8").then(function(contents) {
- assert.equal(contents, "Dark Blue");
- });
+test('file in zip can be read after being written', function() {
+ var zip = emptyZipFile();
+ assert(!zip.exists("song/title"));
+
+ zip.write("song/title", "Dark Blue");
+
+ assert(zip.exists("song/title"));
+ return zip.read("song/title", "utf8").then(function(contents) {
+ assert.equal(contents, "Dark Blue");
});
});