browser_events_textchange.js (3415B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 function checkTextChangeEvent( 8 event, 9 id, 10 text, 11 start, 12 end, 13 isInserted, 14 isFromUserInput 15 ) { 16 let tcEvent = event.QueryInterface(nsIAccessibleTextChangeEvent); 17 is(tcEvent.start, start, `Correct start offset for ${prettyName(id)}`); 18 is(tcEvent.length, end - start, `Correct length for ${prettyName(id)}`); 19 is( 20 tcEvent.isInserted, 21 isInserted, 22 `Correct isInserted flag for ${prettyName(id)}` 23 ); 24 is(tcEvent.modifiedText, text, `Correct text for ${prettyName(id)}`); 25 is( 26 tcEvent.isFromUserInput, 27 isFromUserInput, 28 `Correct value of isFromUserInput for ${prettyName(id)}` 29 ); 30 ok( 31 tcEvent.accessibleDocument instanceof nsIAccessibleDocument, 32 "Accessible document not present." 33 ); 34 } 35 36 async function changeText(browser, id, value, events) { 37 let onEvents = waitForOrderedEvents( 38 events.map(({ isInserted }) => { 39 let eventType = isInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED; 40 return [eventType, id]; 41 }) 42 ); 43 // Change text in the subtree. 44 await invokeContentTask(browser, [id, value], (contentId, contentValue) => { 45 content.document.getElementById(contentId).firstChild.textContent = 46 contentValue; 47 }); 48 let resolvedEvents = await onEvents; 49 50 events.forEach(({ isInserted, str, offset }, idx) => 51 checkTextChangeEvent( 52 resolvedEvents[idx], 53 id, 54 str, 55 offset, 56 offset + str.length, 57 isInserted, 58 false 59 ) 60 ); 61 } 62 63 async function removeTextFromInput(browser, id, value, start, end) { 64 let onTextRemoved = waitForEvent(EVENT_TEXT_REMOVED, id); 65 // Select text and delete it. 66 await invokeContentTask( 67 browser, 68 [id, start, end], 69 (contentId, contentStart, contentEnd) => { 70 let el = content.document.getElementById(contentId); 71 el.focus(); 72 el.setSelectionRange(contentStart, contentEnd); 73 } 74 ); 75 await invokeContentTask(browser, [], () => { 76 const { ContentTaskUtils } = ChromeUtils.importESModule( 77 "resource://testing-common/ContentTaskUtils.sys.mjs" 78 ); 79 const EventUtils = ContentTaskUtils.getEventUtils(content); 80 EventUtils.sendChar("VK_DELETE", content); 81 }); 82 83 let event = await onTextRemoved; 84 checkTextChangeEvent(event, id, value, start, end, false, true); 85 } 86 87 /** 88 * Test text change event and its interface: 89 * - start 90 * - length 91 * - isInserted 92 * - modifiedText 93 * - isFromUserInput 94 */ 95 addAccessibleTask( 96 ` 97 <p id="p">abc</p> 98 <input id="input" value="input" />`, 99 async function (browser) { 100 let events = [ 101 { isInserted: false, str: "abc", offset: 0 }, 102 { isInserted: true, str: "def", offset: 0 }, 103 ]; 104 await changeText(browser, "p", "def", events); 105 106 // Adding text should not send events with diffs for non-editable text. 107 // We do this to avoid screen readers reading out confusing diffs for 108 // live regions. 109 events = [ 110 { isInserted: false, str: "def", offset: 0 }, 111 { isInserted: true, str: "deDEFf", offset: 0 }, 112 ]; 113 await changeText(browser, "p", "deDEFf", events); 114 115 // Test isFromUserInput property. 116 await removeTextFromInput(browser, "input", "n", 1, 2); 117 }, 118 { iframe: true, remoteIframe: true } 119 );