Significant improvements to dialog tests
This commit is contained in:
+79
-5
@@ -9,12 +9,22 @@ import shutil
|
||||
from os import path, mkdir
|
||||
from nwdummy import DummyMain
|
||||
|
||||
from PyQt5.QtWidgets import QFileDialog, QMessageBox
|
||||
|
||||
sys.path.insert(1, path.abspath(path.join(path.dirname(__file__), path.pardir)))
|
||||
|
||||
from nw.config import Config # noqa: E402
|
||||
|
||||
##
|
||||
# Core Test Folders
|
||||
##
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def nwTemp():
|
||||
"""A temporary folder for the test session. This folder is
|
||||
presistent after the test so that the status of generated files can
|
||||
be checked. The folder is instead cleared before a new test session.
|
||||
"""
|
||||
testDir = path.dirname(__file__)
|
||||
tempDir = path.join(testDir, "temp")
|
||||
if path.isdir(tempDir):
|
||||
@@ -25,31 +35,51 @@ def nwTemp():
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def nwRef():
|
||||
"""The folder where all the reference files are stored for verifying
|
||||
the results of tests.
|
||||
"""
|
||||
testDir = path.dirname(__file__)
|
||||
refDir = path.join(testDir, "reference")
|
||||
return refDir
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def nwConf(nwRef, nwTemp):
|
||||
theConf = Config()
|
||||
theConf.initConfig(nwRef, nwTemp)
|
||||
return theConf
|
||||
##
|
||||
# novelWriter Objects
|
||||
##
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def tmpConf(nwTemp):
|
||||
"""Create a temporary novelWriter configuration object.
|
||||
"""
|
||||
theConf = Config()
|
||||
theConf.initConfig(nwTemp, nwTemp)
|
||||
theConf.setLastPath("")
|
||||
return theConf
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def nwConf(nwRef, nwTemp):
|
||||
"""Temporary novelWriter configuration used for the dummy instance
|
||||
of novelWriter's main GUI.
|
||||
"""
|
||||
theConf = Config()
|
||||
theConf.initConfig(nwRef, nwTemp)
|
||||
return theConf
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def nwDummy(nwRef, nwTemp, nwConf):
|
||||
"""Create a dummy instance of novelWriter's main GUI class.
|
||||
"""
|
||||
theDummy = DummyMain()
|
||||
theDummy.mainConf = nwConf
|
||||
return theDummy
|
||||
|
||||
##
|
||||
# Temporary Test Folders
|
||||
##
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def nwTempProj(nwTemp):
|
||||
"""A temporary folder for project tests.
|
||||
"""
|
||||
projDir = path.join(nwTemp, "proj")
|
||||
if not path.isdir(projDir):
|
||||
mkdir(projDir)
|
||||
@@ -57,6 +87,8 @@ def nwTempProj(nwTemp):
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def nwTempGUI(nwTemp):
|
||||
"""A temporary folder for GUI tests.
|
||||
"""
|
||||
guiDir = path.join(nwTemp, "gui")
|
||||
if not path.isdir(guiDir):
|
||||
mkdir(guiDir)
|
||||
@@ -64,6 +96,8 @@ def nwTempGUI(nwTemp):
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def nwTempBuild(nwTemp):
|
||||
"""A temporary folder for build tests.
|
||||
"""
|
||||
buildDir = path.join(nwTemp, "build")
|
||||
if not path.isdir(buildDir):
|
||||
mkdir(buildDir)
|
||||
@@ -71,6 +105,8 @@ def nwTempBuild(nwTemp):
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def nwFuncTemp(nwTemp):
|
||||
"""A temporary folder for a single test function.
|
||||
"""
|
||||
funcDir = path.join(nwTemp, "ftemp")
|
||||
if path.isdir(funcDir):
|
||||
shutil.rmtree(funcDir)
|
||||
@@ -81,8 +117,14 @@ def nwFuncTemp(nwTemp):
|
||||
shutil.rmtree(funcDir)
|
||||
return
|
||||
|
||||
##
|
||||
# Temp Folders for Projects
|
||||
##
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def nwMinimal(nwTemp):
|
||||
"""A minimal novelWriter example project.
|
||||
"""
|
||||
testDir = path.dirname(__file__)
|
||||
minimalStore = path.join(testDir, "minimal")
|
||||
minimalDir = path.join(nwTemp, "minimal")
|
||||
@@ -102,6 +144,9 @@ def nwMinimal(nwTemp):
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def nwLipsum(nwTemp):
|
||||
"""A medium sized novelWriter example project with a lot of Lorem
|
||||
Ipsum dummy text.
|
||||
"""
|
||||
testDir = path.dirname(__file__)
|
||||
lipsumStore = path.join(testDir, "lipsum")
|
||||
lipsumDir = path.join(nwTemp, "lipsum")
|
||||
@@ -121,6 +166,8 @@ def nwLipsum(nwTemp):
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def nwOldProj(nwTemp):
|
||||
"""A minimal movelWriter project using the old folder structure.
|
||||
"""
|
||||
testDir = path.dirname(__file__)
|
||||
oldProjStore = path.join(testDir, "oldproj")
|
||||
oldProjDir = path.join(nwTemp, "oldproj")
|
||||
@@ -131,3 +178,30 @@ def nwOldProj(nwTemp):
|
||||
if path.isdir(oldProjDir):
|
||||
shutil.rmtree(oldProjDir)
|
||||
return
|
||||
|
||||
##
|
||||
# Monkey Patch Dialogs
|
||||
##
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def mnkQtDialogs(monkeypatch, nwTemp):
|
||||
"""Mock Qt dialog functions to prevent GUI blocking while testing.
|
||||
"""
|
||||
monkeypatch.setattr(
|
||||
QFileDialog, "getExistingDirectory", lambda *args, **kwargs: nwTemp
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
QMessageBox, "question", lambda *args, **kwargs: QMessageBox.Yes
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
QMessageBox, "information", lambda *args, **kwargs: None
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
QMessageBox, "warning", lambda *args, **kwargs: None
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
QMessageBox, "critical", lambda *args, **kwargs: None
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
+84
-16
@@ -7,13 +7,14 @@ import pytest
|
||||
import json
|
||||
|
||||
from shutil import copyfile
|
||||
from nwtools import cmpFiles
|
||||
from nwtools import cmpFiles, getGuiItem
|
||||
|
||||
from os import path
|
||||
|
||||
from PyQt5.QtCore import Qt, QItemSelectionModel
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialogButtonBox, QTreeWidgetItem, QListWidgetItem, QDialog
|
||||
QDialogButtonBox, QTreeWidgetItem, QListWidgetItem, QDialog, QAction,
|
||||
QMessageBox
|
||||
)
|
||||
|
||||
from nw.gui import (
|
||||
@@ -28,22 +29,34 @@ keyDelay = 2
|
||||
stepDelay = 20
|
||||
|
||||
@pytest.mark.gui
|
||||
def testProjectEditor(qtbot, nwFuncTemp, nwTempGUI, nwRef, nwTemp):
|
||||
def testProjectSettings(qtbot, monkeypatch, nwFuncTemp, nwTempGUI, nwRef, nwTemp):
|
||||
nwGUI = nw.main(["--testmode", "--config=%s" % nwFuncTemp, "--data=%s" % nwTemp])
|
||||
qtbot.addWidget(nwGUI)
|
||||
nwGUI.show()
|
||||
qtbot.waitForWindowShown(nwGUI)
|
||||
qtbot.wait(stepDelay)
|
||||
|
||||
# Create new, save, open project
|
||||
# Check that we cannot open when there is no project
|
||||
nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger)
|
||||
assert getGuiItem("GuiProjectSettings") is None
|
||||
|
||||
# Create new project
|
||||
nwGUI.theProject.projTree.setSeed(42)
|
||||
assert nwGUI.newProject({"projPath": nwFuncTemp}, True)
|
||||
nwGUI.mainConf.backupPath = nwFuncTemp
|
||||
|
||||
projEdit = GuiProjectSettings(nwGUI, nwGUI.theProject)
|
||||
# Get the dialog object
|
||||
monkeypatch.setattr(GuiProjectSettings, "exec_", lambda *args: None)
|
||||
monkeypatch.setattr(GuiProjectSettings, "result", lambda *args: QDialog.Accepted)
|
||||
nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger)
|
||||
qtbot.waitUntil(lambda: getGuiItem("GuiProjectSettings") is not None, timeout=1000)
|
||||
|
||||
projEdit = getGuiItem("GuiProjectSettings")
|
||||
assert isinstance(projEdit, GuiProjectSettings)
|
||||
projEdit.show()
|
||||
qtbot.addWidget(projEdit)
|
||||
|
||||
# Main settings
|
||||
qtbot.wait(stepDelay)
|
||||
projEdit.tabMain.editName.setText("")
|
||||
for c in "Project Name":
|
||||
@@ -199,6 +212,10 @@ def testWritingStatsExport(qtbot, nwFuncTemp, nwTemp):
|
||||
assert nwGUI.closeProject()
|
||||
qtbot.wait(stepDelay)
|
||||
|
||||
# Check that we cannot open when there is no project
|
||||
nwGUI.mainMenu.aWritingStats.activate(QAction.Trigger)
|
||||
assert getGuiItem("GuiWritingStats") is None
|
||||
|
||||
assert nwGUI.openProject(nwFuncTemp)
|
||||
qtbot.wait(stepDelay)
|
||||
|
||||
@@ -239,8 +256,11 @@ def testWritingStatsExport(qtbot, nwFuncTemp, nwTemp):
|
||||
qtbot.wait(stepDelay)
|
||||
|
||||
nwGUI.mainConf.lastPath = nwFuncTemp
|
||||
sessLog = GuiWritingStats(nwGUI, nwGUI.theProject)
|
||||
sessLog.show()
|
||||
nwGUI.mainMenu.aWritingStats.activate(QAction.Trigger)
|
||||
qtbot.waitUntil(lambda: getGuiItem("GuiWritingStats") is not None, timeout=1000)
|
||||
|
||||
sessLog = getGuiItem("GuiWritingStats")
|
||||
assert isinstance(sessLog, GuiWritingStats)
|
||||
qtbot.wait(stepDelay)
|
||||
|
||||
assert sessLog._saveData(sessLog.FMT_CSV)
|
||||
@@ -337,17 +357,29 @@ def testWritingStatsExport(qtbot, nwFuncTemp, nwTemp):
|
||||
nwGUI.closeMain()
|
||||
|
||||
@pytest.mark.gui
|
||||
def testAboutBox(qtbot, nwFuncTemp, nwTemp):
|
||||
def testAboutBox(qtbot, monkeypatch, nwFuncTemp, nwTemp):
|
||||
nwGUI = nw.main(["--testmode", "--config=%s" % nwFuncTemp, "--data=%s" % nwTemp])
|
||||
qtbot.addWidget(nwGUI)
|
||||
nwGUI.show()
|
||||
qtbot.waitForWindowShown(nwGUI)
|
||||
qtbot.wait(stepDelay)
|
||||
|
||||
msgAbout = GuiAbout(nwGUI)
|
||||
# NW About
|
||||
monkeypatch.setattr(GuiAbout, "exec_", lambda *args: None)
|
||||
nwGUI.mainMenu.aAboutNW.activate(QAction.Trigger)
|
||||
qtbot.waitUntil(lambda: getGuiItem("GuiAbout") is not None, timeout=1000)
|
||||
|
||||
msgAbout = getGuiItem("GuiAbout")
|
||||
assert isinstance(msgAbout, GuiAbout)
|
||||
msgAbout.show()
|
||||
|
||||
assert msgAbout.pageAbout.document().characterCount() > 100
|
||||
assert msgAbout.pageLicense.document().characterCount() > 100
|
||||
|
||||
# Qt About
|
||||
monkeypatch.setattr(QMessageBox, "aboutQt", lambda *args, **kwargs: None)
|
||||
nwGUI.mainMenu.aAboutQt.activate(QAction.Trigger)
|
||||
|
||||
# qtbot.stopForInteraction()
|
||||
msgAbout._doClose()
|
||||
nwGUI.closeMain()
|
||||
@@ -361,11 +393,20 @@ def testBuildTool(qtbot, nwTempBuild, nwLipsum, nwRef, nwTemp):
|
||||
qtbot.waitForWindowShown(nwGUI)
|
||||
qtbot.wait(stepDelay)
|
||||
|
||||
assert nwGUI.openProject(nwLipsum)
|
||||
# Check that we cannot open when there is no project
|
||||
nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger)
|
||||
assert getGuiItem("GuiBuildNovel") is None
|
||||
|
||||
# Open a project
|
||||
assert nwGUI.openProject(nwLipsum)
|
||||
nwGUI.mainConf.lastPath = nwLipsum
|
||||
|
||||
nwBuild = GuiBuildNovel(nwGUI, nwGUI.theProject)
|
||||
# Open the tool
|
||||
nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger)
|
||||
qtbot.waitUntil(lambda: getGuiItem("GuiBuildNovel") is not None, timeout=1000)
|
||||
|
||||
nwBuild = getGuiItem("GuiBuildNovel")
|
||||
assert isinstance(nwBuild, GuiBuildNovel)
|
||||
|
||||
# Default Settings
|
||||
qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)
|
||||
@@ -764,7 +805,7 @@ def testNewProjectWizard(qtbot, nwLipsum, nwTemp):
|
||||
nwGUI.closeMain()
|
||||
|
||||
@pytest.mark.gui
|
||||
def testLoadProject(qtbot, nwMinimal, nwTemp):
|
||||
def testLoadProject(qtbot, monkeypatch, nwMinimal, nwTemp):
|
||||
nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % nwTemp])
|
||||
qtbot.addWidget(nwGUI)
|
||||
nwGUI.show()
|
||||
@@ -774,7 +815,13 @@ def testLoadProject(qtbot, nwMinimal, nwTemp):
|
||||
assert nwGUI.openProject(nwMinimal)
|
||||
assert nwGUI.closeProject()
|
||||
|
||||
nwLoad = GuiProjectLoad(nwGUI)
|
||||
monkeypatch.setattr(GuiProjectLoad, "exec_", lambda *args: None)
|
||||
monkeypatch.setattr(GuiProjectLoad, "result", lambda *args: QDialog.Accepted)
|
||||
nwGUI.mainMenu.aOpenProject.activate(QAction.Trigger)
|
||||
qtbot.waitUntil(lambda: getGuiItem("GuiProjectLoad") is not None, timeout=1000)
|
||||
|
||||
nwLoad = getGuiItem("GuiProjectLoad")
|
||||
assert isinstance(nwLoad, GuiProjectLoad)
|
||||
nwLoad.show()
|
||||
|
||||
recentCount = nwLoad.listBox.topLevelItemCount()
|
||||
@@ -793,6 +840,7 @@ def testLoadProject(qtbot, nwMinimal, nwTemp):
|
||||
assert nwLoad.openPath == selPath
|
||||
assert nwLoad.openState == nwLoad.OPEN_STATE
|
||||
|
||||
# Just create a new project load from scratch for the rest of the test
|
||||
del nwLoad
|
||||
nwLoad = GuiProjectLoad(nwGUI)
|
||||
nwLoad.show()
|
||||
@@ -815,7 +863,7 @@ def testLoadProject(qtbot, nwMinimal, nwTemp):
|
||||
nwGUI.closeMain()
|
||||
|
||||
@pytest.mark.gui
|
||||
def testPreferences(qtbot, nwMinimal, nwTemp, nwRef, tmpConf):
|
||||
def testPreferences(qtbot, monkeypatch, mnkQtDialogs, nwMinimal, nwTemp, nwRef, tmpConf):
|
||||
nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % nwTemp])
|
||||
qtbot.addWidget(nwGUI)
|
||||
nwGUI.show()
|
||||
@@ -823,11 +871,17 @@ def testPreferences(qtbot, nwMinimal, nwTemp, nwRef, tmpConf):
|
||||
qtbot.wait(stepDelay)
|
||||
|
||||
assert nwGUI.openProject(nwMinimal)
|
||||
nwPrefs = GuiPreferences(nwGUI, nwGUI.theProject)
|
||||
|
||||
monkeypatch.setattr(GuiPreferences, "exec_", lambda *args: None)
|
||||
monkeypatch.setattr(GuiPreferences, "result", lambda *args: QDialog.Accepted)
|
||||
nwGUI.mainMenu.aPreferences.activate(QAction.Trigger)
|
||||
qtbot.waitUntil(lambda: getGuiItem("GuiPreferences") is not None, timeout=1000)
|
||||
|
||||
nwPrefs = getGuiItem("GuiPreferences")
|
||||
assert isinstance(nwPrefs, GuiPreferences)
|
||||
nwPrefs.show()
|
||||
|
||||
# Override Config
|
||||
tmpConf.blockGUI = False
|
||||
tmpConf.confPath = nwMinimal
|
||||
nwGUI.mainConf = tmpConf
|
||||
nwPrefs.mainConf = tmpConf
|
||||
@@ -991,3 +1045,17 @@ def testQuotesDialog(qtbot, nwMinimal, nwTemp):
|
||||
nwQuot.close()
|
||||
nwGUI.closeMain()
|
||||
nwGUI.close()
|
||||
|
||||
@pytest.mark.gui
|
||||
def testDialogsOpenClose(qtbot, mnkQtDialogs, nwMinimal, nwTemp):
|
||||
nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % nwTemp, nwMinimal])
|
||||
qtbot.addWidget(nwGUI)
|
||||
nwGUI.show()
|
||||
qtbot.waitForWindowShown(nwGUI)
|
||||
qtbot.wait(stepDelay)
|
||||
|
||||
assert nwGUI.selectProjectPath() == nwTemp
|
||||
|
||||
# qtbot.stopForInteraction()
|
||||
nwGUI.closeMain()
|
||||
nwGUI.close()
|
||||
|
||||
@@ -223,6 +223,10 @@ def testDocEditor(qtbot, nwFuncTemp, nwTempGUI, nwRef, nwTemp):
|
||||
qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay)
|
||||
qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
|
||||
|
||||
# Trigger autosaves before making more changes
|
||||
nwGUI._autoSaveDocument()
|
||||
nwGUI._autoSaveProject()
|
||||
|
||||
# Select the 'New Scene' file
|
||||
nwGUI.setFocus(1)
|
||||
nwGUI.treeView.clearSelection()
|
||||
|
||||
@@ -580,9 +580,9 @@ def testOrphanedFiles(nwDummy, nwLipsum):
|
||||
assert theProject.closeProject()
|
||||
|
||||
@pytest.mark.project
|
||||
def testOldProject(nwDummy, nwOldProj):
|
||||
def testOldProject(nwDummy, nwOldProj, mnkQtDialogs):
|
||||
theProject = NWProject(nwDummy)
|
||||
theProject.mainConf.blockGUI = False
|
||||
theProject.mainConf.showGUI = False
|
||||
|
||||
# Create dummy files for known legacy files
|
||||
deleteFiles = [
|
||||
|
||||
Reference in New Issue
Block a user