From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- widget/tests/TestChromeMargin.cpp | 130 + widget/tests/browser/browser.ini | 66 + widget/tests/browser/browser_test_ContentCache.js | 296 + .../tests/browser/browser_test_InputContextURI.js | 156 + .../tests/browser/browser_test_clipboardcache.js | 141 + .../tests/browser/browser_test_fullscreen_size.js | 66 + ...tenteditable_on_focus_move_in_remote_content.js | 122 + ...ditable_on_readonly_change_in_remote_content.js | 261 + ...n_designMode_on_focus_move_in_remote_content.js | 116 + ...r_test_ime_state_in_plugin_in_remote_content.js | 120 + ...in_text_control_on_reframe_in_remote_content.js | 78 + ...e_on_editable_state_change_in_remote_content.js | 297 + ...st_ime_state_on_focus_move_in_remote_content.js | 128 + ...state_on_input_type_change_in_remote_content.js | 70 + ...e_state_on_readonly_change_in_remote_content.js | 68 + .../tests/browser/browser_test_scrollbar_colors.js | 146 + widget/tests/browser/browser_test_swipe_gesture.js | 1275 +++ widget/tests/browser/file_ime_state_tests.html | 48 + widget/tests/browser/helper_scrollbar_colors.html | 22 + widget/tests/browser/helper_swipe_gesture.html | 20 + widget/tests/bug586713_window.xhtml | 50 + widget/tests/chrome.ini | 134 + widget/tests/clipboard_helper.js | 83 + widget/tests/empty_window.xhtml | 4 + widget/tests/file_bug596600.html | 4 + widget/tests/file_ime_state_test_helper.js | 197 + .../file_input_events_on_deactive_window.html | 5 + widget/tests/file_secure_input.html | 1 + ..._state_in_contenteditable_on_readonly_change.js | 616 ++ ...le_test_ime_state_in_text_control_on_reframe.js | 190 + widget/tests/file_test_ime_state_on_focus_move.js | 1588 +++ .../file_test_ime_state_on_input_type_change.js | 315 + .../file_test_ime_state_on_readonly_change.js | 242 + widget/tests/gtest/MockWinWidget.cpp | 77 + widget/tests/gtest/MockWinWidget.h | 85 + widget/tests/gtest/TestTimeConverter.cpp | 265 + widget/tests/gtest/TestTouchResampler.cpp | 941 ++ widget/tests/gtest/TestWinHeaderOnlyUtils.cpp | 37 + widget/tests/gtest/TestWinMessageLoggingUtils.cpp | 101 + .../tests/gtest/TestWinWindowOcclusionTracker.cpp | 167 + .../TestWinWindowOcclusionTrackerInteractive.cpp | 402 + widget/tests/gtest/moz.build | 27 + widget/tests/mochitest.ini | 27 + widget/tests/moz.build | 125 + widget/tests/native_menus_window.xhtml | 282 + widget/tests/standalone_native_menu_window.xhtml | 374 + widget/tests/system_font_changes.xhtml | 63 + widget/tests/taskbar_previews.xhtml | 116 + ...AltGr_key_events_in_web_content_on_windows.html | 106 + widget/tests/test_actionhint.html | 114 + widget/tests/test_alwaysontop_focus.xhtml | 38 + widget/tests/test_assign_event_data.html | 708 ++ widget/tests/test_autocapitalize.html | 65 + widget/tests/test_bug1123480.xhtml | 153 + widget/tests/test_bug343416.xhtml | 191 + widget/tests/test_bug413277.html | 35 + widget/tests/test_bug428405.xhtml | 166 + widget/tests/test_bug429954.xhtml | 42 + widget/tests/test_bug444800.xhtml | 97 + widget/tests/test_bug466599.xhtml | 103 + widget/tests/test_bug478536.xhtml | 33 + widget/tests/test_bug485118.xhtml | 72 + widget/tests/test_bug517396.xhtml | 53 + widget/tests/test_bug522217.xhtml | 35 + widget/tests/test_bug538242.xhtml | 55 + widget/tests/test_bug565392.html | 62 + widget/tests/test_bug586713.xhtml | 29 + widget/tests/test_bug593307.xhtml | 40 + widget/tests/test_bug596600.xhtml | 190 + widget/tests/test_bug673301.xhtml | 33 + widget/tests/test_bug760802.xhtml | 83 + widget/tests/test_clipboard.xhtml | 111 + widget/tests/test_clipboard_asyncSetData.xhtml | 173 + widget/tests/test_clipboard_cache.xhtml | 56 + widget/tests/test_clipboard_owner.xhtml | 80 + .../tests/test_composition_text_querycontent.xhtml | 34 + ...ntenteditable_on_readonly_change_in_parent.html | 72 + .../tests/test_ime_state_in_plugin_in_parent.html | 92 + ...state_in_text_control_on_reframe_in_parent.html | 42 + ...e_state_on_editable_state_change_in_parent.html | 263 + .../test_ime_state_on_focus_move_in_parent.html | 88 + ...t_ime_state_on_input_type_change_in_parent.html | 39 + ...est_ime_state_on_readonly_change_in_parent.html | 31 + widget/tests/test_ime_state_others_in_parent.html | 153 + .../test_input_events_on_deactive_window.xhtml | 233 + widget/tests/test_key_event_counts.xhtml | 90 + widget/tests/test_keycodes.xhtml | 5626 ++++++++++ .../tests/test_keypress_event_with_alt_on_mac.html | 106 + .../test_mouse_event_with_control_on_mac.html | 116 + widget/tests/test_mouse_scroll.xhtml | 35 + widget/tests/test_native_key_bindings_mac.html | 336 + widget/tests/test_native_menus.xhtml | 29 + widget/tests/test_panel_mouse_coords.xhtml | 78 + widget/tests/test_picker_no_crash.html | 30 + widget/tests/test_platform_colors.xhtml | 106 + widget/tests/test_position_on_resize.xhtml | 90 + widget/tests/test_secure_input.html | 141 + widget/tests/test_sizemode_events.xhtml | 148 + widget/tests/test_standalone_native_menu.xhtml | 29 + widget/tests/test_system_font_changes.xhtml | 28 + widget/tests/test_system_status_bar.xhtml | 53 + widget/tests/test_taskbar_progress.xhtml | 117 + widget/tests/test_textScaleFactor_system_font.html | 139 + widget/tests/test_transferable_overflow.xhtml | 151 + widget/tests/test_wheeltransaction.xhtml | 27 + widget/tests/unit/test_macsharingservice.js | 61 + widget/tests/unit/test_macwebapputils.js | 34 + widget/tests/unit/test_taskbar_jumplistitems.js | 282 + widget/tests/unit/xpcshell.ini | 11 + widget/tests/window_bug429954.xhtml | 44 + widget/tests/window_bug478536.xhtml | 211 + widget/tests/window_bug522217.xhtml | 80 + widget/tests/window_bug538242.xhtml | 3 + widget/tests/window_bug593307_centerscreen.xhtml | 26 + widget/tests/window_bug593307_offscreen.xhtml | 33 + .../window_composition_text_querycontent.xhtml | 10977 +++++++++++++++++++ widget/tests/window_imestate_iframes.html | 358 + widget/tests/window_mouse_scroll_win.html | 1516 +++ widget/tests/window_mouse_scroll_win_2.html | 6 + widget/tests/window_picker_no_crash_child.html | 6 + widget/tests/window_state_windows.xhtml | 80 + widget/tests/window_wheeltransaction.xhtml | 1569 +++ 122 files changed, 36886 insertions(+) create mode 100644 widget/tests/TestChromeMargin.cpp create mode 100644 widget/tests/browser/browser.ini create mode 100644 widget/tests/browser/browser_test_ContentCache.js create mode 100644 widget/tests/browser/browser_test_InputContextURI.js create mode 100644 widget/tests/browser/browser_test_clipboardcache.js create mode 100644 widget/tests/browser/browser_test_fullscreen_size.js create mode 100644 widget/tests/browser/browser_test_ime_state_in_contenteditable_on_focus_move_in_remote_content.js create mode 100644 widget/tests/browser/browser_test_ime_state_in_contenteditable_on_readonly_change_in_remote_content.js create mode 100644 widget/tests/browser/browser_test_ime_state_in_designMode_on_focus_move_in_remote_content.js create mode 100644 widget/tests/browser/browser_test_ime_state_in_plugin_in_remote_content.js create mode 100644 widget/tests/browser/browser_test_ime_state_in_text_control_on_reframe_in_remote_content.js create mode 100644 widget/tests/browser/browser_test_ime_state_on_editable_state_change_in_remote_content.js create mode 100644 widget/tests/browser/browser_test_ime_state_on_focus_move_in_remote_content.js create mode 100644 widget/tests/browser/browser_test_ime_state_on_input_type_change_in_remote_content.js create mode 100644 widget/tests/browser/browser_test_ime_state_on_readonly_change_in_remote_content.js create mode 100644 widget/tests/browser/browser_test_scrollbar_colors.js create mode 100644 widget/tests/browser/browser_test_swipe_gesture.js create mode 100644 widget/tests/browser/file_ime_state_tests.html create mode 100644 widget/tests/browser/helper_scrollbar_colors.html create mode 100644 widget/tests/browser/helper_swipe_gesture.html create mode 100644 widget/tests/bug586713_window.xhtml create mode 100644 widget/tests/chrome.ini create mode 100644 widget/tests/clipboard_helper.js create mode 100644 widget/tests/empty_window.xhtml create mode 100644 widget/tests/file_bug596600.html create mode 100644 widget/tests/file_ime_state_test_helper.js create mode 100644 widget/tests/file_input_events_on_deactive_window.html create mode 100644 widget/tests/file_secure_input.html create mode 100644 widget/tests/file_test_ime_state_in_contenteditable_on_readonly_change.js create mode 100644 widget/tests/file_test_ime_state_in_text_control_on_reframe.js create mode 100644 widget/tests/file_test_ime_state_on_focus_move.js create mode 100644 widget/tests/file_test_ime_state_on_input_type_change.js create mode 100644 widget/tests/file_test_ime_state_on_readonly_change.js create mode 100644 widget/tests/gtest/MockWinWidget.cpp create mode 100644 widget/tests/gtest/MockWinWidget.h create mode 100644 widget/tests/gtest/TestTimeConverter.cpp create mode 100644 widget/tests/gtest/TestTouchResampler.cpp create mode 100644 widget/tests/gtest/TestWinHeaderOnlyUtils.cpp create mode 100644 widget/tests/gtest/TestWinMessageLoggingUtils.cpp create mode 100644 widget/tests/gtest/TestWinWindowOcclusionTracker.cpp create mode 100644 widget/tests/gtest/TestWinWindowOcclusionTrackerInteractive.cpp create mode 100644 widget/tests/gtest/moz.build create mode 100644 widget/tests/mochitest.ini create mode 100644 widget/tests/moz.build create mode 100644 widget/tests/native_menus_window.xhtml create mode 100644 widget/tests/standalone_native_menu_window.xhtml create mode 100644 widget/tests/system_font_changes.xhtml create mode 100644 widget/tests/taskbar_previews.xhtml create mode 100644 widget/tests/test_AltGr_key_events_in_web_content_on_windows.html create mode 100644 widget/tests/test_actionhint.html create mode 100644 widget/tests/test_alwaysontop_focus.xhtml create mode 100644 widget/tests/test_assign_event_data.html create mode 100644 widget/tests/test_autocapitalize.html create mode 100644 widget/tests/test_bug1123480.xhtml create mode 100644 widget/tests/test_bug343416.xhtml create mode 100644 widget/tests/test_bug413277.html create mode 100644 widget/tests/test_bug428405.xhtml create mode 100644 widget/tests/test_bug429954.xhtml create mode 100644 widget/tests/test_bug444800.xhtml create mode 100644 widget/tests/test_bug466599.xhtml create mode 100644 widget/tests/test_bug478536.xhtml create mode 100644 widget/tests/test_bug485118.xhtml create mode 100644 widget/tests/test_bug517396.xhtml create mode 100644 widget/tests/test_bug522217.xhtml create mode 100644 widget/tests/test_bug538242.xhtml create mode 100644 widget/tests/test_bug565392.html create mode 100644 widget/tests/test_bug586713.xhtml create mode 100644 widget/tests/test_bug593307.xhtml create mode 100644 widget/tests/test_bug596600.xhtml create mode 100644 widget/tests/test_bug673301.xhtml create mode 100644 widget/tests/test_bug760802.xhtml create mode 100644 widget/tests/test_clipboard.xhtml create mode 100644 widget/tests/test_clipboard_asyncSetData.xhtml create mode 100644 widget/tests/test_clipboard_cache.xhtml create mode 100644 widget/tests/test_clipboard_owner.xhtml create mode 100644 widget/tests/test_composition_text_querycontent.xhtml create mode 100644 widget/tests/test_ime_state_in_contenteditable_on_readonly_change_in_parent.html create mode 100644 widget/tests/test_ime_state_in_plugin_in_parent.html create mode 100644 widget/tests/test_ime_state_in_text_control_on_reframe_in_parent.html create mode 100644 widget/tests/test_ime_state_on_editable_state_change_in_parent.html create mode 100644 widget/tests/test_ime_state_on_focus_move_in_parent.html create mode 100644 widget/tests/test_ime_state_on_input_type_change_in_parent.html create mode 100644 widget/tests/test_ime_state_on_readonly_change_in_parent.html create mode 100644 widget/tests/test_ime_state_others_in_parent.html create mode 100644 widget/tests/test_input_events_on_deactive_window.xhtml create mode 100644 widget/tests/test_key_event_counts.xhtml create mode 100644 widget/tests/test_keycodes.xhtml create mode 100644 widget/tests/test_keypress_event_with_alt_on_mac.html create mode 100644 widget/tests/test_mouse_event_with_control_on_mac.html create mode 100644 widget/tests/test_mouse_scroll.xhtml create mode 100644 widget/tests/test_native_key_bindings_mac.html create mode 100644 widget/tests/test_native_menus.xhtml create mode 100644 widget/tests/test_panel_mouse_coords.xhtml create mode 100644 widget/tests/test_picker_no_crash.html create mode 100644 widget/tests/test_platform_colors.xhtml create mode 100644 widget/tests/test_position_on_resize.xhtml create mode 100644 widget/tests/test_secure_input.html create mode 100644 widget/tests/test_sizemode_events.xhtml create mode 100644 widget/tests/test_standalone_native_menu.xhtml create mode 100644 widget/tests/test_system_font_changes.xhtml create mode 100644 widget/tests/test_system_status_bar.xhtml create mode 100644 widget/tests/test_taskbar_progress.xhtml create mode 100644 widget/tests/test_textScaleFactor_system_font.html create mode 100644 widget/tests/test_transferable_overflow.xhtml create mode 100644 widget/tests/test_wheeltransaction.xhtml create mode 100644 widget/tests/unit/test_macsharingservice.js create mode 100644 widget/tests/unit/test_macwebapputils.js create mode 100644 widget/tests/unit/test_taskbar_jumplistitems.js create mode 100644 widget/tests/unit/xpcshell.ini create mode 100644 widget/tests/window_bug429954.xhtml create mode 100644 widget/tests/window_bug478536.xhtml create mode 100644 widget/tests/window_bug522217.xhtml create mode 100644 widget/tests/window_bug538242.xhtml create mode 100644 widget/tests/window_bug593307_centerscreen.xhtml create mode 100644 widget/tests/window_bug593307_offscreen.xhtml create mode 100644 widget/tests/window_composition_text_querycontent.xhtml create mode 100644 widget/tests/window_imestate_iframes.html create mode 100644 widget/tests/window_mouse_scroll_win.html create mode 100644 widget/tests/window_mouse_scroll_win_2.html create mode 100644 widget/tests/window_picker_no_crash_child.html create mode 100644 widget/tests/window_state_windows.xhtml create mode 100644 widget/tests/window_wheeltransaction.xhtml (limited to 'widget/tests') diff --git a/widget/tests/TestChromeMargin.cpp b/widget/tests/TestChromeMargin.cpp new file mode 100644 index 0000000000..0eed86b208 --- /dev/null +++ b/widget/tests/TestChromeMargin.cpp @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* This tests the margin parsing functionality in nsAttrValue.cpp, which + * is accessible via nsContentUtils, and is used in setting chromemargins + * to widget windows. It's located here due to linking issues in the + * content directory. + */ + +/* This test no longer compiles now that we've removed nsIContentUtils (bug + * 647273). We need to be internal code in order to include nsContentUtils.h, + * but defining MOZILLA_INTERNAL_API is not enough to make us internal. + */ + +#include "TestHarness.h" + +#ifndef MOZILLA_INTERNAL_API +# error This test needs MOZILLA_INTERNAL_API (see bug 652123) +#endif + +#include "nscore.h" +#include "nsContentUtils.h" +#include "nsString.h" + +struct DATA { + bool shouldfail; + const char* margins; + int top; + int right; + int bottom; + int left; +}; + +const bool SHOULD_FAIL = true; +const int SHOULD_PASS = false; + +const DATA Data[] = { + {SHOULD_FAIL, "", 1, 2, 3, 4}, + {SHOULD_FAIL, "1,0,0,0", 1, 2, 3, 4}, + {SHOULD_FAIL, "1,2,0,0", 1, 2, 3, 4}, + {SHOULD_FAIL, "1,2,3,0", 1, 2, 3, 4}, + {SHOULD_FAIL, "4,3,2,1", 1, 2, 3, 4}, + {SHOULD_FAIL, "azsasdasd", 0, 0, 0, 0}, + {SHOULD_FAIL, ",azsasdasd", 0, 0, 0, 0}, + {SHOULD_FAIL, " ", 1, 2, 3, 4}, + {SHOULD_FAIL, + "azsdfsdfsdfsdfsdfsasdasd,asdasdasdasdasdasd,asdadasdasd,asdasdasdasd", 0, + 0, 0, 0}, + {SHOULD_FAIL, "as,as,as,as", 0, 0, 0, 0}, + {SHOULD_FAIL, "0,0,0", 0, 0, 0, 0}, + {SHOULD_FAIL, "0,0", 0, 0, 0, 0}, + {SHOULD_FAIL, "4.6,1,1,1", 0, 0, 0, 0}, + {SHOULD_FAIL, ",,,,", 0, 0, 0, 0}, + {SHOULD_FAIL, "1, , , ,", 0, 0, 0, 0}, + {SHOULD_FAIL, "1, , ,", 0, 0, 0, 0}, + {SHOULD_FAIL, "@!@%^&^*()", 1, 2, 3, 4}, + {SHOULD_PASS, "4,3,2,1", 4, 3, 2, 1}, + {SHOULD_PASS, "-4,-3,-2,-1", -4, -3, -2, -1}, + {SHOULD_PASS, "10000,3,2,1", 10000, 3, 2, 1}, + {SHOULD_PASS, "4 , 3 , 2 , 1", 4, 3, 2, 1}, + {SHOULD_PASS, "4, 3 ,2,1", 4, 3, 2, 1}, + {SHOULD_FAIL, "4,3,2,10000000000000 --", 4, 3, 2, 10000000000000}, + {SHOULD_PASS, "4,3,2,1000", 4, 3, 2, 1000}, + {SHOULD_PASS, "2147483647,3,2,1000", 2147483647, 3, 2, 1000}, + {SHOULD_PASS, "2147483647,2147483647,2147483647,2147483647", 2147483647, + 2147483647, 2147483647, 2147483647}, + {SHOULD_PASS, "-2147483647,3,2,1000", -2147483647, 3, 2, 1000}, + {SHOULD_FAIL, "2147483648,3,2,1000", 1, 3, 2, 1000}, + {0, nullptr, 0, 0, 0, 0}}; + +void DoAttrValueTest() { + int idx = -1; + bool didFail = false; + while (Data[++idx].margins) { + nsAutoString str; + str.AssignLiteral(Data[idx].margins); + nsIntMargin values(99, 99, 99, 99); + bool result = nsContentUtils::ParseIntMarginValue(str, values); + + // if the parse fails + if (!result) { + if (Data[idx].shouldfail) continue; + fail(Data[idx].margins); + didFail = true; + printf("*1\n"); + continue; + } + + if (Data[idx].shouldfail) { + if (Data[idx].top == values.top && Data[idx].right == values.right && + Data[idx].bottom == values.bottom && Data[idx].left == values.left) { + // not likely + fail(Data[idx].margins); + didFail = true; + printf("*2\n"); + continue; + } + // good failure, parse failed and that's what we expected. + continue; + } +#if 0 + printf("%d==%d %d==%d %d==%d %d==%d\n", + Data[idx].top, values.top, + Data[idx].right, values.right, + Data[idx].bottom, values.bottom, + Data[idx].left, values.left); +#endif + if (Data[idx].top == values.top && Data[idx].right == values.right && + Data[idx].bottom == values.bottom && Data[idx].left == values.left) { + // good parse results + continue; + } else { + fail(Data[idx].margins); + didFail = true; + printf("*3\n"); + continue; + } + } + + if (!didFail) passed("nsAttrValue margin parsing tests passed."); +} + +int main(int argc, char** argv) { + ScopedXPCOM xpcom(""); + if (xpcom.failed()) return 1; + DoAttrValueTest(); + return 0; +} diff --git a/widget/tests/browser/browser.ini b/widget/tests/browser/browser.ini new file mode 100644 index 0000000000..5bd1ce0dc1 --- /dev/null +++ b/widget/tests/browser/browser.ini @@ -0,0 +1,66 @@ +[DEFAULT] +skip-if = os == 'andriod' + +[browser_test_ContentCache.js] +[browser_test_InputContextURI.js] +[browser_test_clipboardcache.js] +skip-if = + (os == 'linux' && ccov) || tsan # Bug 1613516, the test consistently timeouts on Linux coverage builds. + os == "win" && bits == 32 && !debug # Bug 1759422 + os == "linux" # Bug 1792749 +[browser_test_fullscreen_size.js] +[browser_test_ime_state_in_contenteditable_on_focus_move_in_remote_content.js] +support-files = + file_ime_state_tests.html + ../file_ime_state_test_helper.js + ../file_test_ime_state_on_focus_move.js +[browser_test_ime_state_in_contenteditable_on_readonly_change_in_remote_content.js] +support-files = + file_ime_state_tests.html + ../file_ime_state_test_helper.js + ../file_test_ime_state_in_contenteditable_on_readonly_change.js +[browser_test_ime_state_in_designMode_on_focus_move_in_remote_content.js] +support-files = + file_ime_state_tests.html + ../file_ime_state_test_helper.js + ../file_test_ime_state_on_focus_move.js +[browser_test_ime_state_in_plugin_in_remote_content.js] +support-files = + ../file_ime_state_test_helper.js +[browser_test_ime_state_in_text_control_on_reframe_in_remote_content.js] +support-files = + ../file_ime_state_test_helper.js + ../file_test_ime_state_in_text_control_on_reframe.js +[browser_test_ime_state_on_editable_state_change_in_remote_content.js] +support-files = + ../file_ime_state_test_helper.js +[browser_test_ime_state_on_focus_move_in_remote_content.js] +support-files = + file_ime_state_tests.html + ../file_ime_state_test_helper.js + ../file_test_ime_state_on_focus_move.js +[browser_test_ime_state_on_input_type_change_in_remote_content.js] +skip-if = true # Bug 1817704 +support-files = + file_ime_state_tests.html + ../file_ime_state_test_helper.js + ../file_test_ime_state_on_input_type_change.js +[browser_test_ime_state_on_readonly_change_in_remote_content.js] +support-files = + file_ime_state_tests.html + ../file_ime_state_test_helper.js + ../file_test_ime_state_on_readonly_change.js +[browser_test_scrollbar_colors.js] +skip-if = (os == 'linux') # bug 1460109 +support-files = + helper_scrollbar_colors.html +[browser_test_swipe_gesture.js] +run-if = (os == 'mac' || os == 'win' || os == 'linux') +skip-if = + os == "win" && bits == 32 && !debug # Bug 1759422 + verify # Bug 1800022 + os == "linux" # Bug 1784772 +support-files = + helper_swipe_gesture.html + !/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js + !/gfx/layers/apz/test/mochitest/apz_test_utils.js diff --git a/widget/tests/browser/browser_test_ContentCache.js b/widget/tests/browser/browser_test_ContentCache.js new file mode 100644 index 0000000000..7b64e00f13 --- /dev/null +++ b/widget/tests/browser/browser_test_ContentCache.js @@ -0,0 +1,296 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function () { + const TIP = Cc["@mozilla.org/text-input-processor;1"].createInstance( + Ci.nsITextInputProcessor + ); + let notifications = []; + const observer = (aTIP, aNotification) => { + switch (aNotification.type) { + case "request-to-commit": + aTIP.commitComposition(); + break; + case "request-to-cancel": + aTIP.cancelComposition(); + break; + case "notify-end-input-transaction": + case "notify-focus": + case "notify-blur": + case "notify-text-change": + case "notify-selection-change": + notifications.push(aNotification); + break; + } + return true; + }; + + function checkNotifications(aExpectedNotifications, aDescription) { + for (const expectedNotification of aExpectedNotifications) { + const notification = notifications.find( + element => element.type == expectedNotification.type + ); + if (expectedNotification.expected) { + isnot( + notification, + undefined, + `"${expectedNotification.type}" should be notified ${aDescription}` + ); + } else { + is( + notification, + undefined, + `"${expectedNotification.type}" should not be notified ${aDescription}` + ); + } + } + } + + ok( + TIP.beginInputTransaction(window, observer), + "nsITextInputProcessor.beingInputTransaction should return true" + ); + ok( + TIP.beginInputTransactionForTests(window, observer), + "nsITextInputProcessor.beginInputTransactionForTests should return true" + ); + + await BrowserTestUtils.withNewTab( + "https://example.com/browser/toolkit/content/tests/browser/file_empty.html", + async function (browser) { + ok(browser.isRemoteBrowser, "This test passes only in e10s mode"); + + // IMEContentObserver flushes pending IME notifications at next vsync + // after something happens. Therefore, after doing something in content + // process, we need to guarantee that IMEContentObserver has a change to + // send IME notifications to the main process with calling this function. + function waitForSendingIMENotificationsInContent() { + return SpecialPowers.spawn(browser, [], async () => { + await new Promise(resolve => + content.requestAnimationFrame(() => + content.requestAnimationFrame(resolve) + ) + ); + }); + } + + /** + * Test when empty editor gets focus + */ + notifications = []; + await SpecialPowers.spawn(browser, [], () => { + content.document.body.innerHTML = "

"; + const editor = content.document.querySelector("div[contenteditable]"); + editor.focus(); + }); + + await waitForSendingIMENotificationsInContent(); + + (function () { + checkNotifications( + [ + { type: "notify-focus", expected: true }, + { type: "notify-blur", expected: false }, + { type: "notify-end-input-transaction", expected: false }, + { type: "notify-text-change", expected: false }, + { type: "notify-selection-change", expected: false }, + ], + "after empty editor gets focus" + ); + const text = EventUtils.synthesizeQueryTextContent(0, 1000); + ok( + text?.succeeded, + "query text content should succeed after empty editor gets focus" + ); + if (text?.succeeded) { + is( + text.text.replace(/[\r\n]/g, ""), + "", + "text should be only line breaks after empty editor gets focus" + ); + } + const selection = EventUtils.synthesizeQuerySelectedText(); + ok( + selection?.succeeded, + "query selected text should succeed after empty editor gets focus" + ); + if (selection?.succeeded) { + ok( + !selection.notFound, + "query selected text should find a selection range after empty editor gets focus" + ); + if (!selection.notFound) { + is( + selection.text, + "", + "selection should be collapsed after empty editor gets focus" + ); + } + } + })(); + + /** + * Test when there is non-collapsed selection + */ + notifications = []; + await SpecialPowers.spawn(browser, [], () => { + const editor = content.document.querySelector("div[contenteditable]"); + editor.innerHTML = "

abc

def

"; + content + .getSelection() + .setBaseAndExtent( + editor.querySelector("p").firstChild, + 2, + editor.querySelector("p + p").firstChild, + 1 + ); + }); + + await waitForSendingIMENotificationsInContent(); + + (function () { + checkNotifications( + [ + { type: "notify-focus", expected: false }, + { type: "notify-blur", expected: false }, + { type: "notify-end-input-transaction", expected: false }, + { type: "notify-text-change", expected: true }, + { type: "notify-selection-change", expected: true }, + ], + "after modifying focused editor" + ); + const text = EventUtils.synthesizeQueryTextContent(0, 1000); + ok( + text?.succeeded, + "query text content should succeed after modifying focused editor" + ); + if (text?.succeeded) { + is( + text.text.trim().replace(/\r\n/g, "\n").replace(/\n\n+/g, "\n"), + "abc\ndef", + "text should include the both paragraph's text after modifying focused editor" + ); + } + const selection = EventUtils.synthesizeQuerySelectedText(); + ok( + selection?.succeeded, + "query selected text should succeed after modifying focused editor" + ); + if (selection?.succeeded) { + ok( + !selection.notFound, + "query selected text should find a selection range after modifying focused editor" + ); + if (!selection.notFound) { + is( + selection.text + .trim() + .replace(/\r\n/g, "\n") + .replace(/\n\n+/g, "\n"), + "c\nd", + "selection should have the selected characters in the both paragraphs after modifying focused editor" + ); + } + } + })(); + + /** + * Test when there is no selection ranges + */ + notifications = []; + await SpecialPowers.spawn(browser, [], () => { + content.getSelection().removeAllRanges(); + }); + + await waitForSendingIMENotificationsInContent(); + + (function () { + checkNotifications( + [ + { type: "notify-focus", expected: false }, + { type: "notify-blur", expected: false }, + { type: "notify-end-input-transaction", expected: false }, + { type: "notify-text-change", expected: false }, + { type: "notify-selection-change", expected: true }, + ], + "after removing all selection ranges from the focused editor" + ); + const text = EventUtils.synthesizeQueryTextContent(0, 1000); + ok( + text?.succeeded, + "query text content should succeed after removing all selection ranges from the focused editor" + ); + if (text?.succeeded) { + is( + text.text.trim().replace(/\r\n/g, "\n").replace(/\n\n+/g, "\n"), + "abc\ndef", + "text should include the both paragraph's text after removing all selection ranges from the focused editor" + ); + } + const selection = EventUtils.synthesizeQuerySelectedText(); + ok( + selection?.succeeded, + "query selected text should succeed after removing all selection ranges from the focused editor" + ); + if (selection?.succeeded) { + ok( + selection.notFound, + "query selected text should find no selection range after removing all selection ranges from the focused editor" + ); + } + })(); + + /** + * Test when no editable element has focus. + */ + notifications = []; + await SpecialPowers.spawn(browser, [], () => { + content.document.body.innerHTML = "abcdef"; + }); + + await waitForSendingIMENotificationsInContent(); + + (function () { + checkNotifications( + [ + { type: "notify-focus", expected: false }, + { type: "notify-blur", expected: true }, + ], + "removing editor should make ContentCacheInParent not have any data" + ); + const text = EventUtils.synthesizeQueryTextContent(0, 1000); + ok( + !text?.succeeded, + "query text content should fail because no editable element has focus" + ); + const selection = EventUtils.synthesizeQuerySelectedText(); + ok( + !selection?.succeeded, + "query selected text should fail because no editable element has focus" + ); + const caret = EventUtils.synthesizeQueryCaretRect(0); + ok( + !caret?.succeeded, + "query caret rect should fail because no editable element has focus" + ); + const textRect = EventUtils.synthesizeQueryTextRect(0, 5, false); + ok( + !textRect?.succeeded, + "query text rect should fail because no editable element has focus" + ); + const textRectArray = EventUtils.synthesizeQueryTextRectArray(0, 5); + ok( + !textRectArray?.succeeded, + "query text rect array should fail because no editable element has focus" + ); + const editorRect = EventUtils.synthesizeQueryEditorRect(); + todo( + !editorRect?.succeeded, + "query editor rect should fail because no editable element has focus" + ); + })(); + } + ); +}); diff --git a/widget/tests/browser/browser_test_InputContextURI.js b/widget/tests/browser/browser_test_InputContextURI.js new file mode 100644 index 0000000000..52f05d90f9 --- /dev/null +++ b/widget/tests/browser/browser_test_InputContextURI.js @@ -0,0 +1,156 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const gDOMWindowUtils = EventUtils._getDOMWindowUtils(window); + +function promiseURLBarFocus() { + const waitForFocusInURLBar = BrowserTestUtils.waitForEvent(gURLBar, "focus"); + gURLBar.blur(); + gURLBar.focus(); + return Promise.all([ + waitForFocusInURLBar, + TestUtils.waitForCondition( + () => + gDOMWindowUtils.IMEStatus === Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED && + gDOMWindowUtils.inputContextOrigin === + Ci.nsIDOMWindowUtils.INPUT_CONTEXT_ORIGIN_MAIN + ), + ]); +} + +function promiseIMEStateEnabledByRemote() { + return TestUtils.waitForCondition( + () => + gDOMWindowUtils.IMEStatus === Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED && + gDOMWindowUtils.inputContextOrigin === + Ci.nsIDOMWindowUtils.INPUT_CONTEXT_ORIGIN_CONTENT + ); +} + +async function test_url_bar_url(aDesc) { + await promiseURLBarFocus(); + + is( + gDOMWindowUtils.inputContextURI, + null, + `When the search bar has focus, input context URI should be null because of in chrome document (${aDesc})` + ); +} + +async function test_input_in_http_or_https(aIsHTTPS) { + await promiseURLBarFocus(); + + const scheme = aIsHTTPS ? "https" : "http"; + const url = `${scheme}://example.com/browser/toolkit/content/tests/browser/file_empty.html`; + await BrowserTestUtils.withNewTab(url, async browser => { + ok(browser.isRemoteBrowser, "This test passes only in e10s mode"); + + await SpecialPowers.spawn(browser, [], async () => { + content.document.body.innerHTML = ""; + const input = content.document.querySelector("input"); + input.focus(); + + // Wait for a tick for flushing IMEContentObserver's pending notifications. + await new Promise(resolve => + content.requestAnimationFrame(() => + content.requestAnimationFrame(resolve) + ) + ); + }); + + await promiseIMEStateEnabledByRemote(); + if (!gDOMWindowUtils.inputContextURI) { + ok( + false, + `Input context should have valid URI when the scheme of focused tab's URL is ${scheme}` + ); + return; + } + is( + gDOMWindowUtils.inputContextURI.spec, + url, + `Input context should have the document URI when the scheme of focused tab's URL is ${scheme}` + ); + }); +} + +add_task(async () => { + await test_url_bar_url("first check"); +}); +add_task(async () => { + await test_input_in_http_or_https(true); +}); +add_task(async () => { + await test_url_bar_url("check after remote content sets the URI"); +}); +add_task(async () => { + await test_input_in_http_or_https(false); +}); + +add_task(async function test_input_in_data() { + await BrowserTestUtils.withNewTab("data:text/html,", async browser => { + ok(browser.isRemoteBrowser, "This test passes only in e10s mode"); + + await SpecialPowers.spawn(browser, [], async () => { + const input = content.document.querySelector("input"); + input.focus(); + + // Wait for a tick for flushing IMEContentObserver's pending notifications. + await new Promise(resolve => + content.requestAnimationFrame(() => + content.requestAnimationFrame(resolve) + ) + ); + }); + + await promiseIMEStateEnabledByRemote(); + is( + gDOMWindowUtils.inputContextURI, + null, + "Input context should not have data URI" + ); + }); +}); + +add_task(async function test_omit_private_things_in_URL() { + await SpecialPowers.pushPrefEnv({ + set: [["network.auth.confirmAuth.enabled", false]], + }); + await promiseURLBarFocus(); + + await BrowserTestUtils.withNewTab( + "https://username:password@example.com/browser/toolkit/content/tests/browser/file_empty.html?query=some#ref", + async browser => { + ok(browser.isRemoteBrowser, "This test passes only in e10s mode"); + + await SpecialPowers.spawn(browser, [], async () => { + content.document.body.innerHTML = ""; + const input = content.document.querySelector("input"); + input.focus(); + + // Wait for a tick for flushing IMEContentObserver's pending notifications. + await new Promise(resolve => + content.requestAnimationFrame(() => + content.requestAnimationFrame(resolve) + ) + ); + }); + + await promiseIMEStateEnabledByRemote(); + if (!gDOMWindowUtils.inputContextURI) { + ok( + false, + `Input context should have valid URI even when the URL contains some private things` + ); + return; + } + is( + gDOMWindowUtils.inputContextURI.spec, + "https://example.com/browser/toolkit/content/tests/browser/file_empty.html", + `Input context should have the document URI which omit some private things in the URL` + ); + } + ); +}); diff --git a/widget/tests/browser/browser_test_clipboardcache.js b/widget/tests/browser/browser_test_clipboardcache.js new file mode 100644 index 0000000000..bce0b9a918 --- /dev/null +++ b/widget/tests/browser/browser_test_clipboardcache.js @@ -0,0 +1,141 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +// Note: widget/tests/test_bug1123480.xhtml checks whether nsTransferable behaves +// as expected with regards to private browsing mode and the clipboard cache, +// i.e. that the clipboard is not cached to the disk when private browsing mode +// is enabled. +// +// This test tests that the clipboard is not cached to the disk by IPC, +// as a regression test for bug 1396224. +// It indirectly uses nsTransferable, via the async navigator.clipboard API. + +// Create over 1 MB of sample garbage text. JavaScript strings are represented +// by UTF16 strings, so the size is twice as much as the actual string length. +// This value is chosen such that the size of the memory for the string exceeds +// the kLargeDatasetSize threshold in nsTransferable.h. +// It is also not a round number to reduce the odds of having an accidental +// collisions with another file (since the test below looks at the file size +// to identify the file). +var Ipsum = "0123456789".repeat(1234321); +var IpsumByteLength = Ipsum.length * 2; +var SHORT_STRING_NO_CACHE = "short string that will not be cached to the disk"; + +// Get a list of open file descriptors that refer to a file with the same size +// as the expected data (and assume that any mutations in file descriptor counts +// are caused by our test). +// TODO: This logic only counts file descriptors that are still open (e.g. when +// data persists after a copy). It does not detect cache files that exist only +// temporarily (e.g. after a paste). +function getClipboardCacheFDCount() { + let dir; + if (AppConstants.platform === "win") { + // On Windows, nsAnonymousTemporaryFile does not immediately delete a file. + // Instead, the Windows-specific FILE_FLAG_DELETE_ON_CLOSE flag is used, + // which means that the file is deleted when the last handle is closed. + // Apparently, this flag is unreliable (e.g. when the application crashes), + // so nsAnonymousTemporaryFile stores the temporary files in a subdirectory, + // which is cleaned up some time after start-up. + + // This is just a test, and during the test we deterministically close the + // handles, so if FILE_FLAG_DELETE_ON_CLOSE does the thing it promises, the + // file is actually removed when the handle is closed. + + let { FileUtils } = ChromeUtils.importESModule( + "resource://gre/modules/FileUtils.sys.mjs" + ); + // Path from nsAnonymousTemporaryFile.cpp, GetTempDir. + dir = FileUtils.getFile("TmpD", ["mozilla-temp-files"]); + } else { + dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); + dir.initWithPath("/dev/fd"); + } + let count = 0; + for (let fdFile of dir.directoryEntries) { + let fileSize; + try { + fileSize = fdFile.fileSize; + } catch (e) { + // This can happen on macOS. + continue; + } + if (fileSize === IpsumByteLength) { + // Assume that the file was created by us if the size matches. + ++count; + } + } + return count; +} + +async function testCopyPaste(isPrivate) { + let win = await BrowserTestUtils.openNewBrowserWindow({ private: isPrivate }); + let tab = await BrowserTestUtils.openNewForegroundTab(win); + let browser = tab.linkedBrowser; + + // Sanitize environment + await ContentTask.spawn(browser, SHORT_STRING_NO_CACHE, async shortStr => { + await content.navigator.clipboard.writeText(shortStr); + }); + + let initialFdCount = getClipboardCacheFDCount(); + + await SpecialPowers.spawn(browser, [Ipsum], async largeString => { + await content.navigator.clipboard.writeText(largeString); + }); + + let fdCountAfterCopy = getClipboardCacheFDCount(); + if (isPrivate) { + is(fdCountAfterCopy, initialFdCount, "Private write"); + } else { + is(fdCountAfterCopy, initialFdCount + 1, "Cached write"); + } + + let readStr = await SpecialPowers.spawn(browser, [], async () => { + let { document } = content; + document.body.contentEditable = true; + document.body.focus(); + let pastePromise = new Promise(resolve => { + document.addEventListener( + "paste", + e => { + resolve(e.clipboardData.getData("text/plain")); + }, + { once: true } + ); + }); + document.execCommand("paste"); + return pastePromise; + }); + ok(readStr === Ipsum, "Read what we pasted"); + + if (isPrivate) { + is(getClipboardCacheFDCount(), fdCountAfterCopy, "Private read"); + } else { + // Upon reading from the clipboard, a temporary nsTransferable is used, for + // which the cache is disabled. The content process does not cache clipboard + // data either. So the file descriptor count should be identical. + is(getClipboardCacheFDCount(), fdCountAfterCopy, "Read not cached"); + } + + // Cleanup. + await SpecialPowers.spawn( + browser, + [SHORT_STRING_NO_CACHE], + async shortStr => { + await content.navigator.clipboard.writeText(shortStr); + } + ); + is(getClipboardCacheFDCount(), initialFdCount, "Drop clipboard cache if any"); + + BrowserTestUtils.removeTab(tab); + await BrowserTestUtils.closeWindow(win); +} + +add_task(async function test_private() { + await testCopyPaste(true); +}); + +add_task(async function test_non_private() { + await testCopyPaste(false); +}); diff --git a/widget/tests/browser/browser_test_fullscreen_size.js b/widget/tests/browser/browser_test_fullscreen_size.js new file mode 100644 index 0000000000..c358d335d8 --- /dev/null +++ b/widget/tests/browser/browser_test_fullscreen_size.js @@ -0,0 +1,66 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +function waitForReflow(aWindow) { + return new Promise(resolve => { + aWindow.requestAnimationFrame(() => { + aWindow.requestAnimationFrame(resolve); + }); + }); +} + +add_task(async function fullscreen_size() { + let win = await BrowserTestUtils.openNewBrowserWindow({}); + win.gBrowser.selectedBrowser.focus(); + + info("Enter browser fullscreen mode"); + let promise = Promise.all([ + BrowserTestUtils.waitForEvent(win, "fullscreen"), + BrowserTestUtils.waitForEvent(win, "resize"), + ]); + win.fullScreen = true; + await promise; + + info("Await reflow of the chrome window"); + await waitForReflow(win); + + is(win.innerHeight, win.outerHeight, "Check height"); + is(win.innerWidth, win.outerWidth, "Check width"); + + await BrowserTestUtils.closeWindow(win); +}); + +// https://bugzilla.mozilla.org/show_bug.cgi?id=1830721 +add_task(async function fullscreen_size_moz_appearance() { + const win = await BrowserTestUtils.openNewBrowserWindow({}); + win.gBrowser.selectedBrowser.focus(); + + info("Add -moz-appearance style to chrome document"); + const style = win.document.createElement("style"); + style.innerHTML = ` + #main-window { + -moz-appearance: -moz-win-borderless-glass; + } + `; + win.document.head.appendChild(style); + + info("Await reflow of the chrome window"); + await waitForReflow(win); + + info("Enter browser fullscreen mode"); + let promise = Promise.all([ + BrowserTestUtils.waitForEvent(win, "fullscreen"), + BrowserTestUtils.waitForEvent(win, "resize"), + ]); + win.fullScreen = true; + await promise; + + info("Await reflow of the chrome window"); + await waitForReflow(win); + + is(win.innerHeight, win.outerHeight, "Check height"); + is(win.innerWidth, win.outerWidth, `Check width`); + + await BrowserTestUtils.closeWindow(win); +}); diff --git a/widget/tests/browser/browser_test_ime_state_in_contenteditable_on_focus_move_in_remote_content.js b/widget/tests/browser/browser_test_ime_state_in_contenteditable_on_focus_move_in_remote_content.js new file mode 100644 index 0000000000..50b19f0cc3 --- /dev/null +++ b/widget/tests/browser/browser_test_ime_state_in_contenteditable_on_focus_move_in_remote_content.js @@ -0,0 +1,122 @@ +/* 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 */ +/* import-globals-from ../file_test_ime_state_on_focus_move.js */ + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_ime_state_test_helper.js", + this +); +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_test_ime_state_on_focus_move.js", + this +); +add_task(async function () { + await BrowserTestUtils.withNewTab( + "https://example.com/browser/widget/tests/browser/file_ime_state_tests.html", + async function (browser) { + const tipWrapper = new TIPWrapper(window); + ok( + tipWrapper.isAvailable(), + "TextInputProcessor should've been initialized" + ); + + // isnot is used in file_test_ime_state_on_focus_move.js, but it's not + // defined as the alias of Assert.notEqual in browser-chrome tests. + // Therefore, we need to define it here. + // eslint-disable-next-line no-unused-vars + const isnot = Assert.notEqual; + + async function runIMEStateOnFocusMoveTests(aDescription) { + await (async function test_IMEState_without_focused_element() { + const checker = new IMEStateWhenNoActiveElementTester(aDescription); + const expectedData = await SpecialPowers.spawn( + browser, + [aDescription], + description => { + const runner = + content.wrappedJSObject.createIMEStateWhenNoActiveElementTester( + description + ); + return runner.run(content.document, content.window); + } + ); + checker.check(expectedData); + })(); + for ( + let index = 0; + index < IMEStateOnFocusMoveTester.numberOfTests; + ++index + ) { + const checker = new IMEStateOnFocusMoveTester(aDescription, index); + const expectedData = await SpecialPowers.spawn( + browser, + [aDescription, index], + (description, aIndex) => { + content.wrappedJSObject.runner = + content.wrappedJSObject.createIMEStateOnFocusMoveTester( + description, + aIndex, + content.window + ); + return content.wrappedJSObject.runner.prepareToRun( + content.document.querySelector("div") + ); + } + ); + checker.prepareToCheck(expectedData, tipWrapper); + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.run(); + }); + checker.check(expectedData); + + if (checker.canTestOpenCloseState(expectedData)) { + for (const defaultOpenState of [false, true]) { + const expectedOpenStateData = await SpecialPowers.spawn( + browser, + [], + () => { + return content.wrappedJSObject.runner.prepareToRunOpenCloseTest( + content.document.querySelector("div") + ); + } + ); + checker.prepareToCheckOpenCloseTest( + defaultOpenState, + expectedOpenStateData + ); + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runOpenCloseTest(); + }); + checker.checkOpenCloseTest(expectedOpenStateData); + } + } + await SpecialPowers.spawn(browser, [], () => { + content.wrappedJSObject.runner.destroy(); + content.wrappedJSObject.runner = undefined; + }); + checker.destroy(); + } // for loop iterating test of IMEStateOnFocusMoveTester + } // definition of runIMEStateOnFocusMoveTests + + // test for contentEditable="true" + await SpecialPowers.spawn(browser, [], async () => { + content.document + .querySelector("div") + .setAttribute("contenteditable", "true"); + }); + await runIMEStateOnFocusMoveTests("in div[contenteditable]"); + + // test for contentEditable="false" + await SpecialPowers.spawn(browser, [], async () => { + content.document + .querySelector("div") + .setAttribute("contenteditable", "false"); + }); + await runIMEStateOnFocusMoveTests('in div[contenteditable="false"]'); + } + ); +}); diff --git a/widget/tests/browser/browser_test_ime_state_in_contenteditable_on_readonly_change_in_remote_content.js b/widget/tests/browser/browser_test_ime_state_in_contenteditable_on_readonly_change_in_remote_content.js new file mode 100644 index 0000000000..33217d1d2c --- /dev/null +++ b/widget/tests/browser/browser_test_ime_state_in_contenteditable_on_readonly_change_in_remote_content.js @@ -0,0 +1,261 @@ +/* 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 */ +/* import-globals-from ../file_test_ime_state_in_contenteditable_on_readonly_change.js */ + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_ime_state_test_helper.js", + this +); +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_test_ime_state_in_contenteditable_on_readonly_change.js", + this +); +add_task(async function () { + await BrowserTestUtils.withNewTab( + "https://example.com/browser/widget/tests/browser/file_ime_state_tests.html", + async function (browser) { + const tipWrapper = new TIPWrapper(window); + ok( + tipWrapper.isAvailable(), + "TextInputProcessor should've been initialized" + ); + + await (async function test_ime_state_in_contenteditable_on_readonly_change() { + const expectedDataOfInitialization = await SpecialPowers.spawn( + browser, + [], + () => { + content.document.body.innerHTML = "

"; + content.wrappedJSObject.runner = + content.wrappedJSObject.createIMEStateInContentEditableOnReadonlyChangeTester(); + const editingHost = content.document.querySelector( + "div[contenteditable]" + ); + return content.wrappedJSObject.runner.prepareToRun( + editingHost, + editingHost, + content.window + ); + } + ); + const tester = new IMEStateInContentEditableOnReadonlyChangeTester(); + tester.checkResultOfPreparation( + expectedDataOfInitialization, + window, + tipWrapper + ); + const expectedDataOfReadonly = await SpecialPowers.spawn( + browser, + [], + () => { + return content.wrappedJSObject.runner.runToMakeHTMLEditorReadonly(); + } + ); + tester.checkResultOfMakingHTMLEditorReadonly(expectedDataOfReadonly); + const expectedDataOfEditable = await SpecialPowers.spawn( + browser, + [], + () => { + return content.wrappedJSObject.runner.runToMakeHTMLEditorEditable(); + } + ); + tester.checkResultOfMakingHTMLEditorEditable(expectedDataOfEditable); + const expectedDataOfFinalization = await SpecialPowers.spawn( + browser, + [], + () => { + return content.wrappedJSObject.runner.runToRemoveContentEditableAttribute(); + } + ); + tester.checkResultOfRemovingContentEditableAttribute( + expectedDataOfFinalization + ); + tester.clear(); + })(); + + await (async function test_ime_state_in_button_in_contenteditable_on_readonly_change() { + const expectedDataOfInitialization = await SpecialPowers.spawn( + browser, + [], + () => { + content.document.body.innerHTML = + "

"; + content.wrappedJSObject.runner = + content.wrappedJSObject.createIMEStateInContentEditableOnReadonlyChangeTester(); + const editingHost = content.document.querySelector( + "div[contenteditable]" + ); + return content.wrappedJSObject.runner.prepareToRun( + editingHost, + editingHost.querySelector("button"), + content.window + ); + } + ); + const tester = new IMEStateInContentEditableOnReadonlyChangeTester(); + tester.checkResultOfPreparation( + expectedDataOfInitialization, + window, + tipWrapper + ); + const expectedDataOfReadonly = await SpecialPowers.spawn( + browser, + [], + () => { + return content.wrappedJSObject.runner.runToMakeHTMLEditorReadonly(); + } + ); + tester.checkResultOfMakingHTMLEditorReadonly(expectedDataOfReadonly); + const expectedDataOfEditable = await SpecialPowers.spawn( + browser, + [], + () => { + return content.wrappedJSObject.runner.runToMakeHTMLEditorEditable(); + } + ); + tester.checkResultOfMakingHTMLEditorEditable(expectedDataOfEditable); + const expectedDataOfFinalization = await SpecialPowers.spawn( + browser, + [], + () => { + return content.wrappedJSObject.runner.runToRemoveContentEditableAttribute(); + } + ); + tester.checkResultOfRemovingContentEditableAttribute( + expectedDataOfFinalization + ); + tester.clear(); + })(); + + await (async function test_ime_state_of_text_controls_in_contenteditable_on_readonly_change() { + const tester = + new IMEStateOfTextControlInContentEditableOnReadonlyChangeTester(); + await SpecialPowers.spawn(browser, [], () => { + content.document.body.innerHTML = "
"; + content.wrappedJSObject.runner = + content.wrappedJSObject.createIMEStateOfTextControlInContentEditableOnReadonlyChangeTester(); + }); + for ( + let index = 0; + index < + IMEStateOfTextControlInContentEditableOnReadonlyChangeTester.numberOfTextControlTypes; + index++ + ) { + const expectedDataOfInitialization = await SpecialPowers.spawn( + browser, + [index], + aIndex => { + const editingHost = content.document.querySelector("div"); + return content.wrappedJSObject.runner.prepareToRun( + aIndex, + editingHost, + content.window + ); + } + ); + tester.checkResultOfPreparation( + expectedDataOfInitialization, + window, + tipWrapper + ); + const expectedDataOfMakingParentEditingHost = + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runToMakeParentEditingHost(); + }); + tester.checkResultOfMakingParentEditingHost( + expectedDataOfMakingParentEditingHost + ); + const expectedDataOfMakingHTMLEditorReadonly = + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runToMakeHTMLEditorReadonly(); + }); + tester.checkResultOfMakingHTMLEditorReadonly( + expectedDataOfMakingHTMLEditorReadonly + ); + const expectedDataOfMakingHTMLEditorEditable = + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runToMakeHTMLEditorEditable(); + }); + tester.checkResultOfMakingHTMLEditorEditable( + expectedDataOfMakingHTMLEditorEditable + ); + const expectedDataOfMakingParentNonEditable = + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runToMakeParentNonEditingHost(); + }); + tester.checkResultOfMakingParentNonEditable( + expectedDataOfMakingParentNonEditable + ); + tester.clear(); + } + })(); + + await (async function test_ime_state_outside_contenteditable_on_readonly_change() { + const tester = + new IMEStateOutsideContentEditableOnReadonlyChangeTester(); + await SpecialPowers.spawn(browser, [], () => { + content.document.body.innerHTML = "
"; + content.wrappedJSObject.runner = + content.wrappedJSObject.createIMEStateOutsideContentEditableOnReadonlyChangeTester(); + }); + for ( + let index = 0; + index < + IMEStateOutsideContentEditableOnReadonlyChangeTester.numberOfFocusTargets; + index++ + ) { + const expectedDataOfInitialization = await SpecialPowers.spawn( + browser, + [index], + aIndex => { + const editingHost = content.document.querySelector("div"); + return content.wrappedJSObject.runner.prepareToRun( + aIndex, + editingHost, + content.window + ); + } + ); + tester.checkResultOfPreparation( + expectedDataOfInitialization, + window, + tipWrapper + ); + const expectedDataOfMakingParentEditingHost = + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runToMakeParentEditingHost(); + }); + tester.checkResultOfMakingParentEditingHost( + expectedDataOfMakingParentEditingHost + ); + const expectedDataOfMakingHTMLEditorReadonly = + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runToMakeHTMLEditorReadonly(); + }); + tester.checkResultOfMakingHTMLEditorReadonly( + expectedDataOfMakingHTMLEditorReadonly + ); + const expectedDataOfMakingHTMLEditorEditable = + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runToMakeHTMLEditorEditable(); + }); + tester.checkResultOfMakingHTMLEditorEditable( + expectedDataOfMakingHTMLEditorEditable + ); + const expectedDataOfMakingParentNonEditable = + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runToMakeParentNonEditingHost(); + }); + tester.checkResultOfMakingParentNonEditable( + expectedDataOfMakingParentNonEditable + ); + tester.clear(); + } + })(); + } + ); +}); diff --git a/widget/tests/browser/browser_test_ime_state_in_designMode_on_focus_move_in_remote_content.js b/widget/tests/browser/browser_test_ime_state_in_designMode_on_focus_move_in_remote_content.js new file mode 100644 index 0000000000..5ea5990e96 --- /dev/null +++ b/widget/tests/browser/browser_test_ime_state_in_designMode_on_focus_move_in_remote_content.js @@ -0,0 +1,116 @@ +/* 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 */ +/* import-globals-from ../file_test_ime_state_on_focus_move.js */ + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_ime_state_test_helper.js", + this +); +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_test_ime_state_on_focus_move.js", + this +); +add_task(async function () { + await BrowserTestUtils.withNewTab( + "https://example.com/browser/widget/tests/browser/file_ime_state_tests.html", + async function (browser) { + const tipWrapper = new TIPWrapper(window); + ok( + tipWrapper.isAvailable(), + "TextInputProcessor should've been initialized" + ); + + // isnot is used in file_test_ime_state_on_focus_move.js, but it's not + // defined as the alias of Assert.notEqual in browser-chrome tests. + // Therefore, we need to define it here. + // eslint-disable-next-line no-unused-vars + const isnot = Assert.notEqual; + + async function runIMEStateOnFocusMoveTests(aDescription) { + await (async function test_IMEState_without_focused_element() { + const checker = new IMEStateWhenNoActiveElementTester(aDescription); + const expectedData = await SpecialPowers.spawn( + browser, + [aDescription], + description => { + const runner = + content.wrappedJSObject.createIMEStateWhenNoActiveElementTester( + description + ); + return runner.run(content.document, content.window); + } + ); + checker.check(expectedData); + })(); + for ( + let index = 0; + index < IMEStateOnFocusMoveTester.numberOfTests; + ++index + ) { + const checker = new IMEStateOnFocusMoveTester(aDescription, index); + const expectedData = await SpecialPowers.spawn( + browser, + [aDescription, index], + (description, aIndex) => { + content.wrappedJSObject.runner = + content.wrappedJSObject.createIMEStateOnFocusMoveTester( + description, + aIndex, + content.window + ); + return content.wrappedJSObject.runner.prepareToRun( + content.document.querySelector("div") + ); + } + ); + checker.prepareToCheck(expectedData, tipWrapper); + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.run(); + }); + checker.check(expectedData); + + if (checker.canTestOpenCloseState(expectedData)) { + for (const defaultOpenState of [false, true]) { + const expectedOpenStateData = await SpecialPowers.spawn( + browser, + [], + () => { + return content.wrappedJSObject.runner.prepareToRunOpenCloseTest( + content.document.querySelector("div") + ); + } + ); + checker.prepareToCheckOpenCloseTest( + defaultOpenState, + expectedOpenStateData + ); + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runOpenCloseTest(); + }); + checker.checkOpenCloseTest(expectedOpenStateData); + } + } + await SpecialPowers.spawn(browser, [], () => { + content.wrappedJSObject.runner.destroy(); + content.wrappedJSObject.runner = undefined; + }); + checker.destroy(); + } // for loop iterating test of IMEStateOnFocusMoveTester + } // definition of runIMEStateOnFocusMoveTests + + // test designMode + await SpecialPowers.spawn(browser, [], async () => { + content.document.designMode = "on"; + }); + await runIMEStateOnFocusMoveTests('in designMode="on"'); + await SpecialPowers.spawn(browser, [], async () => { + content.document.designMode = "off"; + }); + await runIMEStateOnFocusMoveTests('in designMode="off"'); + } + ); +}); diff --git a/widget/tests/browser/browser_test_ime_state_in_plugin_in_remote_content.js b/widget/tests/browser/browser_test_ime_state_in_plugin_in_remote_content.js new file mode 100644 index 0000000000..0862b51080 --- /dev/null +++ b/widget/tests/browser/browser_test_ime_state_in_plugin_in_remote_content.js @@ -0,0 +1,120 @@ +/* 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 */ + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_ime_state_test_helper.js", + this +); +add_task(async function () { + await BrowserTestUtils.withNewTab( + "https://example.com/browser/toolkit/content/tests/browser/file_empty.html", + async function (browser) { + const tipWrapper = new TIPWrapper(window); + ok( + tipWrapper.isAvailable(), + "TextInputProcessor should've been initialized" + ); + + await SpecialPowers.spawn(browser, [], () => { + content.wrappedJSObject.waitForIMEContentObserverSendingNotifications = + () => { + return new content.window.Promise(resolve => + content.window.requestAnimationFrame(() => + content.window.requestAnimationFrame(resolve) + ) + ); + }; + content.document.body.innerHTML = + ''; + }); + + await SpecialPowers.spawn(browser, [], () => { + content.document.activeElement?.blur(); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + "IME enabled state should be disabled when no element has focus" + ); + ok( + !tipWrapper.IMEHasFocus, + "IME should not have focus when no element has focus" + ); + + await SpecialPowers.spawn(browser, [], () => { + content.document.querySelector("object").focus(); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + "IME enabled state should be disabled when an for plugin has focus" + ); + ok( + !tipWrapper.IMEHasFocus, + "IME enabled state should not have focus when an for plugin has focus" + ); + + await SpecialPowers.spawn(browser, [], () => { + content.document.querySelector("object").blur(); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + "IME enabled state should be disabled when an for plugin gets blurred" + ); + ok( + !tipWrapper.IMEHasFocus, + "IME should not have focus when an for plugin gets blurred" + ); + + await SpecialPowers.spawn(browser, [], () => { + content.document.querySelector("object").focus(); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + "IME enabled state should be disabled when an for plugin gets focused again" + ); + ok( + !tipWrapper.IMEHasFocus, + "IME should not have focus when an for plugin gets focused again" + ); + + await SpecialPowers.spawn(browser, [], () => { + content.document.querySelector("object").remove(); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + "IME enabled state should be disabled when focused for plugin is removed from the document" + ); + ok( + !tipWrapper.IMEHasFocus, + "IME should not have focus when focused for plugin is removed from the document" + ); + + await SpecialPowers.spawn(browser, [], () => { + content.document.querySelector("input").focus(); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED, + "IME enabled state should be enabled after gets focus" + ); + ok( + tipWrapper.IMEHasFocus, + "IME should have focus after gets focus" + ); + } + ); +}); diff --git a/widget/tests/browser/browser_test_ime_state_in_text_control_on_reframe_in_remote_content.js b/widget/tests/browser/browser_test_ime_state_in_text_control_on_reframe_in_remote_content.js new file mode 100644 index 0000000000..4d8acab1ff --- /dev/null +++ b/widget/tests/browser/browser_test_ime_state_in_text_control_on_reframe_in_remote_content.js @@ -0,0 +1,78 @@ +/* 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 */ +/* import-globals-from ../file_test_ime_state_in_text_control_on_reframe.js */ + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_ime_state_test_helper.js", + this +); +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_test_ime_state_in_text_control_on_reframe.js", + this +); +add_task(async function () { + await BrowserTestUtils.withNewTab( + "https://example.com/browser/widget/tests/browser/file_ime_state_tests.html", + async function (browser) { + const tipWrapper = new TIPWrapper(window); + ok( + tipWrapper.isAvailable(), + "TextInputProcessor should've been initialized" + ); + + await (async function test_ime_state_outside_contenteditable_on_readonly_change() { + const tester = new IMEStateInTextControlOnReframeTester(); + await SpecialPowers.spawn(browser, [], () => { + content.document.body.innerHTML = "
"; + content.wrappedJSObject.runner = + content.wrappedJSObject.createIMEStateInTextControlOnReframeTester(); + }); + for ( + let index = 0; + index < IMEStateInTextControlOnReframeTester.numberOfTextControlTypes; + index++ + ) { + tipWrapper.clearFocusBlurNotifications(); + const expectedData1 = await SpecialPowers.spawn( + browser, + [index], + aIndex => { + return content.wrappedJSObject.runner.prepareToRun( + aIndex, + content.document, + content.window + ); + } + ); + tipWrapper.typeA(); + await SpecialPowers.spawn(browser, [], () => { + return new Promise(resolve => + content.window.requestAnimationFrame(() => + content.window.requestAnimationFrame(resolve) + ) + ); + }); + tester.checkResultAfterTypingA(expectedData1, window, tipWrapper); + + const expectedData2 = await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.prepareToRun2(); + }); + tipWrapper.typeA(); + await SpecialPowers.spawn(browser, [], () => { + return new Promise(resolve => + content.window.requestAnimationFrame(() => + content.window.requestAnimationFrame(resolve) + ) + ); + }); + tester.checkResultAfterTypingA2(expectedData2); + tester.clear(); + } + })(); + } + ); +}); diff --git a/widget/tests/browser/browser_test_ime_state_on_editable_state_change_in_remote_content.js b/widget/tests/browser/browser_test_ime_state_on_editable_state_change_in_remote_content.js new file mode 100644 index 0000000000..8c38f97b72 --- /dev/null +++ b/widget/tests/browser/browser_test_ime_state_on_editable_state_change_in_remote_content.js @@ -0,0 +1,297 @@ +/* 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 */ + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_ime_state_test_helper.js", + this +); +add_task(async function () { + await BrowserTestUtils.withNewTab( + "https://example.com/browser/toolkit/content/tests/browser/file_empty.html", + async function (browser) { + const tipWrapper = new TIPWrapper(window); + ok( + tipWrapper.isAvailable(), + "TextInputProcessor should've been initialized" + ); + + await SpecialPowers.spawn(browser, [], () => { + content.wrappedJSObject.waitForIMEContentObserverSendingNotifications = + () => { + return new content.window.Promise(resolve => + content.window.requestAnimationFrame(() => + content.window.requestAnimationFrame(resolve) + ) + ); + }; + content.wrappedJSObject.resetIMEStateWithFocusMove = () => { + const input = content.document.createElement("input"); + content.document.body.appendChild(input); + input.focus(); + input.remove(); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }; + content.document.body.innerHTML = "
"; + }); + + function resetIMEStateWithFocusMove() { + return SpecialPowers.spawn(browser, [], () => { + const input = content.document.createElement("input"); + content.document.body.appendChild(input); + input.focus(); + input.remove(); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + } + + await (async function test_setting_contenteditable_of_focused_div() { + await SpecialPowers.spawn(browser, [], () => { + const div = content.document.querySelector("div"); + div.setAttribute("tabindex", "0"); + div.focus(); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + "test_setting_contenteditable_of_focused_div: IME should be disabled when non-editable
has focus" + ); + await SpecialPowers.spawn(browser, [], () => { + content.document + .querySelector("div") + .setAttribute("contenteditable", ""); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED, + "test_setting_contenteditable_of_focused_div: IME should be enabled when contenteditable of focused
is set" + ); + ok( + tipWrapper.IMEHasFocus, + "test_setting_contenteditable_of_focused_div: IME should have focus when contenteditable of focused
is set" + ); + await SpecialPowers.spawn(browser, [], () => { + content.document + .querySelector("div") + .removeAttribute("contenteditable"); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + "test_setting_contenteditable_of_focused_div: IME should be disabled when contenteditable of focused
is removed" + ); + ok( + !tipWrapper.IMEHasFocus, + "test_setting_contenteditable_of_focused_div: IME should not have focus when contenteditable of focused
is removed" + ); + await SpecialPowers.spawn(browser, [], () => { + content.document.querySelector("div").removeAttribute("tabindex"); + }); + })(); + + await resetIMEStateWithFocusMove(); + + await (async function test_removing_contenteditable_of_non_last_editable_div() { + await SpecialPowers.spawn(browser, [], async () => { + const div = content.document.querySelector("div"); + div.setAttribute("tabindex", "0"); + div.setAttribute("contenteditable", ""); + const anotherEditableDiv = content.document.createElement("div"); + anotherEditableDiv.setAttribute("contenteditable", ""); + div.parentElement.appendChild(anotherEditableDiv); + div.focus(); + await content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + div.removeAttribute("contenteditable"); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + "test_removing_contenteditable_of_non_last_editable_div: IME should be disabled when contenteditable of focused
is removed" + ); + ok( + !tipWrapper.IMEHasFocus, + "test_removing_contenteditable_of_non_last_editable_div: IME should not have focus when contenteditable of focused
is removed" + ); + await SpecialPowers.spawn(browser, [], () => { + const divs = content.document.querySelectorAll("div"); + divs[1].remove(); + divs[0].removeAttribute("tabindex"); + }); + })(); + + await resetIMEStateWithFocusMove(); + + await (async function test_setting_designMode() { + await SpecialPowers.spawn(browser, [], () => { + content.window.focus(); + content.document.designMode = "on"; + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED, + 'test_setting_designMode: IME should be enabled when designMode is set to "on"' + ); + ok( + tipWrapper.IMEHasFocus, + 'test_setting_designMode: IME should have focus when designMode is set to "on"' + ); + await SpecialPowers.spawn(browser, [], () => { + content.document.designMode = "off"; + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + 'test_setting_designMode: IME should be disabled when designMode is set to "off"' + ); + ok( + !tipWrapper.IMEHasFocus, + 'test_setting_designMode: IME should not have focus when designMode is set to "off"' + ); + })(); + + await resetIMEStateWithFocusMove(); + + async function test_setting_content_editable_of_body_when_shadow_DOM_has_focus( + aMode + ) { + await SpecialPowers.spawn(browser, [aMode], mode => { + const div = content.document.querySelector("div"); + const shadow = div.attachShadow({ mode }); + content.wrappedJSObject.divInShadow = + content.document.createElement("div"); + content.wrappedJSObject.divInShadow.setAttribute("tabindex", "0"); + shadow.appendChild(content.wrappedJSObject.divInShadow); + content.wrappedJSObject.divInShadow.focus(); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + `test_setting_content_editable_of_body_when_shadow_DOM_has_focus(${aMode}): IME should be disabled when non-editable
in a shadow DOM has focus` + ); + await SpecialPowers.spawn(browser, [], () => { + content.document.body.setAttribute("contenteditable", ""); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + // todo_is because of bug 1807597. Gecko does not update focus when focused + // element becomes an editable child. Therefore, cannot initialize + // HTMLEditor with the new editing host. + todo_is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED, + `test_setting_content_editable_of_body_when_shadow_DOM_has_focus(${aMode}): IME should be enabled when the becomes editable` + ); + todo( + tipWrapper.IMEHasFocus, + `test_setting_content_editable_of_body_when_shadow_DOM_has_focus(${aMode}): IME should have focus when the becomes editable` + ); + await SpecialPowers.spawn(browser, [], () => { + content.document.body.removeAttribute("contenteditable"); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + `test_setting_content_editable_of_body_when_shadow_DOM_has_focus)${aMode}): IME should be disabled when the becomes not editable` + ); + ok( + !tipWrapper.IMEHasFocus, + `test_setting_content_editable_of_body_when_shadow_DOM_has_focus)${aMode}): IME should not have focus when the becomes not editable` + ); + await SpecialPowers.spawn(browser, [], () => { + content.document.querySelector("div").remove(); + content.document.body.appendChild( + content.document.createElement("div") + ); + }); + } + + async function test_setting_designMode_when_shadow_DOM_has_focus(aMode) { + await SpecialPowers.spawn(browser, [aMode], mode => { + const div = content.document.querySelector("div"); + const shadow = div.attachShadow({ mode }); + content.wrappedJSObject.divInShadow = + content.document.createElement("div"); + content.wrappedJSObject.divInShadow.setAttribute("tabindex", "0"); + shadow.appendChild(content.wrappedJSObject.divInShadow); + content.wrappedJSObject.divInShadow.focus(); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + `test_setting_designMode_when_shadow_DOM_has_focus(${aMode}): IME should be disabled when non-editable
in a shadow DOM has focus` + ); + await SpecialPowers.spawn(browser, [], () => { + content.document.designMode = "on"; + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + `test_setting_designMode_when_shadow_DOM_has_focus(${aMode}): IME should stay disabled when designMode is set` + ); + ok( + !tipWrapper.IMEHasFocus, + `test_setting_designMode_when_shadow_DOM_has_focus(${aMode}): IME should not have focus when designMode is set` + ); + await SpecialPowers.spawn(browser, [], () => { + content.wrappedJSObject.divInShadow.setAttribute( + "contenteditable", + "" + ); + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + // todo_is because of bug 1807597. Gecko does not update focus when focused + // document is into the design mode. Therefore, cannot initialize + // HTMLEditor with the document node properly. + todo_is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED, + `test_setting_designMode_when_shadow_DOM_has_focus(${aMode}): IME should be enabled when focused
in a shadow DOM becomes editable` + ); + todo( + tipWrapper.IMEHasFocus, + `test_setting_designMode_when_shadow_DOM_has_focus(${aMode}): IME should have focus when focused
in a shadow DOM becomes editable` + ); + await SpecialPowers.spawn(browser, [], () => { + content.document.designMode = "off"; + return content.wrappedJSObject.waitForIMEContentObserverSendingNotifications(); + }); + is( + window.windowUtils.IMEStatus, + Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED, + `test_setting_designMode_when_shadow_DOM_has_focus(${aMode}): IME should be disabled when designMode is unset` + ); + ok( + !tipWrapper.IMEHasFocus, + `test_setting_designMode_when_shadow_DOM_has_focus(${aMode}): IME should not have focus when designMode is unset` + ); + await SpecialPowers.spawn(browser, [], () => { + content.document.querySelector("div").remove(); + content.document.body.appendChild( + content.document.createElement("div") + ); + }); + } + + for (const mode of ["open", "closed"]) { + await test_setting_content_editable_of_body_when_shadow_DOM_has_focus( + mode + ); + await resetIMEStateWithFocusMove(); + await test_setting_designMode_when_shadow_DOM_has_focus(mode); + await resetIMEStateWithFocusMove(); + } + } + ); +}); diff --git a/widget/tests/browser/browser_test_ime_state_on_focus_move_in_remote_content.js b/widget/tests/browser/browser_test_ime_state_on_focus_move_in_remote_content.js new file mode 100644 index 0000000000..3916d3d47c --- /dev/null +++ b/widget/tests/browser/browser_test_ime_state_on_focus_move_in_remote_content.js @@ -0,0 +1,128 @@ +/* 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 */ +/* import-globals-from ../file_test_ime_state_on_focus_move.js */ + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_ime_state_test_helper.js", + this +); +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_test_ime_state_on_focus_move.js", + this +); +add_task(async function () { + await BrowserTestUtils.withNewTab( + "https://example.com/browser/widget/tests/browser/file_ime_state_tests.html", + async function (browser) { + const tipWrapper = new TIPWrapper(window); + ok( + tipWrapper.isAvailable(), + "TextInputProcessor should've been initialized" + ); + + // isnot is used in file_test_ime_state_on_focus_move.js, but it's not + // defined as the alias of Assert.notEqual in browser-chrome tests. + // Therefore, we need to define it here. + // eslint-disable-next-line no-unused-vars + const isnot = Assert.notEqual; + + async function runIMEStateOnFocusMoveTests(aDescription) { + await (async function test_IMEState_without_focused_element() { + const checker = new IMEStateWhenNoActiveElementTester(aDescription); + const expectedData = await SpecialPowers.spawn( + browser, + [aDescription], + description => { + const runner = + content.wrappedJSObject.createIMEStateWhenNoActiveElementTester( + description + ); + return runner.run(content.document, content.window); + } + ); + checker.check(expectedData); + })(); + for ( + let index = 0; + index < IMEStateOnFocusMoveTester.numberOfTests; + ++index + ) { + const checker = new IMEStateOnFocusMoveTester(aDescription, index); + const expectedData = await SpecialPowers.spawn( + browser, + [aDescription, index], + (description, aIndex) => { + content.wrappedJSObject.runner = + content.wrappedJSObject.createIMEStateOnFocusMoveTester( + description, + aIndex, + content.window + ); + return content.wrappedJSObject.runner.prepareToRun( + content.document.querySelector("div") + ); + } + ); + checker.prepareToCheck(expectedData, tipWrapper); + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.run(); + }); + checker.check(expectedData); + + if (checker.canTestOpenCloseState(expectedData)) { + for (const defaultOpenState of [false, true]) { + const expectedOpenStateData = await SpecialPowers.spawn( + browser, + [], + () => { + return content.wrappedJSObject.runner.prepareToRunOpenCloseTest( + content.document.querySelector("div") + ); + } + ); + checker.prepareToCheckOpenCloseTest( + defaultOpenState, + expectedOpenStateData + ); + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runOpenCloseTest(); + }); + checker.checkOpenCloseTest(expectedOpenStateData); + } + } + await SpecialPowers.spawn(browser, [], () => { + content.wrappedJSObject.runner.destroy(); + content.wrappedJSObject.runner = undefined; + }); + checker.destroy(); + } // for loop iterating test of IMEStateOnFocusMoveTester + } // definition of runIMEStateOnFocusMoveTests + + // test for normal contents. + await runIMEStateOnFocusMoveTests("in non-editable container"); + + // test for removing contentEditable + await SpecialPowers.spawn(browser, [], async () => { + content.document + .querySelector("div") + .setAttribute("contenteditable", "true"); + content.document.querySelector("div").focus(); + await new Promise(resolve => + content.window.requestAnimationFrame(() => + content.window.requestAnimationFrame(resolve) + ) + ); + content.document + .querySelector("div") + .removeAttribute("contenteditable"); + }); + await runIMEStateOnFocusMoveTests( + "after removing contenteditable from the container" + ); + } + ); +}); diff --git a/widget/tests/browser/browser_test_ime_state_on_input_type_change_in_remote_content.js b/widget/tests/browser/browser_test_ime_state_on_input_type_change_in_remote_content.js new file mode 100644 index 0000000000..2a4bc4c332 --- /dev/null +++ b/widget/tests/browser/browser_test_ime_state_on_input_type_change_in_remote_content.js @@ -0,0 +1,70 @@ +/* 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 */ +/* import-globals-from ../file_test_ime_state_on_input_type_change.js */ + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_ime_state_test_helper.js", + this +); +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_test_ime_state_on_input_type_change.js", + this +); +add_task(async function () { + await BrowserTestUtils.withNewTab( + "https://example.com/browser/widget/tests/browser/file_ime_state_tests.html", + async function (browser) { + const tipWrapper = new TIPWrapper(window); + ok( + tipWrapper.isAvailable(), + "TextInputProcessor should've been initialized" + ); + + for ( + let srcIndex = 0; + srcIndex < IMEStateOnInputTypeChangeTester.numberOfTests; + srcIndex++ + ) { + const tester = new IMEStateOnInputTypeChangeTester(srcIndex); + for ( + let destIndex = 0; + destIndex < IMEStateOnInputTypeChangeTester.numberOfTests; + destIndex++ + ) { + const expectedResultBefore = await SpecialPowers.spawn( + browser, + [srcIndex, destIndex], + (aSrcIndex, aDestIndex) => { + content.wrappedJSObject.runner = + content.wrappedJSObject.createIMEStateOnInputTypeChangeTester( + aSrcIndex + ); + return content.wrappedJSObject.runner.prepareToRun( + aDestIndex, + content.window, + content.document.body + ); + } + ); + if (expectedResultBefore === false) { + continue; + } + tester.checkBeforeRun(expectedResultBefore, tipWrapper); + const expectedResult = await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.run(); + }); + tester.checkResult(expectedResultBefore, expectedResult); + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.clear(); + }); + tipWrapper.clearFocusBlurNotifications(); + } + tester.clear(); + } + } + ); +}); diff --git a/widget/tests/browser/browser_test_ime_state_on_readonly_change_in_remote_content.js b/widget/tests/browser/browser_test_ime_state_on_readonly_change_in_remote_content.js new file mode 100644 index 0000000000..a0c0019328 --- /dev/null +++ b/widget/tests/browser/browser_test_ime_state_on_readonly_change_in_remote_content.js @@ -0,0 +1,68 @@ +/* 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 */ +/* import-globals-from ../file_test_ime_state_on_readonly_change.js */ + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_ime_state_test_helper.js", + this +); +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/widget/tests/browser/file_test_ime_state_on_readonly_change.js", + this +); +add_task(async function () { + await BrowserTestUtils.withNewTab( + "https://example.com/browser/widget/tests/browser/file_ime_state_tests.html", + async function (browser) { + const tipWrapper = new TIPWrapper(window); + ok( + tipWrapper.isAvailable(), + "TextInputProcessor should've been initialized" + ); + + const tester = new IMEStateOnReadonlyChangeTester(); + for ( + let i = 0; + i < IMEStateOnReadonlyChangeTester.numberOfTextControlTypes; + i++ + ) { + const expectedResultBefore = await SpecialPowers.spawn( + browser, + [i], + aIndex => { + content.wrappedJSObject.runner = + content.wrappedJSObject.createIMEStateOnReadonlyChangeTester( + aIndex + ); + return content.wrappedJSObject.runner.prepareToRun( + aIndex, + content.window, + content.document.body + ); + } + ); + tester.checkBeforeRun(expectedResultBefore, tipWrapper); + const expectedResultOfMakingTextControlReadonly = + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runToMakeTextControlReadonly(); + }); + tester.checkResultOfMakingTextControlReadonly( + expectedResultOfMakingTextControlReadonly + ); + const expectedResultOfMakingTextControlEditable = + await SpecialPowers.spawn(browser, [], () => { + return content.wrappedJSObject.runner.runToMakeTextControlEditable(); + }); + tester.checkResultOfMakingTextControlEditable( + expectedResultOfMakingTextControlEditable + ); + tipWrapper.clearFocusBlurNotifications(); + tester.clear(); + } + } + ); +}); diff --git a/widget/tests/browser/browser_test_scrollbar_colors.js b/widget/tests/browser/browser_test_scrollbar_colors.js new file mode 100644 index 0000000000..2152412071 --- /dev/null +++ b/widget/tests/browser/browser_test_scrollbar_colors.js @@ -0,0 +1,146 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ + +"use strict"; + +add_task(async () => { + const URL_ROOT = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + "http://mochi.test:8888/" + ); + + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + URL_ROOT + "helper_scrollbar_colors.html" + ); + + await SpecialPowers.spawn(tab.linkedBrowser, [], () => { + ChromeUtils.defineESModuleGetters(this, { + WindowsVersionInfo: + "resource://gre/modules/components-utils/WindowsVersionInfo.sys.mjs", + }); + + Services.scriptloader.loadSubScript( + "chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js", + this + ); + + // == Native theme == + + const WIN_REFERENCES = [ + // Yellow background + ["255,255,0", 6889], + // Blue scrollbar face + ["0,0,255", 540], + // Cyan scrollbar track + ["0,255,255", 2487], + ]; + + const MAC_REFERENCES = [ + // Yellow background + ["255,255,0", 7225], + // Blue scrollbar face + ["0,0,255", 416], + // Cyan scrollbar track + ["0,255,255", 1760], + ]; + + // Values have been updated from 8100, 720, 1180 for linux1804 + const LINUX_REFERENCES = [ + // Yellow background + ["255,255,0", 7744], + // Blue scrollbar face + ["0,0,255", 1104], + // Cyan scrollbar track + ["0,255,255", 1152], + ]; + + // == Non-native theme == + + const WIN10_NNT_REFERENCES = [ + // Yellow background + ["255,255,0", 6889], + // Blue scrollbar face + ["0,0,255", 612], + // Cyan scrollbar track + ["0,255,255", 2355], + ]; + + const WIN11_NNT_REFERENCES = [ + // Yellow background + ["255,255,0", 6889], + // Blue scrollbar face + ["0,0,255", 324], + // Cyan scrollbar track + ["0,255,255", 2787], + ]; + + const MAC_NNT_REFERENCES = MAC_REFERENCES; + + const LINUX_NNT_REFERENCES = [ + // Yellow background + ["255,255,0", 7744], + // Blue scrollbar face + ["0,0,255", 368], + // Cyan scrollbar track + ["0,255,255", 1852], + ]; + + function countPixels(canvas) { + let result = new Map(); + let ctx = canvas.getContext("2d"); + let image = ctx.getImageData(0, 0, canvas.width, canvas.height); + let data = image.data; + let size = image.width * image.height; + for (let i = 0; i < size; i++) { + let key = data.subarray(i * 4, i * 4 + 3).toString(); + let value = result.get(key); + value = value ? value : 0; + result.set(key, value + 1); + } + return result; + } + + let outer = content.document.querySelector(".outer"); + let outerRect = outer.getBoundingClientRect(); + if ( + outerRect.width == outer.clientWidth && + outerRect.height == outer.clientHeight + ) { + ok(true, "Using overlay scrollbar, skip this test"); + return; + } + content.document.querySelector("#style").textContent = ` + .outer { scrollbar-color: blue cyan; } + `; + + let canvas = snapshotRect(content.window, outerRect); + let stats = countPixels(canvas); + let isNNT = SpecialPowers.getBoolPref("widget.non-native-theme.enabled"); + + let references; + if (content.navigator.platform.startsWith("Win")) { + if (!isNNT) { + references = WIN_REFERENCES; + } else if (WindowsVersionInfo.get().buildNumber >= 22000) { + // Windows 11 NNT + references = WIN11_NNT_REFERENCES; + } else { + // Windows 10 NNT + references = WIN10_NNT_REFERENCES; + } + } else if (content.navigator.platform.startsWith("Mac")) { + references = isNNT ? MAC_NNT_REFERENCES : MAC_REFERENCES; + } else if (content.navigator.platform.startsWith("Linux")) { + references = isNNT ? LINUX_NNT_REFERENCES : LINUX_REFERENCES; + } else { + ok(false, "Unsupported platform"); + } + for (let [color, count] of references) { + let value = stats.get(color); + is(value, count, `Pixel count of color ${color}`); + } + }); + + BrowserTestUtils.removeTab(tab); +}); diff --git a/widget/tests/browser/browser_test_swipe_gesture.js b/widget/tests/browser/browser_test_swipe_gesture.js new file mode 100644 index 0000000000..e66e2f10b9 --- /dev/null +++ b/widget/tests/browser/browser_test_swipe_gesture.js @@ -0,0 +1,1275 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ + +"use strict"; + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_utils.js", + this +); + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js", + this +); + +async function waitForWhile() { + await new Promise(resolve => { + requestIdleCallback(resolve, { timeout: 300 }); + }); + await new Promise(r => requestAnimationFrame(r)); +} + +requestLongerTimeout(2); + +add_task(async () => { + // Set the default values for an OS that supports swipe to nav, except for + // whole-page-pixel-size which varies by OS, we vary it in differente tests + // in this file. + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["widget.swipe.velocity-twitch-tolerance", 0.0000001], + // Set the velocity-contribution to 0 so we can exactly control the + // values in the swipe tracker via the delta in the events that we send. + ["widget.swipe.success-velocity-contribution", 0.0], + ["widget.swipe.whole-page-pixel-size", 550.0], + ], + }); + + const firstPage = "about:about"; + const secondPage = "about:mozilla"; + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + firstPage, + true /* waitForLoad */ + ); + + BrowserTestUtils.loadURIString(tab.linkedBrowser, secondPage); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage); + + // Make sure we can go back to the previous page. + ok(gBrowser.webNavigation.canGoBack); + // and we cannot go forward to the next page. + ok(!gBrowser.webNavigation.canGoForward); + + let wheelEventCount = 0; + tab.linkedBrowser.addEventListener("wheel", () => { + wheelEventCount++; + }); + + // Send a pan that starts a navigate back but doesn't have enough delta to do + // anything. Don't send the pan end because we want to check the opacity + // before the MSD animation in SwipeTracker starts which can temporarily put + // us at 1 opacity. + await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 0.9); + await panLeftToRightUpdate(tab.linkedBrowser, 100, 100, 0.9); + + // Check both getComputedStyle instead of element.style.opacity because we use a transition on the opacity. + let computedOpacity = window + .getComputedStyle(gHistorySwipeAnimation._prevBox) + .getPropertyValue("opacity"); + is(computedOpacity, "1", "opacity of prevbox is 1"); + let opacity = gHistorySwipeAnimation._prevBox.style.opacity; + is(opacity, "", "opacity style isn't explicitly set"); + + const isTranslatingIcon = + Services.prefs.getIntPref( + "browser.swipe.navigation-icon-start-position", + 0 + ) != 0 || + Services.prefs.getIntPref( + "browser.swipe.navigation-icon-end-position", + 0 + ) != 0; + if (isTranslatingIcon != 0) { + isnot( + window + .getComputedStyle(gHistorySwipeAnimation._prevBox) + .getPropertyValue("translate"), + "none", + "translate of prevbox is not `none` during gestures" + ); + } + + await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 0.9); + + // NOTE: We only get a wheel event for the beginPhase, rest of events have + // been captured by the swipe gesture module. + is(wheelEventCount, 1, "Received a wheel event"); + + await waitForWhile(); + // Make sure any navigation didn't happen. + is(tab.linkedBrowser.currentURI.spec, secondPage); + + // Try to navigate backward. + wheelEventCount = 0; + let startLoadingPromise = BrowserTestUtils.browserStarted( + tab.linkedBrowser, + firstPage + ); + let stoppedLoadingPromise = BrowserTestUtils.browserStopped( + tab.linkedBrowser, + firstPage + ); + await panLeftToRight(tab.linkedBrowser, 100, 100, 1); + // NOTE: We only get a wheel event for the beginPhase, rest of events have + // been captured by the swipe gesture module. + is(wheelEventCount, 1, "Received a wheel event"); + + // The element.style opacity will be 0 because we set it to 0 on successful navigation, however + // we have a tranisition on it so the computed style opacity will still be 1 because the transition hasn't started yet. + computedOpacity = window + .getComputedStyle(gHistorySwipeAnimation._prevBox) + .getPropertyValue("opacity"); + ok(computedOpacity == 1, "computed opacity of prevbox is 1"); + opacity = gHistorySwipeAnimation._prevBox.style.opacity; + ok(opacity == 0, "element.style opacity of prevbox 0"); + + if (isTranslatingIcon) { + // We don't have a transition for translate property so that we still have + // some amount of translate. + isnot( + window + .getComputedStyle(gHistorySwipeAnimation._prevBox) + .getPropertyValue("translate"), + "none", + "translate of prevbox is not `none` during the opacity transition" + ); + } + + // Make sure the gesture triggered going back to the previous page. + await Promise.all([startLoadingPromise, stoppedLoadingPromise]); + + ok(gBrowser.webNavigation.canGoForward); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +// Same test as above but whole-page-pixel-size is increased and the multipliers passed to panLeftToRight correspondingly increased. +add_task(async () => { + // Set the default values for an OS that supports swipe to nav, except for + // whole-page-pixel-size which varies by OS, we vary it in differente tests + // in this file. + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["widget.swipe.velocity-twitch-tolerance", 0.0000001], + // Set the velocity-contribution to 0 so we can exactly control the + // values in the swipe tracker via the delta in the events that we send. + ["widget.swipe.success-velocity-contribution", 0.0], + ["widget.swipe.whole-page-pixel-size", 1100.0], + ], + }); + + const firstPage = "about:about"; + const secondPage = "about:mozilla"; + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + firstPage, + true /* waitForLoad */ + ); + + BrowserTestUtils.loadURIString(tab.linkedBrowser, secondPage); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage); + + // Make sure we can go back to the previous page. + ok(gBrowser.webNavigation.canGoBack); + // and we cannot go forward to the next page. + ok(!gBrowser.webNavigation.canGoForward); + + let wheelEventCount = 0; + tab.linkedBrowser.addEventListener("wheel", () => { + wheelEventCount++; + }); + + // Send a pan that starts a navigate back but doesn't have enough delta to do + // anything. Don't send the pan end because we want to check the opacity + // before the MSD animation in SwipeTracker starts which can temporarily put + // us at 1 opacity. + await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 1.8); + await panLeftToRightUpdate(tab.linkedBrowser, 100, 100, 1.8); + + // Check both getComputedStyle instead of element.style.opacity because we use a transition on the opacity. + let computedOpacity = window + .getComputedStyle(gHistorySwipeAnimation._prevBox) + .getPropertyValue("opacity"); + is(computedOpacity, "1", "opacity of prevbox is 1"); + let opacity = gHistorySwipeAnimation._prevBox.style.opacity; + is(opacity, "", "opacity style isn't explicitly set"); + + await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 1.8); + + // NOTE: We only get a wheel event for the beginPhase, rest of events have + // been captured by the swipe gesture module. + is(wheelEventCount, 1, "Received a wheel event"); + + await waitForWhile(); + // Make sure any navigation didn't happen. + is(tab.linkedBrowser.currentURI.spec, secondPage); + + // Try to navigate backward. + wheelEventCount = 0; + let startLoadingPromise = BrowserTestUtils.browserStarted( + tab.linkedBrowser, + firstPage + ); + let stoppedLoadingPromise = BrowserTestUtils.browserStopped( + tab.linkedBrowser, + firstPage + ); + await panLeftToRight(tab.linkedBrowser, 100, 100, 2); + // NOTE: We only get a wheel event for the beginPhase, rest of events have + // been captured by the swipe gesture module. + is(wheelEventCount, 1, "Received a wheel event"); + + // The element.style opacity will be 0 because we set it to 0 on successful navigation, however + // we have a tranisition on it so the computed style opacity will still be 1 because the transition hasn't started yet. + computedOpacity = window + .getComputedStyle(gHistorySwipeAnimation._prevBox) + .getPropertyValue("opacity"); + ok(computedOpacity == 1, "computed opacity of prevbox is 1"); + opacity = gHistorySwipeAnimation._prevBox.style.opacity; + ok(opacity == 0, "element.style opacity of prevbox 0"); + + // Make sure the gesture triggered going back to the previous page. + await Promise.all([startLoadingPromise, stoppedLoadingPromise]); + + ok(gBrowser.webNavigation.canGoForward); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async () => { + // Set the default values for an OS that supports swipe to nav, except for + // whole-page-pixel-size which varies by OS, we vary it in different tests + // in this file. + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["widget.swipe.velocity-twitch-tolerance", 0.0000001], + // Set the velocity-contribution to 1 (default 0.05f) so velocity is a + // large contribution to the success value in SwipeTracker.cpp so it + // pushes us into success territory without going into success territory + // purely from th deltas. + ["widget.swipe.success-velocity-contribution", 2.0], + ["widget.swipe.whole-page-pixel-size", 550.0], + ], + }); + + async function runTest() { + const firstPage = "about:about"; + const secondPage = "about:mozilla"; + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + firstPage, + true /* waitForLoad */ + ); + + BrowserTestUtils.loadURIString(tab.linkedBrowser, secondPage); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage); + + // Make sure we can go back to the previous page. + ok(gBrowser.webNavigation.canGoBack); + // and we cannot go forward to the next page. + ok(!gBrowser.webNavigation.canGoForward); + + let wheelEventCount = 0; + tab.linkedBrowser.addEventListener("wheel", () => { + wheelEventCount++; + }); + + let startLoadingPromise = BrowserTestUtils.browserStarted( + tab.linkedBrowser, + firstPage + ); + let stoppedLoadingPromise = BrowserTestUtils.browserStopped( + tab.linkedBrowser, + firstPage + ); + let startTime = performance.now(); + await panLeftToRight(tab.linkedBrowser, 100, 100, 0.2); + let endTime = performance.now(); + + // If sending the events took too long then we might not have been able + // to generate enough velocity. + // The value 230 was picked based on try runs, in particular test verify + // runs on mac were the long pole, and when we get times near this we can + // still achieve the required velocity. + if (endTime - startTime > 230) { + BrowserTestUtils.removeTab(tab); + return false; + } + + // NOTE: We only get a wheel event for the beginPhase, rest of events have + // been captured by the swipe gesture module. + is(wheelEventCount, 1, "Received a wheel event"); + + // The element.style opacity will be 0 because we set it to 0 on successful navigation, however + // we have a tranisition on it so the computed style opacity will still be 1 because the transition hasn't started yet. + let computedOpacity = window + .getComputedStyle(gHistorySwipeAnimation._prevBox) + .getPropertyValue("opacity"); + ok(computedOpacity == 1, "computed opacity of prevbox is 1"); + let opacity = gHistorySwipeAnimation._prevBox.style.opacity; + ok(opacity == 0, "element.style opacity of prevbox 0"); + + // Make sure the gesture triggered going back to the previous page. + await Promise.all([startLoadingPromise, stoppedLoadingPromise]); + + ok(gBrowser.webNavigation.canGoForward); + + BrowserTestUtils.removeTab(tab); + + return true; + } + + let numTries = 15; + while (numTries > 0) { + await new Promise(r => requestAnimationFrame(r)); + await new Promise(resolve => requestIdleCallback(resolve)); + await new Promise(r => requestAnimationFrame(r)); + + // runTest return value indicates if test was able to run to the end. + if (await runTest()) { + break; + } + numTries--; + } + ok(numTries > 0, "never ran the test"); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async () => { + // Set the default values for an OS that supports swipe to nav, except for + // whole-page-pixel-size which varies by OS, we vary it in differente tests + // in this file. + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["widget.swipe.velocity-twitch-tolerance", 0.0000001], + // Set the velocity-contribution to 0 so we can exactly control the + // values in the swipe tracker via the delta in the events that we send. + ["widget.swipe.success-velocity-contribution", 0.0], + ["widget.swipe.whole-page-pixel-size", 550.0], + ], + }); + + const firstPage = "about:about"; + const secondPage = "about:mozilla"; + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + firstPage, + true /* waitForLoad */ + ); + + BrowserTestUtils.loadURIString(tab.linkedBrowser, secondPage); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage); + + // Make sure we can go back to the previous page. + ok(gBrowser.webNavigation.canGoBack); + // and we cannot go forward to the next page. + ok(!gBrowser.webNavigation.canGoForward); + + let startLoadingPromise = BrowserTestUtils.browserStarted( + tab.linkedBrowser, + firstPage + ); + let stoppedLoadingPromise = BrowserTestUtils.browserStopped( + tab.linkedBrowser, + firstPage + ); + await panLeftToRight(tab.linkedBrowser, 100, 100, 2); + + // Make sure the gesture triggered going back to the previous page. + await Promise.all([startLoadingPromise, stoppedLoadingPromise]); + + ok(gBrowser.webNavigation.canGoForward); + + while ( + gHistorySwipeAnimation._prevBox != null || + gHistorySwipeAnimation._nextBox != null + ) { + await new Promise(r => requestAnimationFrame(r)); + } + + ok( + gHistorySwipeAnimation._prevBox == null && + gHistorySwipeAnimation._nextBox == null + ); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async () => { + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["widget.swipe.velocity-twitch-tolerance", 0.0000001], + // Set the velocity-contribution to 0 so we can exactly control the + // values in the swipe tracker via the delta in the events that we send. + ["widget.swipe.success-velocity-contribution", 0.0], + ["widget.swipe.whole-page-pixel-size", 550.0], + ], + }); + + function swipeGestureEndPromise() { + return new Promise(resolve => { + let promiseObserver = { + handleEvent(aEvent) { + switch (aEvent.type) { + case "MozSwipeGestureEnd": + gBrowser.tabbox.removeEventListener( + "MozSwipeGestureEnd", + promiseObserver, + true + ); + resolve(); + break; + } + }, + }; + gBrowser.tabbox.addEventListener( + "MozSwipeGestureEnd", + promiseObserver, + true + ); + }); + } + + const firstPage = "about:about"; + const secondPage = "about:mozilla"; + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + firstPage, + true /* waitForLoad */ + ); + + BrowserTestUtils.loadURIString(tab.linkedBrowser, secondPage); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage); + + // Make sure we can go back to the previous page. + ok(gBrowser.webNavigation.canGoBack); + // and we cannot go forward to the next page. + ok(!gBrowser.webNavigation.canGoForward); + + let numSwipeGestureEndEvents = 0; + var anObserver = { + handleEvent(aEvent) { + switch (aEvent.type) { + case "MozSwipeGestureEnd": + numSwipeGestureEndEvents++; + break; + } + }, + }; + + gBrowser.tabbox.addEventListener("MozSwipeGestureEnd", anObserver, true); + + let gestureEndPromise = swipeGestureEndPromise(); + + is( + numSwipeGestureEndEvents, + 0, + "expected no MozSwipeGestureEnd got " + numSwipeGestureEndEvents + ); + + // Send a pan that starts a navigate back but doesn't have enough delta to do + // anything. + await panLeftToRight(tab.linkedBrowser, 100, 100, 0.9); + + await waitForWhile(); + // Make sure any navigation didn't happen. + is(tab.linkedBrowser.currentURI.spec, secondPage); + // end event comes after a swipe that does not navigate + await gestureEndPromise; + is( + numSwipeGestureEndEvents, + 1, + "expected one MozSwipeGestureEnd got " + numSwipeGestureEndEvents + ); + + // Try to navigate backward. + let startLoadingPromise = BrowserTestUtils.browserStarted( + tab.linkedBrowser, + firstPage + ); + let stoppedLoadingPromise = BrowserTestUtils.browserStopped( + tab.linkedBrowser, + firstPage + ); + + gestureEndPromise = swipeGestureEndPromise(); + + await panLeftToRight(tab.linkedBrowser, 100, 100, 1); + + // Make sure the gesture triggered going back to the previous page. + await Promise.all([startLoadingPromise, stoppedLoadingPromise]); + + ok(gBrowser.webNavigation.canGoForward); + + await gestureEndPromise; + + is( + numSwipeGestureEndEvents, + 2, + "expected one MozSwipeGestureEnd got " + (numSwipeGestureEndEvents - 1) + ); + + gBrowser.tabbox.removeEventListener("MozSwipeGestureEnd", anObserver, true); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async () => { + // success-velocity-contribution is very high and whole-page-pixel-size is + // very low so that one swipe goes over the threshold asap. + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["widget.swipe.velocity-twitch-tolerance", 0.0000001], + ["widget.swipe.success-velocity-contribution", 999999.0], + ["widget.swipe.whole-page-pixel-size", 1.0], + ], + }); + + const firstPage = "about:about"; + const secondPage = "about:mozilla"; + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + firstPage, + true /* waitForLoad */ + ); + + BrowserTestUtils.loadURIString(tab.linkedBrowser, secondPage); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage); + + // Make sure we can go back to the previous page. + ok(gBrowser.webNavigation.canGoBack); + // and we cannot go forward to the next page. + ok(!gBrowser.webNavigation.canGoForward); + + // Navigate backward. + let startLoadingPromise = BrowserTestUtils.browserStarted( + tab.linkedBrowser, + firstPage + ); + let stoppedLoadingPromise = BrowserTestUtils.browserStopped( + tab.linkedBrowser, + firstPage + ); + + await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 100); + + ok(gHistorySwipeAnimation._prevBox != null, "should have prevbox"); + let transitionCancelPromise = new Promise(resolve => { + gHistorySwipeAnimation._prevBox.addEventListener( + "transitioncancel", + event => { + if ( + event.propertyName == "opacity" && + event.target == gHistorySwipeAnimation._prevBox + ) { + resolve(); + } + }, + { once: true } + ); + }); + let transitionStartPromise = new Promise(resolve => { + gHistorySwipeAnimation._prevBox.addEventListener( + "transitionstart", + event => { + if ( + event.propertyName == "opacity" && + event.target == gHistorySwipeAnimation._prevBox + ) { + resolve(); + } + }, + { once: true } + ); + }); + + await panLeftToRightUpdate(tab.linkedBrowser, 100, 100, 100); + await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 100); + + // Make sure the gesture triggered going back to the previous page. + await Promise.all([startLoadingPromise, stoppedLoadingPromise]); + + ok(gBrowser.webNavigation.canGoForward); + + await Promise.any([transitionStartPromise, transitionCancelPromise]); + + await TestUtils.waitForCondition(() => { + return ( + gHistorySwipeAnimation._prevBox == null && + gHistorySwipeAnimation._nextBox == null + ); + }); + + // Navigate forward and check the forward navigation icon box state. + startLoadingPromise = BrowserTestUtils.browserStarted( + tab.linkedBrowser, + secondPage + ); + stoppedLoadingPromise = BrowserTestUtils.browserStopped( + tab.linkedBrowser, + secondPage + ); + + await panRightToLeftBegin(tab.linkedBrowser, 100, 100, 100); + + ok(gHistorySwipeAnimation._nextBox != null, "should have nextbox"); + transitionCancelPromise = new Promise(resolve => { + gHistorySwipeAnimation._nextBox.addEventListener( + "transitioncancel", + event => { + if ( + event.propertyName == "opacity" && + event.target == gHistorySwipeAnimation._nextBox + ) { + resolve(); + } + } + ); + }); + transitionStartPromise = new Promise(resolve => { + gHistorySwipeAnimation._nextBox.addEventListener( + "transitionstart", + event => { + if ( + event.propertyName == "opacity" && + event.target == gHistorySwipeAnimation._nextBox + ) { + resolve(); + } + } + ); + }); + + await panRightToLeftUpdate(tab.linkedBrowser, 100, 100, 100); + await panRightToLeftEnd(tab.linkedBrowser, 100, 100, 100); + + // Make sure the gesture triggered going forward to the next page. + await Promise.all([startLoadingPromise, stoppedLoadingPromise]); + + ok(gBrowser.webNavigation.canGoBack); + + await Promise.any([transitionStartPromise, transitionCancelPromise]); + + await TestUtils.waitForCondition(() => { + return ( + gHistorySwipeAnimation._nextBox == null && + gHistorySwipeAnimation._prevBox == null + ); + }); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +// A simple test case on RTL. +add_task(async () => { + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["widget.swipe.velocity-twitch-tolerance", 0.0000001], + ["widget.swipe.success-velocity-contribution", 0.5], + ["intl.l10n.pseudo", "bidi"], + ], + }); + + const newWin = await BrowserTestUtils.openNewBrowserWindow(); + + const firstPage = "about:about"; + const secondPage = "about:mozilla"; + const tab = await BrowserTestUtils.openNewForegroundTab( + newWin.gBrowser, + firstPage, + true /* waitForLoad */ + ); + + BrowserTestUtils.loadURIString(tab.linkedBrowser, secondPage); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage); + + // Make sure we can go back to the previous page. + ok(newWin.gBrowser.webNavigation.canGoBack); + // and we cannot go forward to the next page. + ok(!newWin.gBrowser.webNavigation.canGoForward); + + // Make sure that our gesture support stuff has been initialized in the new + // browser window. + await TestUtils.waitForCondition(() => { + return newWin.gHistorySwipeAnimation.active; + }); + + // Try to navigate backward. + let startLoadingPromise = BrowserTestUtils.browserStarted( + tab.linkedBrowser, + firstPage + ); + let stoppedLoadingPromise = BrowserTestUtils.browserStopped( + tab.linkedBrowser, + firstPage + ); + await panRightToLeft(tab.linkedBrowser, 100, 100, 1); + await Promise.all([startLoadingPromise, stoppedLoadingPromise]); + + ok(newWin.gBrowser.webNavigation.canGoForward); + + // Now try to navigate forward again. + startLoadingPromise = BrowserTestUtils.browserStarted( + tab.linkedBrowser, + secondPage + ); + stoppedLoadingPromise = BrowserTestUtils.browserStopped( + tab.linkedBrowser, + secondPage + ); + await panLeftToRight(tab.linkedBrowser, 100, 100, 1); + await Promise.all([startLoadingPromise, stoppedLoadingPromise]); + + ok(newWin.gBrowser.webNavigation.canGoBack); + + await BrowserTestUtils.closeWindow(newWin); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async () => { + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["widget.swipe.velocity-twitch-tolerance", 0.0000001], + ["widget.swipe.success-velocity-contribution", 0.5], + ["apz.overscroll.enabled", true], + ["apz.test.logging_enabled", true], + ], + }); + + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:about", + true /* waitForLoad */ + ); + + const URL_ROOT = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + "http://mochi.test:8888/" + ); + BrowserTestUtils.loadURIString( + tab.linkedBrowser, + URL_ROOT + "helper_swipe_gesture.html" + ); + await BrowserTestUtils.browserLoaded( + tab.linkedBrowser, + false /* includeSubFrames */, + URL_ROOT + "helper_swipe_gesture.html" + ); + + // Make sure we can go back to the previous page. + ok(gBrowser.webNavigation.canGoBack); + + await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { + // Set `overscroll-behavior-x: contain` and flush it. + content.document.documentElement.style.overscrollBehaviorX = "contain"; + content.document.documentElement.getBoundingClientRect(); + await content.wrappedJSObject.promiseApzFlushedRepaints(); + }); + + // Start a pan gesture but keep touching. + await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 2); + + // Flush APZ pending requests to make sure the pan gesture has been processed. + await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { + await content.wrappedJSObject.promiseApzFlushedRepaints(); + }); + + const isOverscrolled = await SpecialPowers.spawn( + tab.linkedBrowser, + [], + () => { + const scrollId = SpecialPowers.DOMWindowUtils.getViewId( + content.document.scrollingElement + ); + const data = SpecialPowers.DOMWindowUtils.getCompositorAPZTestData(); + return data.additionalData.some(entry => { + return ( + entry.key == scrollId && + entry.value.split(",").includes("overscrolled") + ); + }); + } + ); + + ok(isOverscrolled, "The root scroller should have overscrolled"); + + // Finish the pan gesture. + await panLeftToRightUpdate(tab.linkedBrowser, 100, 100, 2); + await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 2); + + // And wait a while to give a chance to navigate. + await waitForWhile(); + + // Make sure any navigation didn't happen. + is(tab.linkedBrowser.currentURI.spec, URL_ROOT + "helper_swipe_gesture.html"); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +// A test case to make sure the short circuit path for swipe-to-navigations in +// APZ works, i.e. cases where we know for sure that the target APZC for a given +// pan-start event isn't scrollable in the pan-start event direction. +add_task(async () => { + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["apz.overscroll.enabled", true], + ], + }); + + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:about", + true /* waitForLoad */ + ); + + const URL_ROOT = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + "http://mochi.test:8888/" + ); + BrowserTestUtils.loadURIString( + tab.linkedBrowser, + URL_ROOT + "helper_swipe_gesture.html" + ); + await BrowserTestUtils.browserLoaded( + tab.linkedBrowser, + false /* includeSubFrames */, + URL_ROOT + "helper_swipe_gesture.html" + ); + + // Make sure the content can allow both of overscrolling and + // swipe-to-navigations. + const overscrollBehaviorX = await SpecialPowers.spawn( + tab.linkedBrowser, + [], + () => { + return content.window.getComputedStyle(content.document.documentElement) + .overscrollBehaviorX; + } + ); + is(overscrollBehaviorX, "auto"); + + // Make sure we can go back to the previous page. + ok(gBrowser.webNavigation.canGoBack); + + // Start a pan gesture but keep touching. + await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 2); + + // The above pan event should invoke a SwipeGestureStart event immediately so + // that the swipe-to-navigation icon box should be uncollapsed to show it. + ok(!gHistorySwipeAnimation._prevBox.collapsed); + + // Finish the pan gesture, i.e. sending a pan-end event, otherwise a new + // pan-start event in the next will also generate a pan-interrupt event which + // will break the test. + await panLeftToRightUpdate(tab.linkedBrowser, 100, 100, 2); + await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 2); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async () => { + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["widget.swipe.velocity-twitch-tolerance", 0.0000001], + ["widget.swipe.success-velocity-contribution", 0.5], + ["apz.overscroll.enabled", true], + ["apz.test.logging_enabled", true], + ], + }); + + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:about", + true /* waitForLoad */ + ); + + const URL_ROOT = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + "http://mochi.test:8888/" + ); + BrowserTestUtils.loadURIString( + tab.linkedBrowser, + URL_ROOT + "helper_swipe_gesture.html" + ); + await BrowserTestUtils.browserLoaded( + tab.linkedBrowser, + false /* includeSubFrames */, + URL_ROOT + "helper_swipe_gesture.html" + ); + + // Make sure we can go back to the previous page. + ok(gBrowser.webNavigation.canGoBack); + + // Start a pan gesture but keep touching. + await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 2); + + // Flush APZ pending requests to make sure the pan gesture has been processed. + await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { + await content.wrappedJSObject.promiseApzFlushedRepaints(); + }); + + const isOverscrolled = await SpecialPowers.spawn( + tab.linkedBrowser, + [], + () => { + const scrollId = SpecialPowers.DOMWindowUtils.getViewId( + content.document.scrollingElement + ); + const data = SpecialPowers.DOMWindowUtils.getCompositorAPZTestData(); + return data.additionalData.some(entry => { + return entry.key == scrollId && entry.value.includes("overscrolled"); + }); + } + ); + + ok(!isOverscrolled, "The root scroller should not have overscrolled"); + + await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 0); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async () => { + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["widget.swipe.velocity-twitch-tolerance", 0.0000001], + ["widget.swipe.success-velocity-contribution", 0.5], + ], + }); + + // Load three pages and go to the second page so that it can be navigated + // to both back and forward. + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:about", + true /* waitForLoad */ + ); + + BrowserTestUtils.loadURIString(tab.linkedBrowser, "about:mozilla"); + await BrowserTestUtils.browserLoaded( + tab.linkedBrowser, + false /* includeSubFrames */, + "about:mozilla" + ); + + BrowserTestUtils.loadURIString(tab.linkedBrowser, "about:home"); + await BrowserTestUtils.browserLoaded( + tab.linkedBrowser, + false /* includeSubFrames */, + "about:home" + ); + + gBrowser.goBack(); + await BrowserTestUtils.browserLoaded( + tab.linkedBrowser, + false /* includeSubFrames */, + "about:mozilla" + ); + + // Make sure we can go back and go forward. + ok(gBrowser.webNavigation.canGoBack); + ok(gBrowser.webNavigation.canGoForward); + + // Start a history back pan gesture but keep touching. + await panLeftToRightBegin(tab.linkedBrowser, 100, 100, 1); + + ok( + !gHistorySwipeAnimation._prevBox.collapsed, + "The icon box for the previous navigation should NOT be collapsed" + ); + ok( + gHistorySwipeAnimation._nextBox.collapsed, + "The icon box for the next navigation should be collapsed" + ); + + // Pan back to the opposite direction so that the gesture should be cancelled. + // eslint-disable-next-line no-undef + await NativePanHandler.promiseNativePanEvent( + tab.linkedBrowser, + 100, + 100, + // eslint-disable-next-line no-undef + NativePanHandler.delta, + 0, + // eslint-disable-next-line no-undef + NativePanHandler.updatePhase + ); + + ok( + gHistorySwipeAnimation._prevBox.collapsed, + "The icon box for the previous navigation should be collapsed" + ); + ok( + gHistorySwipeAnimation._nextBox.collapsed, + "The icon box for the next navigation should be collapsed" + ); + + await panLeftToRightEnd(tab.linkedBrowser, 100, 100, 0); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async () => { + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["widget.swipe.velocity-twitch-tolerance", 0.0000001], + ["widget.swipe.success-velocity-contribution", 0.5], + ["apz.overscroll.enabled", true], + ["apz.overscroll.damping", 5.0], + ["apz.content_response_timeout", 0], + ], + }); + + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:about", + true /* waitForLoad */ + ); + + const URL_ROOT = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + "http://mochi.test:8888/" + ); + + // Load a horizontal scrollable content. + BrowserTestUtils.loadURIString( + tab.linkedBrowser, + URL_ROOT + "helper_swipe_gesture.html" + ); + await BrowserTestUtils.browserLoaded( + tab.linkedBrowser, + false /* includeSubFrames */, + URL_ROOT + "helper_swipe_gesture.html" + ); + + // Make sure we can go back to the previous page. + ok(gBrowser.webNavigation.canGoBack); + + // Shift the horizontal scroll position slightly to make the content + // overscrollable. + await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { + content.document.documentElement.scrollLeft = 1; + content.document.documentElement.getBoundingClientRect(); + await content.wrappedJSObject.promiseApzFlushedRepaints(); + }); + + // Swipe horizontally to overscroll. + await panLeftToRight(tab.linkedBrowser, 1, 100, 1); + + // Swipe again over the overscroll gutter. + await panLeftToRight(tab.linkedBrowser, 1, 100, 1); + + // Wait the overscroll gutter is restored. + await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { + // For some reasons using functions in apz_test_native_event_utils.js + // sometimes causes "TypeError content.wrappedJSObject.XXXX is not a + // function" error, so we observe "APZ:TransformEnd" instead of using + // promiseTransformEnd(). + await new Promise((resolve, reject) => { + SpecialPowers.Services.obs.addObserver(function observer( + subject, + topic, + data + ) { + try { + SpecialPowers.Services.obs.removeObserver(observer, topic); + resolve([subject, data]); + } catch (ex) { + SpecialPowers.Services.obs.removeObserver(observer, topic); + reject(ex); + } + }, + "APZ:TransformEnd"); + }); + }); + + // Set up an APZ aware event listener and... + await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { + content.document.documentElement.addEventListener("wheel", e => {}, { + passive: false, + }); + await content.wrappedJSObject.promiseApzFlushedRepaints(); + }); + + // Try to swipe back again without overscrolling to make sure swipe-navigation + // works with the APZ aware event listener. + await panLeftToRight(tab.linkedBrowser, 100, 100, 1); + + let startLoadingPromise = BrowserTestUtils.browserStarted( + tab.linkedBrowser, + "about:about" + ); + let stoppedLoadingPromise = BrowserTestUtils.browserStopped( + tab.linkedBrowser, + "about:about" + ); + + await Promise.all([startLoadingPromise, stoppedLoadingPromise]); + + ok(gBrowser.webNavigation.canGoForward); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); + +// NOTE: This test listens wheel events so that it causes an overscroll issue +// (bug 1800022). To avoid the bug, we need to run this test case at the end +// of this file. +add_task(async () => { + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.gesture.swipe.left", "Browser:BackOrBackDuplicate"], + ["browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate"], + ["widget.disable-swipe-tracker", false], + ["widget.swipe.velocity-twitch-tolerance", 0.0000001], + ["widget.swipe.success-velocity-contribution", 0.5], + ], + }); + + const firstPage = "about:about"; + const secondPage = "about:mozilla"; + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + firstPage, + true /* waitForLoad */ + ); + + BrowserTestUtils.loadURIString(tab.linkedBrowser, secondPage); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, secondPage); + + // Make sure we can go back to the previous page. + ok(gBrowser.webNavigation.canGoBack); + // and we cannot go forward to the next page. + ok(!gBrowser.webNavigation.canGoForward); + + let wheelEventCount = 0; + tab.linkedBrowser.addEventListener("wheel", () => { + wheelEventCount++; + }); + + // Try to navigate forward. + await panRightToLeft(tab.linkedBrowser, 100, 100, 1); + // NOTE: The last endPhase shouldn't fire a wheel event since + // its delta is zero. + is(wheelEventCount, 2, "Received 2 wheel events"); + + await waitForWhile(); + // Make sure any navigation didn't happen. + is(tab.linkedBrowser.currentURI.spec, secondPage); + + // Try to navigate backward. + wheelEventCount = 0; + let startLoadingPromise = BrowserTestUtils.browserStarted( + tab.linkedBrowser, + firstPage + ); + let stoppedLoadingPromise = BrowserTestUtils.browserStopped( + tab.linkedBrowser, + firstPage + ); + await panLeftToRight(tab.linkedBrowser, 100, 100, 1); + // NOTE: We only get a wheel event for the beginPhase, rest of events have + // been captured by the swipe gesture module. + is(wheelEventCount, 1, "Received a wheel event"); + + // Make sure the gesture triggered going back to the previous page. + await Promise.all([startLoadingPromise, stoppedLoadingPromise]); + + ok(gBrowser.webNavigation.canGoForward); + + // Now try to navigate forward again. + wheelEventCount = 0; + startLoadingPromise = BrowserTestUtils.browserStarted( + tab.linkedBrowser, + secondPage + ); + stoppedLoadingPromise = BrowserTestUtils.browserStopped( + tab.linkedBrowser, + secondPage + ); + await panRightToLeft(tab.linkedBrowser, 100, 100, 1); + is(wheelEventCount, 1, "Received a wheel event"); + + await Promise.all([startLoadingPromise, stoppedLoadingPromise]); + + ok(gBrowser.webNavigation.canGoBack); + + // Now try to navigate backward again but with preventDefault-ed event + // handler. + wheelEventCount = 0; + let wheelEventListener = event => { + event.preventDefault(); + }; + tab.linkedBrowser.addEventListener("wheel", wheelEventListener); + await panLeftToRight(tab.linkedBrowser, 100, 100, 1); + is(wheelEventCount, 3, "Received all wheel events"); + + await waitForWhile(); + // Make sure any navigation didn't happen. + is(tab.linkedBrowser.currentURI.spec, secondPage); + + // Now drop the event handler and disable the swipe tracker and try to swipe + // again. + wheelEventCount = 0; + tab.linkedBrowser.removeEventListener("wheel", wheelEventListener); + await SpecialPowers.pushPrefEnv({ + set: [["widget.disable-swipe-tracker", true]], + }); + + await panLeftToRight(tab.linkedBrowser, 100, 100, 1); + is(wheelEventCount, 3, "Received all wheel events"); + + await waitForWhile(); + // Make sure any navigation didn't happen. + is(tab.linkedBrowser.currentURI.spec, secondPage); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); diff --git a/widget/tests/browser/file_ime_state_tests.html b/widget/tests/browser/file_ime_state_tests.html new file mode 100644 index 0000000000..d6b63f1e52 --- /dev/null +++ b/widget/tests/browser/file_ime_state_tests.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + +
+ diff --git a/widget/tests/browser/helper_scrollbar_colors.html b/widget/tests/browser/helper_scrollbar_colors.html new file mode 100644 index 0000000000..e6001906e2 --- /dev/null +++ b/widget/tests/browser/helper_scrollbar_colors.html @@ -0,0 +1,22 @@ + + + +Test for scrollbar-*-color properties + + +
+
+
+
+ diff --git a/widget/tests/browser/helper_swipe_gesture.html b/widget/tests/browser/helper_swipe_gesture.html new file mode 100644 index 0000000000..1fa79dbbf3 --- /dev/null +++ b/widget/tests/browser/helper_swipe_gesture.html @@ -0,0 +1,20 @@ + + + + + + +
+ diff --git a/widget/tests/bug586713_window.xhtml b/widget/tests/bug586713_window.xhtml new file mode 100644 index 0000000000..c180c00235 --- /dev/null +++ b/widget/tests/bug586713_window.xhtml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + diff --git a/widget/tests/chrome.ini b/widget/tests/chrome.ini new file mode 100644 index 0000000000..8395374ce0 --- /dev/null +++ b/widget/tests/chrome.ini @@ -0,0 +1,134 @@ +[DEFAULT] +skip-if = os == 'android' +support-files = + empty_window.xhtml + clipboard_helper.js + +[test_alwaysontop_focus.xhtml] + +# Privacy relevant +[test_bug1123480.xhtml] +skip-if = os == "win" && bits == 32 + +[test_bug343416.xhtml] +skip-if = debug +[test_bug413277.html] +skip-if = toolkit != "cocoa" # Cocoa widget test +[test_bug428405.xhtml] +skip-if = toolkit != "cocoa" # Cocoa widget test +[test_bug429954.xhtml] +support-files = window_bug429954.xhtml +[test_bug444800.xhtml] +[test_bug466599.xhtml] +skip-if = toolkit != "cocoa" # Cocoa widget test +[test_bug478536.xhtml] +skip-if = true # Bug 561929 +support-files = window_bug478536.xhtml +[test_bug485118.xhtml] +skip-if = toolkit != "cocoa" # Cocoa widget test +[test_bug517396.xhtml] +skip-if = (verify && (os == 'win')) +[test_bug522217.xhtml] +tags = fullscreen +skip-if = toolkit != "cocoa" # Cocoa widget test +support-files = window_bug522217.xhtml +[test_bug538242.xhtml] +support-files = window_bug538242.xhtml +[test_bug565392.html] +skip-if = toolkit != "windows" +[test_bug586713.xhtml] +skip-if = toolkit != "cocoa" # Cocoa widget test +support-files = bug586713_window.xhtml +[test_bug593307.xhtml] +support-files = window_bug593307_offscreen.xhtml window_bug593307_centerscreen.xhtml +[test_bug596600.xhtml] +support-files = file_bug596600.html +skip-if = toolkit != "cocoa" # Cocoa widget test +[test_bug673301.xhtml] +skip-if = toolkit != "cocoa" # Cocoa widget test +[test_bug760802.xhtml] +[test_clipboard.xhtml] +[test_clipboard_asyncSetData.xhtml] +[test_clipboard_cache.xhtml] +[test_clipboard_owner.xhtml] +[test_composition_text_querycontent.xhtml] +support-files = window_composition_text_querycontent.xhtml +[test_ime_state_in_contenteditable_on_readonly_change_in_parent.html] +support-files = + file_ime_state_test_helper.js + file_test_ime_state_in_contenteditable_on_readonly_change.js +[test_ime_state_in_plugin_in_parent.html] +support-files = + file_ime_state_test_helper.js +[test_ime_state_in_text_control_on_reframe_in_parent.html] +support-files = + file_ime_state_test_helper.js + file_test_ime_state_in_text_control_on_reframe.js +[test_ime_state_on_editable_state_change_in_parent.html] +support-files = + file_ime_state_test_helper.js +[test_ime_state_on_focus_move_in_parent.html] +support-files = + file_ime_state_test_helper.js + file_test_ime_state_on_focus_move.js +[test_ime_state_on_input_type_change_in_parent.html] +skip-if = true # Bug 1817704 +support-files = + file_ime_state_test_helper.js + file_test_ime_state_on_input_type_change.js +[test_ime_state_on_readonly_change_in_parent.html] +support-files = + file_ime_state_test_helper.js + file_test_ime_state_on_readonly_change.js +[test_ime_state_others_in_parent.html] +support-files = window_imestate_iframes.html +[test_input_events_on_deactive_window.xhtml] +support-files = file_input_events_on_deactive_window.html +[test_key_event_counts.xhtml] +skip-if = toolkit != "cocoa" # Cocoa widget test +[test_keycodes.xhtml] +[test_mouse_scroll.xhtml] +skip-if = toolkit != "windows" # Windows widget test +support-files = + window_mouse_scroll_win.html + window_mouse_scroll_win_2.html +[test_native_key_bindings_mac.html] +skip-if = + toolkit != "cocoa" # Cocoa widget test + verify +[test_native_menus.xhtml] +skip-if = toolkit != "cocoa" # Cocoa widget test +support-files = native_menus_window.xhtml +[test_panel_mouse_coords.xhtml] +skip-if = toolkit == "windows" # bug 1009955 +[test_platform_colors.xhtml] +#skip-if = toolkit != "cocoa" # Cocoa widget test +skip-if = true # Bug 1207190 +[test_position_on_resize.xhtml] +skip-if = + verify && (os == 'win') + (os == "linux" && bits == 64) # Bug 1616760 +[test_secure_input.html] +support-files = file_secure_input.html +skip-if = toolkit != "cocoa" # Cocoa widget test +[test_sizemode_events.xhtml] +[test_standalone_native_menu.xhtml] +skip-if = toolkit != "cocoa" # Cocoa widget test +support-files = standalone_native_menu_window.xhtml +[test_system_font_changes.xhtml] +support-files = system_font_changes.xhtml +run-if = toolkit == 'gtk' # Currently the test works on only gtk3 +[test_system_status_bar.xhtml] +skip-if = toolkit != "cocoa" # Cocoa widget test +[test_taskbar_progress.xhtml] +skip-if = + toolkit != "cocoa" && toolkit != "windows" + (os == "win" && os_version == "10.0" && !ccov) # Bug 1456811 +[test_transferable_overflow.xhtml] +skip-if = (verify && (os == 'mac' || os == 'linux')) +[test_wheeltransaction.xhtml] +support-files = window_wheeltransaction.xhtml + +# Windows +# taskbar_previews.xhtml +# window_state_windows.xhtml diff --git a/widget/tests/clipboard_helper.js b/widget/tests/clipboard_helper.js new file mode 100644 index 0000000000..7315bd19ac --- /dev/null +++ b/widget/tests/clipboard_helper.js @@ -0,0 +1,83 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const clipboard = SpecialPowers.Services.clipboard; +const clipboardTypes = [ + clipboard.kGlobalClipboard, + clipboard.kSelectionClipboard, + clipboard.kFindClipboard, + clipboard.kSelectionCache, +]; + +function cleanupAllClipboard() { + clipboardTypes.forEach(function (type) { + if (clipboard.isClipboardTypeSupported(type)) { + info(`cleanup clipboard ${type}`); + clipboard.emptyClipboard(type); + } + }); +} + +function generateRandomString() { + return "random number: " + Math.random(); +} + +function writeStringToClipboard( + aStr, + aFlavor, + aClipboardType, + aClipboardOwner = null, + aAsync = false +) { + let trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( + Ci.nsITransferable + ); + trans.init(null); + trans.addDataFlavor(aFlavor); + + let supportsStr = Cc["@mozilla.org/supports-string;1"].createInstance( + Ci.nsISupportsString + ); + supportsStr.data = aStr; + trans.setTransferData(aFlavor, supportsStr); + + if (aAsync) { + let request = clipboard.asyncSetData(aClipboardType); + request.setData(trans, aClipboardOwner); + return; + } + + clipboard.setData(trans, aClipboardOwner, aClipboardType); +} + +function writeRandomStringToClipboard( + aFlavor, + aClipboardType, + aClipboardOwner = null, + aAsync = false +) { + let randomString = generateRandomString(); + writeStringToClipboard( + randomString, + aFlavor, + aClipboardType, + aClipboardOwner, + aAsync + ); + return randomString; +} + +function getClipboardData(aFlavor, aClipboardType) { + var trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( + Ci.nsITransferable + ); + trans.init(null); + trans.addDataFlavor(aFlavor); + clipboard.getData(trans, aClipboardType); + + var data = {}; + trans.getTransferData(aFlavor, data); + return data.value.QueryInterface(SpecialPowers.Ci.nsISupportsString).data; +} diff --git a/widget/tests/empty_window.xhtml b/widget/tests/empty_window.xhtml new file mode 100644 index 0000000000..f0e01761d2 --- /dev/null +++ b/widget/tests/empty_window.xhtml @@ -0,0 +1,4 @@ + + + diff --git a/widget/tests/file_bug596600.html b/widget/tests/file_bug596600.html new file mode 100644 index 0000000000..1b178a6b68 --- /dev/null +++ b/widget/tests/file_bug596600.html @@ -0,0 +1,4 @@ + + +Content page + diff --git a/widget/tests/file_ime_state_test_helper.js b/widget/tests/file_ime_state_test_helper.js new file mode 100644 index 0000000000..0cee5c036f --- /dev/null +++ b/widget/tests/file_ime_state_test_helper.js @@ -0,0 +1,197 @@ +"use strict"; + +function IsIMEOpenStateSupported() { + // We support to control IME open state on Windows and Mac actually. However, + // we cannot test it on Mac if the current keyboard layout is not CJK. And also + // we cannot test it on Win32 if the system didn't be installed IME. So, + // currently we should not run the open state testing. + return false; +} + +/** + * @param {Node} aNode + */ +function nodeIsInShadowDOM(aNode) { + for (let node = aNode; node; node = node.parentNode) { + if (node instanceof ShadowRoot) { + return true; + } + if (node == node.parentNode) { + break; + } + } + return false; +} + +/** + * @param {Node} aNode + */ +function nodeIsInDesignMode(aNode) { + return ( + aNode.isConnected && + !nodeIsInShadowDOM(aNode) && + aNode.ownerDocument.designMode == "on" + ); +} + +/** + * param {Node} aNode + */ +function getEditingHost(aNode) { + if (nodeIsInDesignMode(aNode)) { + return aNode.ownerDocument.documentElement; + } + for ( + let element = + aNode.nodeType == Node.ELEMENT_NODE ? aNode : aNode.parentElement; + element; + element = element.parentElement + ) { + const contenteditable = element.getAttribute("contenteditable"); + if (contenteditable === "true" || contenteditable === "") { + return element; + } + if (contenteditable === "false") { + return null; + } + } + return null; +} + +/** + * @param {Node} aNode + */ +function nodeIsEditable(aNode) { + if (nodeIsInDesignMode(aNode)) { + return true; + } + if (!aNode.isConnected) { + return false; + } + return getEditingHost(aNode) != null; +} + +/** + * @param {Element} aElement + */ +function elementIsEditingHost(aElement) { + return ( + nodeIsEditable(aElement) && + (!aElement.parentElement || !getEditingHost(aElement) == aElement) + ); +} + +/** + * @returns {Element} Retrieve focused element. If focused element is a element + * in UA widget, this returns its host element. E.g., when + * a button in the controls of
+
+
+
+ + diff --git a/widget/tests/test_alwaysontop_focus.xhtml b/widget/tests/test_alwaysontop_focus.xhtml new file mode 100644 index 0000000000..b9cc3ee33c --- /dev/null +++ b/widget/tests/test_alwaysontop_focus.xhtml @@ -0,0 +1,38 @@ + + + + + Test that alwaysontop windows do not pull focus when opened. + + + + + +

+ +

+
+
diff --git a/widget/tests/test_assign_event_data.html b/widget/tests/test_assign_event_data.html
new file mode 100644
index 0000000000..1da9bb535f
--- /dev/null
+++ b/widget/tests/test_assign_event_data.html
@@ -0,0 +1,708 @@
+
+
+
+  Testing ns*Event::Assign*EventData()
+  
+  
+  
+  
+  
+
+
+
+ + + hyper link + span +
+
form
+
 
+
+ +
+
+ + + diff --git a/widget/tests/test_autocapitalize.html b/widget/tests/test_autocapitalize.html new file mode 100644 index 0000000000..833dafe1af --- /dev/null +++ b/widget/tests/test_autocapitalize.html @@ -0,0 +1,65 @@ + + + +Tests for autocapitalize that is used by software keyboard + + + + + +

+ + +
+
+
+
+
+
+
+
+
+
+
+

+

+

+

+
+ +
+
+
+ + diff --git a/widget/tests/test_bug1123480.xhtml b/widget/tests/test_bug1123480.xhtml new file mode 100644 index 0000000000..c84a9c1d59 --- /dev/null +++ b/widget/tests/test_bug1123480.xhtml @@ -0,0 +1,153 @@ + + + + + + nsTransferable PBM Overflow Selection Test + + + + + Mozilla Bug 1123480 + + diff --git a/widget/tests/test_bug343416.xhtml b/widget/tests/test_bug343416.xhtml new file mode 100644 index 0000000000..bf4dbbb9b4 --- /dev/null +++ b/widget/tests/test_bug343416.xhtml @@ -0,0 +1,191 @@ + + + + + + + + + diff --git a/widget/tests/test_bug413277.html b/widget/tests/test_bug413277.html new file mode 100644 index 0000000000..d9f6aaa807 --- /dev/null +++ b/widget/tests/test_bug413277.html @@ -0,0 +1,35 @@ + + + + + Test for Bug 413277 + + + + +Mozilla Bug 413277 +

+ +
+
+
+ diff --git a/widget/tests/test_bug428405.xhtml b/widget/tests/test_bug428405.xhtml new file mode 100644 index 0000000000..ebfe9f127d --- /dev/null +++ b/widget/tests/test_bug428405.xhtml @@ -0,0 +1,166 @@ + + + + + + + + + + +

+ +

+  
+
+
diff --git a/widget/tests/test_bug429954.xhtml b/widget/tests/test_bug429954.xhtml new file mode 100644 index 0000000000..40de88cd32 --- /dev/null +++ b/widget/tests/test_bug429954.xhtml @@ -0,0 +1,42 @@ + + + + + + + + + diff --git a/widget/tests/test_bug444800.xhtml b/widget/tests/test_bug444800.xhtml new file mode 100644 index 0000000000..85a73b3288 --- /dev/null +++ b/widget/tests/test_bug444800.xhtml @@ -0,0 +1,97 @@ + + + + + + + diff --git a/widget/tests/test_bug466599.xhtml b/widget/tests/test_bug466599.xhtml new file mode 100644 index 0000000000..6a81b16af2 --- /dev/null +++ b/widget/tests/test_bug466599.xhtml @@ -0,0 +1,103 @@ + + + + + + + diff --git a/widget/tests/test_bug478536.xhtml b/widget/tests/test_bug478536.xhtml new file mode 100644 index 0000000000..383c0bb42f --- /dev/null +++ b/widget/tests/test_bug478536.xhtml @@ -0,0 +1,33 @@ + + + + + + + Test for Bug 478536 + + + diff --git a/widget/tests/test_bug485118.xhtml b/widget/tests/test_bug485118.xhtml new file mode 100644 index 0000000000..5c635f2982 --- /dev/null +++ b/widget/tests/test_bug485118.xhtml @@ -0,0 +1,72 @@ + + + + + + + + + diff --git a/widget/tests/test_bug517396.xhtml b/widget/tests/test_bug517396.xhtml new file mode 100644 index 0000000000..c88baf49ab --- /dev/null +++ b/widget/tests/test_bug517396.xhtml @@ -0,0 +1,53 @@ + + + + + + + + + diff --git a/widget/tests/test_bug522217.xhtml b/widget/tests/test_bug522217.xhtml new file mode 100644 index 0000000000..0fa55a65e8 --- /dev/null +++ b/widget/tests/test_bug522217.xhtml @@ -0,0 +1,35 @@ + + + + + + + + + diff --git a/widget/tests/test_bug538242.xhtml b/widget/tests/test_bug538242.xhtml new file mode 100644 index 0000000000..4608a74e35 --- /dev/null +++ b/widget/tests/test_bug538242.xhtml @@ -0,0 +1,55 @@ + + + + + + + + + diff --git a/widget/tests/test_bug565392.html b/widget/tests/test_bug565392.html new file mode 100644 index 0000000000..a0efc0a7f9 --- /dev/null +++ b/widget/tests/test_bug565392.html @@ -0,0 +1,62 @@ + + + + + Test for Bug 565392 + + + + +Mozilla Bug 565392 +

+ +
+
+
+ + diff --git a/widget/tests/test_bug586713.xhtml b/widget/tests/test_bug586713.xhtml new file mode 100644 index 0000000000..4733202264 --- /dev/null +++ b/widget/tests/test_bug586713.xhtml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/widget/tests/test_bug593307.xhtml b/widget/tests/test_bug593307.xhtml new file mode 100644 index 0000000000..770dd390cb --- /dev/null +++ b/widget/tests/test_bug593307.xhtml @@ -0,0 +1,40 @@ + + + + + + + + + diff --git a/widget/tests/test_bug596600.xhtml b/widget/tests/test_bug596600.xhtml new file mode 100644 index 0000000000..4acdab79bc --- /dev/null +++ b/widget/tests/test_bug596600.xhtml @@ -0,0 +1,190 @@ + + + + + + + + diff --git a/widget/tests/test_bug673301.xhtml b/widget/tests/test_bug673301.xhtml new file mode 100644 index 0000000000..663f18397e --- /dev/null +++ b/widget/tests/test_bug673301.xhtml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/widget/tests/test_bug760802.xhtml b/widget/tests/test_bug760802.xhtml new file mode 100644 index 0000000000..383a2be8b4 --- /dev/null +++ b/widget/tests/test_bug760802.xhtml @@ -0,0 +1,83 @@ + + + + + + + diff --git a/widget/tests/test_clipboard.xhtml b/widget/tests/test_clipboard.xhtml new file mode 100644 index 0000000000..9d1afe2432 --- /dev/null +++ b/widget/tests/test_clipboard.xhtml @@ -0,0 +1,111 @@ + + + + + + + diff --git a/widget/tests/test_clipboard_asyncSetData.xhtml b/widget/tests/test_clipboard_asyncSetData.xhtml new file mode 100644 index 0000000000..27f5fad58c --- /dev/null +++ b/widget/tests/test_clipboard_asyncSetData.xhtml @@ -0,0 +1,173 @@ + + + + + + + diff --git a/widget/tests/test_clipboard_cache.xhtml b/widget/tests/test_clipboard_cache.xhtml new file mode 100644 index 0000000000..39cf8113dd --- /dev/null +++ b/widget/tests/test_clipboard_cache.xhtml @@ -0,0 +1,56 @@ + + + + + + + diff --git a/widget/tests/test_clipboard_owner.xhtml b/widget/tests/test_clipboard_owner.xhtml new file mode 100644 index 0000000000..4fd530d8ff --- /dev/null +++ b/widget/tests/test_clipboard_owner.xhtml @@ -0,0 +1,80 @@ + + + + + + + diff --git a/widget/tests/test_composition_text_querycontent.xhtml b/widget/tests/test_composition_text_querycontent.xhtml new file mode 100644 index 0000000000..48b7af8100 --- /dev/null +++ b/widget/tests/test_composition_text_querycontent.xhtml @@ -0,0 +1,34 @@ + + + + + + + diff --git a/widget/tests/test_ime_state_in_contenteditable_on_readonly_change_in_parent.html b/widget/tests/test_ime_state_in_contenteditable_on_readonly_change_in_parent.html new file mode 100644 index 0000000000..8d8662a8d8 --- /dev/null +++ b/widget/tests/test_ime_state_in_contenteditable_on_readonly_change_in_parent.html @@ -0,0 +1,72 @@ + + + Test for IME state of contenteditable on readonly state change + + + + + + +

+ diff --git a/widget/tests/test_ime_state_in_plugin_in_parent.html b/widget/tests/test_ime_state_in_plugin_in_parent.html new file mode 100644 index 0000000000..9f3892ab88 --- /dev/null +++ b/widget/tests/test_ime_state_in_plugin_in_parent.html @@ -0,0 +1,92 @@ + + + Test for IME state on plugin + + + + + + + + + + diff --git a/widget/tests/test_ime_state_in_text_control_on_reframe_in_parent.html b/widget/tests/test_ime_state_in_text_control_on_reframe_in_parent.html new file mode 100644 index 0000000000..ab38806261 --- /dev/null +++ b/widget/tests/test_ime_state_in_text_control_on_reframe_in_parent.html @@ -0,0 +1,42 @@ + + + Test for IME state of contenteditable on readonly state change + + + + + + + + diff --git a/widget/tests/test_ime_state_on_editable_state_change_in_parent.html b/widget/tests/test_ime_state_on_editable_state_change_in_parent.html new file mode 100644 index 0000000000..a1b307a51f --- /dev/null +++ b/widget/tests/test_ime_state_on_editable_state_change_in_parent.html @@ -0,0 +1,263 @@ + + + + + Test for IME state management at changing editable state + + + + + +
+ + + diff --git a/widget/tests/test_ime_state_on_focus_move_in_parent.html b/widget/tests/test_ime_state_on_focus_move_in_parent.html new file mode 100644 index 0000000000..fd74d61c7e --- /dev/null +++ b/widget/tests/test_ime_state_on_focus_move_in_parent.html @@ -0,0 +1,88 @@ + + + + + Test for IME state management on focus move in parent process + + + + + + + +
+ + + diff --git a/widget/tests/test_ime_state_on_input_type_change_in_parent.html b/widget/tests/test_ime_state_on_input_type_change_in_parent.html new file mode 100644 index 0000000000..2644c31e3f --- /dev/null +++ b/widget/tests/test_ime_state_on_input_type_change_in_parent.html @@ -0,0 +1,39 @@ + + + Test for IME state on input type change + + + + + + + + + diff --git a/widget/tests/test_ime_state_on_readonly_change_in_parent.html b/widget/tests/test_ime_state_on_readonly_change_in_parent.html new file mode 100644 index 0000000000..0557856542 --- /dev/null +++ b/widget/tests/test_ime_state_on_readonly_change_in_parent.html @@ -0,0 +1,31 @@ + + + Test for IME state on readonly state change + + + + + + + + + diff --git a/widget/tests/test_ime_state_others_in_parent.html b/widget/tests/test_ime_state_others_in_parent.html new file mode 100644 index 0000000000..e6ae0ab272 --- /dev/null +++ b/widget/tests/test_ime_state_others_in_parent.html @@ -0,0 +1,153 @@ + + + Test for IME state controlling in some special cases + + + + + + +
+ +

+
+
+
diff --git a/widget/tests/test_input_events_on_deactive_window.xhtml b/widget/tests/test_input_events_on_deactive_window.xhtml
new file mode 100644
index 0000000000..d54699f76c
--- /dev/null
+++ b/widget/tests/test_input_events_on_deactive_window.xhtml
@@ -0,0 +1,233 @@
+
+
+
+
+
+  
+
diff --git a/widget/tests/test_key_event_counts.xhtml b/widget/tests/test_key_event_counts.xhtml
new file mode 100644
index 0000000000..6eda6a52fb
--- /dev/null
+++ b/widget/tests/test_key_event_counts.xhtml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+  
+
+
diff --git a/widget/tests/test_keycodes.xhtml b/widget/tests/test_keycodes.xhtml
new file mode 100644
index 0000000000..7dd2250f7d
--- /dev/null
+++ b/widget/tests/test_keycodes.xhtml
@@ -0,0 +1,5626 @@
+
+
+
+
+
+  
+
+
diff --git a/widget/tests/test_keypress_event_with_alt_on_mac.html b/widget/tests/test_keypress_event_with_alt_on_mac.html
new file mode 100644
index 0000000000..01d4100f97
--- /dev/null
+++ b/widget/tests/test_keypress_event_with_alt_on_mac.html
@@ -0,0 +1,106 @@
+
+
+
+  Testing if keypress event is fired when alt key is pressed
+  
+  
+  
+  
+
+
+
+ + + + + + +
+ +
+
+ + + + \ No newline at end of file diff --git a/widget/tests/test_mouse_event_with_control_on_mac.html b/widget/tests/test_mouse_event_with_control_on_mac.html new file mode 100644 index 0000000000..52ce206d35 --- /dev/null +++ b/widget/tests/test_mouse_event_with_control_on_mac.html @@ -0,0 +1,116 @@ + + + Test control+click on Mac + + + + + + + + + +
+ + + diff --git a/widget/tests/test_mouse_scroll.xhtml b/widget/tests/test_mouse_scroll.xhtml new file mode 100644 index 0000000000..82cb6a3ea3 --- /dev/null +++ b/widget/tests/test_mouse_scroll.xhtml @@ -0,0 +1,35 @@ + + + + + + + diff --git a/widget/tests/test_native_key_bindings_mac.html b/widget/tests/test_native_key_bindings_mac.html new file mode 100644 index 0000000000..8767a5a77d --- /dev/null +++ b/widget/tests/test_native_key_bindings_mac.html @@ -0,0 +1,336 @@ + + + + + Native Key Bindings for Cocoa Test + + + + + + +
+

Stretching attack nullam stuck in a tree zzz, suspendisse cras nec + suspendisse lick suscipit. Nunc egestas amet litter box, nullam climb the + curtains biting I don't like that food tristique biting sleep on your + keyboard non. Lay down in your way cras nec tempus chase the red dot cras + nec, pharetra pharetra eat the grass leap run orci turpis attack. + Consectetur sleep in the sink eat I don't like that food, knock over the + lamp catnip in viverra tail flick zzz meow etiam enim. Ac ac hiss shed + everywhere kittens rhoncus, attack your ankles zzz iaculis kittens. Nullam + pellentesque rip the couch iaculis rhoncus nibh, give me fish orci turpis + purr sleep on your face quis nunc bibendum.

+ +

Neque jump on the table bat iaculis, adipiscing sleep on your keyboard + jump vel justo shed everywhere suspendisse lick. Zzz enim faucibus + hairball faucibus, pharetra sunbathe biting bat leap rip the couch attack. + Tortor nibh in viverra quis hairball nam, vulputate adipiscing sleep on + your keyboard purr knock over the lamp orci turpis. Vestibulum I don't + like that food et chase the red dot, adipiscing neque bibendum rutrum + accumsan quis rhoncus claw. Leap accumsan vehicula enim biting sleep on + your face, pharetra nam accumsan egestas kittens sunbathe. Pharetra chase + the red dot sniff non eat the grass, vulputate fluffy fur aliquam puking + judging you.

+ +

Claw purr sollicitudin sollicitudin lay down in your way consectetur, + pellentesque vehicula zzz orci turpis consectetur. I don't like that food + rhoncus pellentesque sniff attack, rhoncus tortor attack your ankles + iaculis scratched hiss vel. Tortor zzz tortor nullam rip the couch rutrum, + bat enim ut leap hairball iaculis. Bibendum sunbathe elit suspendisse + nibh, puking adipiscing sleep on your face sleep on your face zzz catnip. + Judging you rutrum bat sunbathe sleep on your face, jump on the table leap + tincidunt a faucibus sleep in the sink. Stuck in a tree tristique zzz hiss + in viverra nullam, quis tortor pharetra attack.

+
+ + + + + + + + diff --git a/widget/tests/test_native_menus.xhtml b/widget/tests/test_native_menus.xhtml new file mode 100644 index 0000000000..d62c57f21c --- /dev/null +++ b/widget/tests/test_native_menus.xhtml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/widget/tests/test_panel_mouse_coords.xhtml b/widget/tests/test_panel_mouse_coords.xhtml new file mode 100644 index 0000000000..43c4e10249 --- /dev/null +++ b/widget/tests/test_panel_mouse_coords.xhtml @@ -0,0 +1,78 @@ + + + + + + + diff --git a/widget/tests/test_picker_no_crash.html b/widget/tests/test_picker_no_crash.html new file mode 100644 index 0000000000..dbb75627b5 --- /dev/null +++ b/widget/tests/test_picker_no_crash.html @@ -0,0 +1,30 @@ + +Test for crashes when the parent window of a file picker is closed via script + + + + diff --git a/widget/tests/test_platform_colors.xhtml b/widget/tests/test_platform_colors.xhtml new file mode 100644 index 0000000000..c82e1f486e --- /dev/null +++ b/widget/tests/test_platform_colors.xhtml @@ -0,0 +1,106 @@ + + + + + + + + diff --git a/widget/tests/test_position_on_resize.xhtml b/widget/tests/test_position_on_resize.xhtml new file mode 100644 index 0000000000..a7c5551018 --- /dev/null +++ b/widget/tests/test_position_on_resize.xhtml @@ -0,0 +1,90 @@ + + + + + + + + + +

+

+ +
+
+ + +
diff --git a/widget/tests/test_secure_input.html b/widget/tests/test_secure_input.html new file mode 100644 index 0000000000..846465b4c2 --- /dev/null +++ b/widget/tests/test_secure_input.html @@ -0,0 +1,141 @@ + + + + Test for secure input mode + + + + + + + +
+
+ +

+
+
+
+
+
+
+

+
+ + + + diff --git a/widget/tests/test_sizemode_events.xhtml b/widget/tests/test_sizemode_events.xhtml new file mode 100644 index 0000000000..bd1e3a38d1 --- /dev/null +++ b/widget/tests/test_sizemode_events.xhtml @@ -0,0 +1,148 @@ + + + + + + + + diff --git a/widget/tests/test_standalone_native_menu.xhtml b/widget/tests/test_standalone_native_menu.xhtml new file mode 100644 index 0000000000..96e41036c3 --- /dev/null +++ b/widget/tests/test_standalone_native_menu.xhtml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/widget/tests/test_system_font_changes.xhtml b/widget/tests/test_system_font_changes.xhtml new file mode 100644 index 0000000000..036c775463 --- /dev/null +++ b/widget/tests/test_system_font_changes.xhtml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/widget/tests/test_system_status_bar.xhtml b/widget/tests/test_system_status_bar.xhtml new file mode 100644 index 0000000000..f2348fa6f5 --- /dev/null +++ b/widget/tests/test_system_status_bar.xhtml @@ -0,0 +1,53 @@ + + + + + + + diff --git a/widget/tests/test_taskbar_progress.xhtml b/widget/tests/test_taskbar_progress.xhtml new file mode 100644 index 0000000000..f2494a27bb --- /dev/null +++ b/widget/tests/test_taskbar_progress.xhtml @@ -0,0 +1,117 @@ + + + + + + + + +

+ +

+  
+
+
diff --git a/widget/tests/test_textScaleFactor_system_font.html b/widget/tests/test_textScaleFactor_system_font.html new file mode 100644 index 0000000000..bd2b55fbb6 --- /dev/null +++ b/widget/tests/test_textScaleFactor_system_font.html @@ -0,0 +1,139 @@ + + + + + Test that system font sizing is independent from ui.textScaleFactor + + + + + + +

Default text.

+ + + diff --git a/widget/tests/test_transferable_overflow.xhtml b/widget/tests/test_transferable_overflow.xhtml new file mode 100644 index 0000000000..5c6ff443c4 --- /dev/null +++ b/widget/tests/test_transferable_overflow.xhtml @@ -0,0 +1,151 @@ + + + + + nsTransferable with large string + + + + + This test checks whether a big string can be copied to the clipboard, and then retrieved in the same form. + On non-Windows, the test also checks whether the data of the transferable is really stored in a file. + + diff --git a/widget/tests/test_wheeltransaction.xhtml b/widget/tests/test_wheeltransaction.xhtml new file mode 100644 index 0000000000..23e855c39b --- /dev/null +++ b/widget/tests/test_wheeltransaction.xhtml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/widget/tests/unit/test_macsharingservice.js b/widget/tests/unit/test_macsharingservice.js new file mode 100644 index 0000000000..f6b0a8e3fc --- /dev/null +++ b/widget/tests/unit/test_macsharingservice.js @@ -0,0 +1,61 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Basic tests to verify that MacSharingService returns expected data + +function test_getSharingProviders() { + let sharingService = Cc["@mozilla.org/widget/macsharingservice;1"].getService( + Ci.nsIMacSharingService + ); + + // Ensure these URL's are accepted without error by the getSharingProviders() + // method. This does not test if the URL's are interpreted correctly by + // the platform implementation and does not test that the URL will be + // successfully shared to the target application if the shareURL method is + // used. It does indicate the Mac API's used to get the sharing providers + // successfully created a URL object for the URL provided and returned at + // least one provider. + let urls = [ + "http://example.org", + "http://example.org/#", + "http://example.org/dkl??", + "http://example.org/dkl?a=b;c=d#thisisaref", + "http://example.org/dkl?a=b;c=d#thisisaref#double", + "http://example.org/#/", + "http://example.org/#/#", + "http://example.org/#/#/", + // This test fails due to the '|' in the path which needs additional + // encoding before conversion to NSURL. See bug 1740565. + // "http://example.org/foo/bar/x|page.html#this_is_a_fragment", + "http://example.org/page.html#this_is_a_fragment", + "http://example.org/page.html#this_is_a_fragment#and_another", + "http://example.org/foo/bar;#foo", + "http://example.org/a file with spaces.html", + "https://chat.mozilla.org/#/room/#macdev:mozilla.org", + "https://chat.mozilla.org/#/room/%23macdev:mozilla.org", + ]; + + urls.forEach(url => testGetSharingProvidersForUrl(sharingService, url)); +} + +function testGetSharingProvidersForUrl(sharingService, url) { + let providers = sharingService.getSharingProviders(url); + Assert.greater(providers.length, 1, "There are providers returned"); + providers.forEach(provider => { + Assert.ok("name" in provider, "Provider has name"); + Assert.ok("menuItemTitle" in provider, "Provider has menuItemTitle"); + Assert.ok("image" in provider, "Provider has image"); + + Assert.notEqual( + provider.title, + "Mail", + "Known filtered provider not returned" + ); + }); +} + +function run_test() { + test_getSharingProviders(); +} diff --git a/widget/tests/unit/test_macwebapputils.js b/widget/tests/unit/test_macwebapputils.js new file mode 100644 index 0000000000..8967f8a593 --- /dev/null +++ b/widget/tests/unit/test_macwebapputils.js @@ -0,0 +1,34 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Basic tests to verify that MacWebAppUtils works + +function test_find_app() { + var mwaUtils = Cc["@mozilla.org/widget/mac-web-app-utils;1"].createInstance( + Ci.nsIMacWebAppUtils + ); + let sig = "com.apple.TextEdit"; + + let path; + path = mwaUtils.pathForAppWithIdentifier(sig); + info("TextEdit path: " + path + "\n"); + Assert.notEqual(path, ""); +} + +function test_dont_find_fake_app() { + var mwaUtils = Cc["@mozilla.org/widget/mac-web-app-utils;1"].createInstance( + Ci.nsIMacWebAppUtils + ); + let sig = "calliope.penitentiary.dramamine"; + + let path; + path = mwaUtils.pathForAppWithIdentifier(sig); + Assert.equal(path, ""); +} + +function run_test() { + test_find_app(); + test_dont_find_fake_app(); +} diff --git a/widget/tests/unit/test_taskbar_jumplistitems.js b/widget/tests/unit/test_taskbar_jumplistitems.js new file mode 100644 index 0000000000..f839160bde --- /dev/null +++ b/widget/tests/unit/test_taskbar_jumplistitems.js @@ -0,0 +1,282 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This tests taskbar jump list functionality available on win7 and up. + +function test_basics() { + var item = Cc["@mozilla.org/windows-jumplistitem;1"].createInstance( + Ci.nsIJumpListItem + ); + + var sep = Cc["@mozilla.org/windows-jumplistseparator;1"].createInstance( + Ci.nsIJumpListSeparator + ); + + var shortcut = Cc["@mozilla.org/windows-jumplistshortcut;1"].createInstance( + Ci.nsIJumpListShortcut + ); + + var link = Cc["@mozilla.org/windows-jumplistlink;1"].createInstance( + Ci.nsIJumpListLink + ); + + Assert.ok(!item.equals(sep)); + Assert.ok(!item.equals(shortcut)); + Assert.ok(!item.equals(link)); + + Assert.ok(!sep.equals(item)); + Assert.ok(!sep.equals(shortcut)); + Assert.ok(!sep.equals(link)); + + Assert.ok(!shortcut.equals(item)); + Assert.ok(!shortcut.equals(sep)); + Assert.ok(!shortcut.equals(link)); + + Assert.ok(!link.equals(item)); + Assert.ok(!link.equals(sep)); + Assert.ok(!link.equals(shortcut)); + + Assert.ok(item.equals(item)); + Assert.ok(sep.equals(sep)); + Assert.ok(link.equals(link)); + Assert.ok(shortcut.equals(shortcut)); +} + +function test_separator() { + // separators: + + var item = Cc["@mozilla.org/windows-jumplistseparator;1"].createInstance( + Ci.nsIJumpListSeparator + ); + + Assert.ok(item.type == Ci.nsIJumpListItem.JUMPLIST_ITEM_SEPARATOR); +} + +function test_hashes() { + var link = Cc["@mozilla.org/windows-jumplistlink;1"].createInstance( + Ci.nsIJumpListLink + ); + var uri1 = Cc["@mozilla.org/network/simple-uri-mutator;1"] + .createInstance(Ci.nsIURIMutator) + .setSpec("http://www.123.com/") + .finalize(); + var uri2 = Cc["@mozilla.org/network/simple-uri-mutator;1"] + .createInstance(Ci.nsIURIMutator) + .setSpec("http://www.123.com/") + .finalize(); + + link.uri = uri1; + + Assert.ok(link.compareHash(uri2)); + uri2 = uri2.mutate().setSpec("http://www.456.com/").finalize(); + Assert.ok(!link.compareHash(uri2)); + uri2 = uri2.mutate().setSpec("http://www.123.com/").finalize(); + Assert.ok(link.compareHash(uri2)); + uri2 = uri2.mutate().setSpec("https://www.123.com/").finalize(); + Assert.ok(!link.compareHash(uri2)); + uri2 = uri2.mutate().setSpec("http://www.123.com/test/").finalize(); + Assert.ok(!link.compareHash(uri2)); + uri1 = uri1.mutate().setSpec("http://www.123.com/test/").finalize(); + link.uri = uri1; + uri2 = uri2.mutate().setSpec("http://www.123.com/test/").finalize(); + Assert.ok(link.compareHash(uri2)); + uri1 = uri1.mutate().setSpec("https://www.123.com/test/").finalize(); + link.uri = uri1; + uri2 = uri2.mutate().setSpec("https://www.123.com/test/").finalize(); + Assert.ok(link.compareHash(uri2)); + uri2 = uri2.mutate().setSpec("ftp://www.123.com/test/").finalize(); + Assert.ok(!link.compareHash(uri2)); + uri2 = uri2.mutate().setSpec("http://123.com/test/").finalize(); + Assert.ok(!link.compareHash(uri2)); + uri1 = uri1.mutate().setSpec("https://www.123.com/test/").finalize(); + link.uri = uri1; + uri2 = uri2.mutate().setSpec("https://www.123.com/Test/").finalize(); + Assert.ok(!link.compareHash(uri2)); + + uri1 = uri1.mutate().setSpec("http://www.123.com/").finalize(); + link.uri = uri1; + Assert.equal(link.uriHash, "QGLmWuwuTozr3tOfXSf5mg=="); + uri1 = uri1.mutate().setSpec("http://www.123.com/test/").finalize(); + link.uri = uri1; + Assert.equal(link.uriHash, "AG87Ls+GmaUYSUJFETRr3Q=="); + uri1 = uri1.mutate().setSpec("https://www.123.com/").finalize(); + link.uri = uri1; + Assert.equal(link.uriHash, "iSx6UH1a9enVPzUA9JZ42g=="); +} + +function test_links() { + // links: + var link1 = Cc["@mozilla.org/windows-jumplistlink;1"].createInstance( + Ci.nsIJumpListLink + ); + var link2 = Cc["@mozilla.org/windows-jumplistlink;1"].createInstance( + Ci.nsIJumpListLink + ); + + var uri1 = Cc["@mozilla.org/network/simple-uri-mutator;1"] + .createInstance(Ci.nsIURIMutator) + .setSpec("http://www.test.com/") + .finalize(); + var uri2 = Cc["@mozilla.org/network/simple-uri-mutator;1"] + .createInstance(Ci.nsIURIMutator) + .setSpec("http://www.test.com/") + .finalize(); + + link1.uri = uri1; + link1.uriTitle = "Test"; + link2.uri = uri2; + link2.uriTitle = "Test"; + + Assert.ok(link1.equals(link2)); + + link2.uriTitle = "Testing"; + + Assert.ok(!link1.equals(link2)); + + link2.uriTitle = "Test"; + uri2 = uri2.mutate().setSpec("http://www.testing.com/").finalize(); + link2.uri = uri2; + + Assert.ok(!link1.equals(link2)); +} + +function test_shortcuts() { + // shortcuts: + var sc = Cc["@mozilla.org/windows-jumplistshortcut;1"].createInstance( + Ci.nsIJumpListShortcut + ); + + var handlerApp = Cc[ + "@mozilla.org/uriloader/local-handler-app;1" + ].createInstance(Ci.nsILocalHandlerApp); + + handlerApp.name = "TestApp"; + handlerApp.detailedDescription = "TestApp detailed description."; + handlerApp.appendParameter("-test"); + + sc.iconIndex = 1; + Assert.equal(sc.iconIndex, 1); + + var faviconPageUri = Cc["@mozilla.org/network/simple-uri-mutator;1"] + .createInstance(Ci.nsIURIMutator) + .setSpec("http://www.123.com/") + .finalize(); + sc.faviconPageUri = faviconPageUri; + Assert.equal(sc.faviconPageUri, faviconPageUri); + + var notepad = Services.dirsvc.get("WinD", Ci.nsIFile); + notepad.append("notepad.exe"); + if (notepad.exists()) { + handlerApp.executable = notepad; + sc.app = handlerApp; + Assert.equal(sc.app.detailedDescription, "TestApp detailed description."); + Assert.equal(sc.app.name, "TestApp"); + Assert.ok(sc.app.parameterExists("-test")); + Assert.ok(!sc.app.parameterExists("-notset")); + } +} + +async function test_jumplist() { + // Jump lists can't register links unless the application is the default + // protocol handler for the protocol of the link, so we skip off testing + // those in these tests. We'll init the jump list for the xpc shell harness, + // add a task item, and commit it. + + // not compiled in + if (Ci.nsIWinTaskbar == null) { + return; + } + + var taskbar = Cc["@mozilla.org/windows-taskbar;1"].getService( + Ci.nsIWinTaskbar + ); + + // Since we're only testing the general functionality of the JumpListBuilder + // et. al, we can just test the non-private browsing version. + // (The only difference between the two at this level is the App User Model ID.) + var builder = taskbar.createJumpListBuilder(false); + + Assert.notEqual(builder, null); + + // Win7 and up only + try { + var ver = parseFloat(Services.sysinfo.getProperty("version")); + if (ver < 6.1) { + Assert.ok(!builder.available); + return; + } + } catch (ex) {} + + Assert.ok(taskbar.available); + + builder.deleteActiveList(); + + var items = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); + + var sc = Cc["@mozilla.org/windows-jumplistshortcut;1"].createInstance( + Ci.nsIJumpListShortcut + ); + + var handlerApp = Cc[ + "@mozilla.org/uriloader/local-handler-app;1" + ].createInstance(Ci.nsILocalHandlerApp); + + handlerApp.name = "Notepad"; + handlerApp.detailedDescription = "Testing detailed description."; + + var notepad = Services.dirsvc.get("WinD", Ci.nsIFile); + notepad.append("notepad.exe"); + if (notepad.exists()) { + // To ensure "profile-before-change" will fire before + // "xpcom-shutdown-threads" + do_get_profile(); + + handlerApp.executable = notepad; + sc.app = handlerApp; + items.appendElement(sc); + + var removed = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); + Assert.ok(builder.initListBuild(removed)); + Assert.ok(builder.addListToBuild(builder.JUMPLIST_CATEGORY_TASKS, items)); + Assert.ok(builder.addListToBuild(builder.JUMPLIST_CATEGORY_RECENT)); + Assert.ok(builder.addListToBuild(builder.JUMPLIST_CATEGORY_FREQUENT)); + let rv = new Promise(resolve => { + builder.commitListBuild(resolve); + }); + Assert.ok(await rv); + + builder.deleteActiveList(); + + Assert.ok(builder.initListBuild(removed)); + Assert.ok( + builder.addListToBuild( + builder.JUMPLIST_CATEGORY_CUSTOMLIST, + items, + "Custom List" + ) + ); + rv = new Promise(resolve => { + builder.commitListBuild(resolve); + }); + Assert.ok(await rv); + + builder.deleteActiveList(); + } +} + +function run_test() { + if (mozinfo.os != "win") { + return; + } + test_basics(); + test_separator(); + test_hashes(); + test_links(); + test_shortcuts(); + + run_next_test(); +} + +add_task(test_jumplist); diff --git a/widget/tests/unit/xpcshell.ini b/widget/tests/unit/xpcshell.ini new file mode 100644 index 0000000000..e6fafa44f0 --- /dev/null +++ b/widget/tests/unit/xpcshell.ini @@ -0,0 +1,11 @@ +[DEFAULT] +head = + +[test_taskbar_jumplistitems.js] +skip-if = + os == "win" && os_version == "10.0" # Bug 1457329 + os == "win" && os_version == "6.1" # Skip on Azure - frequent failure +[test_macsharingservice.js] +skip-if = os != "mac" +[test_macwebapputils.js] +skip-if = os != "mac" diff --git a/widget/tests/window_bug429954.xhtml b/widget/tests/window_bug429954.xhtml new file mode 100644 index 0000000000..ca26d52621 --- /dev/null +++ b/widget/tests/window_bug429954.xhtml @@ -0,0 +1,44 @@ + + + + + + + diff --git a/widget/tests/window_bug478536.xhtml b/widget/tests/window_bug478536.xhtml new file mode 100644 index 0000000000..7318eb0bff --- /dev/null +++ b/widget/tests/window_bug478536.xhtml @@ -0,0 +1,211 @@ + + + + + + + diff --git a/widget/tests/window_bug522217.xhtml b/widget/tests/window_bug522217.xhtml new file mode 100644 index 0000000000..8d03879521 --- /dev/null +++ b/widget/tests/window_bug522217.xhtml @@ -0,0 +1,80 @@ + + + + + + + diff --git a/widget/tests/window_bug538242.xhtml b/widget/tests/window_bug538242.xhtml new file mode 100644 index 0000000000..fb878b1383 --- /dev/null +++ b/widget/tests/window_bug538242.xhtml @@ -0,0 +1,3 @@ + + diff --git a/widget/tests/window_bug593307_centerscreen.xhtml b/widget/tests/window_bug593307_centerscreen.xhtml new file mode 100644 index 0000000000..816e314262 --- /dev/null +++ b/widget/tests/window_bug593307_centerscreen.xhtml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/widget/tests/window_bug593307_offscreen.xhtml b/widget/tests/window_bug593307_offscreen.xhtml new file mode 100644 index 0000000000..422c406812 --- /dev/null +++ b/widget/tests/window_bug593307_offscreen.xhtml @@ -0,0 +1,33 @@ + + + + + + + diff --git a/widget/tests/window_composition_text_querycontent.xhtml b/widget/tests/window_composition_text_querycontent.xhtml new file mode 100644 index 0000000000..7cdbf28568 --- /dev/null +++ b/widget/tests/window_composition_text_querycontent.xhtml @@ -0,0 +1,10977 @@ + + + + + + + + diff --git a/widget/tests/window_imestate_iframes.html b/widget/tests/window_imestate_iframes.html new file mode 100644 index 0000000000..c8b182977f --- /dev/null +++ b/widget/tests/window_imestate_iframes.html @@ -0,0 +1,358 @@ + + + Test for IME state controling and focus moving for iframes + + + + + +

+ +
+
+ + +
+
+
+
+ +
+

+ + + + diff --git a/widget/tests/window_mouse_scroll_win.html b/widget/tests/window_mouse_scroll_win.html new file mode 100644 index 0000000000..69eca9ebb0 --- /dev/null +++ b/widget/tests/window_mouse_scroll_win.html @@ -0,0 +1,1516 @@ + + + Test for mouse scroll handling on Windows + + + + + +
+

1st <p>.

+

2nd <p>.

+
+ + + + diff --git a/widget/tests/window_mouse_scroll_win_2.html b/widget/tests/window_mouse_scroll_win_2.html new file mode 100644 index 0000000000..c8d3762405 --- /dev/null +++ b/widget/tests/window_mouse_scroll_win_2.html @@ -0,0 +1,6 @@ + + + + Helper file for window_mouse_scroll_win.html + + diff --git a/widget/tests/window_picker_no_crash_child.html b/widget/tests/window_picker_no_crash_child.html new file mode 100644 index 0000000000..c980f979be --- /dev/null +++ b/widget/tests/window_picker_no_crash_child.html @@ -0,0 +1,6 @@ + +Picker window +
+ + +
diff --git a/widget/tests/window_state_windows.xhtml b/widget/tests/window_state_windows.xhtml new file mode 100644 index 0000000000..60989db144 --- /dev/null +++ b/widget/tests/window_state_windows.xhtml @@ -0,0 +1,80 @@ + + + + + + + + + + + +

+ +

+  
+
diff --git a/widget/tests/window_wheeltransaction.xhtml b/widget/tests/window_wheeltransaction.xhtml new file mode 100644 index 0000000000..f3c081b105 --- /dev/null +++ b/widget/tests/window_wheeltransaction.xhtml @@ -0,0 +1,1569 @@ + + + + + + + -- cgit v1.2.3