Files
Veronica Berglyd Olsen 5bdbd7c195 Update linting for tests
2025-08-27 21:04:32 +02:00

259 lines
9.2 KiB
Python
Raw Permalink 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 (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
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/>.
""" # noqa
from __future__ import annotations
from datetime import datetime
from pathlib import Path
import pytest
from PyQt6.QtCore import QPoint
from PyQt6.QtGui import QAction
from PyQt6.QtWidgets import QFileDialog, QMenu
from novelwriter import CONFIG, SHARED
from novelwriter.constants import nwFiles
from novelwriter.core.projectdata import NWProjectData
from novelwriter.enum import nwItemClass
from novelwriter.tools.welcome import GuiWelcome
from novelwriter.types import QtMouseLeft
@pytest.mark.gui
def testToolWelcome_Main(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.btnNew.click()
assert welcome.mainStack.currentIndex() == 1
# Revert to project lits
welcome.btnList.click()
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.btnBrowse.click()
assert signal.args and signal.args[0] == fncPath
# qtbot.stop()
welcome.close()
@pytest.mark.gui
def testToolWelcome_Open(qtbot, monkeypatch, nwGUI, fncPath):
"""Test the open tab in the Welcome window."""
monkeypatch.setattr(QMenu, "exec", lambda *a: None)
monkeypatch.setattr(QMenu, "setParent", lambda *a: None)
data1 = NWProjectData(SHARED.project)
data2 = NWProjectData(SHARED.project)
data1.setUuid(None)
data2.setUuid(None)
data1.setName("Project One")
data2.setName("Project Two")
data1.setCurrCounts(12345, 0)
data2.setCurrCounts(54321, 0)
CONFIG.recentProjects.update("/stuff/project_one", data1, 1690000000)
CONFIG.recentProjects.update("/stuff/project_two", data2, 1700000000)
dateOne = CONFIG.localDate(datetime.fromtimestamp(1700000000))
dateTwo = CONFIG.localDate(datetime.fromtimestamp(1690000000))
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, QtMouseLeft, pos=posTwo, delay=10)
assert tabOpen.selectedPath.text() == "Path: /stuff/project_one"
# Double click item
qtbot.mouseClick(vPort, QtMouseLeft, 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, QtMouseLeft, pos=posTwo, delay=10)
assert signal.args and signal.args[0] == Path("/stuff/project_one")
# Press open button
qtbot.mouseClick(vPort, QtMouseLeft, 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.btnOpen.click()
assert signal.args and signal.args[0] == Path("/stuff/project_one")
# Context Menu
def getMenuForPos(pos: QPoint) -> QMenu | None:
tabOpen._openContextMenu(pos)
for obj in tabOpen.children():
if isinstance(obj, QMenu) and obj.objectName() == "ContextMenu":
return obj
return None
qtbot.mouseClick(vPort, QtMouseLeft, 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()
# @pytest.mark.skip
@pytest.mark.gui
def testToolWelcome_New(qtbot, caplog, monkeypatch, nwGUI, fncPath):
"""Test the new project tab in the Welcome window."""
welcome = GuiWelcome(nwGUI)
with qtbot.waitExposed(welcome):
welcome.show()
welcome.btnNew.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.extraWidget.isVisible() 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.extraWidget.isVisible() is False
# Change back to fill blank using the menu
newForm.fillMenu.actions()[0].activate(QAction.ActionEvent.Trigger)
assert newForm._fillMode == newForm.FILL_BLANK
assert newForm.projFill.text() == "Fresh Project"
assert newForm.extraWidget.isVisible() is True
# Creating a project without a name, pops an error
caplog.clear()
welcome.btnCreate.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",
"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:
welcome.btnCreate.click()
assert signal.args and signal.args[0] == projPath
assert (projPath / nwFiles.PROJ_FILE).exists()
# qtbot.stop()
welcome.close()