| // Initial setup |
| //@{ |
| var globalValue; |
| if (globalValue === undefined) { |
| globalValue = command in defaultValues ? defaultValues[command] : ""; |
| } |
| var keyPrefix = globalValue == "" |
| ? "manualtest-" + command + "-" |
| : "manualtest-" + command + "-" + globalValue + "-"; |
| (function(){ |
| var manualTests = tests[command] |
| .map(function(test) { return normalizeTest(command, test) }) |
| .filter(function(test) { return test[1][1] == globalValue }); |
| var relevantMultiTests = tests.multitest |
| .map(function(test) { return normalizeTest("multitest", test) }) |
| .filter(function(test) { |
| // We only want multitests if there's exactly one occurrence of the |
| // command we're testing for, and the value is correct, and that's |
| // the last command we're testing. Some of these limitations could |
| // be removed in the future. |
| return test[test.length - 1][0] === command |
| && test[test.length - 1][1] === globalValue; |
| }); |
| |
| tests = manualTests.concat(relevantMultiTests); |
| })(); |
| //@} |
| |
| function clearCachedResults() { |
| //@{ |
| for (var key in localStorage) { |
| if (key.indexOf(keyPrefix) === 0) { |
| localStorage.removeItem(key); |
| } |
| } |
| } |
| //@} |
| |
| var numManualTests = 0; |
| var currentTestIdx = null; |
| |
| // Make sure styleWithCss is always reset to false at the start of a test run |
| // (I'm looking at you, Firefox) |
| try { document.execCommand("stylewithcss", false, "false") } catch(e) {} |
| |
| function runTests() { |
| //@{ |
| // We don't ask the user to hit a key on all tests, so make sure not to |
| // claim more tests are going to be run than actually are. |
| for (var i = 0; i < tests.length; i++) { |
| if (localStorage.getItem(keyPrefix + JSON.stringify(tests[i])) === null) { |
| numManualTests++; |
| } |
| } |
| |
| currentTestIdx = 0; |
| |
| var runTestsButton = document.querySelector("#tests input[type=button]"); |
| runTestsButton.parentNode.removeChild(runTestsButton); |
| |
| var addTestButton = document.querySelector("#tests input[type=button]"); |
| var input = document.querySelector("#tests label input"); |
| // This code actually focuses and clicks everything because for some |
| // reason, anything else doesn't work in IE9 . . . |
| input.value = JSON.stringify(tests[0]); |
| input.focus(); |
| addTestButton.click(); |
| } |
| //@} |
| |
| function addTest() { |
| //@{ |
| var tr = doSetup("#tests table", 0); |
| var input = document.querySelector("#tests label input"); |
| var test = JSON.parse(input.value); |
| doInputCell(tr, test, test.length == 2 ? command : "multitest"); |
| doSpecCell(tr, test, test.length == 2 ? command : "multitest"); |
| if (localStorage.getItem(keyPrefix + JSON.stringify(test)) !== null) { |
| // Yay, I get to cheat. Remove the overlay div so the user doesn't |
| // keep hitting the key, in case it takes a while. |
| var browserCell = document.createElement("td"); |
| tr.appendChild(browserCell); |
| browserCell.innerHTML = localStorage[keyPrefix + JSON.stringify(test)]; |
| doBrowserCellButton(browserCell, test); |
| document.getElementById("overlay").style.display = ""; |
| doSameCell(tr); |
| runNextTest(test); |
| } else { |
| doBrowserCell(tr, test, function() { |
| doSameCell(tr); |
| runNextTest(); |
| }); |
| } |
| } |
| //@} |
| |
| function runNextTest() { |
| //@{ |
| doTearDown(); |
| var input = document.querySelector("#tests label input"); |
| if (currentTestIdx === null |
| || currentTestIdx + 1 >= tests.length) { |
| currentTestIdx = null; |
| document.getElementById("overlay").style.display = ""; |
| input.value = ""; |
| return; |
| } |
| currentTestIdx++; |
| input.value = JSON.stringify(tests[currentTestIdx]); |
| input.focus(); |
| addTest(); |
| } |
| //@} |
| |
| function doBrowserCell(tr, test, callback) { |
| //@{ |
| var browserCell = document.createElement("td"); |
| tr.appendChild(browserCell); |
| |
| try { |
| var points = setupCell(browserCell, test[0]); |
| |
| var testDiv = browserCell.firstChild; |
| // Work around weird Firefox bug: |
| // https://bugzilla.mozilla.org/show_bug.cgi?id=649138 |
| document.body.appendChild(testDiv); |
| testDiv.onkeyup = function() { |
| continueBrowserCell(test, testDiv, browserCell); |
| callback(); |
| }; |
| testDiv.contentEditable = "true"; |
| testDiv.spellcheck = false; |
| if (currentTestIdx === null) { |
| document.getElementById("testcount").style.display = "none"; |
| } else { |
| document.getElementById("testcount").style.display = ""; |
| document.querySelector("#testcount > span").textContent = numManualTests; |
| numManualTests--; |
| } |
| document.getElementById("overlay").style.display = "block"; |
| testDiv.focus(); |
| setSelection(points[0], points[1], points[2], points[3]); |
| // Execute any extra commands beforehand, for multitests |
| for (var i = 1; i < test.length - 1; i++) { |
| document.execCommand(test[i][0], false, test[i][1]); |
| } |
| } catch (e) { |
| browserCellException(e, testDiv, browserCell); |
| callback(); |
| } |
| } |
| //@} |
| |
| function continueBrowserCell(test, testDiv, browserCell) { |
| //@{ |
| try { |
| testDiv.contentEditable = "inherit"; |
| testDiv.removeAttribute("spellcheck"); |
| var compareDiv1 = testDiv.cloneNode(true); |
| |
| if (getSelection().rangeCount) { |
| addBrackets(getSelection().getRangeAt(0)); |
| } |
| browserCell.insertBefore(testDiv, browserCell.firstChild); |
| |
| if (!browserCell.childNodes.length == 2) { |
| throw "The cell didn't have two children. Did something spill outside the test div?"; |
| } |
| |
| compareDiv1.normalize(); |
| // Sigh, Gecko is crazy |
| var treeWalker = document.createTreeWalker(compareDiv1, NodeFilter.SHOW_ELEMENT, null, null); |
| while (treeWalker.nextNode()) { |
| var remove = [].filter.call(treeWalker.currentNode.attributes, function(attrib) { |
| return /^_moz_/.test(attrib.name) || attrib.value == "_moz"; |
| }); |
| for (var i = 0; i < remove.length; i++) { |
| treeWalker.currentNode.removeAttribute(remove[i].name); |
| } |
| } |
| var compareDiv2 = compareDiv1.cloneNode(false); |
| compareDiv2.innerHTML = compareDiv1.innerHTML; |
| if (!compareDiv1.isEqualNode(compareDiv2) |
| && compareDiv1.innerHTML != compareDiv2.innerHTML) { |
| throw "DOM does not round-trip through serialization! " |
| + compareDiv1.innerHTML + " vs. " + compareDiv2.innerHTML; |
| } |
| if (!compareDiv1.isEqualNode(compareDiv2)) { |
| throw "DOM does not round-trip through serialization (although innerHTML is the same)! " |
| + compareDiv1.innerHTML; |
| } |
| |
| browserCell.lastChild.textContent = browserCell.firstChild.innerHTML; |
| } catch (e) { |
| browserCellException(e, testDiv, browserCell); |
| } |
| |
| localStorage[keyPrefix + JSON.stringify(test)] = browserCell.innerHTML; |
| |
| doBrowserCellButton(browserCell, test); |
| } |
| //@} |
| |
| function doBrowserCellButton(browserCell, test) { |
| //@{ |
| var button = document.createElement("button"); |
| browserCell.lastChild.appendChild(button); |
| button.textContent = "Redo browser output"; |
| button.onclick = function() { |
| localStorage.removeItem(keyPrefix + JSON.stringify(test)); |
| var tr = browserCell.parentNode; |
| while (browserCell.nextSibling) { |
| tr.removeChild(browserCell.nextSibling); |
| } |
| tr.removeChild(browserCell); |
| doBrowserCell(tr, test, function() { |
| doSameCell(tr); |
| doTearDown(); |
| document.getElementById("overlay").style.display = ""; |
| tr.scrollIntoView(); |
| }); |
| }; |
| } |
| //@} |
| // vim: foldmarker=@{,@} foldmethod=marker |