Files
novelWriter/tests/test_tools/test_tools_welcome.py
T
2024-02-20 12:48:14 +01:00

272 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
novelWriter Welcome Window Tester
===================================
This file is a part of novelWriter
Copyright 20182024, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
import pytest
from pathlib import Path
from datetime import datetime
from pytestqt.qtbot import QtBot
from PyQt5.QtCore import QPoint, Qt
from PyQt5.QtWidgets import QAction, QDialogButtonBox, QFileDialog, QMenu
from novelwriter import CONFIG, SHARED
from novelwriter.enum import nwItemClass
from novelwriter.constants import nwFiles
from novelwriter.tools.welcome import GuiWelcome
@pytest.mark.gui
def testToolWelcome_Main(qtbot: QtBot, monkeypatch, nwGUI, fncPath):
"""Test the main Welcome window."""
welcome = GuiWelcome(nwGUI)
with qtbot.waitExposed(welcome):
# This ensures the paint event is executed
welcome.show()
# By default, the project list is shown
assert welcome.mainStack.currentIndex() == 0
# Show the new project form
welcome.newButton.click()
assert welcome.mainStack.currentIndex() == 1
# Revert to project lits
welcome.tabNew.cancelNewProject.emit()
assert welcome.mainStack.currentIndex() == 0
# Open a project
with monkeypatch.context() as mp:
mp.setattr(SHARED, "getProjectPath", lambda *a, **k: fncPath)
with qtbot.waitSignal(welcome.openProjectRequest) as signal:
welcome.browseButton.click()
assert signal.args and signal.args[0] == fncPath
# qtbot.stop()
welcome.close()
# END Test testToolWelcome_Main
@pytest.mark.gui
def testToolWelcome_Open(qtbot: QtBot, monkeypatch, nwGUI, fncPath):
"""Test the open tab in the Welcome window."""
monkeypatch.setattr(QMenu, "exec_", lambda *a: None)
monkeypatch.setattr(QMenu, "deleteLater", lambda *a: None)
CONFIG.recentProjects.update("/stuff/project_one", "Project One", 12345, 1690000000)
CONFIG.recentProjects.update("/stuff/project_two", "Project Two", 54321, 1700000000)
dateOne = datetime.fromtimestamp(1700000000).strftime("%x")
dateTwo = datetime.fromtimestamp(1690000000).strftime("%x")
welcome = GuiWelcome(nwGUI)
with qtbot.waitExposed(welcome):
welcome.show()
assert welcome.mainStack.currentIndex() == 0
tabOpen = welcome.tabOpen
listModel = tabOpen.listModel
vPort = tabOpen.listWidget.viewport()
posOne = tabOpen.listWidget.rectForIndex(listModel.createIndex(0, 0)).center()
posTwo = tabOpen.listWidget.rectForIndex(listModel.createIndex(1, 0)).center()
# Check items, which should be in opposite order
assert listModel.data(listModel.createIndex(0, 0)) == (
"Project Two", "/stuff/project_two", f"Last Opened: {dateOne}, Word Count: 54.3\u2009k"
)
assert listModel.data(listModel.createIndex(1, 0)) == (
"Project One", "/stuff/project_one", f"Last Opened: {dateTwo}, Word Count: 12.3\u2009k"
)
# Single click item
assert tabOpen.selectedPath.text() == "Path: /stuff/project_two"
qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10)
assert tabOpen.selectedPath.text() == "Path: /stuff/project_one"
# Double click item
qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10)
with monkeypatch.context() as mp:
mp.setattr(welcome, "close", lambda *a: None)
with qtbot.waitSignal(welcome.openProjectRequest, timeout=5000) as signal:
qtbot.mouseDClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10)
assert signal.args and signal.args[0] == Path("/stuff/project_one")
# Press open button
qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posTwo, delay=10)
with monkeypatch.context() as mp:
mp.setattr(welcome, "close", lambda *a: None)
with qtbot.waitSignal(welcome.openProjectRequest, timeout=5000) as signal:
welcome.btnBox.button(QDialogButtonBox.StandardButton.Open).click()
assert signal.args and signal.args[0] == Path("/stuff/project_one")
# Context Menu
def getMenuForPos(pos: QPoint) -> QMenu | None:
nonlocal tabOpen
tabOpen._openContextMenu(pos)
for obj in tabOpen.children():
if isinstance(obj, QMenu) and obj.objectName() == "ContextMenu":
return obj
return None
qtbot.mouseClick(vPort, Qt.MouseButton.LeftButton, pos=posOne, delay=10)
ctxMenu = getMenuForPos(posOne)
assert isinstance(ctxMenu, QMenu)
assert ctxMenu.actions()[0].text() == "Open Project"
assert ctxMenu.actions()[1].text() == "Remove Project"
# Open item from context menu
with monkeypatch.context() as mp:
mp.setattr(welcome, "close", lambda *a: None)
with qtbot.waitSignal(welcome.openProjectRequest, timeout=5000) as signal:
ctxMenu.actions()[0].activate(QAction.ActionEvent.Trigger)
assert signal.args and signal.args[0] == Path("/stuff/project_two")
ctxMenu.setObjectName("")
ctxMenu.deleteLater()
# Delete item from context menu
ctxMenu = getMenuForPos(posOne)
assert isinstance(ctxMenu, QMenu)
ctxMenu.actions()[1].activate(QAction.ActionEvent.Trigger)
assert len(CONFIG.recentProjects.listEntries()) == 1
ctxMenu.setObjectName("")
ctxMenu.deleteLater()
# Check removing entry error handling
assert listModel.data(listModel.createIndex(1, 0)) == ("", "", "")
assert listModel.removeEntry(listModel.createIndex(1, 0)) is False
with monkeypatch.context() as mp:
mp.setattr(listModel, "data", lambda *a: ("a", "b", "c"))
assert listModel.removeEntry(listModel.createIndex(1, 0)) is False
# qtbot.stop()
welcome.close()
# END Test testToolWelcome_Open
@pytest.mark.gui
def testToolWelcome_New(qtbot: QtBot, caplog, monkeypatch, nwGUI, fncPath):
"""Test the new project tab in the Welcome window."""
welcome = GuiWelcome(nwGUI)
with qtbot.waitExposed(welcome):
welcome.show()
welcome.newButton.click()
assert welcome.mainStack.currentIndex() == 1
tabNew = welcome.tabNew
newForm = tabNew.projectForm
# Populate the path
with monkeypatch.context() as mp:
mp.setattr(QFileDialog, "getExistingDirectory", lambda *a, **k: fncPath)
newForm.browsePath.click()
assert newForm.projPath.text() == str(fncPath)
# Turning off root folders should disable notes switch
newForm.addNotes.setChecked(True)
newForm.addPlot.setChecked(False)
newForm.addChar.setChecked(False)
newForm.addWorld.setChecked(False)
newForm._syncSwitches()
assert newForm.addNotes.isChecked() is False
# Change fill info to sample
newForm.fillSample.trigger()
assert newForm._fillMode == newForm.FILL_SAMPLE
assert newForm.projFill.text() == "Example Project"
assert newForm.addNotes.isEnabled() is False
assert newForm.addPlot.isEnabled() is False
assert newForm.addChar.isEnabled() is False
assert newForm.addWorld.isEnabled() is False
assert newForm.numChapters.isEnabled() is False
assert newForm.numScenes.isEnabled() is False
# Change fill info to template
with monkeypatch.context() as mp:
mp.setattr(SHARED, "getProjectPath", lambda *a, **k: fncPath)
newForm.fillCopy.trigger()
assert newForm._fillMode == newForm.FILL_COPY
assert newForm.projFill.text() == f"Template: {fncPath}"
assert newForm.addNotes.isEnabled() is False
assert newForm.addPlot.isEnabled() is False
assert newForm.addChar.isEnabled() is False
assert newForm.addWorld.isEnabled() is False
assert newForm.numChapters.isEnabled() is False
assert newForm.numScenes.isEnabled() is False
# Change back to fill blank using the menu
newForm.browseFill.click()
assert newForm.fillMenu.isVisible() is True
newForm.fillMenu.actions()[0].activate(QAction.ActionEvent.Trigger)
newForm.fillMenu.close()
assert newForm._fillMode == newForm.FILL_BLANK
assert newForm.projFill.text() == "Fresh Project"
assert newForm.addNotes.isEnabled() is True
assert newForm.addPlot.isEnabled() is True
assert newForm.addChar.isEnabled() is True
assert newForm.addWorld.isEnabled() is True
assert newForm.numChapters.isEnabled() is True
assert newForm.numScenes.isEnabled() is True
# Creating a project without a name, pops an error
caplog.clear()
tabNew.createButton.click()
assert "A project name is required." in caplog.text
# Set some more values, and extract data
projPath = fncPath / "Test Project"
newForm.projName.setText("Test Project")
newForm.projAuthor.setText("Jane Smith")
newForm.addPlot.setChecked(True)
newForm.addChar.setChecked(True)
newForm.addWorld.setChecked(True)
newForm.addNotes.setChecked(True)
newForm.numChapters.setValue(10)
newForm.numScenes.setValue(6)
assert newForm.getProjectData() == {
"name": "Test Project",
"author": "Jane Smith",
"language": "en_GB",
"path": str(projPath),
"blank": True,
"sample": False,
"template": None,
"chapters": 10,
"scenes": 6,
"roots": [nwItemClass.PLOT, nwItemClass.CHARACTER, nwItemClass.WORLD],
"notes": True,
}
# Create a project with these values
with qtbot.waitSignal(welcome.openProjectRequest, timeout=5000) as signal:
tabNew.createButton.click()
assert signal.args and signal.args[0] == projPath
assert (projPath / nwFiles.PROJ_FILE).exists()
# qtbot.stop()
welcome.close()
# END Test testToolWelcome_New