From dcd5cf7c4b0c913a5af2f5c6271074d2bbcf4789 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 08:30:35 -0300 Subject: [PATCH 01/18] Pin typing-extensions in Python 3.6 typing-extensions 4.2.0 is not compatible with Python 3.6, and breaks `pytest`. --- environment.devenv.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/environment.devenv.yml b/environment.devenv.yml index f29d696..4f42184 100644 --- a/environment.devenv.yml +++ b/environment.devenv.yml @@ -24,6 +24,7 @@ dependencies: - pytest-rerunfailures - pytest-selenium >=1,<2 - pytest-timeout + - typing-extensions <4.2.0 # [PYTHON_VERSION=="3.6"] {% if sys.platform != 'win32' %} - pytest-xvfb {% endif %} From 885ea41ac2c243c14fa9bc3630d7792327e7f4fc Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 08:51:33 -0300 Subject: [PATCH 02/18] Pin importlib_resources `5.10` (the latst version) seems to be incompatible with `jaraco.text`, which is an indirect dependency of `cherrypy`. Fix #151 --- environment.devenv.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/environment.devenv.yml b/environment.devenv.yml index 4f42184..daa1ef2 100644 --- a/environment.devenv.yml +++ b/environment.devenv.yml @@ -18,15 +18,14 @@ dependencies: {% if TEST_QMXGRAPH %} - cherrypy - - hypothesis ==3.11.0 + - hypothesis =3.11 - pytest-mock - pytest-qt - pytest-rerunfailures - pytest-selenium >=1,<2 - pytest-timeout - typing-extensions <4.2.0 # [PYTHON_VERSION=="3.6"] - {% if sys.platform != 'win32' %} - - pytest-xvfb - {% endif %} - + # Pin importlib_resources due to #151. + - importlib_resources <5.10 + - pytest-xvfb # [linux] {% endif %} From 9efb3b77496121695dcb53ef4f49be6848543e15 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 09:19:00 -0300 Subject: [PATCH 03/18] Fix python version handling in CI The variables were incorrectly defined, resulting in all builds being done in Python 3.6. --- .github/workflows/main.yml | 4 ++-- environment.devenv.yml | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 79cb464..89657a2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - CONDA_PY: ["36", "37", "38", "39"] + python: ["3.6", "3.7", "3.8", "3.9"] steps: - uses: actions/checkout@v2 @@ -32,7 +32,7 @@ jobs: channel-priority: true - name: Install env: - CONDA_PY: ${{ matrix.CONDA_PY }} + PYTHON_VERSION: ${{ matrix.python }} run: | conda config --system --set always_yes yes --set changeps1 no conda install -c conda-forge conda-devenv diff --git a/environment.devenv.yml b/environment.devenv.yml index daa1ef2..a9356a7 100644 --- a/environment.devenv.yml +++ b/environment.devenv.yml @@ -1,6 +1,5 @@ {% set TEST_QMXGRAPH = os.environ.get('TEST_QMXGRAPH', '0') != '0' %} -{% set PYTHON_VERSION = os.environ.get('PYTHON_VERSION', '3.6') %} -{% set PYTHON_VERSION = os.environ.get('TRAVIS_PYTHON_VERSION', PYTHON_VERSION) %} +{% set PYTHON_VERSION = os.environ['PYTHON_VERSION'] %} name: qmxgraph From ac60de1605b25bfc71d7dccbed1118a78dbfd1b5 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 09:26:37 -0300 Subject: [PATCH 04/18] Add missing phantomjs to test dependencies --- environment.devenv.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/environment.devenv.yml b/environment.devenv.yml index a9356a7..5d3cf52 100644 --- a/environment.devenv.yml +++ b/environment.devenv.yml @@ -18,6 +18,7 @@ dependencies: {% if TEST_QMXGRAPH %} - cherrypy - hypothesis =3.11 + - phantomjs - pytest-mock - pytest-qt - pytest-rerunfailures From f7245c9d51c762e145fba406d84769b5c6e11f68 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 09:39:28 -0300 Subject: [PATCH 05/18] Remove pinning of pyqt 5.12 To test in all platforms we cannot pin to 5.12, as it is not available in later Pythons. --- _base_environment.devenv.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_base_environment.devenv.yml b/_base_environment.devenv.yml index 3dffab8..d6e937c 100644 --- a/_base_environment.devenv.yml +++ b/_base_environment.devenv.yml @@ -11,7 +11,7 @@ dependencies: - oop-ext - pip - pre-commit - - pyqt =5.12 + - pyqt environment: PYTHONPATH: From 923ba5126ebe7abda8a1474dc9351c00e673b060 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 10:07:22 -0300 Subject: [PATCH 06/18] Ensure phantomjs is available in PATH before starting tests --- _base_environment.devenv.yml | 2 +- tests/conftest.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/_base_environment.devenv.yml b/_base_environment.devenv.yml index d6e937c..d30969c 100644 --- a/_base_environment.devenv.yml +++ b/_base_environment.devenv.yml @@ -11,7 +11,7 @@ dependencies: - oop-ext - pip - pre-commit - - pyqt + - pyqt >=5.12 environment: PYTHONPATH: diff --git a/tests/conftest.py b/tests/conftest.py index fcc8792..e104cd1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,6 @@ +import os +import shutil + import pytest @@ -7,7 +10,9 @@ def pytest_configure(config): # of pytest so they can't reliably be removed by a fixture. config.cache.set('qmxgraph/ports', []) - import os + # Ensure phantomjs is available. + phantomjs = shutil.which("phantomjs") + assert phantomjs is not None lock_file = _get_port_lock_filename(config.rootdir) if os.path.isfile(lock_file): From f83f61190160cdd38bd37862a5577cad5b48d5de Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 10:08:44 -0300 Subject: [PATCH 07/18] WIP test only in py36 --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 89657a2..96d2fa4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,8 @@ jobs: strategy: fail-fast: false matrix: - python: ["3.6", "3.7", "3.8", "3.9"] + #python: ["3.6", "3.7", "3.8", "3.9"] + python: ["3.6"] steps: - uses: actions/checkout@v2 From 89e3c6edcb0e6fcc14008a74b4c17c8e9c503f72 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 10:10:20 -0300 Subject: [PATCH 08/18] List conda environment after creation --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 96d2fa4..e11c05c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,6 +41,7 @@ jobs: export TEST_QMXGRAPH=1 conda devenv -n qmxgraph conda install -n qmxgraph coveralls pytest-cov + conda list -n qmxgraph conda init bash - name: Tests shell: bash -l {0} From 36e3a916b8e4fb53b9604b84688e55d8ab5c35f3 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 10:56:17 -0300 Subject: [PATCH 09/18] Revamp timeout handling in _wait_graph_page_ready --- .gitignore | 1 + tasks.py | 2 +- tests/conftest.py | 17 ++++++----------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 9cafdac..c06cd28 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,4 @@ resource_*.py environment.yml docs_environment.yml esss_environment.yml +mxgraph/ diff --git a/tasks.py b/tasks.py index 9d97a88..443d21e 100644 --- a/tasks.py +++ b/tasks.py @@ -137,7 +137,7 @@ def docs(ctx, python_version=None): @invoke.task def test(ctx): print_message('test'.format(), color=Fore.BLUE, bright=True) - cmd = 'pytest --cov=qmxgraph --timeout=30 -v --durations=10' + cmd = 'pytest --cov=qmxgraph --timeout=60 -v --durations=10' import subprocess diff --git a/tests/conftest.py b/tests/conftest.py index e104cd1..0608218 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -18,10 +18,6 @@ def pytest_configure(config): if os.path.isfile(lock_file): os.remove(lock_file) - import socket - - socket.setdefaulttimeout(15.0) - # Fixtures -------------------------------------------------------------------- @@ -949,25 +945,24 @@ def _wait_graph_page_ready(host, selenium): import socket from selenium.common.exceptions import TimeoutException - timeout = 15 + timeout = 30 timeout_exceptions = (TimeoutException, TimeoutError, socket.timeout) - selenium.set_page_load_timeout(1) + selenium.set_page_load_timeout(timeout) refresh = True try: selenium.get(host.address) refresh = False except timeout_exceptions: pass - + tries = 3 if refresh: - for n in range(timeout): + for n in range(tries): try: selenium.refresh() break except timeout_exceptions: - pass - else: - raise TimeoutException("All page load tries resulted in timeout") + if n == tries - 1: + raise from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.by import By From f20a6f2a1d517002d2d231c0157a4a23ab1a2995 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 11:20:15 -0300 Subject: [PATCH 10/18] Remove install Qt step This should not be needed anymore, installing from conda-forge is sufficient. --- .github/workflows/main.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e11c05c..a7d26be 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,10 +20,6 @@ jobs: steps: - uses: actions/checkout@v2 - # We need to install Qt on the system otherwise tests in - # tests/test_qt_js_integration.py crash. - - name: Install Qt - uses: jurplel/install-qt-action@v2 - uses: conda-incubator/setup-miniconda@v2 with: auto-update-conda: true From 4adffc4ce4ef37bf0db0650bdc521511ac816312 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 13:00:38 -0300 Subject: [PATCH 11/18] Use Firefox as webdriver for tests --- environment.devenv.yml | 7 ++++--- scripts/run_tests.sh | 1 - tests/conftest.py | 34 +++------------------------------- 3 files changed, 7 insertions(+), 35 deletions(-) diff --git a/environment.devenv.yml b/environment.devenv.yml index 5d3cf52..89985d7 100644 --- a/environment.devenv.yml +++ b/environment.devenv.yml @@ -9,7 +9,7 @@ includes: environment: # Tip: Use `--driver ` to change driver for a single run {% if TEST_QMXGRAPH %} - PYTEST_ADDOPTS: --driver PhantomJS + PYTEST_ADDOPTS: --driver Firefox {% endif %} dependencies: @@ -18,11 +18,12 @@ dependencies: {% if TEST_QMXGRAPH %} - cherrypy - hypothesis =3.11 - - phantomjs + - firefox + - geckodriver - pytest-mock - pytest-qt - pytest-rerunfailures - - pytest-selenium >=1,<2 + - pytest-selenium - pytest-timeout - typing-extensions <4.2.0 # [PYTHON_VERSION=="3.6"] # Pin importlib_resources due to #151. diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 7ec1393..9585a0d 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -1,6 +1,5 @@ #!/bin/bash git clone --depth=1 --branch v3.7.5 https://github.com/jgraph/mxgraph.git -export PYTEST_ADDOPTS="--driver PhantomJS" export MXGRAPHPATH=mxgraph inv qrc inv test diff --git a/tests/conftest.py b/tests/conftest.py index 0608218..bfe24cf 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,4 @@ import os -import shutil import pytest @@ -10,43 +9,16 @@ def pytest_configure(config): # of pytest so they can't reliably be removed by a fixture. config.cache.set('qmxgraph/ports', []) - # Ensure phantomjs is available. - phantomjs = shutil.which("phantomjs") - assert phantomjs is not None - lock_file = _get_port_lock_filename(config.rootdir) if os.path.isfile(lock_file): os.remove(lock_file) # Fixtures -------------------------------------------------------------------- - - -@pytest.fixture -def phantomjs_driver(capabilities, driver_path, port): - """ - Overrides default `phantomjs_driver` driver from pytest-selenium. - - Default implementation uses ephemeral ports just as our tests but - it doesn't provide any way to configure them, for this reason we basically - recreate the driver fixture using port fixture. - """ - kwargs = {} - if capabilities: - kwargs['desired_capabilities'] = capabilities - if driver_path is not None: - kwargs['executable_path'] = driver_path - - kwargs['port'] = port.get() - - from selenium.webdriver import PhantomJS - - return PhantomJS(**kwargs) - - @pytest.fixture -def driver_args(): - return ['--debug=true'] +def firefox_options(firefox_options): + firefox_options.headless = True + return firefox_options @pytest.fixture(autouse=True) From 8d8175e7ba5ccf142108d5e1e49dd51d6b132f19 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 13:21:52 -0300 Subject: [PATCH 12/18] Debug Firefox error --- tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks.py b/tasks.py index 443d21e..f095f51 100644 --- a/tasks.py +++ b/tasks.py @@ -137,7 +137,7 @@ def docs(ctx, python_version=None): @invoke.task def test(ctx): print_message('test'.format(), color=Fore.BLUE, bright=True) - cmd = 'pytest --cov=qmxgraph --timeout=60 -v --durations=10' + cmd = 'pytest --cov=qmxgraph --timeout=60 -v --durations=10 -x' import subprocess From d15922ef6a145a9e57d8c8ffa3661d53336eebad Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 9 Dec 2022 14:32:12 -0300 Subject: [PATCH 13/18] Change 'callback' to 'window.callback' per Prusse's suggestion --- tests/conftest.py | 8 ++++++-- tests/test_js_graph.py | 14 +++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index bfe24cf..3c09973 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -300,7 +300,9 @@ def __init__(self, selenium, host): ' window.__added__.push.apply(window.__added__, cellIds);' '}' ) - self.eval_js_function('api.registerCellsAddedHandler', qmxgraph.js.Variable('callback')) + self.eval_js_function( + 'api.registerCellsAddedHandler', qmxgraph.js.Variable('window.callback') + ) selenium.execute_script( 'callback = function(cellId, newLabel, oldLabel) {' @@ -310,7 +312,9 @@ def __init__(self, selenium, host): ' window.__labels__.push({cellId: cellId, newLabel: newLabel, oldLabel: oldLabel});' # noqa '}' ) - self.eval_js_function('api.registerLabelChangedHandler', qmxgraph.js.Variable('callback')) + self.eval_js_function( + 'api.registerLabelChangedHandler', qmxgraph.js.Variable('window.callback') + ) def get_container(self): """ diff --git a/tests/test_js_graph.py b/tests/test_js_graph.py index 5c9ce48..54d7f25 100644 --- a/tests/test_js_graph.py +++ b/tests/test_js_graph.py @@ -683,7 +683,7 @@ def test_on_cells_removed(graph_cases) -> None: graph = graph_cases('2v_1e') graph.selenium.execute_script('callback = function(cellIds) {window.cellIds = cellIds;}') - graph.eval_js_function('api.registerCellsRemovedHandler', js.Variable('callback')) + graph.eval_js_function('api.registerCellsRemovedHandler', js.Variable('window.callback')) cell_ids = [ graph.get_id(graph.get_vertices()[0]), @@ -899,7 +899,7 @@ def test_insert_with_tags(graph_cases, cell_type) -> None: ' );' '}' ) - graph.eval_js_function('api.registerCellsAddedHandler', js.Variable('callback')) + graph.eval_js_function('api.registerCellsAddedHandler', js.Variable('window.callback')) tags = {'tagTest': '1'} cell_id = insert_by_parametrized_type(graph, cell_type, tags=tags) @@ -1194,7 +1194,9 @@ def test_set_double_click_handler(graph_cases) -> None: ' window.__dblClick__.push(cellId);' '}' ) - graph.eval_js_function('api.registerDoubleClickHandler', qmxgraph.js.Variable('callback')) + graph.eval_js_function( + 'api.registerDoubleClickHandler', qmxgraph.js.Variable('window.callback') + ) actions = ActionChains(graph.selenium) actions.double_click(graph.get_vertex()) @@ -1220,7 +1222,9 @@ def test_add_selection_change_handler(graph_cases) -> None: ' window.__selectionChange__.push(cellIds);' '}' ) - graph.eval_js_function('api.registerSelectionChangedHandler', qmxgraph.js.Variable('callback')) + graph.eval_js_function( + 'api.registerSelectionChangedHandler', qmxgraph.js.Variable('window.callback') + ) # Select all cells. actions = ActionChains(graph.selenium) @@ -1271,7 +1275,7 @@ def test_set_popup_menu_handler(graph_cases) -> None: ' window.__popupMenu__.push([cellId, x, y]);' '}' ) - graph.eval_js_function('api.registerPopupMenuHandler', qmxgraph.js.Variable('callback')) + graph.eval_js_function('api.registerPopupMenuHandler', qmxgraph.js.Variable('window.callback')) vertex_label_el = graph.get_label_element(graph.get_vertex()) actions = ActionChains(graph.selenium) From d841d7fc281d223c47ea31203cab43b560f990f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Pr=C3=BCsse?= Date: Fri, 9 Dec 2022 16:19:26 -0300 Subject: [PATCH 14/18] Use `window.callback` when creating the callbacks --- tests/conftest.py | 4 ++-- tests/test_js_graph.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 3c09973..9205ac7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -293,7 +293,7 @@ def __init__(self, selenium, host): _wait_graph_page_ready(host=host, selenium=selenium) selenium.execute_script( - 'callback = function(cellIds) {' + 'window.callback = function(cellIds) {' ' if (!window.__added__) {' ' window.__added__ = [];' ' }' @@ -305,7 +305,7 @@ def __init__(self, selenium, host): ) selenium.execute_script( - 'callback = function(cellId, newLabel, oldLabel) {' + 'window.callback = function(cellId, newLabel, oldLabel) {' ' if (!window.__labels__) {' ' window.__labels__ = [];' ' }' diff --git a/tests/test_js_graph.py b/tests/test_js_graph.py index 54d7f25..9a7cd06 100644 --- a/tests/test_js_graph.py +++ b/tests/test_js_graph.py @@ -891,7 +891,7 @@ def test_insert_with_tags(graph_cases, cell_type) -> None: # Listen to on cells added event to be sure tags are already configured # as soon as cell is created graph.selenium.execute_script( - 'callback = function(cellIds) {' + 'window.callback = function(cellIds) {' ' window.tags = cellIds.map(' ' function(cellId) {' ' return api.hasTag(cellId, "tagTest")? api.getTag(cellId, "tagTest") : null;' # noqa @@ -1187,7 +1187,7 @@ def test_set_double_click_handler(graph_cases) -> None: vertex_id = graph.get_id(graph.get_vertex()) graph.selenium.execute_script( - 'callback = function(cellId) {' + 'window.callback = function(cellId) {' ' if (!window.__dblClick__) {' ' window.__dblClick__ = [];' ' }' @@ -1215,7 +1215,7 @@ def test_add_selection_change_handler(graph_cases) -> None: edge = graph.get_edge(source, target) graph.selenium.execute_script( - 'callback = function(cellIds) {' + 'window.callback = function(cellIds) {' ' if (!window.__selectionChange__) {' ' window.__selectionChange__ = [];' ' }' @@ -1268,7 +1268,7 @@ def test_set_popup_menu_handler(graph_cases) -> None: vertex_id = graph.get_id(graph.get_vertex()) graph.selenium.execute_script( - 'callback = function(cellId, x, y) {' + 'window.callback = function(cellId, x, y) {' ' if (!window.__popupMenu__) {' ' window.__popupMenu__ = [];' ' }' From 556327b22b3626991e65484634b43249f2c9d2d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Pr=C3=BCsse?= Date: Fri, 9 Dec 2022 16:36:56 -0300 Subject: [PATCH 15/18] Update error msg expected values When changing from phantomsj to firefox the messages started to be prefixed with "ERROR: ". I could also have changed `SeleniumExtras.get_exception_message` to drop the prefix, in retrospect that would have been easier because the expected values will not have to be changed. --- tests/test_js_graph.py | 102 +++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 56 deletions(-) diff --git a/tests/test_js_graph.py b/tests/test_js_graph.py index 9a7cd06..20f4e75 100644 --- a/tests/test_js_graph.py +++ b/tests/test_js_graph.py @@ -152,16 +152,14 @@ def test_insert_edge_error_endpoint_not_found(graph_cases, selenium_extras) -> N with pytest.raises(WebDriverException) as e: graph.eval_js_function("api.insertEdge", invalid_source_id, graph.get_id(vertex)) - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - invalid_source_id - ) + expected_msg = f"Unable to find cell with id {invalid_source_id}" + assert expected_msg in selenium_extras.get_exception_message(e) with pytest.raises(WebDriverException) as e: graph.eval_js_function("api.insertEdge", graph.get_id(vertex), invalid_target_id) - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - invalid_target_id - ) + expected_msg = f"Unable to find cell with id {invalid_target_id}" + assert expected_msg in selenium_extras.get_exception_message(e) def test_insert_decoration(graph_cases) -> None: @@ -441,16 +439,14 @@ def test_set_visible_error_not_found(graph_cases, selenium_extras) -> None: with pytest.raises(WebDriverException) as e: graph.set_visible(cell_id, False) - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - cell_id - ) + expected_msg = f"Unable to find cell with id {cell_id}" + assert expected_msg in selenium_extras.get_exception_message(e) with pytest.raises(WebDriverException) as e: graph.is_visible(cell_id) - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - cell_id - ) + expected_msg = f"Unable to find cell with id {cell_id}" + assert expected_msg in selenium_extras.get_exception_message(e) def test_get_geometry_plain(graph_cases) -> None: @@ -479,9 +475,8 @@ def test_get_geometry_error_not_found(graph_cases, selenium_extras) -> None: with pytest.raises(WebDriverException) as e: graph.get_geometry(cell_id) - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - cell_id - ) + expected_msg = f"Unable to find cell with id {cell_id}" + assert expected_msg in selenium_extras.get_exception_message(e) def test_insert_table(graph_cases) -> None: @@ -619,9 +614,8 @@ def test_update_table_error_not_found(graph_cases, selenium_extras) -> None: js.prepare_js_call('api.updateTable', table_id, contents, title) ) - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - table_id - ) + expected_msg = f"Unable to find cell with id {table_id}" + assert expected_msg in selenium_extras.get_exception_message(e) def test_update_table_error_not_table(graph_cases, selenium_extras) -> None: @@ -640,7 +634,8 @@ def test_update_table_error_not_table(graph_cases, selenium_extras) -> None: js.prepare_js_call('api.updateTable', table_id, contents, title) ) - assert selenium_extras.get_exception_message(e) == "Cell is not a table" + expected_msg = "Cell is not a table" + assert expected_msg in selenium_extras.get_exception_message(e) def test_remove_cells(graph_cases) -> None: @@ -671,9 +666,8 @@ def test_remove_cells_error_not_found(graph_cases, selenium_extras) -> None: with pytest.raises(WebDriverException) as e: graph.eval_js_function('api.removeCells', [cell_id]) - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - cell_id - ) + expected_msg = f"Unable to find cell with id {cell_id}" + assert expected_msg in selenium_extras.get_exception_message(e) def test_on_cells_removed(graph_cases) -> None: @@ -682,7 +676,7 @@ def test_on_cells_removed(graph_cases) -> None: """ graph = graph_cases('2v_1e') - graph.selenium.execute_script('callback = function(cellIds) {window.cellIds = cellIds;}') + graph.selenium.execute_script('window.callback = function(cellIds) {window.cellIds = cellIds;}') graph.eval_js_function('api.registerCellsRemovedHandler', js.Variable('window.callback')) cell_ids = [ @@ -819,9 +813,8 @@ def test_get_label_error_not_found(graph_cases, selenium_extras) -> None: with pytest.raises(WebDriverException) as e: graph.get_label(cell_id) - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - cell_id - ) + expected_msg = f"Unable to find cell with id {cell_id}" + assert expected_msg in selenium_extras.get_exception_message(e) def test_has_cell(graph_cases) -> None: @@ -867,9 +860,8 @@ def test_get_cell_type_error_not_found(graph_cases, selenium_extras) -> None: with pytest.raises(WebDriverException) as e: graph.eval_js_function("api.getCellType", cell_id) - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - cell_id - ) + expected_msg = f"Unable to find cell with id {cell_id}" + assert expected_msg in selenium_extras.get_exception_message(e) @pytest.mark.parametrize( @@ -928,12 +920,14 @@ def test_insert_with_tags_error_value_not_string(graph_cases, cell_type, seleniu """ graph = graph_cases('empty') - tags = {'tagTest': 999} + test_tag_name = 'tagTest' + tags = {test_tag_name: 999} with pytest.raises(WebDriverException) as e: insert_by_parametrized_type(graph, cell_type, tags=tags) - assert selenium_extras.get_exception_message(e) == "Tag '{}' is not a string".format("tagTest") + expected_msg = f"Tag '{test_tag_name}' is not a string" + assert expected_msg in selenium_extras.get_exception_message(e) @pytest.mark.parametrize( @@ -978,14 +972,14 @@ def test_set_get_tag_error_tag_not_found(graph_cases, cell_type, selenium_extras graph = graph_cases('empty') cell_id = insert_by_parametrized_type(graph, cell_type) - assert not graph.eval_js_function("api.hasTag", cell_id, "test") + test_tag_name = "test" + assert not graph.eval_js_function("api.hasTag", cell_id, test_tag_name) with pytest.raises(WebDriverException) as e: - graph.eval_js_function("api.getTag", cell_id, "test") + graph.eval_js_function("api.getTag", cell_id, test_tag_name) - assert selenium_extras.get_exception_message( - e - ) == "Tag '{}' not found in cell with id {}".format("test", cell_id) + expected_msg = f"Tag '{test_tag_name}' not found in cell with id {cell_id}" + assert expected_msg in selenium_extras.get_exception_message(e) @pytest.mark.parametrize( @@ -1006,11 +1000,13 @@ def test_set_get_tag_error_value_not_string(graph_cases, cell_type, selenium_ext graph = graph_cases('empty') cell_id = insert_by_parametrized_type(graph, cell_type) + test_tag_name = "test" with pytest.raises(WebDriverException) as e: - graph.eval_js_function("api.setTag", cell_id, "test", 999) + graph.eval_js_function("api.setTag", cell_id, test_tag_name, 999) - assert selenium_extras.get_exception_message(e) == "Tag '{}' is not a string".format("test") + expected_msg = f"Tag '{test_tag_name}' is not a string" + assert expected_msg in selenium_extras.get_exception_message(e) @pytest.mark.parametrize( @@ -1050,23 +1046,20 @@ def test_set_get_tag_error_cell_not_found(graph_cases, selenium_extras) -> None: with pytest.raises(WebDriverException) as e: graph.eval_js_function("api.setTag", cell_id, "test", "foo") - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - cell_id - ) + expected_msg = f"Unable to find cell with id {cell_id}" + assert expected_msg in selenium_extras.get_exception_message(e) with pytest.raises(WebDriverException) as e: graph.eval_js_function("api.getTag", cell_id, "test") - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - cell_id - ) + expected_msg = f"Unable to find cell with id {cell_id}" + assert expected_msg in selenium_extras.get_exception_message(e) with pytest.raises(WebDriverException) as e: graph.eval_js_function("api.hasTag", cell_id, "test") - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - cell_id - ) + expected_msg = f"Unable to find cell with id {cell_id}" + assert expected_msg in selenium_extras.get_exception_message(e) def test_set_get_tag_without_initial_tag_support(graph_cases) -> None: @@ -1174,9 +1167,8 @@ def test_set_label_error_not_found(graph_cases, selenium_extras) -> None: with pytest.raises(WebDriverException) as e: graph.eval_js_function('api.setLabel', cell_id, 'foo') - assert selenium_extras.get_exception_message(e) == "Unable to find cell with id {}".format( - cell_id - ) + expected_msg = f"Unable to find cell with id {cell_id}" + assert expected_msg in selenium_extras.get_exception_message(e) def test_set_double_click_handler(graph_cases) -> None: @@ -1489,9 +1481,8 @@ def test_get_edge_terminals_error_edge_not_found(graph_cases, selenium_extras) - with pytest.raises(WebDriverException) as e: graph.eval_js_function('api.getEdgeTerminals', edge_id) - assert selenium_extras.get_exception_message(e) == "Unable to find edge with id {}".format( - edge_id - ) + expected_msg = f"Unable to find edge with id {edge_id}" + assert expected_msg in selenium_extras.get_exception_message(e) def test_get_edge_terminals_error_not_an_edge(graph_cases, selenium_extras) -> None: @@ -1505,9 +1496,8 @@ def test_get_edge_terminals_error_not_an_edge(graph_cases, selenium_extras) -> N with pytest.raises(WebDriverException) as e: graph.eval_js_function('api.getEdgeTerminals', graph.get_id(vertex)) - assert selenium_extras.get_exception_message(e) == "Cell with id {} is not an edge".format( - graph.get_id(vertex) - ) + expected_msg = f"Cell with id {graph.get_id(vertex)} is not an edge" + assert expected_msg in selenium_extras.get_exception_message(e) def test_custom_font_family(graph_cases_factory, port) -> None: From cf9f3c6fe8431316f8c6a9376acee83caa7b94dc Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 12 Dec 2022 08:47:55 -0300 Subject: [PATCH 16/18] Update expected test coordinates --- tests/test_js_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_js_graph.py b/tests/test_js_graph.py index 20f4e75..bc0faff 100644 --- a/tests/test_js_graph.py +++ b/tests/test_js_graph.py @@ -461,7 +461,7 @@ def test_get_geometry_plain(graph_cases) -> None: # Table geometry is dependent on how the contents are rendered. # Using `pytest.approx` to account for platform differences. obtained_table_geometry = graph.get_geometry(graph.get_tables()[0]) - assert pytest.approx(obtained_table_geometry, rel=0.1) == [20, 60, 108, 72] + assert obtained_table_geometry == pytest.approx([20, 60, 96, 72], rel=0.1) def test_get_geometry_error_not_found(graph_cases, selenium_extras) -> None: From 8aebe0717deba55b475b2d6ceea3a6429aab7b18 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 12 Dec 2022 09:17:10 -0300 Subject: [PATCH 17/18] Fix test_set_popup_menu_handler to handle async results --- tests/test_js_graph.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/test_js_graph.py b/tests/test_js_graph.py index bc0faff..d809ba5 100644 --- a/tests/test_js_graph.py +++ b/tests/test_js_graph.py @@ -3,6 +3,7 @@ from typing import List import pytest +from pytestqt.qtbot import QtBot from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import WebDriverException from selenium.webdriver import ActionChains @@ -1251,7 +1252,7 @@ def test_add_selection_change_handler(graph_cases) -> None: ] -def test_set_popup_menu_handler(graph_cases) -> None: +def test_set_popup_menu_handler(graph_cases, qtbot: QtBot) -> None: """ :type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory """ @@ -1274,9 +1275,12 @@ def test_set_popup_menu_handler(graph_cases) -> None: actions.context_click(vertex_label_el) actions.perform() - x = vertex_label_el.location['x'] + vertex_label_el.size['width'] // 2 - y = vertex_label_el.location['y'] + vertex_label_el.size['height'] // 2 - assert graph.selenium.execute_script('return window.__popupMenu__') == [[vertex_id, x, y]] + def check() -> None: + x = vertex_label_el.location['x'] + vertex_label_el.size['width'] // 2 + y = vertex_label_el.location['y'] + vertex_label_el.size['height'] // 2 + assert graph.selenium.execute_script('return window.__popupMenu__') == [[vertex_id, x, y]] + + qtbot.waitUntil(check) @pytest.mark.parametrize( From eb2704638488d95700d06e7f51b126485f3d01b5 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 12 Dec 2022 09:32:43 -0300 Subject: [PATCH 18/18] Remove -x from test command --- tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks.py b/tasks.py index f095f51..443d21e 100644 --- a/tasks.py +++ b/tasks.py @@ -137,7 +137,7 @@ def docs(ctx, python_version=None): @invoke.task def test(ctx): print_message('test'.format(), color=Fore.BLUE, bright=True) - cmd = 'pytest --cov=qmxgraph --timeout=60 -v --durations=10 -x' + cmd = 'pytest --cov=qmxgraph --timeout=60 -v --durations=10' import subprocess