/* * Copyright (C) 2012 Igalia S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2,1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "config.h" #include "WebViewTest.h" #include #include class ContextMenuTest: public WebViewTest { public: enum ContextMenuItemStateFlags { Visible = 1 << 0, Enabled = 1 << 1, Checked = 1 << 2 }; void checkContextMenuEvent(GdkEvent* event) { g_assert(event); g_assert_cmpint(event->type, ==, GDK_BUTTON_PRESS); g_assert_cmpint(event->button.button, ==, 3); g_assert_cmpint(event->button.x, ==, m_menuPositionX); g_assert_cmpint(event->button.y, ==, m_menuPositionY); } static gboolean contextMenuCallback(WebKitWebView* webView, WebKitContextMenu* contextMenu, GdkEvent* event, WebKitHitTestResult* hitTestResult, ContextMenuTest* test) { g_assert(WEBKIT_IS_CONTEXT_MENU(contextMenu)); test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(contextMenu)); test->checkContextMenuEvent(event); g_assert(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult)); test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(hitTestResult)); return test->contextMenu(contextMenu, event, hitTestResult); } static void contextMenuDismissedCallback(WebKitWebView*, ContextMenuTest* test) { test->contextMenuDismissed(); } ContextMenuTest() : m_menuPositionX(0) , m_menuPositionY(0) { g_signal_connect(m_webView, "context-menu", G_CALLBACK(contextMenuCallback), this); g_signal_connect(m_webView, "context-menu-dismissed", G_CALLBACK(contextMenuDismissedCallback), this); } ~ContextMenuTest() { g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); } virtual bool contextMenu(WebKitContextMenu*, GdkEvent*, WebKitHitTestResult*) = 0; virtual void contextMenuDismissed() { quitMainLoop(); } GtkMenu* getPopupMenu() { GUniquePtr toplevels(gtk_window_list_toplevels()); for (GList* iter = toplevels.get(); iter; iter = g_list_next(iter)) { if (!GTK_IS_WINDOW(iter->data)) continue; GtkWidget* child = gtk_bin_get_child(GTK_BIN(iter->data)); if (!GTK_IS_MENU(child)) continue; if (gtk_menu_get_attach_widget(GTK_MENU(child)) == GTK_WIDGET(m_webView)) return GTK_MENU(child); } g_assert_not_reached(); return 0; } void checkActionState(GtkAction* action, unsigned state) { if (state & Visible) g_assert(gtk_action_get_visible(action)); else g_assert(!gtk_action_get_visible(action)); if (state & Enabled) g_assert(gtk_action_get_sensitive(action)); else g_assert(!gtk_action_get_sensitive(action)); if (GTK_IS_TOGGLE_ACTION(action)) { if (state & Checked) g_assert(gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))); else g_assert(!gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))); } } GList* checkCurrentItemIsStockActionAndGetNext(GList* items, WebKitContextMenuAction stockAction, unsigned state) { g_assert(items); g_assert(WEBKIT_IS_CONTEXT_MENU_ITEM(items->data)); WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(items->data); assertObjectIsDeletedWhenTestFinishes(G_OBJECT(item)); GtkAction* action = webkit_context_menu_item_get_action(item); g_assert(GTK_IS_ACTION(action)); g_assert_cmpint(webkit_context_menu_item_get_stock_action(item), ==, stockAction); checkActionState(action, state); return g_list_next(items); } GList* checkCurrentItemIsCustomActionAndGetNext(GList* items, const char* label, unsigned state) { g_assert(items); g_assert(WEBKIT_IS_CONTEXT_MENU_ITEM(items->data)); WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(items->data); assertObjectIsDeletedWhenTestFinishes(G_OBJECT(item)); GtkAction* action = webkit_context_menu_item_get_action(item); g_assert(GTK_IS_ACTION(action)); g_assert_cmpint(webkit_context_menu_item_get_stock_action(item), ==, WEBKIT_CONTEXT_MENU_ACTION_CUSTOM); g_assert_cmpstr(gtk_action_get_label(action), ==, label); checkActionState(action, state); return g_list_next(items); } GList* checkCurrentItemIsSubMenuAndGetNext(GList* items, const char* label, unsigned state, GList** subMenuIter) { g_assert(items); g_assert(WEBKIT_IS_CONTEXT_MENU_ITEM(items->data)); WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(items->data); assertObjectIsDeletedWhenTestFinishes(G_OBJECT(item)); GtkAction* action = webkit_context_menu_item_get_action(item); g_assert(GTK_IS_ACTION(action)); g_assert_cmpstr(gtk_action_get_label(action), ==, label); checkActionState(action, state); WebKitContextMenu* subMenu = webkit_context_menu_item_get_submenu(item); g_assert(WEBKIT_IS_CONTEXT_MENU(subMenu)); if (subMenuIter) *subMenuIter = webkit_context_menu_get_items(subMenu); return g_list_next(items); } GList* checkCurrentItemIsSeparatorAndGetNext(GList* items) { g_assert(items); g_assert(WEBKIT_IS_CONTEXT_MENU_ITEM(items->data)); WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(items->data); g_assert(webkit_context_menu_item_is_separator(item)); return g_list_next(items); } static gboolean doRightClickIdleCallback(ContextMenuTest* test) { test->clickMouseButton(test->m_menuPositionX, test->m_menuPositionY, 3); return FALSE; } void showContextMenuAtPositionAndWaitUntilFinished(int x, int y) { m_menuPositionX = x; m_menuPositionY = y; g_idle_add(reinterpret_cast(doRightClickIdleCallback), this); g_main_loop_run(m_mainLoop); } void showContextMenuAndWaitUntilFinished() { showContextMenuAtPositionAndWaitUntilFinished(0, 0); } static gboolean simulateEscKeyIdleCallback(ContextMenuTest* test) { test->keyStroke(GDK_KEY_Escape); return FALSE; } void dismissContextMenuAndWaitUntilFinished() { g_idle_add(reinterpret_cast(simulateEscKeyIdleCallback), this); g_main_loop_run(m_mainLoop); } double m_menuPositionX; double m_menuPositionY; }; class ContextMenuDefaultTest: public ContextMenuTest { public: MAKE_GLIB_TEST_FIXTURE(ContextMenuDefaultTest); enum DefaultMenuType { Navigation, Link, Image, LinkImage, Video, Audio, Editable, Selection }; ContextMenuDefaultTest() : m_expectedMenuType(Navigation) { } bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent* event, WebKitHitTestResult* hitTestResult) { GList* iter = webkit_context_menu_get_items(contextMenu); switch (m_expectedMenuType) { case Navigation: g_assert(!webkit_hit_test_result_context_is_link(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_image(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_media(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult)); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_BACK, Visible); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD, Visible); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_STOP, Visible); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_RELOAD, Visible | Enabled); break; case Link: g_assert(webkit_hit_test_result_context_is_link(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_image(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_media(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult)); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD, Visible | Enabled); break; case Image: g_assert(!webkit_hit_test_result_context_is_link(hitTestResult)); g_assert(webkit_hit_test_result_context_is_image(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_media(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult)); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_URL_TO_CLIPBOARD, Visible | Enabled); break; case LinkImage: g_assert(webkit_hit_test_result_context_is_link(hitTestResult)); g_assert(webkit_hit_test_result_context_is_image(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_media(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult)); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD, Visible | Enabled); iter = checkCurrentItemIsSeparatorAndGetNext(iter); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_URL_TO_CLIPBOARD, Visible | Enabled); break; case Video: g_assert(!webkit_hit_test_result_context_is_link(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_image(hitTestResult)); g_assert(webkit_hit_test_result_context_is_media(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult)); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PLAY, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE, Visible); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS, Visible | Enabled | Checked); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_LOOP, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_ENTER_VIDEO_FULLSCREEN, Visible | Enabled); iter = checkCurrentItemIsSeparatorAndGetNext(iter); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_VIDEO_LINK_TO_CLIPBOARD, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_VIDEO_IN_NEW_WINDOW, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_VIDEO_TO_DISK, Visible | Enabled); break; case Audio: g_assert(!webkit_hit_test_result_context_is_link(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_image(hitTestResult)); g_assert(webkit_hit_test_result_context_is_media(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult)); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PLAY, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE, Visible); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS, Visible | Enabled | Checked); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_LOOP, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_ENTER_VIDEO_FULLSCREEN, Visible); iter = checkCurrentItemIsSeparatorAndGetNext(iter); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_AUDIO_LINK_TO_CLIPBOARD, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_AUDIO_IN_NEW_WINDOW, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_AUDIO_TO_DISK, Visible | Enabled); break; case Editable: g_assert(!webkit_hit_test_result_context_is_link(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_image(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_media(hitTestResult)); g_assert(webkit_hit_test_result_context_is_editable(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_selection(hitTestResult)); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_CUT, Visible); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY, Visible); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_PASTE, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DELETE, Visible); iter = checkCurrentItemIsSeparatorAndGetNext(iter); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL, Visible | Enabled); iter = checkCurrentItemIsSeparatorAndGetNext(iter); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_UNICODE, Visible | Enabled); break; case Selection: g_assert(!webkit_hit_test_result_context_is_link(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_image(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_media(hitTestResult)); g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult)); g_assert(webkit_hit_test_result_context_is_selection(hitTestResult)); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY, Visible | Enabled); break; default: g_assert_not_reached(); } if (webkit_settings_get_enable_developer_extras(webkit_web_view_get_settings(m_webView))) { iter = checkCurrentItemIsSeparatorAndGetNext(iter); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT, Visible | Enabled); } g_assert(!iter); quitMainLoop(); return true; } DefaultMenuType m_expectedMenuType; }; static void testContextMenuDefaultMenu(ContextMenuDefaultTest* test, gconstpointer) { test->showInWindowAndWaitUntilMapped(); const char* linksHTML = "" " " "" " WebKitGTK+ Website" " " " " " " " " " " "

Lorem ipsum.

" ""; test->loadHtml(linksHTML, "file:///"); test->waitUntilLoadFinished(); // Context menu for selection. // This test should always be the first because any other click removes the selection. test->m_expectedMenuType = ContextMenuDefaultTest::Selection; test->showContextMenuAtPositionAndWaitUntilFinished(2, 115); // Context menu for document. test->m_expectedMenuType = ContextMenuDefaultTest::Navigation; test->showContextMenuAtPositionAndWaitUntilFinished(0, 0); // Context menu for link. test->m_expectedMenuType = ContextMenuDefaultTest::Link; test->showContextMenuAtPositionAndWaitUntilFinished(1, 1); // Context menu for image. test->m_expectedMenuType = ContextMenuDefaultTest::Image; test->showContextMenuAtPositionAndWaitUntilFinished(1, 10); // Enable developer extras now, so that inspector element // will be shown in the default context menu. webkit_settings_set_enable_developer_extras(webkit_web_view_get_settings(test->m_webView), TRUE); // Context menu for image link. test->m_expectedMenuType = ContextMenuDefaultTest::LinkImage; test->showContextMenuAtPositionAndWaitUntilFinished(1, 20); // Context menu for video. test->m_expectedMenuType = ContextMenuDefaultTest::Video; test->showContextMenuAtPositionAndWaitUntilFinished(1, 50); // Context menu for audio. test->m_expectedMenuType = ContextMenuDefaultTest::Audio; test->showContextMenuAtPositionAndWaitUntilFinished(1, 60); // Context menu for editable. test->m_expectedMenuType = ContextMenuDefaultTest::Editable; test->showContextMenuAtPositionAndWaitUntilFinished(5, 35); } class ContextMenuCustomTest: public ContextMenuTest { public: MAKE_GLIB_TEST_FIXTURE(ContextMenuCustomTest); ContextMenuCustomTest() : m_itemToActivateLabel(0) , m_activated(false) , m_toggled(false) { } bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent*, WebKitHitTestResult* hitTestResult) { // Append our custom item to the default menu. webkit_context_menu_append(contextMenu, webkit_context_menu_item_new(m_action.get())); quitMainLoop(); return false; } GtkMenuItem* getMenuItem(GtkMenu* menu, const gchar* itemLabel) { GUniquePtr items(gtk_container_get_children(GTK_CONTAINER(menu))); for (GList* iter = items.get(); iter; iter = g_list_next(iter)) { GtkMenuItem* child = GTK_MENU_ITEM(iter->data); if (g_str_equal(itemLabel, gtk_menu_item_get_label(child))) return child; } g_assert_not_reached(); return 0; } void activateMenuItem() { g_assert(m_itemToActivateLabel); GtkMenu* menu = getPopupMenu(); GtkMenuItem* item = getMenuItem(menu, m_itemToActivateLabel); gtk_menu_shell_activate_item(GTK_MENU_SHELL(menu), GTK_WIDGET(item), TRUE); m_itemToActivateLabel = 0; } static gboolean activateMenuItemIdleCallback(gpointer userData) { ContextMenuCustomTest* test = static_cast(userData); test->activateMenuItem(); return FALSE; } void activateCustomMenuItemAndWaitUntilActivated(const char* actionLabel) { m_activated = m_toggled = false; m_itemToActivateLabel = actionLabel; g_idle_add(activateMenuItemIdleCallback, this); g_main_loop_run(m_mainLoop); } void toggleCustomMenuItemAndWaitUntilToggled(const char* actionLabel) { activateCustomMenuItemAndWaitUntilActivated(actionLabel); } static void actionActivatedCallback(GtkAction*, ContextMenuCustomTest* test) { test->m_activated = true; } static void actionToggledCallback(GtkAction*, ContextMenuCustomTest* test) { test->m_toggled = true; } void setAction(GtkAction* action) { m_action = action; if (GTK_IS_TOGGLE_ACTION(action)) g_signal_connect(action, "toggled", G_CALLBACK(actionToggledCallback), this); else g_signal_connect(action, "activate", G_CALLBACK(actionActivatedCallback), this); } GRefPtr m_action; const char* m_itemToActivateLabel; bool m_activated; bool m_toggled; }; static void testContextMenuPopulateMenu(ContextMenuCustomTest* test, gconstpointer) { test->showInWindowAndWaitUntilMapped(); test->loadHtml("WebKitGTK+ Context menu tests", "file:///"); test->waitUntilLoadFinished(); // Create a custom menu item. GRefPtr action = adoptGRef(gtk_action_new("WebKitGTK+CustomAction", "Custom _Action", 0, 0)); test->setAction(action.get()); test->showContextMenuAndWaitUntilFinished(); test->activateCustomMenuItemAndWaitUntilActivated(gtk_action_get_label(action.get())); g_assert(test->m_activated); g_assert(!test->m_toggled); // Create a custom toggle menu item. GRefPtr toggleAction = adoptGRef(GTK_ACTION(gtk_toggle_action_new("WebKitGTK+CustomToggleAction", "Custom _Toggle Action", 0, 0))); test->setAction(toggleAction.get()); test->showContextMenuAndWaitUntilFinished(); test->toggleCustomMenuItemAndWaitUntilToggled(gtk_action_get_label(toggleAction.get())); g_assert(!test->m_activated); g_assert(test->m_toggled); } class ContextMenuCustomFullTest: public ContextMenuTest { public: MAKE_GLIB_TEST_FIXTURE(ContextMenuCustomFullTest); bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent*, WebKitHitTestResult*) { // Clear proposed menu and build our own. webkit_context_menu_remove_all(contextMenu); g_assert_cmpint(webkit_context_menu_get_n_items(contextMenu), ==, 0); // Add actions from stock. webkit_context_menu_prepend(contextMenu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_GO_BACK)); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD)); webkit_context_menu_insert(contextMenu, webkit_context_menu_item_new_separator(), 2); // Add custom actions. GRefPtr action = adoptGRef(gtk_action_new("WebKitGTK+CustomAction", "Custom _Action", 0, 0)); gtk_action_set_sensitive(action.get(), FALSE); webkit_context_menu_insert(contextMenu, webkit_context_menu_item_new(action.get()), -1); GRefPtr toggleAction = adoptGRef(GTK_ACTION(gtk_toggle_action_new("WebKitGTK+CustomToggleAction", "Custom _Toggle Action", 0, 0))); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(toggleAction.get()), TRUE); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new(toggleAction.get())); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); // Add a submenu. GRefPtr subMenu = adoptGRef(webkit_context_menu_new()); assertObjectIsDeletedWhenTestFinishes(G_OBJECT(subMenu.get())); webkit_context_menu_insert(subMenu.get(), webkit_context_menu_item_new_from_stock_action_with_label(WEBKIT_CONTEXT_MENU_ACTION_STOP, "Stop Load"), 0); webkit_context_menu_insert(subMenu.get(), webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_RELOAD), -1); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_with_submenu("Load options", subMenu.get())); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); // Move Load submenu before custom actions. webkit_context_menu_move_item(contextMenu, webkit_context_menu_last(contextMenu), 3); webkit_context_menu_move_item(contextMenu, webkit_context_menu_last(contextMenu), 3); // If last item is a separator, remove it. if (webkit_context_menu_item_is_separator(webkit_context_menu_last(contextMenu))) webkit_context_menu_remove(contextMenu, webkit_context_menu_last(contextMenu)); // Check the menu. GList* iter = webkit_context_menu_get_items(contextMenu); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_BACK, Visible | Enabled); iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD, Visible | Enabled); iter = checkCurrentItemIsSeparatorAndGetNext(iter); GList* subMenuIter = 0; iter = checkCurrentItemIsSubMenuAndGetNext(iter, "Load options", Visible | Enabled, &subMenuIter); subMenuIter = checkCurrentItemIsStockActionAndGetNext(subMenuIter, WEBKIT_CONTEXT_MENU_ACTION_STOP, Visible | Enabled); subMenuIter = checkCurrentItemIsStockActionAndGetNext(subMenuIter, WEBKIT_CONTEXT_MENU_ACTION_RELOAD, Visible | Enabled); iter = checkCurrentItemIsSeparatorAndGetNext(iter); iter = checkCurrentItemIsCustomActionAndGetNext(iter, "Custom _Action", Visible); iter = checkCurrentItemIsCustomActionAndGetNext(iter, "Custom _Toggle Action", Visible | Enabled | Checked); g_assert(!iter); quitMainLoop(); return true; } }; static void testContextMenuCustomMenu(ContextMenuCustomFullTest* test, gconstpointer) { test->showInWindowAndWaitUntilMapped(); test->loadHtml("WebKitGTK+ Context menu tests", "file:///"); test->waitUntilLoadFinished(); test->showContextMenuAndWaitUntilFinished(); } class ContextMenuDisabledTest: public ContextMenuTest { public: MAKE_GLIB_TEST_FIXTURE(ContextMenuDisabledTest); enum DisableMode { IgnoreClicks, IgnoreDefaultMenu }; static gboolean buttonPressEventCallback(GtkWidget*, GdkEvent* event, ContextMenuDisabledTest* test) { if (event->button.button != 3) return FALSE; return test->rightButtonPressed(); } ContextMenuDisabledTest() : m_disableMode(IgnoreClicks) { g_signal_connect(m_webView, "button-press-event", G_CALLBACK(buttonPressEventCallback), this); } bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent*, WebKitHitTestResult*) { if (m_disableMode == IgnoreClicks) g_assert_not_reached(); else quitMainLoop(); return true; } bool rightButtonPressed() { if (m_disableMode == IgnoreClicks) { quitMainLoopAfterProcessingPendingEvents(); return true; } return false; } DisableMode m_disableMode; }; static void testContextMenuDisableMenu(ContextMenuDisabledTest* test, gconstpointer) { test->showInWindowAndWaitUntilMapped(); test->loadHtml("WebKitGTK+ Context menu tests", "file:///"); test->waitUntilLoadFinished(); test->m_disableMode = ContextMenuDisabledTest::IgnoreDefaultMenu; test->showContextMenuAndWaitUntilFinished(); test->m_disableMode = ContextMenuDisabledTest::IgnoreClicks; test->showContextMenuAndWaitUntilFinished(); } class ContextMenuSubmenuTest: public ContextMenuTest { public: MAKE_GLIB_TEST_FIXTURE(ContextMenuSubmenuTest); bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent*, WebKitHitTestResult*) { size_t menuSize = webkit_context_menu_get_n_items(contextMenu); GRefPtr subMenu = adoptGRef(webkit_context_menu_new()); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_with_submenu("SubMenuItem", subMenu.get())); g_assert_cmpuint(webkit_context_menu_get_n_items(contextMenu), ==, menuSize + 1); GRefPtr subMenu2 = adoptGRef(webkit_context_menu_new()); GRefPtr item = webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK); // Add submenu to newly created item. g_assert(!webkit_context_menu_item_get_submenu(item.get())); webkit_context_menu_item_set_submenu(item.get(), subMenu2.get()); g_assert(webkit_context_menu_item_get_submenu(item.get()) == subMenu2.get()); // Replace the submenu. webkit_context_menu_item_set_submenu(item.get(), 0); g_assert(!webkit_context_menu_item_get_submenu(item.get())); // Try to add a submenu already added to another item. removeLogFatalFlag(G_LOG_LEVEL_WARNING); webkit_context_menu_item_set_submenu(item.get(), subMenu.get()); addLogFatalFlag(G_LOG_LEVEL_WARNING); g_assert(!webkit_context_menu_item_get_submenu(item.get())); // A removed submenu shouldn't have a parent. webkit_context_menu_item_set_submenu(item.get(), subMenu2.get()); g_assert(webkit_context_menu_item_get_submenu(item.get()) == subMenu2.get()); quitMainLoop(); return true; } }; static void testContextMenuSubMenu(ContextMenuSubmenuTest* test, gconstpointer) { test->showInWindowAndWaitUntilMapped(); test->loadHtml("WebKitGTK+ Context menu tests", "file:///"); test->waitUntilLoadFinished(); test->showContextMenuAndWaitUntilFinished(); } class ContextMenuDismissedTest: public ContextMenuTest { public: MAKE_GLIB_TEST_FIXTURE(ContextMenuDismissedTest); ContextMenuDismissedTest() : m_dismissed(false) { } bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent*, WebKitHitTestResult*) { quitMainLoop(); // Show the default context menu. return false; } void contextMenuDismissed() { m_dismissed = true; ContextMenuTest::contextMenuDismissed(); } void showContextMenuAndWaitUntilDismissed() { showContextMenuAndWaitUntilFinished(); dismissContextMenuAndWaitUntilFinished(); } bool m_dismissed; }; static void testContextMenuDismissed(ContextMenuDismissedTest* test, gconstpointer) { test->showInWindowAndWaitUntilMapped(); test->loadHtml("WebKitGTK+ Context menu tests", "file:///"); test->waitUntilLoadFinished(); test->showContextMenuAndWaitUntilDismissed(); g_assert(test->m_dismissed); } class ContextMenuSmartSeparatorsTest: public ContextMenuTest { public: MAKE_GLIB_TEST_FIXTURE(ContextMenuSmartSeparatorsTest); bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent*, WebKitHitTestResult*) { webkit_context_menu_remove_all(contextMenu); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_GO_BACK)); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD)); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_COPY)); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT)); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); quitMainLoop(); return false; } GtkMenu* showContextMenuAndGetGtkMenu() { showContextMenuAndWaitUntilFinished(); return getPopupMenu(); } }; static void testContextMenuSmartSeparators(ContextMenuSmartSeparatorsTest* test, gconstpointer) { test->showInWindowAndWaitUntilMapped(); test->loadHtml("WebKitGTK+ Context menu tests", "file:///"); test->waitUntilLoadFinished(); GtkMenu* menu = test->showContextMenuAndGetGtkMenu(); g_assert(menu); // Leading and trailing separators are not added to the context menu. GUniquePtr menuItems(gtk_container_get_children(GTK_CONTAINER(menu))); g_assert_cmpuint(g_list_length(menuItems.get()), ==, 6); GtkWidget* item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 0)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 1)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 2)); g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 3)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 4)); g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 5)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); // Hiding a menu item between two separators hides the following separator. GtkAction* action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(g_list_nth_data(menuItems.get(), 3))); gtk_action_set_visible(action, FALSE); menuItems.reset(gtk_container_get_children(GTK_CONTAINER(menu))); g_assert_cmpuint(g_list_length(menuItems.get()), ==, 6); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 0)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 1)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 2)); g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 3)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && !gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 4)); g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && !gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 5)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); gtk_action_set_visible(action, TRUE); // Showing an action between two separators shows the hidden separator. item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 0)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 1)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 2)); g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 3)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 4)); g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 5)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); // Trailing separators are hidden too. action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(g_list_nth_data(menuItems.get(), 5))); gtk_action_set_visible(action, FALSE); menuItems.reset(gtk_container_get_children(GTK_CONTAINER(menu))); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 0)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 1)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 2)); g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 3)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 4)); g_assert(GTK_IS_SEPARATOR_MENU_ITEM(item) && !gtk_widget_get_visible(item)); item = GTK_WIDGET(g_list_nth_data(menuItems.get(), 5)); g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && !gtk_widget_get_visible(item)); } class ContextMenuWebExtensionTest: public ContextMenuTest { public: MAKE_GLIB_TEST_FIXTURE(ContextMenuWebExtensionTest); void deserializeContextMenuFromUserData(GVariant* userData) { m_actions.clear(); if (!userData) return; GVariantIter iter; g_variant_iter_init(&iter, userData); m_actions.reserveInitialCapacity(g_variant_iter_n_children(&iter)); uint32_t item; while (g_variant_iter_next(&iter, "u", &item)) m_actions.uncheckedAppend(static_cast(item)); } bool contextMenu(WebKitContextMenu* menu, GdkEvent*, WebKitHitTestResult*) { deserializeContextMenuFromUserData(webkit_context_menu_get_user_data(menu)); GList* items = webkit_context_menu_get_items(menu); g_assert_cmpuint(g_list_length(items), ==, m_actions.size()); unsigned actionIndex = 0; for (GList* it = items; it; it = g_list_next(it)) { WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(it->data); g_assert_cmpuint(webkit_context_menu_item_get_stock_action(item), ==, m_actions[actionIndex++]); } quitMainLoop(); return true; } Vector m_actions; }; static void testContextMenuWebExtensionMenu(ContextMenuWebExtensionTest* test, gconstpointer) { test->showInWindowAndWaitUntilMapped(); test->loadHtml("WebKitGTK+ Context menu tests
" "WebKitGTK+ Website", "ContextMenuTestDefault"); test->waitUntilLoadFinished(); // Default context menu. test->showContextMenuAtPositionAndWaitUntilFinished(1, 1); g_assert_cmpuint(test->m_actions.size(), ==, 4); g_assert_cmpuint(test->m_actions[0], ==, WEBKIT_CONTEXT_MENU_ACTION_GO_BACK); g_assert_cmpuint(test->m_actions[1], ==, WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD); g_assert_cmpuint(test->m_actions[2], ==, WEBKIT_CONTEXT_MENU_ACTION_STOP); g_assert_cmpuint(test->m_actions[3], ==, WEBKIT_CONTEXT_MENU_ACTION_RELOAD); // Link menu. test->showContextMenuAtPositionAndWaitUntilFinished(1, 11); g_assert_cmpuint(test->m_actions.size(), ==, 4); g_assert_cmpuint(test->m_actions[0], ==, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK); g_assert_cmpuint(test->m_actions[1], ==, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW); g_assert_cmpuint(test->m_actions[2], ==, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK); g_assert_cmpuint(test->m_actions[3], ==, WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD); // Custom menu. test->loadHtml("", "ContextMenuTestCustom"); test->showContextMenuAndWaitUntilFinished(); g_assert_cmpuint(test->m_actions.size(), ==, 4); g_assert_cmpuint(test->m_actions[0], ==, WEBKIT_CONTEXT_MENU_ACTION_STOP); g_assert_cmpuint(test->m_actions[1], ==, WEBKIT_CONTEXT_MENU_ACTION_RELOAD); g_assert_cmpuint(test->m_actions[2], ==, WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION); g_assert_cmpuint(test->m_actions[3], ==, WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT); // Menu cleared by the web process. test->loadHtml("", "ContextMenuTestClear"); test->showContextMenuAndWaitUntilFinished(); g_assert_cmpuint(test->m_actions.size(), ==, 0); } class ContextMenuWebExtensionNodeTest: public ContextMenuTest { public: MAKE_GLIB_TEST_FIXTURE(ContextMenuWebExtensionNodeTest); struct Node { enum { NodeUnknown = 0, NodeElement = 1, NodeText = 3 }; typedef unsigned Type; CString name; Type type; CString contents; CString parentName; }; void deserializeNodeFromUserData(GVariant* userData) { GVariantIter iter; g_variant_iter_init(&iter, userData); const char* key; GVariant* value; while (g_variant_iter_next(&iter, "{&sv}", &key, &value)) { if (!strcmp(key, "Name") && g_variant_classify(value) == G_VARIANT_CLASS_STRING) m_node.name = g_variant_get_string(value, nullptr); else if (!strcmp(key, "Type") && g_variant_classify(value) == G_VARIANT_CLASS_UINT32) m_node.type = g_variant_get_uint32(value); else if (!strcmp(key, "Contents") && g_variant_classify(value) == G_VARIANT_CLASS_STRING) m_node.contents = g_variant_get_string(value, nullptr); else if (!strcmp(key, "Parent") && g_variant_classify(value) == G_VARIANT_CLASS_STRING) m_node.parentName = g_variant_get_string(value, nullptr); g_variant_unref(value); } } bool contextMenu(WebKitContextMenu* menu, GdkEvent*, WebKitHitTestResult*) { deserializeNodeFromUserData(webkit_context_menu_get_user_data(menu)); quitMainLoop(); return true; } Node m_node; }; static void testContextMenuWebExtensionNode(ContextMenuWebExtensionNodeTest* test, gconstpointer) { test->showInWindowAndWaitUntilMapped(); test->loadHtml("

WebKitGTK+ Context menu tests


" "WebKitGTK+ Website", "ContextMenuTestNode"); test->waitUntilLoadFinished(); test->showContextMenuAtPositionAndWaitUntilFinished(0, 0); g_assert_cmpstr(test->m_node.name.data(), ==, "HTML"); g_assert_cmpuint(test->m_node.type, ==, ContextMenuWebExtensionNodeTest::Node::NodeElement); g_assert_cmpstr(test->m_node.contents.data(), ==, "WebKitGTK+ Context menu testsWebKitGTK+ Website"); g_assert_cmpstr(test->m_node.parentName.data(), ==, "#document"); test->showContextMenuAtPositionAndWaitUntilFinished(1, 20); g_assert_cmpstr(test->m_node.name.data(), ==, "#text"); g_assert_cmpuint(test->m_node.type, ==, ContextMenuWebExtensionNodeTest::Node::NodeText); g_assert_cmpstr(test->m_node.contents.data(), ==, "WebKitGTK+ Context menu tests"); g_assert_cmpstr(test->m_node.parentName.data(), ==, "P"); // Link menu. test->showContextMenuAtPositionAndWaitUntilFinished(1, 101); g_assert_cmpstr(test->m_node.name.data(), ==, "#text"); g_assert_cmpuint(test->m_node.type, ==, ContextMenuWebExtensionNodeTest::Node::NodeText); g_assert_cmpstr(test->m_node.contents.data(), ==, "WebKitGTK+ Website"); g_assert_cmpstr(test->m_node.parentName.data(), ==, "A"); } void beforeAll() { ContextMenuDefaultTest::add("WebKitWebView", "default-menu", testContextMenuDefaultMenu); ContextMenuCustomTest::add("WebKitWebView", "populate-menu", testContextMenuPopulateMenu); ContextMenuCustomFullTest::add("WebKitWebView", "custom-menu", testContextMenuCustomMenu); ContextMenuDisabledTest::add("WebKitWebView", "disable-menu", testContextMenuDisableMenu); ContextMenuSubmenuTest::add("WebKitWebView", "submenu", testContextMenuSubMenu); ContextMenuDismissedTest::add("WebKitWebView", "menu-dismissed", testContextMenuDismissed); ContextMenuSmartSeparatorsTest::add("WebKitWebView", "smart-separators", testContextMenuSmartSeparators); ContextMenuWebExtensionTest::add("WebKitWebPage", "context-menu", testContextMenuWebExtensionMenu); ContextMenuWebExtensionNodeTest::add("WebKitWebPage", "context-menu-node", testContextMenuWebExtensionNode); } void afterAll() { }