Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
            - /mathml/mathml-console-messages.html - WPT Dashboard Interop Dashboard
 
<!DOCTYPE html>
<meta charset="utf-8">
<title>Test MathML console messages</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
  <script>
    const MessageLevel = {
        ERROR: 0,
        WARNING: 1,
    };
    function retrieveConsoleMessagesFor(markup) {
        return new Promise(resolve => {
            const iframe = document.createElement('iframe');
            iframe.srcdoc = `<!DOCTYPE html>
<script>let messages = [];
  SpecialPowers.registerConsoleListener(msg => {
    if (msg.message == "SENTINEL") {
      window.parent.postMessage(messages);
    } else if (msg.isScriptError) {
      messages.push(msg);
    }
  });
  window.addEventListener("load", () => SpecialPowers.postConsoleSentinel());
<\/script>
<body>${markup}</body>`;
            window.addEventListener("message", event => {
                iframe.remove();
                resolve(event.data);
            }, {once: true});
            document.body.appendChild(iframe);
        });
    }
    function testMessageForMarkup(markup, regexp, level) {
        promise_test(async function() {
            let messages = await retrieveConsoleMessagesFor(markup);
            // Sometimes MathML messages are logged several times, so just
            // ensure there is at least one.
            assert_greater_than_equal(messages.length, 1);
            // Compare against the regexp.
            assert_regexp_match(messages[0].errorMessage, regexp);
            // Check whether this is a warning or an error.
            assert_equals(messages[0].isWarning, level == MessageLevel.WARNING);
        }, `Message for ${markup}`);
    }
    function testNoMessageForMarkup(markup) {
        promise_test(async function() {
            let messages = await retrieveConsoleMessagesFor(markup);
            assert_equals(messages.length, 0);
        }, `No message for ${markup}`);
    }
    // ChildCountIncorrect
    [
        "mroot",
        "msub",
        "msup",
        "mfrac",
        "msubsup",
        "munderover",
    ].forEach(tag => {
        testMessageForMarkup(
            `<math><${tag}></${tag}></math>`,
            new RegExp(`Incorrect number of children for <${tag}/>`),
            MessageLevel.ERROR);
    });
    // AttributeParsingError
    [
        "width",
        "height",
        "voffset",
    ].forEach(attribute => {
        testMessageForMarkup(
            `<math><mpadded ${attribute}="BAD!"></mpadded></math>`,
            new RegExp(`Error in parsing the value ‘BAD!’ for ‘${attribute}’ attribute`),
            MessageLevel.ERROR);
    });
    // LengthParsingError
    [
        '<math><mo rspace="2..0px">+</mo></math>',
        '<math><mo minsize="1.5notaunit">+</mo></math>',
        '<math><mspace width="2"/></math>',
        '<math><mo lspace="BADlspace">+</mo></math>',
        '<math><mspace height="BADheight"/></math>',
        '<math><mspace depth="BADdepth"/></math>',
        '<math><mfrac linethickness="thin"><mn>1</mn><mn>2</mn></mfrac></math>',
        '<math><mfrac linethickness="medium"><mn>1</mn><mn>2</mn></mfrac></math>',
        '<math><mfrac linethickness="thick"><mn>1</mn><mn>2</mn></mfrac></math>',
        '<math><mstyle mathsize="small"></mstyle></math>',
        '<math><mstyle mathsize="normal"></mstyle></math>',
        '<math><mstyle mathsize="big"></mstyle></math>',
        '<math><mspace width="12345."/></math>',
        '<math><mo minsize="17">+</mo></math>',
    ].forEach(markup => {
        const value = /="([a-zA-Z0-9.]+)"/.exec(markup)[1];
        testMessageForMarkup(
            markup,
            new RegExp(`Error in parsing MathML attribute value ‘${value}’`),
            MessageLevel.ERROR);
    });
    // MathML_DeprecatedMathSpaceValueWarning
    [
        '<math><mspace width="mediummathspace"></mspace></math>',
        '<math><mspace width="negativemediummathspace"></mspace></math>',
        '<math><mspace width="negativethickmathspace"></mspace></math>',
        '<math><mspace width="negativethinmathspace"></mspace></math>',
        '<math><mspace width="negativeverythickmathspace"></mspace></math>',
        '<math><mspace width="negativeverythinmathspace"></mspace></math>',
        '<math><mspace width="negativeveryverythickmathspace"></mspace></math>',
        '<math><mspace width="negativeveryverythinmathspace"></mspace></math>',
        '<math><mspace width="thickmathspace"></mspace></math>',
        '<math><mspace width="thinmathspace"></mspace></math>',
        '<math><mspace width="verythickmathspace"></mspace></math>',
        '<math><mspace width="verythinmathspace"></mspace></math>',
        '<math><mspace width="veryverythickmathspace"></mspace></math>',
        '<math><mspace width="veryverythinmathspace"></mspace></math>',
    ].forEach(markup => {
        const value = /="([a-zA-Z0-9.]+)"/.exec(markup)[1];
        testMessageForMarkup(
            markup,
            new RegExp(`MathML length value “${value}” is deprecated`),
            MessageLevel.WARNING);
    });
    // InvalidChild
    [
        `<math>
          <msubsup>
            <mprescripts/>
          </msubsup>
         </math>`,
        `<math>
           <msubsup>
             <mprescripts/>
             <mprescripts/>
           </msubsup>
         </math>`,
        `<math>
           <msub>
           <mtext>a</mtext>
             <mprescripts/>
             <mtext>a</mtext>
           <mprescripts/>
           </msub>
         </math>`,
        '<math><msub><mn>0</mn><mprescripts/></msub></math>',
        '<math><msup><mn>0</mn><mprescripts/></msup></math>',
        '<math><msubsup><mn>0</mn><mn>1</mn><mprescripts/></msubsup></math>',
    ].forEach(markup => {
        const tag = /<math>\s*<([a-z]+)>/.exec(markup)[1];
        testMessageForMarkup(
            markup,
            new RegExp(`<mprescripts> is not allowed as a child of <${tag}>`),
            MessageLevel.ERROR);
    });
    // NoBase
    testMessageForMarkup(
        `<math><mmultiscripts></mmultiscripts></math>`,
        /Expected exactly one Base element/,
        MessageLevel.ERROR
    );
    // AttributeParsingErrorNoTag
    testMessageForMarkup(
        `<math scriptlevel="BAD!"></math>`,
        /Error in parsing the value ‘BAD!’ for ‘scriptlevel’ attribute/,
        MessageLevel.ERROR
    );
    // DuplicateMprescripts
    testMessageForMarkup(
        `<math>
           <mmultiscripts>
             <mprescripts/>
             <mprescripts/>
           </mmultiscripts>
         </math>`,
        /More than one <mprescripts\/>/,
        MessageLevel.ERROR);
    // SubSupMismatch
    [
        `<math>
           <mmultiscripts>
             <mi>x</mi>
             <mi>y</mi>
           </mmultiscripts>
          </math>`,
        `<math>
           <mmultiscripts>
             <mtext>b</mtext>
             <mtext>c</mtext>
             <mprescripts/>
            <mtext>a</mtext>
           </mmultiscripts>
         </math>`,
    ].forEach(markup => {
        testMessageForMarkup(
            markup,
            /Incomplete subscript\/superscript pair/,
            MessageLevel.ERROR);
    });
    // MathML_DeprecatedMathVariantWarning
    testNoMessageForMarkup('<math><mi mathvariant="normal">A</mi></math>');
    [
        "bold",
        "italic",
        "bold-italic",
        "script",
        "bold-script",
        "fraktur",
        "double-struck",
        "bold-fraktur",
        "sans-serif",
        "bold-sans-serif",
        "sans-serif-italic",
        "sans-serif-bold-italic",
        "monospace",
        "initial",
        "tailed",
        "looped",
        "stretched"
    ].forEach((value) => {
        testMessageForMarkup(
            `<math><mi mathvariant="${value}">A</mi></math>`,
            new RegExp(`mathvariant='${value}'” .* deprecated`),
            MessageLevel.WARNING);
    });
  </script>
</body>