Skip to content

Commit

Permalink
🎉 Add graphical integration tests #31
Browse files Browse the repository at this point in the history
Merge pull request #31 from MathisFederico/test/integration
  • Loading branch information
MathisFederico authored Nov 16, 2021
2 parents 444ee34 + 52dd36a commit 72d3e48
Show file tree
Hide file tree
Showing 6 changed files with 600 additions and 12 deletions.
17 changes: 14 additions & 3 deletions .github/workflows/python-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@ jobs:
python-version: 3.9
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install python3-tk python3-dev
sudo apt-get install xvfb
sudo apt install libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
touch /home/runner/.Xauthority
- name: Build unit coverage using pytest-cov
run: |
pip install -r requirements-dev.txt
pytest --cov=opencodeblocks --cov-report=xml tests/unit
score=$(python coverage_score.py --score)
color=$(python coverage_score.py --color)
Expand All @@ -40,14 +47,18 @@ jobs:
style: plastic
- name: Build integration coverage using pytest-cov
run: |
pip install -r requirements-dev.txt
pytest --cov=opencodeblocks --cov-report=xml tests/integration
/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1920x1080x24 -ac +extension GLX
pytest -s --cov=opencodeblocks --cov-report=xml tests/integration
score=$(python coverage_score.py --score)
color=$(python coverage_score.py --color)
echo "COVERAGE_INTEGRATION_SCORE=$score"
echo "COVERAGE_INTEGRATION_COLOR=$color"
echo "COVERAGE_INTEGRATION_SCORE=$score" >> $GITHUB_ENV
echo "COVERAGE_INTEGRATION_COLOR=$color" >> $GITHUB_ENV
env:
DISPLAY: :99
# QT_DEBUG_PLUGINS: 1 # Uncomment to debug Qt library issues.
- name: Create integration coverage badge
uses: schneegans/[email protected]
with:
Expand Down
20 changes: 11 additions & 9 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on: ["push"]
jobs:
build:

runs-on: windows-latest
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8, 3.9]
Expand All @@ -21,16 +21,18 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install python3-tk python3-dev
sudo apt-get install xvfb
sudo apt install libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Lint with flake8
run: |
pip install flake8
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
pip install -r requirements-dev.txt
touch /home/runner/.Xauthority
- name: Test with pytest
run: |
pip install -r requirements-dev.txt
/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1920x1080x24 -ac +extension GLX
pytest tests
env:
DISPLAY: :99
1 change: 1 addition & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
filterwarnings =
ignore::DeprecationWarning
addopts = --pspec
qt_api=pyqt5
2 changes: 2 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ pytest-cov
pytest-mock
pytest-check
pytest-pspec
pytest-qt
pyautogui
pylint
pylint-pytest
171 changes: 171 additions & 0 deletions tests/integration/test_blocks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
"""
Integration tests for OCB.
We use xvfb to perform the tests without opening any windows.
We use pyautogui to move the mouse and interact with the application.
To pass the tests on windows, you need to not move the mouse.
Use this if you need to understand why a test fails.
To pass the tests on linux, you just need to install xvfb and it's dependencies.
On linux, no windows are opened to the user during the test.
To understand why a test fails, pass the flag "--no-xvfb" and use your own X server
to see the test running live.
"""

# Imports needed for testing
import time, threading, queue, os, sys
import pytest
from pytest_mock import MockerFixture
import pytest_check as check
import pyautogui

# Packages tested
from opencodeblocks.graphics.blocks.codeblock import OCBCodeBlock
from opencodeblocks.graphics.socket import OCBSocket
from opencodeblocks.graphics.window import OCBWindow
from opencodeblocks.graphics.widget import OCBWidget

from qtpy.QtWidgets import QApplication
from PyQt5.QtWidgets import QWidget
from PyQt5.QtGui import QFocusEvent, QMouseEvent
from PyQt5.QtCore import QCoreApplication, QEvent, Qt, QPointF, QPoint
from PyQt5 import QtTest

def test_window_opening(qtbot):
""" The OCBWindow should open and close correctly """
wnd = OCBWindow()
wnd.close()

"""
def test_running_python(qtbot):
# The blocks should run arbitrary python when unfocused
wnd = OCBWindow()
EXPRESSION = "3 + 5 * 2"
SOURCE_TEST = \
'''
print(%s)
''' % EXPRESSION
expected_result = str(eval(EXPRESSION))
# Let's add a block with the source to the window !
ocb_widget = OCBWidget()
test_block = OCBCodeBlock(title="Testing block", source=SOURCE_TEST)
ocb_widget.scene.addItem(test_block)
wnd.mdiArea.addSubWindow(ocb_widget)
# Let's run the block !
pyeditor = test_block.source_editor.widget()
# pyeditor.setModified(True)
# test_block._source = ""
QApplication.processEvents()
QtTest.QTest.mouseClick(pyeditor,Qt.MouseButton.LeftButton)
QApplication.processEvents()
QtTest.QTest.keyPress(pyeditor," ")
QApplication.processEvents()
# Click outside the block to lose focus of the previous block.
# This will need to be changed by the click to the run button.
QtTest.QTest.mouseClick(ocb_widget,Qt.MouseButton.LeftButton)
QApplication.processEvents()
# When the execution becomes non-blocking for the UI, a refactor will be needed here.
result = test_block.stdout.strip()
check.equal(expected_result,result)
wnd.close()
"""

def test_move_blocks(qtbot):
"""
Newly created blocks are displayed in the center.
They can be dragged around with the mouse.
"""
wnd = OCBWindow()

ocb_widget = OCBWidget()
subwnd = wnd.mdiArea.addSubWindow(ocb_widget)

test_block1 = OCBCodeBlock(title="Testing block 1", source="print(1)")
ocb_widget.scene.addItem(test_block1)

test_block2 = OCBCodeBlock(title="Testing block 2", source="print(2)")
ocb_widget.scene.addItem(test_block2)

subwnd.show()

QApplication.processEvents()

expected_move_amount = [70,-30]
STOP_MSG = "stop"
CHECK_MSG = "check"

msgQueue = queue.Queue()

def testing_drag(msgQueue):
time.sleep(.4) # Wait for proper setup of app

# test_block1 == (0,0) but it's not crucial for this test.
pos_block_1 = QPoint(int(test_block1.pos().x()),int(test_block1.pos().y()))

pos_block_1.setX(pos_block_1.x() + test_block1.title_height//2)
pos_block_1.setY(pos_block_1.y() + test_block1.title_height//2)

pos_block_1 = ocb_widget.view.mapFromScene(pos_block_1)
pos_block_1 = ocb_widget.view.mapToGlobal(pos_block_1)

pyautogui.moveTo(pos_block_1.x(),pos_block_1.y())
pyautogui.mouseDown(button="left")

iterations = 5
for i in range(iterations+1):
time.sleep(0.05)
pyautogui.moveTo(
pos_block_1.x() + expected_move_amount[0] * i // iterations,
pos_block_1.y() + expected_move_amount[1] * i // iterations
)

pyautogui.mouseUp(button="left")
time.sleep(.2)

move_amount = [test_block2.pos().x(),test_block2.pos().y()]
# rectify because the scene can be zoomed :
move_amount[0] = int(move_amount[0] * ocb_widget.view.zoom)
move_amount[1] = int(move_amount[1] * ocb_widget.view.zoom)

msgQueue.put([
CHECK_MSG,
move_amount,
expected_move_amount,
"Block moved by the correct amound"
])

msgQueue.put([STOP_MSG])


t = threading.Thread(target=testing_drag, args=(msgQueue,))
t.start()

while True:
QApplication.processEvents()
time.sleep(0.02)
if not msgQueue.empty():
msg = msgQueue.get()
if msg[0] == STOP_MSG:
break
elif msg[0] == CHECK_MSG:
check.equal(msg[1],msg[2],msg[3])
t.join()
wnd.close()

def test_open_file():
"""
The application loads files properly.
"""

wnd = OCBWindow()
file_example_path = "./tests/testing_assets/example_graph1.ipyg"
subwnd = wnd.createNewMdiChild(os.path.abspath(file_example_path))
subwnd.show()
wnd.close()
Loading

0 comments on commit 72d3e48

Please sign in to comment.