mathml-console-messages.html (11044B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <title>Test MathML console messages</title> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=553917"/> 7 <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=827713"/> 8 <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1845461"/> 9 <body> 10 <script> 11 const MessageLevel = { 12 ERROR: 0, 13 WARNING: 1, 14 }; 15 16 function retrieveConsoleMessagesFor(markup) { 17 return new Promise(resolve => { 18 const iframe = document.createElement('iframe'); 19 iframe.srcdoc = `<!DOCTYPE html> 20 <script>let messages = []; 21 SpecialPowers.registerConsoleListener(msg => { 22 if (msg.message == "SENTINEL") { 23 window.parent.postMessage(messages); 24 } else if (msg.isScriptError) { 25 messages.push(msg); 26 } 27 }); 28 window.addEventListener("load", () => SpecialPowers.postConsoleSentinel()); 29 <\/script> 30 <body>${markup}</body>`; 31 window.addEventListener("message", event => { 32 iframe.remove(); 33 resolve(event.data); 34 }, {once: true}); 35 document.body.appendChild(iframe); 36 }); 37 } 38 39 function testMessageForMarkup(markup, regexp, level) { 40 promise_test(async function() { 41 let messages = await retrieveConsoleMessagesFor(markup); 42 assert_greater_than_equal(messages.length, 1); 43 44 // Try to match any element in messages against the provided regexp. 45 let found = messages.find(m => regexp.test(m.errorMessage)); 46 assert_true(!!found, `regexp ${regexp} not found in array ${messages.map(m => m.errorMessage)}`); 47 48 // Check whether this is a warning or an error. 49 assert_equals(found.isWarning, level == MessageLevel.WARNING); 50 }, `Message for ${markup}`); 51 } 52 53 function testNoMessageForMarkup(markup) { 54 promise_test(async function() { 55 let messages = await retrieveConsoleMessagesFor(markup); 56 assert_equals(messages.length, 0); 57 }, `No message for ${markup}`); 58 } 59 60 // ChildCountIncorrect 61 [ 62 "mroot", 63 "msub", 64 "msup", 65 "mfrac", 66 "msubsup", 67 "munderover", 68 ].forEach(tag => { 69 testMessageForMarkup( 70 `<math><${tag}></${tag}></math>`, 71 new RegExp(`Incorrect number of children for <${tag}/>`), 72 MessageLevel.ERROR); 73 }); 74 75 // AttributeParsingError 76 [ 77 "width", 78 "height", 79 "voffset", 80 ].forEach(attribute => { 81 testMessageForMarkup( 82 `<math><mpadded ${attribute}="BAD!"></mpadded></math>`, 83 new RegExp(`Error in parsing the value ‘BAD!’ for ‘${attribute}’ attribute`), 84 MessageLevel.ERROR); 85 }); 86 87 // LengthParsingError 88 [ 89 '<math><mo rspace="2..0px">+</mo></math>', 90 '<math><mo minsize="1.5notaunit">+</mo></math>', 91 '<math><mspace width="2"/></math>', 92 '<math><mo lspace="BADlspace">+</mo></math>', 93 '<math><mspace height="BADheight"/></math>', 94 '<math><mspace depth="BADdepth"/></math>', 95 '<math><mfrac linethickness="thin"><mn>1</mn><mn>2</mn></mfrac></math>', 96 '<math><mfrac linethickness="medium"><mn>1</mn><mn>2</mn></mfrac></math>', 97 '<math><mfrac linethickness="thick"><mn>1</mn><mn>2</mn></mfrac></math>', 98 '<math><mstyle mathsize="small"></mstyle></math>', 99 '<math><mstyle mathsize="normal"></mstyle></math>', 100 '<math><mstyle mathsize="big"></mstyle></math>', 101 '<math><mspace width="12345."/></math>', 102 '<math><mo minsize="17">+</mo></math>', 103 ].forEach(markup => { 104 const value = /="([a-zA-Z0-9.]+)"/.exec(markup)[1]; 105 testMessageForMarkup( 106 markup, 107 new RegExp(`Error in parsing MathML attribute value ‘${value}’`), 108 MessageLevel.ERROR); 109 }); 110 111 // MathML_DeprecatedMathSpaceValueWarning 112 [ 113 '<math><mspace width="mediummathspace"></mspace></math>', 114 '<math><mspace width="negativemediummathspace"></mspace></math>', 115 '<math><mspace width="negativethickmathspace"></mspace></math>', 116 '<math><mspace width="negativethinmathspace"></mspace></math>', 117 '<math><mspace width="negativeverythickmathspace"></mspace></math>', 118 '<math><mspace width="negativeverythinmathspace"></mspace></math>', 119 '<math><mspace width="negativeveryverythickmathspace"></mspace></math>', 120 '<math><mspace width="negativeveryverythinmathspace"></mspace></math>', 121 '<math><mspace width="thickmathspace"></mspace></math>', 122 '<math><mspace width="thinmathspace"></mspace></math>', 123 '<math><mspace width="verythickmathspace"></mspace></math>', 124 '<math><mspace width="verythinmathspace"></mspace></math>', 125 '<math><mspace width="veryverythickmathspace"></mspace></math>', 126 '<math><mspace width="veryverythinmathspace"></mspace></math>', 127 ].forEach(markup => { 128 const value = /="([a-zA-Z0-9.]+)"/.exec(markup)[1]; 129 testMessageForMarkup( 130 markup, 131 new RegExp(`MathML length value “${value}” is deprecated`), 132 MessageLevel.WARNING); 133 }); 134 135 // InvalidChild 136 [ 137 `<math> 138 <msubsup> 139 <mprescripts/> 140 </msubsup> 141 </math>`, 142 `<math> 143 <msubsup> 144 <mprescripts/> 145 <mprescripts/> 146 </msubsup> 147 </math>`, 148 `<math> 149 <msub> 150 <mtext>a</mtext> 151 <mprescripts/> 152 <mtext>a</mtext> 153 <mprescripts/> 154 </msub> 155 </math>`, 156 '<math><msub><mn>0</mn><mprescripts/></msub></math>', 157 '<math><msup><mn>0</mn><mprescripts/></msup></math>', 158 '<math><msubsup><mn>0</mn><mn>1</mn><mprescripts/></msubsup></math>', 159 ].forEach(markup => { 160 const tag = /<math>\s*<([a-z]+)>/.exec(markup)[1]; 161 testMessageForMarkup( 162 markup, 163 new RegExp(`<mprescripts> is not allowed as a child of <${tag}>`), 164 MessageLevel.ERROR); 165 }); 166 167 // NoBase 168 testMessageForMarkup( 169 `<math><mmultiscripts></mmultiscripts></math>`, 170 /Expected exactly one Base element/, 171 MessageLevel.ERROR 172 ); 173 174 // AttributeParsingErrorNoTag 175 testMessageForMarkup( 176 `<math scriptlevel="BAD!"></math>`, 177 /Error in parsing the value ‘BAD!’ for ‘scriptlevel’ attribute/, 178 MessageLevel.ERROR 179 ); 180 181 // DuplicateMprescripts 182 testMessageForMarkup( 183 `<math> 184 <mmultiscripts> 185 <mprescripts/> 186 <mprescripts/> 187 </mmultiscripts> 188 </math>`, 189 /More than one <mprescripts\/>/, 190 MessageLevel.ERROR); 191 192 // SubSupMismatch 193 [ 194 `<math> 195 <mmultiscripts> 196 <mi>x</mi> 197 <mi>y</mi> 198 </mmultiscripts> 199 </math>`, 200 `<math> 201 <mmultiscripts> 202 <mtext>b</mtext> 203 <mtext>c</mtext> 204 <mprescripts/> 205 <mtext>a</mtext> 206 </mmultiscripts> 207 </math>`, 208 ].forEach(markup => { 209 testMessageForMarkup( 210 markup, 211 /Incomplete subscript\/superscript pair/, 212 MessageLevel.ERROR); 213 }); 214 215 216 // MathML_DeprecatedMathVariantWarning 217 testNoMessageForMarkup('<math><mi mathvariant="normal">A</mi></math>'); 218 [ 219 "bold", 220 "italic", 221 "bold-italic", 222 "script", 223 "bold-script", 224 "fraktur", 225 "double-struck", 226 "bold-fraktur", 227 "sans-serif", 228 "bold-sans-serif", 229 "sans-serif-italic", 230 "sans-serif-bold-italic", 231 "monospace", 232 "initial", 233 "tailed", 234 "looped", 235 "stretched" 236 ].forEach((value) => { 237 testMessageForMarkup( 238 `<math><mi mathvariant="${value}">A</mi></math>`, 239 new RegExp(`mathvariant='${value}'” .* deprecated`), 240 MessageLevel.WARNING); 241 }); 242 243 244 // MathML_DeprecatedMoExplicitAccent 245 testNoMessageForMarkup(`<math><mrow><mo accent="true">x</mo></mrow></math>`); 246 [ 247 ["mover", "accent", `<mover><mi>A</mi><mo accent="true">x</mo></mover>`], 248 ["munder", "accentunder", `<munder><mi>A</mi><mo accent="true">x</mo></munder>`], 249 ["munderover", "accent/accentunder", `<munderover><mi>A</mi><mo accent="true">x</mo><mo>y</mo></munderover>`], 250 ["munderover", "accent/accentunder", `<munderover><mi>A</mi><mo>x</mo><mo accent="true">y</mo></munderover>`], 251 ["munderover", "accent/accentunder", `<munderover><mi>A</mi><mo accent="true">x</mo><mo accent="true">y</mo></munderover>`], 252 ].forEach(([name, accent, markup]) => { 253 testMessageForMarkup( 254 `<math><${markup}></math>`, 255 new RegExp(`Setting the accent attribute on mo elements is deprecated. Use the “${accent}” attribute on “${name}” instead.`), 256 MessageLevel.WARNING); 257 }); 258 259 260 // MathML_DeprecatedMoverNonExplicitAccent 261 // MathML_DeprecatedMunderNonExplicitAccentunder 262 [ "mover", "munder" ].forEach((name) => { 263 testNoMessageForMarkup(`<math><${name}><mi>A</mi><mo>x</mo></${name}></math>`); 264 }); 265 testNoMessageForMarkup(`<math><munderover><mi>A</mi><mo>x</mo><mo>y</mo></munderover></math>`); 266 [ 267 // Inferring the accent from the operator dictionary. 268 ["mover", "accent", `<mover><mi>B</mi><mo>^</mo></mover>`], 269 ["munder", "accentunder", `<munder><mi>B</mi><mo>^</mo></munder>`], 270 ["munderover", "accent", `<munderover><mi>B</mi><mo>x</mo><mo>^</mo></munderover>`], 271 ["munderover", "accentunder", `<munderover><mi>B</mi><mo>^</mo><mo>x</mo></munderover>`], 272 // Inferring the accent from `accent="true"`. 273 // The last test triggers both accent and accentunder warnings, so we check it twice. 274 ["mover", "accent", `<mover><mi>C</mi><mo accent="true">x</mo></mover>`], 275 ["munder", "accentunder", `<munder><mi>C</mi><mo accent="true">x</mo></munder>`], 276 ["munderover", "accent", `<munderover><mi>C</mi><mo>x</mo><mo accent="true">y</mo></munderover>`], 277 ["munderover", "accentunder", `<munderover><mi>C</mi><mo accent="true">x</mo><mo>y</mo></munderover>`], 278 ["munderover", "accent", `<munderover><mi>C</mi><mo accent="true">x</mo><mo accent="true">y</mo></munderover>`], 279 ["munderover", "accentunder", `<munderover><mi>D</mi><mo accent="true">x</mo><mo accent="true">y</mo></munderover>`], 280 ].forEach(([name, accent, markup]) => { 281 testMessageForMarkup( 282 `<math><${markup}></math>`, 283 new RegExp(`Inferring the ${accent} property from the core operator is deprecated. Consider adding an explicit ${accent} attribute to “${name}”.`), 284 MessageLevel.WARNING); 285 }); 286 </script> 287 </body>