1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/smil/test/test_smilAccessKey.xhtml Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,362 @@ 1.4 +<html xmlns="http://www.w3.org/1999/xhtml"> 1.5 +<head> 1.6 + <title>Test for SMIL accessKey support</title> 1.7 + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> 1.8 + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> 1.9 +</head> 1.10 +<body> 1.11 +<a target="_blank" 1.12 + href="https://bugzilla.mozilla.org/show_bug.cgi?id=587910">Mozilla Bug 1.13 + 587910</a> 1.14 +<p id="display"></p> 1.15 +<div id="content" style="display: none"> 1.16 +<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px"> 1.17 + <circle cx="20" cy="20" r="15" fill="blue" id="circle"/> 1.18 +</svg> 1.19 +</div> 1.20 +<pre id="test"> 1.21 +<script class="testbody" type="text/javascript"> 1.22 +<![CDATA[ 1.23 +/** Test for SMIL accessKey support **/ 1.24 + 1.25 +const gSvgns = "http://www.w3.org/2000/svg"; 1.26 +var gSvg = document.getElementById("svg"); 1.27 +SimpleTest.waitForExplicitFinish(); 1.28 + 1.29 +function main() 1.30 +{ 1.31 + gSvg.pauseAnimations(); 1.32 + 1.33 + // Basic syntax 1.34 + testOk('accessKey(a)', 'a'); 1.35 + testOk(' accessKey(a) ', 'a'); 1.36 + testNotOk('accessKey (a)', 'a'); 1.37 + testNotOk('accessKey( a)', 'a'); 1.38 + testNotOk('accessKey(a )', 'a'); 1.39 + testNotOk('accessKey(a)', 'b'); 1.40 + testNotOk('accessKey()', ' '); 1.41 + 1.42 + // Test the test framework itself 1.43 + testOk('accessKey(a)', 97); 1.44 + 1.45 + // Allow for either accessKey (SVG / SMIL Animation) or accesskey (SMIL2+) 1.46 + testOk('accesskey(a)', 'a'); 1.47 + 1.48 + // Offset 1.49 + testOk('accessKey(a)+0s', 'a'); 1.50 + testOk('accessKey(a) + 0min', 'a'); 1.51 + testOk('accessKey(a) -0h', 'a'); 1.52 + testOk('accessKey(a)+100ms', 'a', 0, 0.1); 1.53 + testOk('accessKey(a)-0.1s', 'a', 0, -0.1); 1.54 + 1.55 + // Id references are not allowed 1.56 + testNotOk('svg.accessKey(a)', 'a'); 1.57 + testNotOk('window.accessKey(a)', 'a'); 1.58 + 1.59 + // Case sensitivity 1.60 + testOk('accessKey(A)', 'A'); 1.61 + testNotOk('accessKey(a)', 'A'); 1.62 + testNotOk('accessKey(A)', 'a'); 1.63 + 1.64 + // Test unusual characters 1.65 + testOk('accessKey(-)', '-'); 1.66 + testOk('accessKey(\\)', '\\'); 1.67 + testOk('accessKey( )', ' '); 1.68 + testOk('accessKey(\x0D)', 0, KeyboardEvent.DOM_VK_RETURN); 1.69 + testOk('accessKey(\n)', 0, KeyboardEvent.DOM_VK_RETURN); // New line 1.70 + testOk('accessKey(\r)', 0, KeyboardEvent.DOM_VK_RETURN); // Carriage return 1.71 + testOk('accessKey(\x08)', 0, KeyboardEvent.DOM_VK_BACK_SPACE); 1.72 + testOk('accessKey(\x1B)', 0, KeyboardEvent.DOM_VK_ESCAPE); 1.73 + testOk('accessKey(\x7F)', 0, KeyboardEvent.DOM_VK_DELETE); 1.74 + 1.75 + // Check some disallowed keys 1.76 + // -- For now we don't allow tab since the interaction with focus causes 1.77 + // confusing results 1.78 + testNotOk('accessKey(\x09)', 0, 9); // Tab 1.79 + 1.80 + // Test setting the keyCode field 1.81 + testNotOk('accessKey(a)', 0, 97); 1.82 + testOk('accessKey(a)', 97, 66); // Give priority to charCode field 1.83 + testNotOk('accessKey(a)', 98, 97); // Give priority to charCode field 1.84 + 1.85 + // Test unicode 1.86 + testOk("accessKey(\u20AC)", 8364); // euro-symbol 1.87 + 1.88 + // Test an astral character just to make sure we don't crash 1.89 + testOk("accessKey(\uD835\uDC00)", 119808); // mathematical bold capital A 1.90 + // 0x1D400 1.91 + // Test bad surrogate pairs don't confuse us either 1.92 + testNotOk("accessKey(\uD800\uD800)", 97); 1.93 + testNotOk("accessKey(\uD80020)", 97); 1.94 + testNotOk("accessKey(\uD800)", 97); 1.95 + 1.96 + // Test modifiers 1.97 + // -- When matching on charCode ignore shift and alt 1.98 + testNotOk('accessKey(a)', 'a', 0, 0, { ctrl: true }); 1.99 + testNotOk('accessKey(a)', 'a', 0, 0, { meta: true }); 1.100 + testOk('accessKey(a)', 'a', 0, 0, { alt: true }); 1.101 + testOk('accessKey(a)', 'a', 0, 0, { shift: true }); 1.102 + testNotOk('accessKey(a)', 'a', 0, 0, { shift: true, ctrl: true }); 1.103 + testNotOk('accessKey(a)', 'a', 0, 0, { alt: true, meta: true }); 1.104 + // -- When matching on keyCode ignore all 1.105 + testNotOk('accessKey(\x0D)', 0, 13, 0, { ctrl: true }); 1.106 + testNotOk('accessKey(\x0D)', 0, 13, 0, { meta: true }); 1.107 + testNotOk('accessKey(\x0D)', 0, 13, 0, { alt: true }); 1.108 + testNotOk('accessKey(\x0D)', 0, 13, 0, { shift: true }); 1.109 + testNotOk('accessKey(\x0D)', 0, 13, 0, { shift: true, ctrl: true }); 1.110 + 1.111 + testOpenEnd(); 1.112 + testPreventDefault(); 1.113 + testDispatchToWindow(); 1.114 + testAdoptNode(); 1.115 + testFauxEvent(); 1.116 + 1.117 + SimpleTest.finish(); 1.118 +} 1.119 + 1.120 +function testOk(spec, charCode, keyCode, offset, modifiers) 1.121 +{ 1.122 + if (typeof offset == 'undefined') offset = 0; 1.123 + var msg = "No interval created for '" + spec + 1.124 + "' with input [charCode: " + charCode + "; keyCode: " + keyCode + "]" + 1.125 + getModifiersDescr(modifiers); 1.126 + ok(test(spec, charCode, keyCode, offset, modifiers), msg); 1.127 +} 1.128 + 1.129 +function testNotOk(spec, charCode, keyCode, offset, modifiers) 1.130 +{ 1.131 + if (typeof offset == 'undefined') offset = 0; 1.132 + var msg = "Interval unexpectedly created for '" + spec + 1.133 + "' with input [charCode: " + charCode + "; keyCode: " + keyCode + "]" + 1.134 + getModifiersDescr(modifiers); 1.135 + ok(!test(spec, charCode, keyCode, offset, modifiers), msg); 1.136 +} 1.137 + 1.138 +function getModifiersDescr(modifiers) 1.139 +{ 1.140 + if (typeof modifiers != 'object') 1.141 + return ''; 1.142 + var str = ' modifiers set:'; 1.143 + for (var key in modifiers) { 1.144 + if (modifiers[key]) str += ' ' + key; 1.145 + } 1.146 + return str; 1.147 +} 1.148 + 1.149 +function test(spec, charCode, keyCode, offset, modifiers) 1.150 +{ 1.151 + gSvg.setCurrentTime(1); 1.152 + ok(gSvg.animationsPaused(), "Expected animations to be paused"); 1.153 + 1.154 + var anim = createAnim(spec); 1.155 + var evt = createEvent(charCode, keyCode, modifiers); 1.156 + 1.157 + document.getElementById('circle').dispatchEvent(evt); 1.158 + 1.159 + var gotStartTimeOk = true; 1.160 + try { 1.161 + var start = anim.getStartTime(); 1.162 + if (offset) { 1.163 + var expected = gSvg.getCurrentTime() + offset; 1.164 + ok(Math.abs(expected - start) <= 0.00001, 1.165 + "Unexpected start time for animation with begin: " + spec + 1.166 + " got " + start + ", expected " + expected); 1.167 + } else { 1.168 + is(start, gSvg.getCurrentTime() + offset, 1.169 + "Unexpected start time for animation with begin: " + spec); 1.170 + } 1.171 + } catch(e) { 1.172 + is(e.name, "InvalidStateError", 1.173 + "Unexpected exception: " + e.name); 1.174 + is(e.code, DOMException.INVALID_STATE_ERR, 1.175 + "Unexpected exception code: " + e.code); 1.176 + gotStartTimeOk = false; 1.177 + } 1.178 + 1.179 + anim.parentNode.removeChild(anim); 1.180 + 1.181 + return gotStartTimeOk; 1.182 +} 1.183 + 1.184 +function createAnim(beginSpec) 1.185 +{ 1.186 + var anim = document.createElementNS(gSvgns, 'animate'); 1.187 + anim.setAttribute('attributeName', 'cx'); 1.188 + anim.setAttribute('values', '0; 100'); 1.189 + anim.setAttribute('dur', '10s'); 1.190 + anim.setAttribute('begin', beginSpec); 1.191 + return document.getElementById('circle').appendChild(anim); 1.192 +} 1.193 + 1.194 +function createEvent(charCode, keyCode, modifiers) 1.195 +{ 1.196 + if (typeof charCode == 'string') { 1.197 + is(charCode.length, 1, 1.198 + "If charCode is a string it should be 1 character long"); 1.199 + charCode = charCode.charCodeAt(0); 1.200 + } else if (typeof charCode == 'undefined') { 1.201 + charCode = 0; 1.202 + } 1.203 + args = { ctrl: false, alt: false, shift: false, meta: false }; 1.204 + if (typeof modifiers == 'object') { 1.205 + for (var key in modifiers) 1.206 + args[key] = modifiers[key]; 1.207 + } 1.208 + if (typeof keyCode == 'undefined') keyCode = 0; 1.209 + var evt = document.createEvent("KeyboardEvent"); 1.210 + evt.initKeyEvent("keypress", true, true, window, 1.211 + args['ctrl'], 1.212 + args['alt'], 1.213 + args['shift'], 1.214 + args['meta'], 1.215 + keyCode, 1.216 + charCode); 1.217 + return evt; 1.218 +} 1.219 + 1.220 +function testOpenEnd() 1.221 +{ 1.222 + // Test that an end specification with an accesskey value is treated as open 1.223 + // ended 1.224 + gSvg.setCurrentTime(0); 1.225 + ok(gSvg.animationsPaused(), "Expected animations to be paused"); 1.226 + 1.227 + var anim = createAnim('0s; 2s'); 1.228 + anim.setAttribute('end', '1s; accessKey(a)'); 1.229 + 1.230 + gSvg.setCurrentTime(2); 1.231 + 1.232 + try { 1.233 + is(anim.getStartTime(), 2, 1.234 + "Unexpected start time for second interval of open-ended animation"); 1.235 + } catch(e) { 1.236 + is(e.name, "InvalidStateError", 1.237 + "Unexpected exception:" + e.name); 1.238 + is(e.code, DOMException.INVALID_STATE_ERR, 1.239 + "Unexpected exception code:" + e.code); 1.240 + ok(false, "Failed to recognise accessKey as qualifying for creating an " + 1.241 + "open-ended interval"); 1.242 + } 1.243 + 1.244 + anim.parentNode.removeChild(anim); 1.245 +} 1.246 + 1.247 +function testPreventDefault() 1.248 +{ 1.249 + // SVG/SMIL don't specify what should happen if preventDefault is called on 1.250 + // the keypress event. For now, for consistency with event timing we ignore 1.251 + // it. 1.252 + gSvg.setCurrentTime(1); 1.253 + ok(gSvg.animationsPaused(), "Expected animations to be paused"); 1.254 + 1.255 + var anim = createAnim('accessKey(a)'); 1.256 + var evt = createEvent('a'); 1.257 + 1.258 + var circle = document.getElementById('circle'); 1.259 + var func = function(evt) { evt.preventDefault(); } 1.260 + circle.addEventListener('keypress', func, false); 1.261 + circle.dispatchEvent(evt); 1.262 + 1.263 + try { 1.264 + var start = anim.getStartTime(); 1.265 + } catch(e) { 1.266 + ok(false, "preventDefault() cancelled accessKey handling"); 1.267 + } 1.268 + 1.269 + circle.removeEventListener('keypress', func, false); 1.270 + anim.parentNode.removeChild(anim); 1.271 +} 1.272 + 1.273 +function testDispatchToWindow() 1.274 +{ 1.275 + gSvg.setCurrentTime(1); 1.276 + ok(gSvg.animationsPaused(), "Expected animations to be paused"); 1.277 + 1.278 + var anim = createAnim('accessKey(a)'); 1.279 + var evt = createEvent('a'); 1.280 + 1.281 + window.dispatchEvent(evt); 1.282 + 1.283 + try { 1.284 + var start = anim.getStartTime(); 1.285 + } catch(e) { 1.286 + ok(false, "Key event dispatched to the window failed to trigger " + 1.287 + "accesskey handling"); 1.288 + } 1.289 + 1.290 + anim.parentNode.removeChild(anim); 1.291 +} 1.292 + 1.293 +function testAdoptNode() 1.294 +{ 1.295 + gSvg.setCurrentTime(1); 1.296 + ok(gSvg.animationsPaused(), "Expected animations to be paused"); 1.297 + 1.298 + // Create a new document with an animation element 1.299 + var newdoc = document.implementation.createDocument(gSvgns, 'svg', null); 1.300 + var anim = newdoc.createElementNS(gSvgns, 'animate'); 1.301 + anim.setAttribute('attributeName', 'cx'); 1.302 + anim.setAttribute('values', '0; 100'); 1.303 + anim.setAttribute('dur', '10s'); 1.304 + anim.setAttribute('begin', 'accesskey(a)'); 1.305 + newdoc.documentElement.appendChild(anim); 1.306 + 1.307 + // Adopt 1.308 + ok(anim.ownerDocument !== document, 1.309 + "Expected newly created animation to belong to a different doc"); 1.310 + document.adoptNode(anim); 1.311 + document.getElementById('circle').appendChild(anim); 1.312 + ok(anim.ownerDocument === document, 1.313 + "Expected newly created animation to belong to the same doc"); 1.314 + 1.315 + var evt = createEvent('a'); 1.316 + 1.317 + // Now fire an event at the original window and check nothing happens 1.318 + newdoc.dispatchEvent(evt); 1.319 + try { 1.320 + var start = anim.getStartTime(); 1.321 + ok(false, "Adopted node still receiving accesskey events from old doc"); 1.322 + } catch(e) { 1.323 + // Ok 1.324 + } 1.325 + 1.326 + // And then fire at our window 1.327 + document.dispatchEvent(evt); 1.328 + try { 1.329 + var start = anim.getStartTime(); 1.330 + } catch(e) { 1.331 + ok(false, "Adopted node failed to catch accesskey event"); 1.332 + } 1.333 + 1.334 + anim.parentNode.removeChild(anim); 1.335 +} 1.336 + 1.337 +function testFauxEvent() 1.338 +{ 1.339 + // Test a non-KeyEvent labelled as a key event 1.340 + gSvg.setCurrentTime(0); 1.341 + ok(gSvg.animationsPaused(), "Expected animations to be paused"); 1.342 + 1.343 + var anim = createAnim('accessKey(a)'); 1.344 + var evt = document.createEvent("SVGEvents"); 1.345 + evt.initEvent("keypress", true, true); 1.346 + document.getElementById('circle').dispatchEvent(evt); 1.347 + 1.348 + // We're really just testing that the above didn't crash us, but while we're 1.349 + // at it, just do a sanity check that we didn't also create an interval 1.350 + try { 1.351 + var start = anim.getStartTime(); 1.352 + ok(false, "Faux event generated interval"); 1.353 + } catch(e) { 1.354 + // All is well 1.355 + } 1.356 + 1.357 + anim.parentNode.removeChild(anim); 1.358 +} 1.359 + 1.360 +window.addEventListener("load", main, false); 1.361 +]]> 1.362 +</script> 1.363 +</pre> 1.364 +</body> 1.365 +</html>