diff options
Diffstat (limited to 'widget/tests/file_test_ime_state_on_focus_move.js')
-rw-r--r-- | widget/tests/file_test_ime_state_on_focus_move.js | 1588 |
1 files changed, 1588 insertions, 0 deletions
diff --git a/widget/tests/file_test_ime_state_on_focus_move.js b/widget/tests/file_test_ime_state_on_focus_move.js new file mode 100644 index 0000000000..f7760d8a09 --- /dev/null +++ b/widget/tests/file_test_ime_state_on_focus_move.js @@ -0,0 +1,1588 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* import-globals-from file_ime_state_test_helper.js */ + +class IMEStateWhenNoActiveElementTester { + #mDescription; + + constructor(aDescription) { + this.#mDescription = aDescription; + } + + async run(aDocument, aWindow = window) { + aWindow.focus(); + aDocument.activeElement?.blur(); + + await new Promise(resolve => + requestAnimationFrame(() => requestAnimationFrame(resolve)) + ); // wait for sending IME notifications + + return { designModeValue: aDocument.designMode }; + } + + check(aExpectedData, aWindow = window) { + const winUtils = SpecialPowers.wrap(aWindow).windowUtils; + if (aExpectedData.designModeValue == "on") { + is( + winUtils.IMEStatus, + SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED, + `IMEStateWhenNoActiveElementTester(${ + this.#mDescription + }): When no element has focus, IME should stay enabled in design mode` + ); + } else { + is( + winUtils.IMEStatus, + SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + `IMEStateWhenNoActiveElementTester(${ + this.#mDescription + }): When no element has focus, IME should be disabled` + ); + } + } +} + +class IMEStateOnFocusMoveTester { + // Common fields + #mDescription; + #mTest; + #mWindow; + #mWindowUtils; + + // Only runner fields + #mCreatedElement; + #mCreatedElementForPreviousFocusedElement; + #mElementToSetFocus; + #mContainerIsEditable; + + // Only checker fields + #mTIPWrapper; + + constructor(aDescription, aIndex, aWindow = window) { + this.#mTest = IMEStateOnFocusMoveTester.#sTestList[aIndex]; + this.#mDescription = `IMEStateOnFocusMoveTester(${aDescription}): ${ + this.#mTest.description + }`; + this.#mWindow = aWindow; + this.#mWindowUtils = SpecialPowers.wrap(this.#mWindow).windowUtils; + } + + /** + * prepareToRun should be called before run only in the process which will run the test. + */ + async prepareToRun(aContainer) { + const doc = aContainer.ownerDocument; + this.#mTest = this.#resolveTest(this.#mTest, aContainer); + this.#mContainerIsEditable = nodeIsEditable(aContainer); + this.#mCreatedElement = this.#mTest.createElement(doc); + const waitForLoadIfIFrame = new Promise(resolve => { + if (this.#mCreatedElement.tagName == "IFRAME") { + this.#mCreatedElement.addEventListener("load", resolve, { + capture: true, + once: true, + }); + } else { + resolve(); + } + }); + aContainer.appendChild(this.#mCreatedElement); + await waitForLoadIfIFrame; + this.#mElementToSetFocus = this.#mCreatedElement.contentDocument + ? this.#mCreatedElement.contentDocument.documentElement + : this.#mCreatedElement; + if (doc.designMode == "on") { + doc.activeElement?.blur(); + } else if (this.#mContainerIsEditable) { + getEditingHost(aContainer).focus(); // FIXME: use editing host instead + } else { + this.#mCreatedElementForPreviousFocusedElement = + doc.createElement("input"); + this.#mCreatedElementForPreviousFocusedElement.setAttribute( + "type", + this.#mTest.expectedEnabledValue == + SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED + ? "password" + : "text" + ); + aContainer.appendChild(this.#mCreatedElementForPreviousFocusedElement); + this.#mCreatedElementForPreviousFocusedElement.focus(); + } + + await new Promise(resolve => + requestAnimationFrame(() => requestAnimationFrame(resolve)) + ); // wait for sending IME notifications + + return { + designModeValue: doc.designMode, + containerIsEditable: this.#mContainerIsEditable, + isFocusable: this.#mTest.isFocusable, + focusEventFired: this.#mTest.focusEventIsExpected, + enabledValue: this.#mTest.expectedEnabledValue, + testedSubDocumentInDesignMode: + this.#mCreatedElement.contentDocument?.designMode == "on", + }; + } + + /** + * prepareToCheck should be called before calling run only in the process which will check the result. + */ + prepareToCheck(aExpectedData, aTIPWrapper) { + info(`Starting ${this.#mDescription} (enable state check)...`); + this.#mTIPWrapper = aTIPWrapper; + this.#mTIPWrapper.onIMEFocusBlur = aNotificationType => { + switch (aNotificationType) { + case "notify-focus": + info(aNotificationType); + is( + this.#mWindowUtils.IMEStatus, + aExpectedData.enabledValue, + `${ + this.#mDescription + }, IME should receive a focus notification after IME state is updated` + ); + break; + case "notify-blur": + info(aNotificationType); + const changingStatus = !( + aExpectedData.containerIsEditable && + aExpectedData.enabledValue == + SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED + ); + if (aExpectedData.designModeValue == "on") { + is( + // FIXME: This is odd, but #mWindowUtils.IMEStatus sometimes IME_STATUS_PASSWORD + SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED, + aExpectedData.enabledValue, + `${ + this.#mDescription + }, IME should receive a blur notification after IME state is updated` + ); + } else if (changingStatus) { + isnot( + this.#mWindowUtils.IMEStatus, + aExpectedData.enabledValue, + `${ + this.#mDescription + }, IME should receive a blur notification BEFORE IME state is updated` + ); + } else { + is( + this.#mWindowUtils.IMEStatus, + aExpectedData.enabledValue, + `${ + this.#mDescription + }, IME should receive a blur notification and its context has expected IME state if the state isn't being changed` + ); + } + break; + } + }; + + this.#mTIPWrapper.clearFocusBlurNotifications(); + } + + /** + * @returns {bool} whether expected element has focus or not after moving focus. + */ + async run() { + const previousFocusedElement = getFocusedElementOrUAWidgetHost(); + if (this.#mTest.setFocusIntoUAWidget) { + this.#mTest.setFocusIntoUAWidget(this.#mElementToSetFocus); + } else { + this.#mElementToSetFocus.focus(); + } + + await new Promise(resolve => + requestAnimationFrame(() => requestAnimationFrame(resolve)) + ); // wait for sending IME notifications + + const currentFocusedElement = getFocusedElementOrUAWidgetHost(); + this.#mCreatedElementForPreviousFocusedElement?.remove(); + if (this.#mTest.isFocusable) { + return this.#mElementToSetFocus == currentFocusedElement; + } + return previousFocusedElement == currentFocusedElement; + } + + check(aExpectedData) { + this.#mTIPWrapper.onIMEFocusBlur = null; + + if (aExpectedData.isFocusable) { + if (aExpectedData.focusEventFired) { + if ( + aExpectedData.enabledValue == + SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED || + aExpectedData.enabledValue == + SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_PASSWORD + ) { + ok( + this.#mTIPWrapper.numberOfFocusNotifications > 0, + `${this.#mDescription}, IME should receive a focus notification` + ); + if ( + aExpectedData.designModeValue == "on" && + !aExpectedData.testedSubDocumentInDesignMode + ) { + is( + this.#mTIPWrapper.numberOfBlurNotifications, + 0, + `${ + this.#mDescription + }, IME shouldn't receive a blur notification in designMode since focus isn't moved from another editor` + ); + } else { + ok( + this.#mTIPWrapper.numberOfBlurNotifications > 0, + `${ + this.#mDescription + }, IME should receive a blur notification for the previous focused editor` + ); + } + ok( + this.#mTIPWrapper.IMEHasFocus, + `${this.#mDescription}, IME should have focus right now` + ); + } else { + is( + this.#mTIPWrapper.numberOfFocusNotifications, + 0, + `${this.#mDescription}, IME shouldn't receive a focus notification` + ); + ok( + this.#mTIPWrapper.numberOfBlurNotifications > 0, + `${this.#mDescription}, IME should receive a blur notification` + ); + ok( + !this.#mTIPWrapper.IMEHasFocus, + `${this.#mDescription}, IME shouldn't have focus right now` + ); + } + } else { + ok(true, `${this.#mDescription}, focus event should be fired`); + } + } else { + is( + this.#mTIPWrapper.numberOfFocusNotifications, + 0, + `${ + this.#mDescription + }, IME shouldn't receive a focus notification at testing non-focusable element` + ); + is( + this.#mTIPWrapper.numberOfBlurNotifications, + 0, + `${ + this.#mDescription + }, IME shouldn't receive a blur notification at testing non-focusable element` + ); + } + + is( + this.#mWindowUtils.IMEStatus, + aExpectedData.enabledValue, + `${this.#mDescription}, wrong enabled state` + ); + if ( + this.#mTest.expectedInputElementType && + aExpectedData.designModeValue != "on" + ) { + is( + this.#mWindowUtils.focusedInputType, + this.#mTest.expectedInputElementType, + `${this.#mDescription}, wrong input type` + ); + } else if (aExpectedData.designModeValue == "on") { + is( + this.#mWindowUtils.focusedInputType, + "", + `${this.#mDescription}, wrong input type` + ); + } + } + + destroy() { + this.#mCreatedElement?.remove(); + this.#mCreatedElementForPreviousFocusedElement?.remove(); + this.#mTIPWrapper?.clearFocusBlurNotifications(); + this.#mTIPWrapper = null; + } + + /** + * Open/Close state test check + * Note that these tests are not run now. + * If these tests should run between `run` and `cleanUp` call of the above + * tests. + */ + canTestOpenCloseState(aExpectedData) { + return ( + IsIMEOpenStateSupported() && + this.#mWindowUtils.IMEStatus == + SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED && + aExpectedData.enabledValue == + SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED + ); + } + async prepareToRunOpenCloseTest(aContainer) { + const doc = aContainer.ownerDocument; + this.#mCreatedElementForPreviousFocusedElement?.remove(); + this.#mCreatedElementForPreviousFocusedElement = doc.createElement("input"); + this.#mCreatedElementForPreviousFocusedElement.setAttribute("type", "text"); + aContainer.appendChild(this.#mCreatedElementForPreviousFocusedElement); + + this.#mContainerIsEditable = nodeIsEditable(aContainer); + this.#mCreatedElement = this.#mTest.createElement(doc); + const waitForLoadIfIFrame = new Promise(resolve => { + if (this.#mCreatedElement.tagName == "IFRAME") { + this.#mCreatedElement.addEventListener("load", resolve, { + capture: true, + once: true, + }); + } else { + resolve(); + } + }); + aContainer.appendChild(this.#mCreatedElement); + await waitForLoadIfIFrame; + this.#mElementToSetFocus = this.#mCreatedElement.contentDocument + ? this.#mCreatedElement.contentDocument.documentElement + : this.#mCreatedElement; + + this.#mCreatedElementForPreviousFocusedElement.focus(); + + return {}; + } + prepareToCheckOpenCloseTest(aPreviousOpenState, aExpectedData) { + info(`Starting ${this.#mDescription} (open/close state check)...`); + this.#mWindowUtils.IMEIsOpen = aPreviousOpenState; + aExpectedData.defaultOpenState = this.#mWindowUtils.IMEIsOpen; + } + async runOpenCloseTest() { + return this.run(); + } + checkOpenCloseTest(aExpectedData) { + const expectedOpenState = + this.#mTest.expectedOpenState != undefined + ? this.#mTest.expectedOpenState + : aExpectedData.defaultOpenState; + is( + this.#mWindowUtils.IMEIsOpen, + expectedOpenState, + `${this.#mDescription}, IME should ${ + expectedOpenState != aExpectedData.defaultOpenState ? "become" : "keep" + } ${expectedOpenState ? "open" : "closed"}` + ); + } + + /** + * Utility methods for defining kIMEStateTestList. + */ + + /** + * @param {Element} aElement + */ + static #elementIsConnectedAndNotInDesignMode(aElement) { + return aElement.isConnected && !nodeIsInDesignMode(aElement); + } + + /** + * @param {Element} aElementContainer + * @param {bool} aElementIsEditingHost + */ + static #elementIsFocusableIfEditingHost( + aElementContainer, + aElementIsEditingHost + ) { + return !nodeIsEditable(aElementContainer) && aElementIsEditingHost; + } + + static #IMEStateEnabledAlways() { + return SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED; + } + + /** + * @param {Element} aElement + * @param {bool} aElementIsEditingHost + */ + static #IMEStateEnabledIfEditable(aElement, aElementIsEditingHost) { + return nodeIsEditable(aElement) || aElementIsEditingHost + ? SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED + : SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED; + } + + /** + * @param {Element} aElement + */ + static #IMEStateEnabledIfInDesignMode(aElement) { + return IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode( + aElement + ) + ? SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED + : SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED; + } + + /** + * @param {Element} aElement + */ + static #IMEStatePasswordIfNotInDesignMode(aElement) { + return IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode( + aElement + ) + ? SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_PASSWORD + : SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED; + } + + /** + * @param {Element} aElement + */ + static #elementIsConnectedAndNotEditable(aElement) { + return aElement.isConnected && !nodeIsEditable(aElement); + } + + /** + * @param {Element} aElementContainer + */ + static #focusEventIsExpectedUnlessEditableChild(aElementContainer) { + return !nodeIsEditable(aElementContainer); + } + + // Form controls except text editable elements are "disable" in normal + // condition, however, if they are editable, they are "enabled". + // XXX Probably there are some bugs: If the form controls editable, they + // shouldn't be focusable. + #resolveTest(aTest, aContainer) { + const isFocusable = aTest.isFocusable( + aContainer, + aTest.isNewElementEditingHost + ); + return { + // Description of the new element + description: aTest.description, + // Create element to check IME state + createElement: aTest.createElement, + // Whether the new element is an editing host if container is not editable + isNewElementEditingHost: aTest.isNewElementEditingHost, + // If the test wants to move focus into an element in UA widget, define + // this and set focus in it. + setFocusIntoUAWidget: aTest.setFocusIntoUAWidget, + // Whether the element is focusable or not + isFocusable, + // Whether focus events are fired on the element if it's focusable + focusEventIsExpected: + isFocusable && + aTest.focusEventIsExpected(aContainer, aTest.isNewElementEditingHost), + // Expected IME enabled state when the element has focus + expectedEnabledValue: aTest.expectedEnabledValue( + aContainer, + aTest.isNewElementEditingHost + ), + // Expected IME open state when the element gets focus + // "undefined" means that IME open state should not be changed + expectedOpenState: aTest.expectedOpenState, + // Expected type of input element if it's an <input> + expectedInputElementType: aTest.expectedInputElementType, + }; + } + static #sTestList = [ + { + description: "input[type=text]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "text"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedInputElementType: "text", + }, + { + description: "input[type=text][readonly]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "text"); + element.setAttribute("readonly", ""); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + }, + { + description: "input[type=password]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "password"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStatePasswordIfNotInDesignMode, + expectedInputElementType: "password", + }, + { + description: "input[type=password][readonly]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "password"); + element.setAttribute("readonly", ""); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + }, + { + description: "input[type=checkbox]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "checkbox"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: + IMEStateOnFocusMoveTester.#focusEventIsExpectedUnlessEditableChild, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + { + description: "input[type=radio]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "radio"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: + IMEStateOnFocusMoveTester.#focusEventIsExpectedUnlessEditableChild, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + { + description: "input[type=submit]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "submit"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + { + description: "input[type=reset]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "reset"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + { + description: "input[type=file]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "file"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: + IMEStateOnFocusMoveTester.#focusEventIsExpectedUnlessEditableChild, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + { + description: "input[type=button]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "button"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + { + description: "input[type=image]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "image"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + { + description: "input[type=url]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "url"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedInputElementType: "url", + }, + { + description: "input[type=email]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "email"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedInputElementType: "email", + }, + { + description: "input[type=search]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "search"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedInputElementType: "search", + }, + { + description: "input[type=tel]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "tel"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedInputElementType: "tel", + }, + { + description: "input[type=number]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "number"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedInputElementType: "number", + }, + { + description: "input[type=date]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "date"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + expectedInputElementType: "date", + }, + { + description: "input[type=datetime-local]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "datetime-local"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + expectedInputElementType: "datetime-local", + }, + { + description: "input[type=time]", + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "time"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + expectedInputElementType: "time", + }, + // TODO(bug 1283382, bug 1283382): month and week + + // form controls + { + description: "button", + createElement: aDocument => aDocument.createElement("button"), + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + { + description: "textarea", + createElement: aDocument => aDocument.createElement("textarea"), + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: "textarea[readonly]", + createElement: aDocument => { + const element = aDocument.createElement("textarea"); + element.setAttribute("readonly", ""); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + }, + { + description: "select (dropdown list)", + createElement: aDocument => { + const select = aDocument.createElement("select"); + const option1 = aDocument.createElement("option"); + option1.textContent = "abc"; + const option2 = aDocument.createElement("option"); + option2.textContent = "def"; + const option3 = aDocument.createElement("option"); + option3.textContent = "ghi"; + select.appendChild(option1); + select.appendChild(option2); + select.appendChild(option3); + return select; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: + IMEStateOnFocusMoveTester.#focusEventIsExpectedUnlessEditableChild, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + { + description: "select (list box)", + createElement: aDocument => { + const select = aDocument.createElement("select"); + select.setAttribute("multiple", "multiple"); + const option1 = aDocument.createElement("option"); + option1.textContent = "abc"; + const option2 = aDocument.createElement("option"); + option2.textContent = "def"; + const option3 = aDocument.createElement("option"); + option3.textContent = "ghi"; + select.appendChild(option1); + select.appendChild(option2); + select.appendChild(option3); + return select; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: + IMEStateOnFocusMoveTester.#focusEventIsExpectedUnlessEditableChild, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + + // a element + { + id: "a_href", + description: "a[href]", + createElement: aDocument => { + const element = aDocument.createElement("a"); + element.setAttribute("href", "about:blank"); + return element; + }, + isFocusable: IMEStateOnFocusMoveTester.#elementIsConnectedAndNotEditable, + focusEventIsExpected: + IMEStateOnFocusMoveTester.#focusEventIsExpectedUnlessEditableChild, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + + // audio element + { + description: "audio[controls]", + createElement: aDocument => { + const element = aDocument.createElement("audio"); + element.setAttribute("controls", ""); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + { + description: "playButton in audio", + createElement: aDocument => { + const element = aDocument.createElement("audio"); + element.setAttribute("controls", ""); + return element; + }, + setFocusIntoUAWidget: aElement => + SpecialPowers.wrap(aElement) + .openOrClosedShadowRoot.getElementById("playButton") + .focus(), + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + }, + { + description: "scrubber in audio", + createElement: aDocument => { + const element = aDocument.createElement("audio"); + element.setAttribute("controls", ""); + return element; + }, + setFocusIntoUAWidget: aElement => + SpecialPowers.wrap(aElement) + .openOrClosedShadowRoot.getElementById("scrubber") + .focus(), + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + }, + { + description: "muteButton in audio", + createElement: aDocument => { + const element = aDocument.createElement("audio"); + element.setAttribute("controls", ""); + return element; + }, + setFocusIntoUAWidget: aElement => + SpecialPowers.wrap(aElement) + .openOrClosedShadowRoot.getElementById("muteButton") + .focus(), + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + }, + { + description: "volumeControl in audio", + createElement: aDocument => { + const element = aDocument.createElement("audio"); + element.setAttribute("controls", ""); + return element; + }, + setFocusIntoUAWidget: aElement => + SpecialPowers.wrap(aElement) + .openOrClosedShadowRoot.getElementById("volumeControl") + .focus(), + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + }, + + // video element + { + description: "video", + createElement: aDocument => { + const element = aDocument.createElement("video"); + element.setAttribute("controls", ""); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfEditable, + }, + { + description: "playButton in video", + createElement: aDocument => { + const element = aDocument.createElement("video"); + element.setAttribute("controls", ""); + return element; + }, + setFocusIntoUAWidget: aElement => + SpecialPowers.wrap(aElement) + .openOrClosedShadowRoot.getElementById("playButton") + .focus(), + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + }, + { + description: "scrubber in video", + createElement: aDocument => { + const element = aDocument.createElement("video"); + element.setAttribute("controls", ""); + return element; + }, + setFocusIntoUAWidget: aElement => + SpecialPowers.wrap(aElement) + .openOrClosedShadowRoot.getElementById("scrubber") + .focus(), + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + }, + { + description: "muteButton in video", + createElement: aDocument => { + const element = aDocument.createElement("video"); + element.setAttribute("controls", ""); + return element; + }, + setFocusIntoUAWidget: aElement => + SpecialPowers.wrap(aElement) + .openOrClosedShadowRoot.getElementById("muteButton") + .focus(), + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + }, + { + description: "volumeControl in video", + createElement: aDocument => { + const element = aDocument.createElement("video"); + element.setAttribute("controls", ""); + return element; + }, + setFocusIntoUAWidget: aElement => + SpecialPowers.wrap(aElement) + .openOrClosedShadowRoot.getElementById("volumeControl") + .focus(), + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStateEnabledIfInDesignMode, + }, + + // ime-mode + { + description: 'input[type=text][style="ime-mode: auto;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "text"); + element.setAttribute("style", "ime-mode: auto;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=text][style="ime-mode: normal;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "text"); + element.setAttribute("style", "ime-mode: normal;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=text][style="ime-mode: active;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "text"); + element.setAttribute("style", "ime-mode: active;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedOpenState: true, + }, + { + description: 'input[type=text][style="ime-mode: inactive;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "text"); + element.setAttribute("style", "ime-mode: inactive;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedOpenState: false, + }, + { + description: 'input[type=text][style="ime-mode: disabled;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "text"); + element.setAttribute("style", "ime-mode: disabled;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStatePasswordIfNotInDesignMode, + }, + + { + description: 'input[type=url][style="ime-mode: auto;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "url"); + element.setAttribute("style", "ime-mode: auto;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=url][style="ime-mode: normal;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "url"); + element.setAttribute("style", "ime-mode: normal;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=url][style="ime-mode: active;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "url"); + element.setAttribute("style", "ime-mode: active;"); + return element; + }, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedOpenState: true, + }, + { + description: 'input[type=url][style="ime-mode: inactive;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "url"); + element.setAttribute("style", "ime-mode: inactive;"); + return element; + }, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedOpenState: false, + }, + { + description: 'input[type=url][style="ime-mode: disabled;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "url"); + element.setAttribute("style", "ime-mode: disabled;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStatePasswordIfNotInDesignMode, + }, + + { + description: 'input[type=email][style="ime-mode: auto;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "email"); + element.setAttribute("style", "ime-mode: auto;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=email][style="ime-mode: normal;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "email"); + element.setAttribute("style", "ime-mode: normal;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=email][style="ime-mode: active;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "email"); + element.setAttribute("style", "ime-mode: active;"); + return element; + }, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedOpenState: true, + }, + { + description: 'input[type=email][style="ime-mode: inactive;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "email"); + element.setAttribute("style", "ime-mode: inactive;"); + return element; + }, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedOpenState: false, + }, + { + description: 'input[type=email][style="ime-mode: disabled;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "email"); + element.setAttribute("style", "ime-mode: disabled;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStatePasswordIfNotInDesignMode, + }, + + { + description: 'input[type=search][style="ime-mode: auto;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "search"); + element.setAttribute("style", "ime-mode: auto;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=search][style="ime-mode: normal;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "search"); + element.setAttribute("style", "ime-mode: normal;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=search][style="ime-mode: active;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "search"); + element.setAttribute("style", "ime-mode: active;"); + return element; + }, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedOpenState: true, + }, + { + description: 'input[type=search][style="ime-mode: inactive;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "search"); + element.setAttribute("style", "ime-mode: inactive;"); + return element; + }, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedOpenState: false, + }, + { + description: 'input[type=search][style="ime-mode: disabled;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "search"); + element.setAttribute("style", "ime-mode: disabled;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStatePasswordIfNotInDesignMode, + }, + + { + description: 'input[type=tel][style="ime-mode: auto;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "tel"); + element.setAttribute("style", "ime-mode: auto;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=tel][style="ime-mode: normal;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "tel"); + element.setAttribute("style", "ime-mode: normal;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=tel][style="ime-mode: active;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "tel"); + element.setAttribute("style", "ime-mode: active;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedOpenState: true, + }, + { + description: 'input[type=tel][style="ime-mode: inactive;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "tel"); + element.setAttribute("style", "ime-mode: inactive;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedOpenState: false, + }, + { + description: 'input[type=tel][style="ime-mode: disabled;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "tel"); + element.setAttribute("style", "ime-mode: disabled;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStatePasswordIfNotInDesignMode, + }, + + { + description: 'input[type=number][style="ime-mode: auto;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "number"); + element.setAttribute("style", "ime-mode: auto;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=number][style="ime-mode: normal;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "number"); + element.setAttribute("style", "ime-mode: normal;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=number][style="ime-mode: active;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "number"); + element.setAttribute("style", "ime-mode: active;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedOpenState: true, + }, + { + description: 'input[type=number][style="ime-mode: inactive;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "number"); + element.setAttribute("style", "ime-mode: inactive;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedOpenState: false, + }, + { + description: 'input[type=number][style="ime-mode: disabled;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "number"); + element.setAttribute("style", "ime-mode: disabled;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStatePasswordIfNotInDesignMode, + }, + + { + description: 'input[type=password][style="ime-mode: auto;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "password"); + element.setAttribute("style", "ime-mode: auto;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStatePasswordIfNotInDesignMode, + }, + { + description: 'input[type=password][style="ime-mode: normal;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "password"); + element.setAttribute("style", "ime-mode: normal;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'input[type=password][style="ime-mode: active;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "password"); + element.setAttribute("style", "ime-mode: active;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedOpenState: true, + }, + { + description: 'input[type=password][style="ime-mode: inactive;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "password"); + element.setAttribute("style", "ime-mode: inactive;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedOpenState: false, + }, + { + description: 'input[type=password][style="ime-mode: disabled;"]', + createElement: aDocument => { + const element = aDocument.createElement("input"); + element.setAttribute("type", "password"); + element.setAttribute("style", "ime-mode: disabled;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStatePasswordIfNotInDesignMode, + }, + { + description: 'textarea[style="ime-mode: auto;"]', + createElement: aDocument => { + const element = aDocument.createElement("textarea"); + element.setAttribute("style", "ime-mode: auto;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'textarea[style="ime-mode: normal;"]', + createElement: aDocument => { + const element = aDocument.createElement("textarea"); + element.setAttribute("style", "ime-mode: normal;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: 'textarea[style="ime-mode: active;"]', + createElement: aDocument => { + const element = aDocument.createElement("textarea"); + element.setAttribute("style", "ime-mode: active;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedOpenState: true, + }, + { + description: 'textarea[style="ime-mode: inactive;"]', + createElement: aDocument => { + const element = aDocument.createElement("textarea"); + element.setAttribute("style", "ime-mode: inactive;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + expectedOpenState: false, + }, + { + description: 'textarea[style="ime-mode: disabled;"]', + createElement: aDocument => { + const element = aDocument.createElement("textarea"); + element.setAttribute("style", "ime-mode: disabled;"); + return element; + }, + isFocusable: + IMEStateOnFocusMoveTester.#elementIsConnectedAndNotInDesignMode, + focusEventIsExpected: () => true, + expectedEnabledValue: + IMEStateOnFocusMoveTester.#IMEStatePasswordIfNotInDesignMode, + }, + + // HTML editors + { + description: 'div[contenteditable="true"]', + createElement: aDocument => { + const div = aDocument.createElement("div"); + div.setAttribute("contenteditable", ""); + return div; + }, + isNewElementEditingHost: true, + isFocusable: IMEStateOnFocusMoveTester.#elementIsFocusableIfEditingHost, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + { + description: "designMode editor", + createElement: aDocument => { + const iframe = aDocument.createElement("iframe"); + iframe.srcdoc = "<!doctype html><html><body></body></html>"; + iframe.addEventListener( + "load", + () => (iframe.contentDocument.designMode = "on"), + { capture: true, once: true } + ); + return iframe; + }, + isFocusable: () => true, + focusEventIsExpected: () => true, + expectedEnabledValue: IMEStateOnFocusMoveTester.#IMEStateEnabledAlways, + }, + ]; + + static get numberOfTests() { + return IMEStateOnFocusMoveTester.#sTestList.length; + } +} |