<!DOCTYPE HTML> <html> <!-- https://bugzilla.mozilla.org/show_bug.cgi?id=722599 --> <head> <title>Test for Bug 722599</title> <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> </head> <body> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=722599">Mozilla Bug 722599</a> <p id="display"></p> <div id="content"> <input type="file" id="fileInput"></input> <textarea id="textarea" onchange="++textareaChange;"></textarea> <input type="text" id="input_text" onchange="++textInputChange[0];"></input> <input type="email" id="input_email" onchange="++textInputChange[1];"></input> <input type="search" id="input_search" onchange="++textInputChange[2];"></input> <input type="tel" id="input_tel" onchange="++textInputChange[3];"></input> <input type="url" id="input_url" onchange="++textInputChange[4];"></input> <input type="password" id="input_password" onchange="++textInputChange[5];"></input> <!-- "Non-text" inputs--> <input type="button" id="input_button" onchange="++NonTextInputChange[0];"></input> <input type="submit" id="input_submit" onchange="++NonTextInputChange[1];"></input> <input type="image" id="input_image" onchange="++NonTextInputChange[2];"></input> <input type="reset" id="input_reset" onchange="++NonTextInputChange[3];"></input> <input type="radio" id="input_radio" onchange="++NonTextInputChange[4];"></input> <input type="checkbox" id="input_checkbox" onchange="++NonTextInputChange[5];"></input> <input type="number" id="input_number" onchange="++numberChange;"></input> <input type="range" id="input_range" onchange="++rangeChange;"></input> <!-- Input text with default value and blurs on focus--> <input type="text" id="input_text_value" onchange="++textInputValueChange" onfocus="this.blur();" value="foo"></input> </div> <pre id="test"> <script class="testbody" type="text/javascript"> /** Test for Bug 722599 **/ const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent); var textareaChange = 0; var fileInputChange = 0; var textInputValueChange = 0; var textInputTypes = ["text", "email", "search", "tel", "url", "password"]; var textInputChange = [0, 0, 0, 0, 0, 0]; var NonTextInputTypes = ["button", "submit", "image", "reset", "radio", "checkbox"]; var NonTextInputChange = [0, 0, 0, 0, 0, 0]; var numberChange = 0; var rangeChange = 0; var blurTestCalled = false; //Sentinel to prevent infinite loop. SimpleTest.waitForExplicitFinish(); var MockFilePicker = SpecialPowers.MockFilePicker; MockFilePicker.init(window); function fileInputBlurTest() { var btn = document.getElementById('fileInput'); btn.focus() btn.blur(); is(fileInputChange, 1, "change event shouldn't be dispatched on blur for file input element(1)"); } function testUserInput() { //Simulating an OK click and with a file name return. MockFilePicker.useBlobFile(); MockFilePicker.returnValue = MockFilePicker.returnOK; var input = document.getElementById('fileInput'); input.focus(); input.addEventListener("change", function (aEvent) { ++fileInputChange; if (!blurTestCalled) { is(fileInputChange, 1, "change event should have been dispatched on file input."); blurTestCalled = true; fileInputBlurTest(); } else { is(fileInputChange, 1, "change event shouldn't be dispatched on blur for file input element (2)"); } }, false); input.click(); // blur the file input, we can't use blur() because of bug 760283 document.getElementById('input_text').focus(); setTimeout(testUserInput2, 0); } function testUserInput2() { var input = document.getElementById('fileInput'); // remove it, otherwise cleanup() opens a native file picker! input.parentNode.removeChild(input); MockFilePicker.cleanup(); //text, email, search, telephone, url & password input tests for (var i = 0; i < textInputTypes.length; ++i) { input = document.getElementById("input_" + textInputTypes[i]); input.focus(); synthesizeKey("VK_RETURN", {}); is(textInputChange[i], 0, "Change event shouldn't be dispatched on " + textInputTypes[i] + " input element"); synthesizeKey("m", {}); synthesizeKey("VK_RETURN", {}); is(textInputChange[i], 1, textInputTypes[i] + " input element should have dispatched change event."); } //focus and blur text input input = document.getElementById("input_text"); input.focus(); synthesizeKey("f", {}); input.blur(); is(textInputChange[0], 2, "text input element should have dispatched change event (2)."); // value being set while focused input.focus(); input.value = 'foo'; input.blur(); is(textInputChange[0], 2, "text input element should not have dispatched change event (2)."); // value being set while focused after being modified manually input.focus(); synthesizeKey("f", {}); input.value = 'bar'; input.blur(); is(textInputChange[0], 3, "text input element should have dispatched change event (3)."); //focus and blur textarea var textarea = document.getElementById("textarea"); textarea.focus(); synthesizeKey("f", {}); textarea.blur(); is(textareaChange, 1, "Textarea element should have dispatched change event."); // value being set while focused textarea.focus(); textarea.value = 'foo'; textarea.blur(); is(textareaChange, 1, "textarea should not have dispatched change event (1)."); // value being set while focused after being modified manually textarea.focus(); synthesizeKey("f", {}); textarea.value = 'bar'; textarea.blur(); is(textareaChange, 2, "textearea should have dispatched change event (2)."); //Non-text input tests: for (var i = 0; i < NonTextInputTypes.length; ++i) { //button, submit, image and reset input type tests. if (i < 4) { input = document.getElementById("input_" + NonTextInputTypes[i]); input.focus(); input.click(); is(NonTextInputChange[i], 0, "Change event shouldn't be dispatched on " + NonTextInputTypes[i] + " input element"); input.blur(); is(NonTextInputChange[i], 0, "Change event shouldn't be dispatched on " + NonTextInputTypes[i] + " input element(2)"); } //for radio and and checkboxes, we require that change event should ONLY be dispatched on setting the value. else { input = document.getElementById("input_" + NonTextInputTypes[i]); input.focus(); input.click(); is(NonTextInputChange[i], 1, NonTextInputTypes[i] + " input element should have dispatched change event."); input.blur(); is(NonTextInputChange[i], 1, "Change event shouldn't be dispatched on " + NonTextInputTypes[i] + " input element"); // Test that change event is not dispatched if click event is cancelled. function preventDefault(e) { e.preventDefault(); } input.addEventListener("click", preventDefault, false); input.click(); is(NonTextInputChange[i], 1, "Change event shouldn't be dispatched if click event is cancelled"); input.removeEventListener("click", preventDefault, false); } } // Special case type=number var number = document.getElementById("input_number"); number.focus(); synthesizeKey("a", {}); number.blur(); is(numberChange, 0, "Change event shouldn't be dispatched on number input element for key changes that don't change its value"); number.value = ""; number.focus(); synthesizeKey("1", {}); synthesizeKey("2", {}); is(numberChange, 0, "Change event shouldn't be dispatched on number input element for keyboard input until it loses focus"); number.blur(); is(numberChange, 1, "Change event should be dispatched on number input element on blur"); is(number.value, "12", "Sanity check that number keys were actually handled"); if (isDesktop) { // up/down arrow keys not supported on android/b2g number.value = ""; number.focus(); synthesizeKey("VK_UP", {}); synthesizeKey("VK_UP", {}); synthesizeKey("VK_DOWN", {}); is(numberChange, 4, "Change event should be dispatched on number input element for up/down arrow keys (a special case)"); is(number.value, "1", "Sanity check that number and arrow keys were actually handled"); } // Special case type=range var range = document.getElementById("input_range"); range.focus(); synthesizeKey("a", {}); range.blur(); is(rangeChange, 0, "Change event shouldn't be dispatched on range input element for key changes that don't change its value"); range.focus(); synthesizeKey("VK_HOME", {}); is(rangeChange, 1, "Change event should be dispatched on range input element for key changes"); range.blur(); is(rangeChange, 1, "Change event shouldn't be dispatched on range input element on blur"); range.focus(); var bcr = range.getBoundingClientRect(); var centerOfRangeX = bcr.width / 2; var centerOfRangeY = bcr.height / 2; synthesizeMouse(range, centerOfRangeX - 10, centerOfRangeY, { type: "mousedown" }); is(rangeChange, 1, "Change event shouldn't be dispatched on range input element for mousedown"); synthesizeMouse(range, centerOfRangeX - 5, centerOfRangeY, { type: "mousemove" }); is(rangeChange, 1, "Change event shouldn't be dispatched on range input element during drag of thumb"); synthesizeMouse(range, centerOfRangeX, centerOfRangeY, { type: "mouseup" }); is(rangeChange, 2, "Change event should be dispatched on range input element at end of drag"); range.blur(); is(rangeChange, 2, "Change event shouldn't be dispatched on range input element when range loses focus after a drag"); synthesizeMouse(range, centerOfRangeX - 10, centerOfRangeY, {}); is(rangeChange, 3, "Change event should be dispatched on range input element for a click that gives the range focus"); if (isDesktop) { // up/down arrow keys not supported on android/b2g synthesizeKey("VK_UP", {}); is(rangeChange, 4, "Change event should be dispatched on range input element for key changes that change its value (VK_UP)"); synthesizeKey("VK_DOWN", {}); is(rangeChange, 5, "Change event should be dispatched on range input element for key changes that change its value (VK_DOWN)"); synthesizeKey("VK_RIGHT", {}); is(rangeChange, 6, "Change event should be dispatched on range input element for key changes that change its value (VK_RIGHT)"); synthesizeKey("VK_LEFT", {}); is(rangeChange, 7, "Change event should be dispatched on range input element for key changes that change its value (VK_LEFT)"); synthesizeKey("VK_UP", {shiftKey: true}); is(rangeChange, 8, "Change event should be dispatched on range input element for key changes that change its value (Shift+VK_UP)"); synthesizeKey("VK_DOWN", {shiftKey: true}); is(rangeChange, 9, "Change event should be dispatched on range input element for key changes that change its value (Shift+VK_DOWN)"); synthesizeKey("VK_RIGHT", {shiftKey: true}); is(rangeChange, 10, "Change event should be dispatched on range input element for key changes that change its value (Shift+VK_RIGHT)"); synthesizeKey("VK_LEFT", {shiftKey: true}); is(rangeChange, 11, "Change event should be dispatched on range input element for key changes that change its value (Shift+VK_LEFT)"); synthesizeKey("VK_PAGE_UP", {}); is(rangeChange, 12, "Change event should be dispatched on range input element for key changes that change its value (VK_PAGE_UP)"); synthesizeKey("VK_PAGE_DOWN", {}); is(rangeChange, 13, "Change event should be dispatched on range input element for key changes that change its value (VK_PAGE_DOWN"); synthesizeKey("VK_RIGHT", {shiftKey: true}); is(rangeChange, 14, "Change event should be dispatched on range input element for key changes that change its value (Shift+VK_PAGE_UP)"); synthesizeKey("VK_LEFT", {shiftKey: true}); is(rangeChange, 15, "Change event should be dispatched on range input element for key changes that change its value (Shift+VK_PAGE_DOWN)"); } //Input type change test. input = document.getElementById("input_checkbox"); input.type = "text"; input.focus(); input.click(); input.blur(); is(NonTextInputChange[5], 1, "Change event shouldn't be dispatched for checkbox ---> text input type change"); setTimeout(testInputWithDefaultValue, 0); } function testInputWithDefaultValue() { // focus and blur an input text should not trigger change event if content hasn't changed. var input = document.getElementById('input_text_value'); input.focus(); is(textInputValueChange, 0, "change event shouldn't be dispatched on input text with default value"); SimpleTest.finish(); } addLoadEvent(testUserInput); </script> </pre> </body> </html>