From dd5476fc8b4de082d81e5f9942dae57ac693e30a Mon Sep 17 00:00:00 2001 From: Alex Hartoto Date: Thu, 4 Apr 2019 22:59:35 -0700 Subject: [PATCH] Include more options in Book window. Also add unittests that use pytest-qt to orchestrate the clicking of buttons, etc. The UI-based unittests will not be running in CI since CI only has Qt4 installed. Github issue: #1, #4 --- .travis.yml | 29 ++++++++++++++++++++--------- booklib/ui/config.py | 4 ++++ booklib/ui/window/admin.py | 18 +++++++++++------- booklib/ui/window/book.py | 21 ++++++++++++++++++++- requirements-dev.txt | 2 ++ tests/ui/window/__init__.py | 0 tests/ui/window/test_admin.py | 34 ++++++++++++++++++++++++++++++++++ 7 files changed, 91 insertions(+), 17 deletions(-) create mode 100644 tests/ui/window/__init__.py create mode 100644 tests/ui/window/test_admin.py diff --git a/.travis.yml b/.travis.yml index 517e9fb..3b264b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,31 @@ # Filename: .travis.yml +sudo: required +dist: xenial + language: python cache: pip -# https://github.com/travis-ci/travis-ci/issues/9815 -# Enable 3.7 without globally enabling sudo and dist: xenial for other build jobs -matrix: - include: - - python: 3.7 - dist: xenial - sudo: true + +python: +- '3.7' + install: - pip install --upgrade -r requirements.txt - pip install --upgrade -r requirements-dev.txt + +# Add xvfb service since we have tests that requires GUI +# https://docs.travis-ci.com/user/gui-and-headless-browsers/#using-services-xvfb +services: +- xvfb + script: #- pylint booklib -- pip install -e . && python -m pytest tests +- qmake -v +- pip install -e . && pytest --ignore=tests/ui/window tests notifications: - slack: curious-minds-101:Wkf5gPKQyJalUZ99Oyql0Zav \ No newline at end of file + slack: + rooms: + secure: Su/kx2T4NUiX3p5HdirVhsseYH3sBDiESXo36fCoySqHir+DMEadIFSwGneL9Pxg1OX6QpNnPrawWerc4Bo3uWIH5rqmZdX4hexVDTyG8Y3S2k7bODgRbrPzFIXdT3DequD17qr9veAj8wbfeEJOqvWwvMAMkPtyEvhsRI2RfOvC417lBKlqX/RH72LW1NgbvaM/hcQYDtHqhMdurPJXI7WXGirC1nmt4bPKYfDwewIK+2rH/VUHiXgLpLqZPD0crl3tv0JKvuKv45O2elD4f7j4oEpKp0+DBZLzPlcGHnDdObF2jv3r+vZLqD/SRoMeBwM6tl6qcay6Te2ZLuqGtdj1KmXw2fvo98yDEyUq0sSbBUlOyUBhtLn0qgbBvwpe2YslAuQPdKZABzCiiSv7uU5+TgSvSEq5Rrh5oTBYsfJzb0X9gZWhlZkDb0RhwvEKtQDWmK8j3shxPSSpYAznjvCnNzLywEycGgdU1bk8U9vsWoM/S13BOu+C26cHpTVK7Go4wL3DYrvy/Qx4J26wp1fBnWSbgE1PahkWvNKAj6Sup7hliJc4GukwumEUOuAdu2G0/mk5rKgIFUjswEufSRPzmJLv3xG6xMusJ93+lrddt+wS2d6b7nlnx6MtFV+qkWrtOm9uN8Rot8jW6XcBQdGvrjRluCBdJxA2xAFWnCU= + on_success: always + on_failure: change \ No newline at end of file diff --git a/booklib/ui/config.py b/booklib/ui/config.py index e389dd4..404ddc6 100644 --- a/booklib/ui/config.py +++ b/booklib/ui/config.py @@ -27,6 +27,8 @@ 'category_txt': 'Categories', 'level_txt': 'Level', 'title_txt': 'Title', + 'authors_txt': 'Authors', + 'publisher_txt': 'Publisher', 'ok_btn': 'OK', 'cancel_btn': 'Cancel', }, @@ -58,6 +60,8 @@ 'category_txt': 'Categories', 'level_txt': 'Level', 'title_txt': 'Title', + 'authors_txt': 'Authors', + 'publisher_txt': 'Publisher', 'ok_btn': 'OK', 'cancel_btn': 'Cancel', }, diff --git a/booklib/ui/window/admin.py b/booklib/ui/window/admin.py index d61fb64..e8469cb 100644 --- a/booklib/ui/window/admin.py +++ b/booklib/ui/window/admin.py @@ -5,11 +5,13 @@ """ # Standard libraries +import typing # PyQt5 import PyQt5.QtWidgets as qtw # BookLib +from booklib import config from booklib.ui.config import LABELS from booklib.ui.window.account import AccountWindow from booklib.ui.window.book import BookWindow @@ -20,15 +22,17 @@ class AdminWindow(qtw.QMainWindow): Main admin window. """ - def __init__(self, cfg, *args, **kwargs): + def __init__(self, cfg: config.MenuConfig, *args, **kwargs): super().__init__(*args, **kwargs) self.cfg = cfg self.label_root = __class__.__name__ # Account window + self.account_btn = None self.account_window = None # Book window + self.book_btn = None self.book_window = None self.init_ui() @@ -54,16 +58,16 @@ def init_window_ui(self): grid = qtw.QGridLayout() vbox_side_menu = qtw.QVBoxLayout() # Add account button - account_btn = qtw.QPushButton(labels['account_btn'], self) - account_btn.clicked.connect(self.show_account_window) + self.account_btn = qtw.QPushButton(labels['account_btn'], self) + self.account_btn.clicked.connect(self.show_account_window) # grid.addWidget(account_btn, 1, 0) - vbox_side_menu.addWidget(account_btn) + vbox_side_menu.addWidget(self.account_btn) # Add book button - book_btn = qtw.QPushButton(labels['book_btn'], self) - book_btn.clicked.connect(self.show_book_window) + self.book_btn = qtw.QPushButton(labels['book_btn'], self) + self.book_btn.clicked.connect(self.show_book_window) # grid.addWidget(book_btn, 2, 0) - vbox_side_menu.addWidget(book_btn) + vbox_side_menu.addWidget(self.book_btn) # Add search menu: text bar + button hbox_search_menu = qtw.QHBoxLayout() diff --git a/booklib/ui/window/book.py b/booklib/ui/window/book.py index 9b8c838..181a144 100644 --- a/booklib/ui/window/book.py +++ b/booklib/ui/window/book.py @@ -11,7 +11,7 @@ from booklib.ui.config import LABELS # BookLib -from booklib.models import BookCategoryEnum +from booklib.models import BookCategoryEnum, ReadingLevelEnum class BookInfo: @@ -47,6 +47,17 @@ def __init__(self): categories_layout.addWidget(self.categories_others_qt, 5, 0) self.categories_box_qt.setLayout(categories_layout) + self.reading_level_qt = qtw.QComboBox() + # Add empty string as default. + self.reading_level_qt.addItem('') + for level in ReadingLevelEnum: + self.reading_level_qt.addItem(level.name) + # self.reading_level_qt.activated[str].connect() + + self.title_qt = qtw.QLineEdit() + self.author_qt = qtw.QLineEdit() + self.publisher_qt = qtw.QLineEdit() + class BookWindow(qtw.QDialog): def __init__(self, admin_window, *args, **kwargs): @@ -64,13 +75,21 @@ def init_ui(self): isbn_no = qtw.QLabel(labels['isbn_no_txt']) call_no = qtw.QLabel(labels['call_no_txt']) + title = qtw.QLabel(labels['title_txt']) + authors = qtw.QLabel(labels['authors_txt']) + publisher = qtw.QLabel(labels['publisher_txt']) categories = qtw.QLabel(labels['category_txt']) + reading_level = qtw.QLabel(labels['level_txt']) # Create forms. form_layout = qtw.QFormLayout() form_layout.addRow(isbn_no, self.book.isbn_no_qt) form_layout.addRow(call_no, self.book.call_no_qt) + form_layout.addRow(title, self.book.title_qt) + form_layout.addRow(authors, self.book.author_qt) + form_layout.addRow(publisher, self.book.publisher_qt) form_layout.addRow(categories, self.book.categories_box_qt) + form_layout.addRow(reading_level, self.book.reading_level_qt) # Add confirmation buttons at the bottom. button_box = qtw.QDialogButtonBox() diff --git a/requirements-dev.txt b/requirements-dev.txt index aaa66e1..ab03790 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,4 +2,6 @@ coverage pylint pyqt5-stubs pytest +pytest-qt +pytest-xvfb pytype diff --git a/tests/ui/window/__init__.py b/tests/ui/window/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/ui/window/test_admin.py b/tests/ui/window/test_admin.py new file mode 100644 index 0000000..cfb26b4 --- /dev/null +++ b/tests/ui/window/test_admin.py @@ -0,0 +1,34 @@ +# Filename: tests/ui/window/test_admin.py + +# Standard library +import os + +# PyQt5 +from PyQt5 import QtCore as qtc + +# PyTest-Qt +from pytestqt import qtbot + +# BookLib +from booklib import config +from booklib.ui.window import admin + + +def test_click_account(qtbot): + cfg = config.MenuConfig() + window = admin.AdminWindow(cfg) + qtbot.addWidget(window) + + qtbot.mouseClick(window.account_btn, qtc.Qt.LeftButton) + assert window.account_window.isVisible() + assert not window.isVisible() + + +def test_click_book(qtbot): + cfg = config.MenuConfig() + window = admin.AdminWindow(cfg) + qtbot.addWidget(window) + + qtbot.mouseClick(window.book_btn, qtc.Qt.LeftButton) + assert window.book_window.isVisible() + assert not window.isVisible()