0
14 |0
15 |alert("Some message"); should be avoided and
5 | * console.log("Some message"); be used instead.
6 | *
7 | * Implementation notes: This test checks all blocks for the usage of discouraged functions.
8 | * In some cases their usage may not be avoided, like for example on their description pages.
9 | * The test does not account for those cases, though.
10 | */
11 |
12 | docTests.alertPrintInCode = {
13 | name: "alert_print_in_code",
14 | desc: "alert_print_in_code_desc",
15 | check: function checkAlertPrintInCode(rootElement) {
16 | let pres = rootElement.getElementsByTagName("pre");
17 | let matches = [];
18 | for (let i = 0; i < pres.length; i++) {
19 | let preMatches = pres[i].textContent.match(/(?:alert|print|eval|document\.write)\s*\((?:.|\n)+?\)/gi) || [];
20 | matches = matches.concat(mapMatches(preMatches, ERROR));
21 | }
22 |
23 | return matches;
24 | }
25 | };
--------------------------------------------------------------------------------
/test/test-summary-heading.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc summaryHeading"] = function testSummaryHeading(assert, done) {
4 | const tests = [
5 | {
6 | str: 'Summary
' +
7 | 'Summary
' +
8 | 'Summary
' +
9 | 'Summary
',
10 | expected: [
11 | {
12 | msg: 'Summary
',
13 | type: ERROR
14 | },
15 | {
16 | msg: 'Summary
',
17 | type: ERROR
18 | },
19 | {
20 | msg: 'Summary
',
21 | type: ERROR
22 | },
23 | {
24 | msg: 'Summary
',
25 | type: ERROR
26 | }
27 | ],
28 | expectedAfterFixing: []
29 | }
30 | ];
31 |
32 | runTests(assert, done, "summaryHeading", "summary heading", url, tests);
33 | };
34 |
35 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/data/tests/font-elements.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for deprecated elements that should be removed or replaced by other
3 | * elements.
4 | *
5 | * Example 1: Emphasized text should be replaced by
6 | * Emphasized text or Emphasized text.
7 | *
8 | * Example 2: Heading
should be replaced by
9 | * Heading
.
10 | *
11 | * Implementation notes: This test searches for all elements, but doesn't provide
12 | * a hint whether they should be removed or replaced by other elements.
13 | */
14 |
15 | docTests.fontElements = {
16 | name: "font_elements",
17 | desc: "font_elements_desc",
18 | check: function checkFontElements(rootElement) {
19 | let fontElements = rootElement.getElementsByTagName("font");
20 | let matches = [];
21 |
22 | for (let i = 0; i < fontElements.length; i++) {
23 | matches.push({
24 | msg: fontElements[i].outerHTML,
25 | type: ERROR
26 | })
27 | }
28 |
29 | return matches;
30 | }
31 | };
--------------------------------------------------------------------------------
/test/test-alert-print-in-code.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc alertPrintInCode"] = function testAlertPrintInCode(assert, done) {
4 | const tests = [
5 | {
6 | str: 'alert("foo")' +
7 | 'print("bar")' +
8 | 'let someOthercode = baz; ' +
9 | 'alert("hello world"); \n let moreCode;' +
10 | 'document.write("foobar");',
11 | expected: [
12 | {
13 | msg: 'alert("foo")',
14 | type: ERROR
15 | },
16 | {
17 | msg: 'print("bar")',
18 | type: ERROR
19 | },
20 | {
21 | msg: 'alert("hello world")',
22 | type: ERROR
23 | },
24 | {
25 | msg: 'document.write("foobar")',
26 | type: ERROR
27 | }
28 | ]
29 | }
30 | ];
31 |
32 | runTests(assert, done, "alertPrintInCode", "alert()/print()/eval()/document.write()", url, tests);
33 | };
34 |
35 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/test/test-name-attribute.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc nameAttribute"] = function testNameAttributes(assert, done) {
4 | const tests = [
5 | {
6 | str: '' +
7 | '' +
8 | 'foo
' +
9 | 'foo bar
' +
10 | 'baz
',
11 | expected: [
12 | {
13 | msg: 'name=""',
14 | type: ERROR
15 | },
16 | {
17 | msg: 'name="foo"',
18 | type: ERROR
19 | },
20 | {
21 | msg: 'name="foo"',
22 | type: ERROR
23 | },
24 | {
25 | msg: 'name="foo_bar"',
26 | type: ERROR
27 | },
28 | {
29 | msg: 'name="baz"',
30 | type: ERROR
31 | }
32 | ],
33 | expectedAfterFixing: []
34 | }
35 | ];
36 |
37 | runTests(assert, done, "nameAttribute", "'name' attribute", url, tests);
38 | };
39 |
40 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/data/tests/shell-prompts.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for shell prompts, i.e. lines starting with '>' or '$' in code blocks.
3 | *
4 | * Example 1: $user:
should rather be replaced by
5 | * .
6 | *
7 | * Implementation notes: This test checks whether lines within elements start with '$' or
8 | * '>'.
9 | */
10 |
11 | docTests.shellPrompts = {
12 | name: "shell_prompts",
13 | desc: "shell_prompts_desc",
14 | check: function checkShellPrompts(rootElement) {
15 | let pres = rootElement.querySelectorAll("pre");
16 | let matches = [];
17 |
18 | for (let i = 0; i < pres.length; i++) {
19 | let code = pres[i].innerHTML.replace(/
/g, "\n").replace(" ", " ");
20 | let shellPrompts = code.match(/^(?:\$|>).*/gm);
21 | if (shellPrompts) {
22 | shellPrompts.forEach(function addMatch(shellPrompt) {
23 | matches.push({
24 | msg: shellPrompt.replace(/<.+?>/g, ""),
25 | type: ERROR
26 | });
27 | });
28 | }
29 | }
30 |
31 | return matches;
32 | }
33 | };
--------------------------------------------------------------------------------
/data/tests/style-attribute.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for incorrectly 'style' attributes.
3 | *
4 | * Example 1: Emphasized text/
should rather be replaced
5 | * by
Emphasized text
.
6 | *
7 | * Implementation notes: This test searches for all 'style' attributes, which are not part of
8 | * CKEditor's new paragraph helper.
9 | */
10 |
11 | docTests.styleAttribute = {
12 | name: "style_attributes",
13 | desc: "style_attributes_desc",
14 | check: function checkStyleAttribute(rootElement) {
15 | let elementsWithStyleAttribute = rootElement.querySelectorAll("[style]");
16 | let matches = [];
17 |
18 | for (let i = 0; i < elementsWithStyleAttribute.length; i++) {
19 | let node = elementsWithStyleAttribute[i];
20 |
21 | // Exclude new paragraph helper
22 | if (isNewParagraphHelper(node) || isNewParagraphHelper(node.firstElementChild)) {
23 | continue;
24 | }
25 |
26 | matches.push({
27 | msg: 'style="' + node.getAttribute("style") + '"',
28 | type: ERROR
29 | })
30 | }
31 |
32 | return matches;
33 | }
34 | };
--------------------------------------------------------------------------------
/test/test-example-colon-heading.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc exampleColonHeading"] = function testExampleColonHeading(assert, done) {
4 | const tests = [
5 | {
6 | str: 'Example
' +
7 | 'Example
' +
8 | 'Example: Foo
' +
9 | 'Example: Using Math.sin
' +
10 | 'Example: Foo
',
11 | expected: [
12 | {
13 | msg: 'Example: Foo
',
14 | type: ERROR
15 | },
16 | {
17 | msg: 'Example: Using Math.sin
',
18 | type: ERROR
19 | },
20 | {
21 | msg: 'Example: Foo
',
22 | type: ERROR
23 | }
24 | ],
25 | expectedAfterFixing: []
26 | }
27 | ];
28 |
29 | runTests(assert, done, "exampleColonHeading", "'Example: ' heading", url, tests);
30 | };
31 |
32 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mdn-doc-tests",
3 | "title": "MDN documentation tester",
4 | "id": "{826e8996-b3c2-11e5-9f22-ba0be0483c18}",
5 | "description": "Checks MDN docs against some tests and cleanup tasks while editing",
6 | "author": "Florian Scholz",
7 | "contributors": [
8 | "Sebastian Zartner"
9 | ],
10 | "license": "MPL 2.0",
11 | "main": "lib/main.js",
12 | "version": "0.6.0",
13 | "icon": "resource://826e8996-b3c2-11e5-9f22-ba0be0483c18/data/icon.png",
14 | "preferences": [
15 | {
16 | "name": "autoExpandErrors",
17 | "title": "Automatically expand errors",
18 | "type": "bool",
19 | "value": false
20 | },
21 | {
22 | "name": "hidePassingTests",
23 | "title": "Hide passing tests",
24 | "type": "bool",
25 | "value": false
26 | },
27 | {
28 | "name": "longArticleWordCountThreshold",
29 | "title": "Long article word count threshold",
30 | "type": "integer",
31 | "value": 2000,
32 | "hidden": true
33 | }
34 | ],
35 | "permissions": {
36 | "private-browsing": true,
37 | "multiprocess": true
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/data/tests/name-attribute.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for elements with 'name' attributes.
3 | *
4 | * Example 1: Syntax
should rather be .
5 | *
6 | * Example 2: The name="" attribute in
paragraph should rather be
7 | * removed.
8 | *
9 | * Implementation notes: This test checks all elements containing 'name' attributes.
10 | */
11 |
12 | docTests.nameAttribute = {
13 | name: "name_attributes",
14 | desc: "name_attributes_desc",
15 | check: function checkNameAttribute(rootElement) {
16 | let elementsWithNameAttribute = rootElement.querySelectorAll("[name]");
17 | let matches = [];
18 |
19 | for (let i = 0; i < elementsWithNameAttribute.length; i++) {
20 | matches.push({
21 | node: elementsWithNameAttribute[i],
22 | msg: 'name="' + elementsWithNameAttribute[i].getAttribute("name") + '"',
23 | type: ERROR
24 | })
25 | }
26 |
27 | return matches;
28 | },
29 | fix: function fixNameAttribute(matches) {
30 | matches.forEach(match => {
31 | match.node.removeAttribute("name");
32 | });
33 | }
34 | };
--------------------------------------------------------------------------------
/test/test-article-length.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, INFO, url, runTests} = require("./testutils");
2 |
3 | exports["test doc articleLength"] = function testArticleLength(assert, done) {
4 | const tests = [
5 | {
6 | str: Array(100).fill("foo").join(" "),
7 | expected: [
8 | {
9 | msg: "article_length_info",
10 | msgParams: ["100", "< 1"],
11 | type: INFO
12 | }
13 | ]
14 | },
15 | {
16 | str: Array(500).fill("foo").join(" "),
17 | expected: [
18 | {
19 | msg: "article_length_info",
20 | msgParams: ["500", "2"],
21 | type: INFO
22 | }
23 | ]
24 | },
25 | {
26 | str: Array(3000).fill("foo").join(" "),
27 | expected: [
28 | {
29 | msg: "article_length_info",
30 | msgParams: ["3000", "11"],
31 | type: INFO
32 | },
33 | {
34 | msg: "long_article",
35 | type: WARNING
36 | }
37 | ]
38 | }
39 | ];
40 |
41 | runTests(assert, done, "articleLength", "article length", url, tests);
42 | };
43 |
44 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/data/tests/old-urls.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for old /en/ MDN URLs.
3 | *
4 | * Example 1: All URLs using MDN links, which contain "/en/" as locale should be replaced by
5 | * "/en-US/" URLs. E.g. CSS should rather be
6 | * CSS.
7 | *
8 | * Implementation notes: This test checks whether a link's 'href' attribute starts with "/en/".
9 | * It does not check whether the link is an internal MDN link, nor does it check different
10 | * locales than the English one.
11 | */
12 |
13 | docTests.oldURLs = {
14 | name: "old_en_urls",
15 | desc: "old_en_urls_desc",
16 | check: function checkOldURLs(rootElement) {
17 | let links = rootElement.querySelectorAll("a[href]");
18 | let matches = [];
19 |
20 | for (let i = 0; i < links.length; i++) {
21 | // This check can be removed once querySelectorAll supports case-insensitive search,
22 | // i.e. a[href^='/en/' i] (see bug 888190, fixed in Firefox 47.0)
23 | if (links[i].getAttribute("href").match(/^\/en\//i)) {
24 | matches.push({
25 | msg: links[i].outerHTML,
26 | type: ERROR
27 | });
28 | }
29 | }
30 |
31 | return matches;
32 | }
33 | };
--------------------------------------------------------------------------------
/test/test-span-count.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc spanCount"] = function testSpanElements(assert, done) {
4 | const tests = [
5 | {
6 | str: 'what?' +
7 | '
nope
' +
8 | 'bar' +
9 | 'foobar ' +
10 | 'seoseoseo' +
11 | ' ', // Simulates new paragraph helper
12 | expected: [
13 | {
14 | msg: 'what?',
15 | type: ERROR
16 | },
17 | {
18 | msg: 'bar',
19 | type: ERROR
20 | },
21 | {
22 | msg: 'foobar ',
23 | type: ERROR
24 | }
25 | ],
26 | expectedAfterFixing: [
27 | {
28 | msg: 'bar',
29 | type: ERROR
30 | }
31 | ]
32 | }
33 | ];
34 |
35 | runTests(assert, done, "spanCount", "", url, tests);
36 | };
37 |
38 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/test/test-shell-prompts.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc shellPrompts"] = function testShellPrompts(assert, done) {
4 | const tests = [
5 | {
6 | str: 'somecommand
' +
7 | '$somecommand
' +
8 | '$ somecommand
' +
9 | '>somecommand
' +
10 | '> somecommand
' +
11 | '$ somecommand\noutput
$ anothercommand
',
12 | expected: [
13 | {
14 | msg: '$somecommand',
15 | type: ERROR
16 | },
17 | {
18 | msg: '$ somecommand',
19 | type: ERROR
20 | },
21 | {
22 | msg: '>somecommand',
23 | type: ERROR
24 | },
25 | {
26 | msg: '> somecommand',
27 | type: ERROR
28 | },
29 | {
30 | msg: '$ somecommand',
31 | type: ERROR
32 | },
33 | {
34 | msg: '$ anothercommand',
35 | type: ERROR
36 | }
37 | ]
38 | }
39 | ];
40 |
41 | runTests(assert, done, "shellPrompts", "shell prompts in code samples", url, tests);
42 | };
43 |
44 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/test/test-api-syntax-headlines.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc apiSyntaxHeadlines"] = function testSummaryHeading(assert, done) {
4 | const tests = [
5 | {
6 | str: 'Syntax
' +
7 | 'Errors
' +
8 | 'Returns
' +
9 | 'Parameters
',
10 | expected: [
11 | {
12 | msg: "invalid_headline_name",
13 | msgParams: ["Errors"],
14 | type: ERROR
15 | },
16 | {
17 | msg: "invalid_headline_name",
18 | msgParams: ["Returns"],
19 | type: ERROR
20 | },
21 | {
22 | msg: "invalid_headline_order",
23 | type: ERROR
24 | },
25 | {
26 | msg: "invalid_headline_order",
27 | type: ERROR
28 | }
29 | ],
30 | expectedAfterFixing: [
31 | {
32 | msg: "invalid_headline_order",
33 | type: ERROR
34 | },
35 | {
36 | msg: "invalid_headline_order",
37 | type: ERROR
38 | }
39 | ]
40 | }
41 | ];
42 |
43 | runTests(assert, done, "apiSyntaxHeadlines", "API syntax headline", url, tests);
44 | };
45 |
46 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/data/tests/code-in-pre.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test whether code blocks unexpectedly contain elements, which break the syntax
3 | * highlighting.
4 | *
5 | * Example 1: var x = 1;
is considered invalid and
6 | * should rather be written as var x = 1;
.
7 | *
8 | * Implementation notes: This test checks whether elements contain elements.
9 | */
10 |
11 | docTests.codeInPre = {
12 | name: "code_in_pre",
13 | desc: "code_in_pre_desc",
14 | check: function checkCodeInPre(rootElement) {
15 | let codesInPres = rootElement.querySelectorAll("pre code");
16 | let matches = [];
17 |
18 | for (let i = 0; i < codesInPres.length; i++) {
19 | matches.push({
20 | node: codesInPres[i],
21 | msg: codesInPres[i].outerHTML,
22 | type: ERROR
23 | });
24 | }
25 |
26 | return matches;
27 | },
28 | fix: function fixCodeInPre(matches) {
29 | matches.forEach(match => {
30 | let children = new DocumentFragment();
31 | for(let i = 0; i < match.node.childNodes.length; i++) {
32 | children.appendChild(match.node.childNodes[i].cloneNode(true));
33 | }
34 | match.node.parentNode.replaceChild(children, match.node);
35 | });
36 | }
37 | };
--------------------------------------------------------------------------------
/data/tests/article-length.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test the length and read time of the article.
3 | *
4 | * Example 1: An article length of 1000 words will result in a read time estimation of 4 minutes.
5 | *
6 | * Implementation notes: This test expects a reading speed of 275 words per minute. The text is
7 | * roughly split by word bounderies using a regular expression. An article exceeding some length
8 | * threshold (2000 words by default) is considered long.
9 | */
10 |
11 | const WORDS_PER_MINUTE = 275;
12 |
13 | docTests.articleLength = {
14 | name: "article_length",
15 | desc: "article_length_desc",
16 | check: function checkArticleLength(rootElement) {
17 | let text = rootElement.textContent;
18 | let wordCount = text.match(/\w+/g).length;
19 | let readTimeEstimation = Math.round(wordCount / WORDS_PER_MINUTE);
20 | if (readTimeEstimation === 0) {
21 | readTimeEstimation = "< 1";
22 | }
23 | let matches = [{
24 | msg: "article_length_info",
25 | msgParams: [String(wordCount), String(readTimeEstimation)],
26 | type: INFO
27 | }];
28 | if (wordCount > self.options.LONG_ARTICLE_WORD_COUNT_THRESHOLD) {
29 | matches.push({
30 | msg: "long_article",
31 | type: WARNING
32 | });
33 | }
34 | return matches;
35 | }
36 | };
--------------------------------------------------------------------------------
/data/tests/example-colon-heading.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for example headings starting with 'Example:'.
3 | *
4 | * Example 1: Example: Simple example
should rather be written as Simple example
5 | *
6 | * Implementation notes: This test checks whether the text of heading elements start with
7 | * 'Example:'.
8 | */
9 |
10 | const reExample = /^\s*Example:[\s_]*/;
11 |
12 | docTests.exampleColonHeading = {
13 | name: "example_headings",
14 | desc: "example_headings_desc",
15 |
16 | check: function checkExampleColonHeading(rootElement) {
17 | let headlines = rootElement.querySelectorAll("h1, h2, h3, h4, h5, h6");
18 | let matches = [];
19 |
20 | for (let i = 0; i < headlines.length; i++) {
21 | if (headlines[i].textContent.match(reExample)) {
22 | matches.push({
23 | node: headlines[i],
24 | msg: headlines[i].outerHTML,
25 | type: ERROR
26 | })
27 | }
28 | }
29 |
30 | return matches;
31 | },
32 |
33 | fix: function fixExampleColonHeading(matches) {
34 | matches.forEach(match => {
35 | match.node.textContent = match.node.textContent.replace(reExample, "");
36 | let id = match.node.getAttribute("id");
37 | id = id.replace(reExample, "");
38 | match.node.setAttribute("id", id);
39 | });
40 | }
41 | };
--------------------------------------------------------------------------------
/data/tests/summary-heading.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for obsolete 'Summary' heading.
3 | *
4 | * Example 1: Summary
is redundant, because the page title is shown above the article,
5 | * so it should be removed.
6 | *
7 | * Implementation notes: This test searches for all headings, which contain the text 'Summary'.
8 | * In CSS articles the summary headings still need to be kept due to bug 1201600, though the test
9 | * currently still marks them as errors (see issue #209). Also, summaries placed at the end of
10 | * articles are incorrectly recognized as errors (see issue #208).
11 | */
12 |
13 | docTests.summaryHeading = {
14 | name: "summary_heading",
15 | desc: "summary_heading_desc",
16 |
17 | check: function checkSummaryHeading(rootElement) {
18 | let headlines = rootElement.querySelectorAll("h1, h2, h3, h4, h5, h6");
19 | let matches = [];
20 |
21 | for (let i = 0; i < headlines.length; i++) {
22 | if (headlines[i].textContent.match(/^\s*Summary\s*$/)) {
23 | matches.push({
24 | node: headlines[i],
25 | msg: headlines[i].outerHTML,
26 | type: ERROR
27 | })
28 | }
29 | }
30 |
31 | return matches;
32 | },
33 |
34 | fix: function fixSummaryHeading(matches) {
35 | matches.forEach(match => match.node.remove());
36 | }
37 | };
--------------------------------------------------------------------------------
/test/test-code-in-pre.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc codeInPre"] = function testSummaryHeading(assert, done) {
4 | const tests = [
5 | {
6 | str: 'no code
' +
7 | 'no code
' +
8 | 'some code
' +
9 | 'some codesome more inline code
' +
10 | 'foo\nsome code\nbar
\nsome code with\nline break\nbaz
',
11 | expected: [
12 | {
13 | msg: 'some code',
14 | type: ERROR
15 | },
16 | {
17 | msg: 'some code',
18 | type: ERROR
19 | },
20 | {
21 | msg: 'some more inline code',
22 | type: ERROR
23 | },
24 | {
25 | msg: 'some code',
26 | type: ERROR
27 | },
28 | {
29 | msg: 'some code with\nline break',
30 | type: ERROR
31 | }
32 | ],
33 | expectedAfterFixing: []
34 | }
35 | ];
36 |
37 | runTests(assert, done, "codeInPre", " in ", url, tests);
38 | };
39 |
40 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/test/test-line-length-in-pre.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc lineLengthInPre"] = function testSummaryHeading(assert, done) {
4 | const tests = [
5 | {
6 | str: '11111111111111111111111 11111111111111111111111 111111111111 111111111111111 1
' +
7 | '11111111111111111111111 11111111111111111111111
111111111111 111111111111111 1
' +
8 | 'short\nstuff
' +
9 | 'Code having some link.
' +
10 | 'foo\nsome code\nbar
\n' +
11 | 'some code with\nline break\nbaz' +
12 | '11111111111 111111111111 function{ foo(); 11111111111111 bar 1111111111111111 111
',
13 | expected: [
14 | {
15 | msg: '11111111111111111111111 11111111111111111111111 111111111111 111111111111111 1',
16 | type: WARNING
17 | },
18 | {
19 | msg: 'baz11111111111 111111111111 function{ foo(); 11111111111111 bar 1111111111111111 111',
20 | type: WARNING
21 | }
22 | ]
23 | }
24 | ];
25 |
26 | runTests(assert, done, "lineLengthInPre", "too long line", url, tests);
27 | };
28 |
29 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/test/test-absolute-urls-for-internal-links.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc absoluteURLsForInternalLinks"] = function testAbsoluteURLsForInternalLinks(assert, done) {
4 | const tests = [
5 | {
6 | str: 'Page' +
7 | 'Anchor' +
8 | 'Anchor' +
9 | 'Anchor' +
10 | 'Anchor' +
11 | 'Anchor',
12 | expected: [
13 | {
14 | msg: 'Anchor',
15 | type: WARNING
16 | },
17 | {
18 | msg: 'Anchor',
19 | type: WARNING
20 | },
21 | {
22 | msg: 'Anchor',
23 | type: WARNING
24 | }
25 | ],
26 | expectedAfterFixing: []
27 | }
28 | ];
29 |
30 | runTests(assert, done, "absoluteURLsForInternalLinks", "absolute URLs for internal links", url, tests);
31 | };
32 |
33 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/test/test-wrong-syntax-class.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc wrongSyntaxClass"] = function testWrongSyntaxClass(assert, done) {
4 | const tests = [
5 | {
6 | str: 'fooSyntax
\\nsyntax
bar',
7 | expected: []
8 | },
9 | {
10 | str: 'fooSyntax
\\nsyntax examples
barFormal syntax
\\nsyntax
',
11 | expected: []
12 | },
13 | {
14 | str: 'fooSyntax
\\nsyntax
bar',
15 | expected: [
16 | {
17 | msg: "wrong_syntax_class_used",
18 | msgParams: ["brush:js"],
19 | type: ERROR
20 | }
21 | ],
22 | expectedAfterFixing: []
23 | },
24 | {
25 | str: 'fooSyntax
\\nsyntax examples
barFormal syntax
\\nsyntax
bazOther section
',
26 | expected: [
27 | {
28 | msg: "wrong_syntax_class_used",
29 | msgParams: ["eval"],
30 | type: ERROR
31 | }
32 | ],
33 | expectedAfterFixing: []
34 | }
35 | ];
36 |
37 | runTests(assert, done, "wrongSyntaxClass", "syntax box class", url, tests);
38 | };
39 |
40 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/test/test-style-attribute.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc styleAttribute"] = function testStyleAttributes(assert, done) {
4 | const tests = [
5 | {
6 | str: '' +
7 | '' +
8 | '' +
9 | 'test' +
10 | '' +
11 | ' ', // Simulates new paragraph helper
12 | expected: [
13 | {
14 | msg: 'style=""',
15 | type: ERROR
16 | },
17 | {
18 | msg: 'style="margin-top:5%"',
19 | type: ERROR
20 | },
21 | {
22 | msg: 'style="background:#fff; color: rgb(234, 234, 234);"',
23 | type: ERROR
24 | },
25 | {
26 | msg: 'style="padding: 5px !important"',
27 | type: ERROR
28 | },
29 | {
30 | msg: 'style="font-family: \'Open Sans\', serif; line-height: 1.5"',
31 | type: ERROR
32 | }
33 | ]
34 | }
35 | ];
36 |
37 | runTests(assert, done, "styleAttribute", "'style' attribute", url, tests);
38 | };
39 |
40 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/test/test-different-locale-links.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc differentLocaleLinks"] = function testDifferentLocaleLinks(assert, done) {
4 | const tests = [
5 | {
6 | str: 'Page' +
7 | 'Page' +
8 | 'Page' +
9 | 'Page' +
10 | 'Page' +
11 | 'Page',
12 | expected: [
13 | {
14 | msg: "link_using_wrong_locale",
15 | msgParams: ["/xx-YY/docs/some/page", "en-US"],
16 | type: ERROR
17 | },
18 | {
19 | msg: "link_using_wrong_locale",
20 | msgParams: ["http://developer.mozilla.org/xx-YY/docs/some/page", "en-US"],
21 | type: ERROR
22 | },
23 | {
24 | msg: "link_using_wrong_locale",
25 | msgParams: ["https://developer.mozilla.org/xx-YY/docs/some/page", "en-US"],
26 | type: ERROR
27 | }
28 | ]
29 | }
30 | ];
31 |
32 | runTests(assert, done, "differentLocaleLinks", "different locale links", url, tests);
33 | };
34 |
35 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/data/tests/span-count.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for incorrectly used elements.
3 | *
4 | * Example 1: Emphasized text/ should rather be replaced
5 | * by Emphasized text.
6 | *
7 | * Implementation notes: This test searches for all elements, which don't hold the SEO
8 | * summary and are not part of CKEditor's new paragraph helper.
9 | */
10 |
11 | docTests.spanCount = {
12 | name: "span_elements",
13 | desc: "span_elements_desc",
14 |
15 | check: function checkSpanCount(rootElement) {
16 | let spanElements = rootElement.querySelectorAll("span:not(.seoSummary)");
17 | let matches = [];
18 |
19 | for (let i = 0; i < spanElements.length; i++) {
20 | let node = spanElements[i];
21 |
22 | // Exclude new paragraph helper
23 | if (isNewParagraphHelper(node) || isNewParagraphHelper(node.firstElementChild)) {
24 | continue;
25 | }
26 |
27 | matches.push({
28 | node: node,
29 | msg: node.outerHTML,
30 | type: ERROR
31 | })
32 | }
33 |
34 | return matches;
35 | },
36 |
37 | fix: function fixSpanCount(matches) {
38 | matches.forEach(match => {
39 | // Remove element in case it is unstyled
40 | if (!match.node.getAttribute("id") && !match.node.getAttribute("class") && !match.node.getAttribute("style")) {
41 | match.node.remove();
42 | }
43 | });
44 | }
45 | };
--------------------------------------------------------------------------------
/data/tests/pre-without-class.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for code blocks without 'class' attribute specifying the syntax highlighting.
3 | *
4 | * Example 1: var x = 1
should rather be replaced by
5 | * var x = 1
.
6 | *
7 | * Implementation notes: This test checks all elements that have either an empty 'class'
8 | * attribute or none at all.
9 | */
10 |
11 | docTests.preWithoutClass = {
12 | name: "pre_without_class",
13 | desc: "pre_without_class_desc",
14 | check: function checkPreWithoutClass(rootElement) {
15 | let presWithoutClass = rootElement.querySelectorAll("pre:-moz-any(:not([class]), [class=''])");
16 | let matches = [];
17 |
18 | for (let i = 0; i < presWithoutClass.length; i++) {
19 | // If the content is recognized as folder structure, don't add a warning for empty
20 | if (presWithoutClass[i].textContent.match(/^\S[^\n\*]*\/\n/)) {
21 | continue;
22 | }
23 |
24 | let type = WARNING;
25 |
26 | // If the content is recognized as code or {{csssyntax}} macro, mark it as error
27 | if (presWithoutClass[i].textContent.match(/^\s*(?:\/\*.+?\*\/|<.+?>|@[^\s\n]+[^\n]*\{\n|\{\{\s*csssyntax(?:\(\))?\s*\}\})/)) {
28 | type = ERROR;
29 | }
30 |
31 | matches.push({
32 | msg: presWithoutClass[i].outerHTML,
33 | type: type
34 | })
35 | }
36 |
37 | return matches;
38 | }
39 | };
--------------------------------------------------------------------------------
/data/tests/html-comments.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for HTML comments (i.e. ).
3 | *
4 | * Example 1: Because an HTML comment like
5 | *
6 | * is only visible to article authors, it should rather either be made visible to readers,
7 | * e.g. by replacing it by
8 | * This is a simple example for how the API is used.
9 | * or just be removed.
10 | *
11 | * Implementation notes: This test searches for all HTML comments. Because CKEditor escapes them
12 | * for security reasons, they need to be decoded first before displaying them.
13 | */
14 |
15 | docTests.htmlComments = {
16 | name: "html_comments",
17 | desc: "html_comments_desc",
18 | check: function checkHTMLComments(rootElement) {
19 | let treeWalker = document.createTreeWalker(
20 | rootElement,
21 | NodeFilter.SHOW_COMMENT
22 | );
23 | let matches = [];
24 |
25 | while(treeWalker.nextNode()) {
26 | let comment = treeWalker.currentNode.data.replace(/\s*\{cke_protected\}\{C\}(\S+)\s*/,
27 | function(match, data) { return decodeURIComponent(data); });
28 | matches.push({
29 | node: treeWalker.currentNode,
30 | msg: comment,
31 | type: ERROR
32 | });
33 | }
34 |
35 | return matches;
36 | },
37 | fix: function fixHTMLComments(matches) {
38 | matches.forEach(match => {
39 | match.node.remove();
40 | });
41 | }
42 | };
--------------------------------------------------------------------------------
/data/tests/different-locale-links.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for wrong locales in links ().
3 | *
4 | * Example 1: If you are in a German document, internal links should
5 | * contain the "de" locale and not e.g. "en-US".
6 | *
7 | * Implementation notes: This test compares the current locale in the slug (document.URL)
8 | * with the locale used in internal links ()
9 | */
10 |
11 | docTests.differentLocaleLinks = {
12 | name: "different_locale_links",
13 | desc: "different_locale_links_desc",
14 | check: function checkDifferentLocaleLinks(rootElement) {
15 | let [, pageDomain, pageLocale] = document.URL.match(/^(?:https?:\/\/)(.+?)\/([^\/]+)/i) ||
16 | ["", "developer.mozilla.org", "en-US"];
17 | let links = rootElement.getElementsByTagName("a");
18 | let matches = [];
19 | for (let i = 0; i < links.length; i++) {
20 | let href = links[i].getAttribute("href");
21 | if (href) {
22 | let [, linkDomain, linkLocale] = href.match(/^(?:https?:\/\/(.+?))?\/([^\/]+)/i) ||
23 | [null, null, null];
24 | if (linkLocale && linkLocale.toLowerCase() !== pageLocale.toLowerCase() &&
25 | (!linkDomain || linkDomain === pageDomain)) {
26 | matches.push({
27 | msg: "link_using_wrong_locale",
28 | msgParams: [href, pageLocale],
29 | type: ERROR
30 | });
31 | }
32 | }
33 | }
34 |
35 | return matches;
36 | }
37 | };
--------------------------------------------------------------------------------
/data/tests/line-length-in-pre.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for the line length in code blocks.
3 | *
4 | * Example 1: Code blocks with very long lines like
5 | * This is some code block with a long line exceeding the maximum of 78 characters.
6 | * should either be shortened or split into several lines to avoid the display of horizontal
7 | * scrollbars.
8 | *
9 | * Implementation notes: This test uses a threshold of 78 characters for the maximum length of
10 | * a line.
tags added while editing are replaced by line breaks and all other HTML tags
11 | * are removed.
12 | */
13 |
14 | docTests.lineLengthInPre = {
15 | name: "pre_line_too_long",
16 | desc: "pre_line_too_long_desc",
17 | check: function checkLineLengthInPre(rootElement) {
18 | let pres = rootElement.getElementsByTagName("pre");
19 | let matches = [];
20 |
21 | for (let i = 0; i < pres.length; i++) {
22 | // While editing it happens that there are
s added instead of line break characters
23 | // Those need to be replaced by line breaks to correctly recognize long lines
24 | let codeBlock = pres[i].innerHTML.replace(/
/g, "\n");
25 |
26 | // Remove all other HTML tags and only display the plain text
27 | codeBlock = codeBlock.replace(/<.+?>/g, "");
28 |
29 | let longLines = codeBlock.match(/^(?:[^\r\n]|\r(?!\n)){78,}$/gm);
30 | if (longLines) {
31 | matches = matches.concat(longLines);
32 | }
33 | }
34 |
35 | return mapMatches(matches, WARNING);
36 | }
37 | };
--------------------------------------------------------------------------------
/test/test-pre-without-class.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc preWithoutClass"] = function testPresWithoutClass(assert, done) {
4 | const tests = [
5 | {
6 | str: '' +
7 | '' +
8 | 'folder/\n file
' +
9 | 'foobar;
' +
10 | '/* comment */\nvar code;
' +
11 | '@rule param {\n descriptor: value;\n}' +
12 | '<tag>
' +
13 | '' +
14 | 'foo
' +
15 | ' \n\r foo
',
16 | expected: [
17 | {
18 | msg: 'foobar;
',
19 | type: WARNING
20 | },
21 | {
22 | msg: '/* comment */\nvar code;
',
23 | type: ERROR
24 | },
25 | {
26 | msg: '@rule param {\n descriptor: value;\n}',
27 | type: ERROR
28 | },
29 | {
30 | msg: '<tag>
',
31 | type: ERROR
32 | },
33 | {
34 | msg: '',
35 | type: WARNING
36 | },
37 | {
38 | msg: 'foo
',
39 | type: WARNING
40 | },
41 | {
42 | msg: ' \n\n foo
',
43 | type: WARNING
44 | }
45 | ]
46 | }
47 | ];
48 |
49 | runTests(assert, done, "preWithoutClass", " w/o class", url, tests);
50 | };
51 |
52 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/test/test-data-macro-note.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc dataMacroNote"] = function testDataMacroNote(assert, done) {
4 | const tests = [
5 | {
6 | str: '{{nondatamacro}}
' +
7 | '{{compat}}
' +
8 | '{{css_ref}}
' +
9 | '{{cssanimatedproperties}}
' +
10 | '{{cssinfo}}
' +
11 | '{{csssyntax}}
' +
12 | '{{WebExtBrowserCompat}}
' +
13 | '{{Compat}}
' +
14 | 'The data is maintained somewhere else.
{{Compat}}
',
15 | expected: [
16 | {
17 | msg: "data_macro_note_missing",
18 | msgParams: ["{{Compat}}"],
19 | type: ERROR
20 | },
21 | {
22 | msg: "data_macro_source_link_missing",
23 | msgParams: ["{{Compat}}"],
24 | type: ERROR
25 | }
26 | ]
27 | }
28 | ];
29 |
30 | runTests(assert, done, "dataMacroNote", "data macro note", url, tests);
31 | };
32 |
33 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/test/test-empty-elements.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc emptyElements"] = function testEmptyElements(assert, done) {
4 | const tests = [
5 | {
6 | str: '
' +
7 | ' \n\r
' +
8 | '
' +
9 | '
' +
10 | '
' +
11 | 'foo
' +
12 | '
' +
13 | '
' +
14 | '' +
15 | 'some text
' +
16 | 'some text
' +
17 | ' ', // Simulates new paragraph helper
18 | expected: [
19 | {
20 | msg: '
',
21 | type: ERROR
22 | },
23 | {
24 | msg: ' \n\n
',
25 | type: ERROR
26 | },
27 | {
28 | msg: '
',
29 | type: ERROR
30 | },
31 | {
32 | msg: '
',
33 | type: ERROR
34 | },
35 | {
36 | msg: '
',
37 | type: ERROR
38 | },
39 | {
40 | msg: '
',
41 | type: WARNING
42 | }
43 | ],
44 | expectedAfterFixing: [
45 | {
46 | msg: '
',
47 | type: WARNING
48 | }
49 | ]
50 | }
51 | ];
52 |
53 | runTests(assert, done, "emptyElements", "empty elements", url, tests);
54 | };
55 |
56 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/test/test-incorrectly-wrapped-sidebar-macros.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc incorrectlyWrappedSidebarMacros"] = function testIncorrectlyWrappedSidebarMacros(assert, done) {
4 | const tests = [
5 | {
6 | str: '{{CSSRef}}',
7 | expected: []
8 | },
9 | {
10 | str: '{{HTMLRef}}',
11 | expected: []
12 | },
13 | {
14 | str: '{{APIRef}}',
15 | expected: []
16 | },
17 | {
18 | str: '{{JSRef}}',
19 | expected: []
20 | },
21 | {
22 | str: '{{SVGRefElem}}',
23 | expected: []
24 | },
25 | {
26 | str: '{{JSSidebar}}',
27 | expected: []
28 | },
29 | {
30 | str: '{{AddonSidebar}}',
31 | expected: []
32 | },
33 | {
34 | str: '{{ APIRef("Some API") }}',
35 | expected: []
36 | },
37 | {
38 | str: '{{CSSRef}}
',
39 | expected: [
40 | {
41 | msg: "wrong_element_wrapping_sidebar_macro",
42 | msgParams: ["{{CSSRef}}", "p"],
43 | type: ERROR
44 | }
45 | ],
46 | expectedAfterFixing: []
47 | },
48 | {
49 | str: '{{ APIRef("Some API") }}',
50 | expected: [
51 | {
52 | msg: "wrong_element_wrapping_sidebar_macro",
53 | msgParams: ["{{ APIRef(\"Some API\") }}", "span"],
54 | type: ERROR
55 | }
56 | ],
57 | expectedAfterFixing: []
58 | }
59 | ];
60 |
61 | runTests(assert, done, "incorrectlyWrappedSidebarMacros", "incorrectly wrapped sidebar macros",
62 | url, tests);
63 | };
64 |
65 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/data/tests/absolute-urls-for-internal-links.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test whether internal MDN links have absolute URLs.
3 | *
4 | * Example 1: An MDN link to the 'display' CSS property should use a the relative URL
5 | * /en-US/docs/Web/CSS/display and not the absolute URL
6 | * https://developer.mozilla.org/en-US/docs/Web/CSS/display.
7 | *
8 | * Implementation notes: This test checks whether the URL begins with the link
9 | * "https://developer.mozilla.org/", this means that allizom.org links are not covered.
10 | * window.location cannot be used for this, because that would break the unit test, which uses
11 | * about:blank as URL.
12 | */
13 |
14 | const reAbsoluteURL = /^(?:https?:)?\/\/developer\.mozilla\.org(?=\/)/i;
15 |
16 | docTests.absoluteURLsForInternalLinks = {
17 | name: "absolute_urls_for_internal_links",
18 | desc: "absolute_urls_for_internal_links_desc",
19 | check: function checkAbsoluteURLsForInternalLinks(rootElement) {
20 | let links = rootElement.getElementsByTagName("a");
21 | let matches = [];
22 | for (let i = 0; i < links.length; i++) {
23 | let href = links[i].getAttribute("href");
24 | if (href && href.match(reAbsoluteURL)) {
25 | matches.push({
26 | node: links[i],
27 | msg: links[i].outerHTML,
28 | type: WARNING
29 | });
30 | }
31 | }
32 |
33 | return matches;
34 | },
35 |
36 | fix: function fixAbsoluteURLsForInternalLinks(matches) {
37 | matches.forEach(match => {
38 | let href = match.node.getAttribute("href");
39 | let relativeURL = href.replace(reAbsoluteURL, "");
40 | match.node.setAttribute("href", relativeURL);
41 | match.node.setAttribute("data-cke-saved-href", relativeURL);
42 | });
43 | }
44 | };
--------------------------------------------------------------------------------
/data/tests/empty-brackets.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for macros with empty brackets.
3 | *
4 | * Example 1: The {{CompatNo}} macro does not expect any parameters, so the parameter brackets
5 | * are redundant and should be avoided, i.e. it should not be written as {{CompatNo()}}.
6 | *
7 | * Implementation notes: This test checks for macros written with empty brackets and requests to
8 | * remove them. It does not check whether the macros actually require parameters.
9 | */
10 |
11 | const reMacroWithEmptyBrackets = /\{\{\s*(.*?)\(\)\s*\}\}/gi;
12 |
13 | docTests.emptyBrackets = {
14 | name: "empty_brackets",
15 | desc: "empty_brackets_desc",
16 |
17 | check: function checkEmptyBrackets(rootElement) {
18 | let treeWalker = document.createTreeWalker(
19 | rootElement,
20 | NodeFilter.SHOW_TEXT,
21 | {
22 | acceptNode: (node) => {
23 | return reMacroWithEmptyBrackets.test(node.textContent) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
24 | }
25 | }
26 | );
27 | let matches = [];
28 |
29 | while(treeWalker.nextNode()) {
30 | let textNodeMatches = treeWalker.currentNode.textContent.match(reMacroWithEmptyBrackets) || [];
31 | textNodeMatches.forEach(match => {
32 | matches.push({
33 | node: treeWalker.currentNode,
34 | msg: match,
35 | type: ERROR
36 | });
37 | });
38 | }
39 |
40 | return matches;
41 | },
42 |
43 | fix: function fixEmptyBrackets(matches) {
44 | let previousNode = null;
45 | matches.forEach(match => {
46 | if (match.node !== previousNode) {
47 | match.node.textContent = match.node.textContent.
48 | replace(reMacroWithEmptyBrackets, "{{$1}}");
49 | }
50 | previousNode = match.node;
51 | });
52 | }
53 | };
--------------------------------------------------------------------------------
/data/tests/url-in-link-title.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for incorrectly used URLs in link titles.
3 | *
4 | * Example 1: The 'title' attribute on
5 | * CSS
6 | * should be removed, because it's redundant.
7 | *
8 | * Example 2: The 'title' attribute on
9 | * CSS
10 | * should be removed, because it's redundant and misleading.
11 | *
12 | * Implementation notes: This test checks whether the 'title' attribute of an element
13 | * contains the same URL or a part of it as within its 'href' attribute. It also handles URLs
14 | * using two-character locales vs. four character locales, e.g. "/en-US/" and "/en/".
15 | */
16 |
17 | docTests.urlInLinkTitle = {
18 | name: "url_in_link_title",
19 | desc: "url_in_link_title_desc",
20 | check: function checkURLsInTitleAttributes(rootElement) {
21 | let linkElements = rootElement.getElementsByTagName("a");
22 | let matches = [];
23 |
24 | for (let i = 0; i < linkElements.length; i++) {
25 | let href = (linkElements[i].getAttribute("href") || "").toLowerCase();
26 | let title = (linkElements[i].getAttribute("title") || "").toLowerCase();
27 | if (title !== "" && (href.indexOf(title) !== -1 ||
28 | (title.match(/[a-z]{2}(?:-[A-Z]{2})?\/docs\/.*?\//) ||
29 | title === href.replace(/([a-z]{2})(?:-[a-z]{2})?\/docs\/(.*)/, "$1/$2")))) {
30 | matches.push({
31 | node: linkElements[i],
32 | msg: linkElements[i].outerHTML,
33 | type: ERROR
34 | });
35 | }
36 | }
37 |
38 | return matches;
39 | },
40 | fix: function fixURLsInTitleAttributes(matches) {
41 | matches.forEach(match => {
42 | match.node.removeAttribute("title");
43 | });
44 | }
45 | };
--------------------------------------------------------------------------------
/test/test-url-in-link-title.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc urlInLinkTitle"] = function testHTTPLinks(assert, done) {
4 | const tests = [
5 | {
6 | str: 'Test' +
7 | 'Test' +
8 | 'Test' +
9 | 'Test' +
10 | 'Test' +
11 | 'Test' +
12 | 'Test' +
13 | 'Test' +
14 | 'Web' +
15 | 'Mozilla',
16 | expected: [
17 | {
18 | msg: 'Test',
19 | type: ERROR
20 | },
21 | {
22 | msg: 'Test',
23 | type: ERROR
24 | },
25 | {
26 | msg: 'Test',
27 | type: ERROR
28 | },
29 | {
30 | msg: 'Test',
31 | type: ERROR
32 | },
33 | {
34 | msg: 'Web',
35 | type: ERROR
36 | },
37 | {
38 | msg: 'Mozilla',
39 | type: ERROR
40 | }
41 | ],
42 | expectedAfterFixing: []
43 | }
44 | ];
45 |
46 | runTests(assert, done, "urlInLinkTitle", "URL in 'title' attribute of link", url, tests);
47 | };
48 |
49 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/test/test-invalid-macros.js:
--------------------------------------------------------------------------------
1 | const {ERROR, WARNING, url, runTests} = require("./testutils");
2 |
3 | exports["test doc invalidMacros"] = function testInvalidMacros(assert, done) {
4 | const tests = [
5 | {
6 | str: '{{apiref}}' +
7 | '{{bug(123456)}}' +
8 | '{{previous("some page"}}' +
9 | '{{cssinfo(\'font-weight\', \'@font\')}}' +
10 | '{{invalidmacroname}}' +
11 | '{{invalidmacroname(123456)}}' +
12 | '{{invalidmacroname("some page")}}' +
13 | '{{invalidmacroname(\'font-weight\', \'@font\')}}' +
14 | '{{ languages( { "ja": "Ja/Browser_chrome_tests" } ) }}',
15 | expected: [
16 | {
17 | msg: '{{invalidmacroname}}',
18 | type: WARNING
19 | },
20 | {
21 | msg: '{{invalidmacroname(123456)}}',
22 | type: WARNING
23 | },
24 | {
25 | msg: '{{invalidmacroname("some page")}}',
26 | type: WARNING
27 | },
28 | {
29 | msg: '{{invalidmacroname(\'font-weight\', \'@font\')}}',
30 | type: WARNING
31 | },
32 | {
33 | msg: 'obsolete_macro',
34 | msgParams: ['{{ languages( { "ja": "Ja/Browser_chrome_tests" } ) }}'],
35 | type: ERROR
36 | }
37 | ],
38 | expectedAfterFixing: [
39 | {
40 | msg: '{{invalidmacroname}}',
41 | type: WARNING
42 | },
43 | {
44 | msg: '{{invalidmacroname(123456)}}',
45 | type: WARNING
46 | },
47 | {
48 | msg: '{{invalidmacroname("some page")}}',
49 | type: WARNING
50 | },
51 | {
52 | msg: '{{invalidmacroname(\'font-weight\', \'@font\')}}',
53 | type: WARNING
54 | }
55 | ]
56 | }
57 | ];
58 |
59 | runTests(assert, done, "invalidMacros", "invalid macros", url, tests);
60 | };
61 |
62 | require("sdk/test").run(exports);
--------------------------------------------------------------------------------
/data/tests/empty-elements.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for empty elements.
3 | *
4 | * Example 1: Paragraphs only containing a non-breaking space (
) should be avoided.
5 | *
6 | * Implementation notes: This test checks for elements containing no text or only space
7 | * characters excluding the new paragraph helper of CKEditor and self-closing elements except
8 | *
and elements.
9 | */
10 |
11 | docTests.emptyElements = {
12 | name: "empty_elements",
13 | desc: "empty_elements_desc",
14 | check: function checkEmptyElements(rootElement) {
15 | let treeWalker = document.createTreeWalker(
16 | rootElement,
17 | NodeFilter.SHOW_ELEMENT,
18 | {
19 | acceptNode: (node) => {
20 | // matching self-closing elements and excluding them
21 | if(!node.localName.match(/^link|track|param|area|command|col|base|meta|hr|source|img|keygen|br|wbr|input$/i) &&
22 | node.textContent.match(/^(?: |\s|\n)*$/)) {
23 |
24 | // Exclude new paragraph helper
25 | if (isNewParagraphHelper(node.firstElementChild)) {
26 | return NodeFilter.FILTER_REJECT;
27 | }
28 |
29 | // Elements containing self-closing elements except
and are considered non-empty
30 | let descendantSelfClosingElements = node.querySelectorAll(
31 | "link,track,param,area,command,col,base,meta,hr,source,img,keygen,input");
32 | return descendantSelfClosingElements.length === 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
33 | } else {
34 | return NodeFilter.FILTER_SKIP;
35 | }
36 | }
37 | }
38 | );
39 | let matches = [];
40 |
41 | while(treeWalker.nextNode()) {
42 | matches.push({
43 | node: treeWalker.currentNode,
44 | msg: treeWalker.currentNode.outerHTML,
45 | type: treeWalker.currentNode.localName === "td" ? WARNING : ERROR
46 | });
47 | }
48 |
49 | return matches;
50 | },
51 |
52 | fix: function fixEmptyElements(matches) {
53 | matches.forEach(match => {
54 | if (match.type === ERROR) {
55 | match.node.remove()
56 | }
57 | });
58 | }
59 | };
--------------------------------------------------------------------------------
/data/tests/incorrectly-wrapped-sidebar-macros.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Title: Test for sidebar macros that are not wrapped in