Skip to content

Commit

Permalink
Prototype to run GUI tests within Qt app
Browse files Browse the repository at this point in the history
  • Loading branch information
devos50 committed Dec 2, 2021
1 parent 0ac5926 commit bcfc9b1
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 59 deletions.
4 changes: 3 additions & 1 deletion src/run_tribler.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.add_argument('--core', action="store_true")
self.add_argument('--gui-test-mode', action="store_true")
self.add_argument('--gui-tests', action="store_true")


def init_sentry_reporter():
Expand Down Expand Up @@ -159,7 +160,8 @@ def init_boot_logger():
root_state_dir,
api_port=api_port,
api_key=api_key,
run_core=True)
run_core=True,
run_gui_tests=parsed_args.gui_tests)
window.setWindowTitle("Tribler")
app.set_activation_window(window)
app.parse_sys_args(sys.argv)
Expand Down
3 changes: 2 additions & 1 deletion src/tribler-gui/tribler_gui/core_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def __init__(self, root_state_dir, api_port, api_key, error_handler):
self.core_process = None
self.api_port = api_port
self.api_key = api_key
self.exit_code = 0
self.events_manager = EventRequestManager(self.api_port, self.api_key, error_handler)

self.shutting_down = False
Expand Down Expand Up @@ -131,4 +132,4 @@ def stop(self, stop_app_on_shutdown=True):
def on_finished(self):
self.tribler_stopped.emit()
if self.shutting_down:
QApplication.quit()
QApplication.exit(returnCode=self.exit_code)
28 changes: 28 additions & 0 deletions src/tribler-gui/tribler_gui/tests/gui_test_runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import logging

from tribler_gui.tribler_window import TriblerWindow


class GUITestRunner:
"""
This class manages the execution of the GUI tests.
"""
logger = logging.getLogger("GUITestRunner")

@staticmethod
def run(window: TriblerWindow):
from tribler_gui.tests import test_gui

success = True
for potential_test_method in dir(test_gui):
if potential_test_method.startswith("test_"):
test_method = getattr(test_gui, potential_test_method)
try:
test_method(window)
print(f"[{potential_test_method}] PASSED")
except Exception as exc:
logging.exception(exc)
print(f"[{potential_test_method}] FAILED")
success = False

return success
59 changes: 2 additions & 57 deletions src/tribler-gui/tribler_gui/tests/test_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,18 @@
import sys
from pathlib import Path

from PyQt5.QtCore import QMetaObject, QPoint, QSettings, QTimer, Q_ARG, Qt
from PyQt5.QtCore import QMetaObject, QPoint, QTimer, Q_ARG, Qt
from PyQt5.QtGui import QKeySequence, QPixmap, QRegion
from PyQt5.QtTest import QTest
from PyQt5.QtWidgets import QApplication, QListWidget, QTableView, QTextEdit, QTreeWidget, QTreeWidgetItem

import pytest
from PyQt5.QtWidgets import QListWidget, QTableView, QTextEdit, QTreeWidget, QTreeWidgetItem

import tribler_common
from tribler_common.reported_error import ReportedError
from tribler_common.tag_constants import MIN_TAG_LENGTH

from tribler_core.utilities.unicode import hexlify

import tribler_gui
from tribler_gui.dialogs.feedbackdialog import FeedbackDialog
from tribler_gui.dialogs.new_channel_dialog import NewChannelDialog
from tribler_gui.tribler_app import TriblerApplication
from tribler_gui.tribler_window import TriblerWindow
from tribler_gui.utilities import connect
from tribler_gui.widgets.loading_list_item import LoadingListItem
from tribler_gui.widgets.tablecontentmodel import Column
Expand All @@ -32,38 +26,6 @@
TORRENT_WITH_DIRS = COMMON_DATA_DIR / "multi_entries.torrent"


@pytest.fixture(scope="module")
def window(tmpdir_factory):
api_key = hexlify(os.urandom(16))
root_state_dir = str(tmpdir_factory.mktemp('tribler_state_dir'))

app = TriblerApplication("triblerapp-guitest", sys.argv)
# We must create a separate instance of QSettings and clear it.
# Otherwise, previous runs of the same app will affect this run.
settings = QSettings("tribler-guitest")
settings.clear()
window = TriblerWindow( # pylint: disable=W0621
settings,
root_state_dir,
api_key=api_key,
core_args=[str(RUN_TRIBLER_PY.absolute()), '--core', '--gui-test-mode'],
) # pylint: disable=W0621
app.set_activation_window(window)
QTest.qWaitForWindowExposed(window)

screenshot(window, name="tribler_loading")
wait_for_signal(
window.core_manager.events_manager.tribler_started,
flag=window.core_manager.events_manager.tribler_started_flag,
)
window.downloads_page.can_update_items = True
yield window

window.close_tribler()
screenshot(window, name="tribler_closing")
QApplication.quit()


def no_abort(*args, **kwargs):
sys.__excepthook__(*args, **kwargs)

Expand Down Expand Up @@ -238,13 +200,11 @@ def tst_channels_widget(window, widget, widget_name, sort_column=1, test_filter=
screenshot(window, name=f"{widget_name}-torrent_details")


@pytest.mark.guitest
def test_discovered_page(window):
QTest.mouseClick(window.left_menu_button_discovered, Qt.LeftButton)
tst_channels_widget(window, window.discovered_page, "discovered_page", sort_column=2)


@pytest.mark.guitest
def test_popular_page(window):
QTest.mouseClick(window.left_menu_button_popular, Qt.LeftButton)
widget = window.popular_page
Expand All @@ -262,7 +222,6 @@ def wait_for_thumbnail(chan_widget):
raise TimeoutException("The thumbnail was not shown within 10 seconds")


@pytest.mark.guitest
def test_edit_channel_torrents(window):
wait_for_list_populated(window.channels_menu_list)

Expand All @@ -280,7 +239,6 @@ def test_edit_channel_torrents(window):
screenshot(window, name="edit_channel_thumbnail_description")


@pytest.mark.guitest
def test_settings(window):
QTest.mouseClick(window.settings_button, Qt.LeftButton)
QTest.mouseClick(window.settings_general_button, Qt.LeftButton)
Expand All @@ -301,7 +259,6 @@ def test_settings(window):
wait_for_signal(window.settings_page.settings_edited)


@pytest.mark.guitest
def test_downloads(window):
go_to_and_wait_for_downloads(window)
screenshot(window, name="downloads_all")
Expand All @@ -317,7 +274,6 @@ def test_downloads(window):
screenshot(window, name="downloads_channels")


@pytest.mark.guitest
def test_download_start_stop_remove_recheck(window):
go_to_and_wait_for_downloads(window)
QTest.mouseClick(window.downloads_list.topLevelItem(0).progress_slider, Qt.LeftButton)
Expand All @@ -328,7 +284,6 @@ def test_download_start_stop_remove_recheck(window):
QTest.mouseClick(window.downloads_page.dialog.buttons[2], Qt.LeftButton)


@pytest.mark.guitest
def test_download_details(window):
go_to_and_wait_for_downloads(window)
QTest.mouseClick(window.downloads_list.topLevelItem(0).progress_slider, Qt.LeftButton)
Expand Down Expand Up @@ -357,15 +312,13 @@ def test_download_details(window):
screenshot(window, name="download_trackers")


@pytest.mark.guitest
def test_search_suggestions(window):
QTest.keyClick(window.top_search_bar, 't')
QTest.keyClick(window.top_search_bar, 'r')
wait_for_signal(window.received_search_completions)
screenshot(window, name="search_suggestions")


@pytest.mark.guitest
def test_search(window):
window.top_search_bar.setText("a") # This is likely to trigger some search results
QTest.keyClick(window.top_search_bar, Qt.Key_Enter)
Expand All @@ -382,7 +335,6 @@ def test_search(window):
)


@pytest.mark.guitest
def test_add_download_url(window):
go_to_and_wait_for_downloads(window)
window.on_add_torrent_from_url()
Expand Down Expand Up @@ -411,7 +363,6 @@ def test_add_download_url(window):
wait_for_signal(window.downloads_page.received_downloads)


@pytest.mark.guitest
def test_feedback_dialog(window):
def screenshot_dialog():
screenshot(dialog, name="feedback_dialog")
Expand All @@ -424,7 +375,6 @@ def screenshot_dialog():
dialog.exec_()


@pytest.mark.guitest
def test_feedback_dialog_report_sent(window):
def screenshot_dialog():
screenshot(dialog, name="feedback_dialog")
Expand All @@ -444,7 +394,6 @@ def on_report_sent():
assert on_report_sent.did_send_report


@pytest.mark.guitest
def test_debug_pane(window):
wait_for_variable(window, "tribler_settings")
QTest.mouseClick(window.settings_button, Qt.LeftButton)
Expand Down Expand Up @@ -553,14 +502,12 @@ def test_debug_pane(window):
window.debug_window.close()


@pytest.mark.guitest
def test_trust_page(window):
QTest.mouseClick(window.token_balance_widget, Qt.LeftButton)
wait_for_variable(window, "trust_page.history")
screenshot(window, name="trust_page_values")


@pytest.mark.guitest
def test_close_dialog_with_esc_button(window):
QTest.mouseClick(window.left_menu_button_new_channel, Qt.LeftButton)
screenshot(window, name="create_new_channel_dialog")
Expand All @@ -569,7 +516,6 @@ def test_close_dialog_with_esc_button(window):
assert not window.findChildren(NewChannelDialog)


@pytest.mark.guitest
def test_tags_dialog(window):
"""
Test the behaviour of the dialog where a user can edit tags.
Expand Down Expand Up @@ -671,7 +617,6 @@ def test_tags_dialog(window):
QTest.qWait(200) # It can take a bit of time to hide the dialog


@pytest.mark.guitest
def test_no_tags(window):
"""
Test removing all tags from a content item.
Expand Down
8 changes: 8 additions & 0 deletions src/tribler-gui/tribler_gui/tribler_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ def __init__(
api_port=None,
api_key=None,
run_core=True,
run_gui_tests=False
):
QMainWindow.__init__(self)
self._logger = logging.getLogger(self.__class__.__name__)
Expand All @@ -146,6 +147,7 @@ def __init__(

self.root_state_dir = Path(root_state_dir)
self.gui_settings = settings
self.run_gui_tests = run_gui_tests
api_port = api_port or int(get_gui_setting(self.gui_settings, "api_port", DEFAULT_API_PORT))
api_key = api_key or get_gui_setting(self.gui_settings, "api_key", hexlify(os.urandom(16)))
if isinstance(api_key, bytes):
Expand Down Expand Up @@ -528,6 +530,12 @@ def on_tribler_started(self, version):

QApplication.setStyle(InstantTooltipStyle(QApplication.style()))

if self.run_gui_tests:
from tribler_gui.tests.gui_test_runner import GUITestRunner
result = GUITestRunner.run(self)
self.core_manager.exit_code = 0 if result else 1
self.close_tribler()

@property
def hide_xxx(self):
return get_gui_setting(self.gui_settings, "family_filter", True, is_bool=True)
Expand Down

0 comments on commit bcfc9b1

Please sign in to comment.