/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ /** * This file tests the CSS syntax highlighter in the MdnDocsWidget object. * * The CSS syntax highlighter accepts: * - a string containing CSS * - a DOM node * * It parses the string and creates a collection of DOM nodes for different * CSS token types. These DOM nodes have CSS classes applied to them, * to apply the right style for that particular token type. The DOM nodes * are returned as children of the node that was passed to the function. * * This test code defines a number of different strings containing valid and * invalid CSS in various forms. For each string it defines the DOM nodes * that it expects to get from the syntax highlighter. * * It then calls the syntax highlighter, and checks that the resulting * collection of DOM nodes is what we expected. */ "use strict"; const {appendSyntaxHighlightedCSS} = require("devtools/client/shared/widgets/MdnDocsWidget"); /** * An array containing the actual test cases. * * The test code tests every case in the array. If you want to add more * test cases, just add more items to the array. * * Each test case consists of: * - description: string describing the salient features of this test case * - example: the string to test * - expected: an array of objects, one for each DOM node we expect, that * captures the information about the node that we expect to test. */ const TEST_DATA = [{ description: "Valid syntax, string value.", example: "name: stringValue;", expected: [{type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, numeric value.", example: "name: 1;", expected: [{type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "1"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, url value.", example: "name: url(./name);", expected: [{type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "url(./name)"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, space before ':'.", example: "name : stringValue;", expected: [{type: "property-name", text: "name"}, {type: "text", text: " "}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, space before ';'.", example: "name: stringValue ;", expected: [{type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue"}, {type: "text", text: " "}, {type: "text", text: ";"} ]}, { description: "Valid syntax, trailing space.", example: "name: stringValue; ", expected: [{type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue"}, {type: "text", text: ";"}, {type: "text", text: " "} ]}, { description: "Valid syntax, leading space.", example: " name: stringValue;", expected: [{type: "text", text: " "}, {type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, two spaces.", example: "name: stringValue;", expected: [{type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, no spaces.", example: "name:stringValue;", expected: [{type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "property-value", text: "stringValue"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, two-part value.", example: "name: stringValue 1;", expected: [{type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue"}, {type: "text", text: " "}, {type: "property-value", text: "1"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, two declarations.", example: "name: stringValue;\n" + "name: 1;", expected: [{type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue"}, {type: "text", text: ";"}, {type: "text", text: "\n"}, {type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "1"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, commented, numeric value.", example: "/* comment */\n" + "name: 1;", expected: [{type: "comment", text: "/* comment */"}, {type: "text", text: "\n"}, {type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "1"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, multiline commented, string value.", example: "/* multiline \n" + "comment */\n" + "name: stringValue;", expected: [{type: "comment", text: "/* multiline \ncomment */"}, {type: "text", text: "\n"}, {type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, commented, two declarations.", example: "/* comment 1 */\n" + "name: 1;\n" + "/* comment 2 */\n" + "name: stringValue;", expected: [{type: "comment", text: "/* comment 1 */"}, {type: "text", text: "\n"}, {type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "1"}, {type: "text", text: ";"}, {type: "text", text: "\n"}, {type: "comment", text: "/* comment 2 */"}, {type: "text", text: "\n"}, {type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, multiline.", example: "name: \n" + "stringValue;", expected: [{type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " \n"}, {type: "property-value", text: "stringValue"}, {type: "text", text: ";"} ]}, { description: "Valid syntax, multiline, two declarations.", example: "name: \n" + "stringValue \n" + "stringValue2;", expected: [{type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " \n"}, {type: "property-value", text: "stringValue"}, {type: "text", text: " \n"}, {type: "property-value", text: "stringValue2"}, {type: "text", text: ";"} ]}, { description: "Invalid: not CSS at all.", example: "not CSS at all", expected: [{type: "property-name", text: "not"}, {type: "text", text: " "}, {type: "property-name", text: "CSS"}, {type: "text", text: " "}, {type: "property-name", text: "at"}, {type: "text", text: " "}, {type: "property-name", text: "all"} ]}, { description: "Invalid: switched ':' and ';'.", example: "name; stringValue:", expected: [{type: "property-name", text: "name"}, {type: "text", text: ";"}, {type: "text", text: " "}, {type: "property-name", text: "stringValue"}, {type: "text", text: ":"} ]}, { description: "Invalid: unterminated comment.", example: "/* unterminated comment\n" + "name: stringValue;", expected: [{type: "comment", text: "/* unterminated comment\nname: stringValue;"} ]}, { description: "Invalid: bad comment syntax.", example: "// invalid comment\n" + "name: stringValue;", expected: [{type: "text", text: "/"}, {type: "text", text: "/"}, {type: "text", text: " "}, {type: "property-name", text: "invalid"}, {type: "text", text: " "}, {type: "property-name", text: "comment"}, {type: "text", text: "\n"}, {type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue"}, {type: "text", text: ";"} ]}, { description: "Invalid: no trailing ';'.", example: "name: stringValue\n" + "name: stringValue2", expected: [{type: "property-name", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue"}, {type: "text", text: "\n"}, {type: "property-value", text: "name"}, {type: "text", text: ":"}, {type: "text", text: " "}, {type: "property-value", text: "stringValue2"}, ]} ]; /** * Iterate through every test case, calling the syntax highlighter, * then calling a helper function to check the output. */ add_task(function* () { let doc = gBrowser.selectedTab.ownerDocument; let parent = doc.createElement("div"); info("Testing all CSS syntax highlighter test cases"); for (let {description, example, expected} of TEST_DATA) { info("Testing: " + description); appendSyntaxHighlightedCSS(example, parent); checkCssSyntaxHighlighterOutput(expected, parent); while (parent.firstChild) { parent.firstChild.remove(); } } });