summaryrefslogtreecommitdiffstats
path: root/widget/tests/file_test_ime_state_on_readonly_change.js
diff options
context:
space:
mode:
Diffstat (limited to 'widget/tests/file_test_ime_state_on_readonly_change.js')
-rw-r--r--widget/tests/file_test_ime_state_on_readonly_change.js242
1 files changed, 242 insertions, 0 deletions
diff --git a/widget/tests/file_test_ime_state_on_readonly_change.js b/widget/tests/file_test_ime_state_on_readonly_change.js
new file mode 100644
index 0000000000..af21f538ba
--- /dev/null
+++ b/widget/tests/file_test_ime_state_on_readonly_change.js
@@ -0,0 +1,242 @@
+/* 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 IMEStateOnReadonlyChangeTester {
+ static #sTextControlTypes = [
+ {
+ description: "<input>",
+ createElement: aDoc => aDoc.createElement("input"),
+ expectedIMEState: SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED,
+ },
+ {
+ description: `<input type="text">`,
+ createElement: aDoc => {
+ const input = aDoc.createElement("input");
+ input.setAttribute("type", "text");
+ return input;
+ },
+ expectedIMEState: SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED,
+ },
+ {
+ description: `<input type="password">`,
+ createElement: aDoc => {
+ const input = aDoc.createElement("input");
+ input.setAttribute("type", "password");
+ return input;
+ },
+ expectedIMEState: SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_PASSWORD,
+ },
+ {
+ description: `<input type="url">`,
+ createElement: aDoc => {
+ const input = aDoc.createElement("input");
+ input.setAttribute("type", "url");
+ return input;
+ },
+ expectedIMEState: SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED,
+ },
+ {
+ description: `<input type="email">`,
+ createElement: aDoc => {
+ const input = aDoc.createElement("input");
+ input.setAttribute("type", "email");
+ return input;
+ },
+ expectedIMEState: SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED,
+ },
+ {
+ description: `<input type="search">`,
+ createElement: aDoc => {
+ const input = aDoc.createElement("input");
+ input.setAttribute("type", "search");
+ return input;
+ },
+ expectedIMEState: SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED,
+ },
+ {
+ description: `<input type="tel">`,
+ createElement: aDoc => {
+ const input = aDoc.createElement("input");
+ input.setAttribute("type", "tel");
+ return input;
+ },
+ expectedIMEState: SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED,
+ },
+ {
+ description: `<input type="number">`,
+ createElement: aDoc => {
+ const input = aDoc.createElement("input");
+ input.setAttribute("type", "number");
+ return input;
+ },
+ expectedIMEState: SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED,
+ },
+ {
+ description: `<textarea></textarea>`,
+ createElement: aDoc => aDoc.createElement("textarea"),
+ expectedIMEState: SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED,
+ },
+ ];
+
+ static get numberOfTextControlTypes() {
+ return IMEStateOnReadonlyChangeTester.#sTextControlTypes.length;
+ }
+
+ // Only runner fields
+ #mTextControl;
+ #mTextControlElement;
+ #mWindow;
+
+ // Only checker fields
+ #mWindowUtils;
+ #mTIPWrapper;
+
+ clear() {
+ this.#mTextControlElement?.remove();
+ this.#mTIPWrapper?.clearFocusBlurNotifications();
+ this.#mTIPWrapper = null;
+ }
+
+ #flushPendingIMENotifications() {
+ return new Promise(resolve =>
+ this.#mWindow.requestAnimationFrame(() =>
+ this.#mWindow.requestAnimationFrame(resolve)
+ )
+ );
+ }
+
+ /**
+ * @param {number} aIndex The index of text control types.
+ * @param {Window} aWindow The window running tests.
+ * @param {Element} aContainer The element which should have new <input> or <textarea>.
+ * @returns {object} Expected data before running tests.
+ */
+ async prepareToRun(aIndex, aWindow, aContainer) {
+ this.#mWindow = aWindow;
+ this.#mTextControl =
+ IMEStateOnReadonlyChangeTester.#sTextControlTypes[aIndex];
+
+ if (aContainer.ownerDocument.activeElement) {
+ aContainer.ownerDocument.activeElement.blur();
+ await this.#flushPendingIMENotifications();
+ }
+ if (this.#mTextControlElement?.isConnected) {
+ this.#mTextControlElement.remove();
+ }
+ this.#mTextControlElement = this.#mTextControl.createElement(
+ aContainer.ownerDocument
+ );
+
+ const waitForFocus = new Promise(resolve =>
+ this.#mTextControlElement.addEventListener("focus", resolve, {
+ once: true,
+ })
+ );
+ aContainer.appendChild(this.#mTextControlElement);
+ this.#mTextControlElement.focus();
+ await waitForFocus;
+
+ await this.#flushPendingIMENotifications();
+
+ return {
+ description: this.#mTextControl.description,
+ expectedIMEState: this.#mTextControl.expectedIMEState,
+ expectedIMEFocus: true,
+ };
+ }
+
+ /**
+ * @param {object} aExpectedData The expected data which was returned by prepareToRun().
+ * @param {TIPWrapper} aTIPWrapper TIP wrapper in aWindow.
+ * @param {Window} aWindow [optional] The window object of which you want to check IME state.
+ */
+ checkBeforeRun(aExpectedData, aTIPWrapper, aWindow = window) {
+ this.#mWindowUtils = SpecialPowers.wrap(aWindow).windowUtils;
+ this.#mTIPWrapper = aTIPWrapper;
+ const description = `IMEStateOnReadonlyChangeTester(${aExpectedData.description})`;
+ is(
+ this.#mWindowUtils.IMEStatus,
+ aExpectedData.expectedIMEState,
+ `${description}: IME state should be set to expected value before setting readonly attribute`
+ );
+ is(
+ this.#mTIPWrapper.IMEHasFocus,
+ aExpectedData.expectedIMEFocus,
+ `${description}: IME state should ${
+ aExpectedData.expectedIMEFocus ? "" : "not"
+ } have focus before setting readonly attribute`
+ );
+ }
+
+ /**
+ * @returns {object} Expected result.
+ */
+ async runToMakeTextControlReadonly() {
+ this.#mTextControlElement.setAttribute("readonly", "");
+
+ await this.#flushPendingIMENotifications();
+
+ return {
+ description: this.#mTextControl.description,
+ expectedIMEState: SpecialPowers.Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED,
+ expectedIMEFocus: false,
+ };
+ }
+
+ /**
+ * @param {object} aExpectedData Expected result which is returned by runToMakeTextControlReadonly().
+ */
+ checkResultOfMakingTextControlReadonly(aExpectedData) {
+ const description = `IMEStateOnReadonlyChangeTester(${aExpectedData.description})`;
+ is(
+ this.#mWindowUtils.IMEStatus,
+ aExpectedData.expectedIMEState,
+ `${description}: IME state should be set to expected value after setting readonly attribute`
+ );
+ is(
+ this.#mTIPWrapper.IMEHasFocus,
+ aExpectedData.expectedIMEFocus,
+ `${description}: IME state should ${
+ aExpectedData.expectedIMEFocus ? "" : "not"
+ } have focus after setting readonly attribute`
+ );
+ }
+
+ /**
+ * @returns {object} Expected result.
+ */
+ async runToMakeTextControlEditable() {
+ this.#mTextControlElement.removeAttribute("readonly");
+
+ await this.#flushPendingIMENotifications();
+
+ return {
+ description: this.#mTextControl.description,
+ expectedIMEState: this.#mTextControl.expectedIMEState,
+ expectedIMEFocus: true,
+ };
+ }
+
+ /**
+ * @param {object} aExpectedData Expected result which is returned by runToMakeTextControlEditable().
+ */
+ checkResultOfMakingTextControlEditable(aExpectedData) {
+ const description = `IMEStateOnReadonlyChangeTester(${aExpectedData.description})`;
+ is(
+ this.#mWindowUtils.IMEStatus,
+ aExpectedData.expectedIMEState,
+ `${description}: IME state should be set to expected value after removing readonly attribute`
+ );
+ is(
+ this.#mTIPWrapper.IMEHasFocus,
+ aExpectedData.expectedIMEFocus,
+ `${description}: IME state should ${
+ aExpectedData.expectedIMEFocus ? "" : "not"
+ } have focus after removing readonly attribute`
+ );
+ }
+}