# -*- coding: utf-8 -*- """ novelWriter – Main GUI Editor Class Tester ========================================== This file is a part of novelWriter Copyright 2018–2021, 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 . """ import pytest import os from shutil import copyfile from tools import cmpFiles from PyQt5.QtCore import Qt from PyQt5.QtGui import QTextCursor from PyQt5.QtWidgets import QAction, QMessageBox from nw.constants import nwItemType, nwDocAction keyDelay = 2 typeDelay = 1 stepDelay = 20 @pytest.mark.gui def testGuiEditor_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj, refDir, outDir): """Test the document editor. """ # Block message box monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes) # Create new, save, close project nwGUI.theProject.projTree.setSeed(42) assert nwGUI.newProject({"projPath": fncProj}) assert nwGUI.saveProject() assert nwGUI.closeProject() assert len(nwGUI.theProject.projTree) == 0 assert len(nwGUI.theProject.projTree._treeOrder) == 0 assert len(nwGUI.theProject.projTree._treeRoots) == 0 assert nwGUI.theProject.projTree.trashRoot() is None assert nwGUI.theProject.projPath is None assert nwGUI.theProject.projMeta is None assert nwGUI.theProject.projFile == "nwProject.nwx" assert nwGUI.theProject.projName == "" assert nwGUI.theProject.bookTitle == "" assert len(nwGUI.theProject.bookAuthors) == 0 assert not nwGUI.theProject.spellCheck # Check the files projFile = os.path.join(fncProj, "nwProject.nwx") testFile = os.path.join(outDir, "guiEditor_Main_Initial_nwProject.nwx") compFile = os.path.join(refDir, "guiEditor_Main_Initial_nwProject.nwx") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) qtbot.wait(stepDelay) # qtbot.stopForInteraction() # Re-open project assert nwGUI.openProject(fncProj) qtbot.wait(stepDelay) # Check that we loaded the data assert len(nwGUI.theProject.projTree) == 8 assert len(nwGUI.theProject.projTree._treeOrder) == 8 assert len(nwGUI.theProject.projTree._treeRoots) == 4 assert nwGUI.theProject.projTree.trashRoot() is None assert nwGUI.theProject.projPath == fncProj assert nwGUI.theProject.projMeta == os.path.join(fncProj, "meta") assert nwGUI.theProject.projFile == "nwProject.nwx" assert nwGUI.theProject.projName == "New Project" assert nwGUI.theProject.bookTitle == "" assert len(nwGUI.theProject.bookAuthors) == 0 assert not nwGUI.theProject.spellCheck # Check that tree items have been created assert nwGUI.treeView._getTreeItem("73475cb40a568") is not None assert nwGUI.treeView._getTreeItem("25fc0e7096fc6") is not None assert nwGUI.treeView._getTreeItem("31489056e0916") is not None assert nwGUI.treeView._getTreeItem("98010bd9270f9") is not None assert nwGUI.treeView._getTreeItem("0e17daca5f3e1") is not None assert nwGUI.treeView._getTreeItem("44cb730c42048") is not None assert nwGUI.treeView._getTreeItem("71ee45a3c0db9") is not None assert nwGUI.treeView._getTreeItem("811786ad1ae74") is not None nwGUI.mainMenu.aSpellCheck.setChecked(True) assert nwGUI.mainMenu._toggleSpellCheck() # Change some settings nwGUI.mainConf.hideHScroll = True nwGUI.mainConf.hideVScroll = True nwGUI.mainConf.scrollPastEnd = True nwGUI.mainConf.autoScrollPos = 80 nwGUI.mainConf.autoScroll = True # Add a Character File nwGUI.setFocus(1) nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem("71ee45a3c0db9").setSelected(True) nwGUI.treeView.newTreeItem(nwItemType.FILE, None) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.setFocus(2) qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay) for c in "# Jane Doe": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@tag: Jane": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "This is a file about Jane.": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) # Add a Plot File nwGUI.setFocus(1) nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem("44cb730c42048").setSelected(True) nwGUI.treeView.newTreeItem(nwItemType.FILE, None) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.setFocus(2) qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay) for c in "# Main Plot": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@tag: MainPlot": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "This is a file detailing the main plot.": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) # Add a World File nwGUI.setFocus(1) nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem("811786ad1ae74").setSelected(True) nwGUI.treeView.newTreeItem(nwItemType.FILE, None) assert nwGUI.openSelectedItem() # Add Some Text nwGUI.docEditor.replaceText("Hello World!") assert nwGUI.docEditor.getText() == "Hello World!" nwGUI.docEditor.replaceText("") # Type something into the document nwGUI.setFocus(2) qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay) for c in "# Main Location": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@tag: Home": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "This is a file describing Jane's home.": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) 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() nwGUI.treeView._getTreeItem("73475cb40a568").setExpanded(True) nwGUI.treeView._getTreeItem("31489056e0916").setExpanded(True) nwGUI.treeView._getTreeItem("0e17daca5f3e1").setSelected(True) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.setFocus(2) qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay) for c in "# Novel": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "## Chapter": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@pov: Jane": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@plot: MainPlot": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "### Scene": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "% How about a comment?": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@pov: Jane": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@plot: MainPlot": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@location: Home": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "#### Some Section": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@char: Jane": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "This is a paragraph of dummy text.": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in ( "This is another paragraph of much longer dummy text. " "It is in fact 1 very very DUMB dummy text! " ): qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "We can also try replacing \"quotes\", even single 'quotes' are replaced. ": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "Isn't that nice? ": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "We can hyphen-ate, make dashes -- and even longer dashes --- if we want. ": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "Ellipsis? Not a problem either ... ": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "How about three hyphens - -": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Left, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Backspace, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Right, delay=keyDelay) for c in "- for long dash? It works too.": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "\"Full line double quoted text.\"": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "'Full line single quoted text.'": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.wait(stepDelay) nwGUI.docEditor.wCounter.run() qtbot.wait(stepDelay) # Save the document assert nwGUI.docEditor.docChanged assert nwGUI.saveDocument() assert not nwGUI.docEditor.docChanged qtbot.wait(stepDelay) nwGUI.rebuildIndex() qtbot.wait(stepDelay) # Open and view the edited document nwGUI.setFocus(3) assert nwGUI.openDocument("0e17daca5f3e1") assert nwGUI.viewDocument("0e17daca5f3e1") qtbot.wait(stepDelay) assert nwGUI.saveProject() assert nwGUI.closeDocViewer() qtbot.wait(stepDelay) # Check a Quick Create and Delete assert nwGUI.treeView.newTreeItem(nwItemType.FILE, None) newHandle = nwGUI.treeView.getSelectedHandle() assert nwGUI.theProject.projTree["2858dcd1057d3"] is not None assert nwGUI.treeView.deleteItem() assert nwGUI.treeView.setSelectedHandle(newHandle) assert nwGUI.treeView.deleteItem() assert nwGUI.theProject.projTree["2fca346db6561"] is not None # Trash assert nwGUI.saveProject() # Check the files projFile = os.path.join(fncProj, "nwProject.nwx") testFile = os.path.join(outDir, "guiEditor_Main_Final_nwProject.nwx") compFile = os.path.join(refDir, "guiEditor_Main_Final_nwProject.nwx") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) projFile = os.path.join(fncProj, "content", "031b4af5197ec.nwd") testFile = os.path.join(outDir, "guiEditor_Main_Final_031b4af5197ec.nwd") compFile = os.path.join(refDir, "guiEditor_Main_Final_031b4af5197ec.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) projFile = os.path.join(fncProj, "content", "1a6562590ef19.nwd") testFile = os.path.join(outDir, "guiEditor_Main_Final_1a6562590ef19.nwd") compFile = os.path.join(refDir, "guiEditor_Main_Final_1a6562590ef19.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) projFile = os.path.join(fncProj, "content", "0e17daca5f3e1.nwd") testFile = os.path.join(outDir, "guiEditor_Main_Final_0e17daca5f3e1.nwd") compFile = os.path.join(refDir, "guiEditor_Main_Final_0e17daca5f3e1.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) projFile = os.path.join(fncProj, "content", "41cfc0d1f2d12.nwd") testFile = os.path.join(outDir, "guiEditor_Main_Final_41cfc0d1f2d12.nwd") compFile = os.path.join(refDir, "guiEditor_Main_Final_41cfc0d1f2d12.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) # qtbot.stopForInteraction() # END Test testGuiEditor_Main @pytest.mark.gui def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum): """Test the document editor search functionality. """ # Block message box monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes) nwGUI.theProject.projTree.setSeed(42) assert nwGUI.openProject(nwLipsum) assert nwGUI.openDocument("4c4f28287af27") origText = nwGUI.docEditor.getText() qtbot.wait(stepDelay) # Select the Word "est" assert nwGUI.docEditor.setCursorPosition(618) nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor) theCursor = nwGUI.docEditor.textCursor() assert theCursor.selectedText() == "est" # Activate Search nwGUI.mainMenu.aFind.activate(QAction.Trigger) assert nwGUI.docEditor.docSearch.isVisible() assert nwGUI.docEditor.docSearch.getSearchText() == "est" # Find Next by Enter monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: True) qtbot.keyClick(nwGUI.docEditor.docSearch.searchBox, Qt.Key_Return, delay=keyDelay) assert abs(nwGUI.docEditor.getCursorPosition() - 1272) < 3 # Find Next by Button qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay) assert abs(nwGUI.docEditor.getCursorPosition() - 1486) < 3 # Activate Loop Search nwGUI.docEditor.docSearch.toggleLoop.activate(QAction.Trigger) assert nwGUI.docEditor.docSearch.toggleLoop.isChecked() assert nwGUI.docEditor.docSearch.doLoop # Find Next by Menu Search > Find Next nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3 # Close Search nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger) assert not nwGUI.docEditor.docSearch.isVisible() assert nwGUI.docEditor.setCursorPosition(15) # Toggle Search Again with Header Button qtbot.mouseClick(nwGUI.docEditor.docHeader.searchButton, Qt.LeftButton, delay=keyDelay) assert nwGUI.docEditor.docSearch.setSearchText("") assert nwGUI.docEditor.docSearch.isVisible() # Enable RegEx Search nwGUI.docEditor.docSearch.toggleRegEx.activate(QAction.Trigger) assert nwGUI.docEditor.docSearch.toggleRegEx.isChecked() assert nwGUI.docEditor.docSearch.isRegEx # Set Invalid RegEx assert nwGUI.docEditor.docSearch.setSearchText(r"\bSus[") qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay) assert nwGUI.docEditor.getCursorPosition() < 3 # No result # Set Valid RegEx assert nwGUI.docEditor.docSearch.setSearchText(r"\bSus") qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay) assert abs(nwGUI.docEditor.getCursorPosition() - 196) < 3 # Find Next and then Prev nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) assert abs(nwGUI.docEditor.getCursorPosition() - 297) < 3 nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger) assert abs(nwGUI.docEditor.getCursorPosition() - 196) < 3 # Make RegEx Case Sensitive nwGUI.docEditor.docSearch.toggleCase.activate(QAction.Trigger) assert nwGUI.docEditor.docSearch.toggleCase.isChecked() assert nwGUI.docEditor.docSearch.isCaseSense # Find Next (One Result) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) assert abs(nwGUI.docEditor.getCursorPosition() - 599) < 3 nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) assert abs(nwGUI.docEditor.getCursorPosition() - 599) < 3 # Trigger Replace nwGUI.mainMenu.aReplace.activate(QAction.Trigger) assert nwGUI.docEditor.docSearch.setReplaceText("foo") # Disable RegEx Case Sensitive nwGUI.docEditor.docSearch.toggleCase.activate(QAction.Trigger) assert not nwGUI.docEditor.docSearch.toggleCase.isChecked() assert not nwGUI.docEditor.docSearch.isCaseSense # Toggle Replace Preserve Case nwGUI.docEditor.docSearch.toggleMatchCap.activate(QAction.Trigger) assert nwGUI.docEditor.docSearch.toggleMatchCap.isChecked() assert nwGUI.docEditor.docSearch.doMatchCap # Replace "Sus" with "Foo" via Menu nwGUI.mainMenu.aReplaceNext.activate(QAction.Trigger) assert nwGUI.docEditor.getText()[596:607] == "Foopendisse" # Find Next to Loop File nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) # Replace "sus" with "foo" via Replace Button qtbot.mouseClick(nwGUI.docEditor.docSearch.replaceButton, Qt.LeftButton, delay=keyDelay) assert nwGUI.docEditor.getText()[193:201] == "foocipit" # Revert Last Two Replaces assert nwGUI.docEditor.docAction(nwDocAction.UNDO) assert nwGUI.docEditor.docAction(nwDocAction.UNDO) assert nwGUI.docEditor.getText() == origText # Disable RegEx Search nwGUI.docEditor.docSearch.toggleRegEx.activate(QAction.Trigger) assert not nwGUI.docEditor.docSearch.toggleRegEx.isChecked() assert not nwGUI.docEditor.docSearch.isRegEx # Close Search and Select "est" Again nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger) assert nwGUI.docEditor.setCursorPosition(618) nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor) theCursor = nwGUI.docEditor.textCursor() assert theCursor.selectedText() == "est" # Activate Search Again nwGUI.mainMenu.aFind.activate(QAction.Trigger) assert nwGUI.docEditor.docSearch.isVisible() assert nwGUI.docEditor.docSearch.getSearchText() == "est" # Enable Full Word Search nwGUI.docEditor.docSearch.toggleWord.activate(QAction.Trigger) assert nwGUI.docEditor.docSearch.toggleWord.isChecked() assert nwGUI.docEditor.docSearch.isWholeWord # Only One Match nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3 nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3 # Enable Next Doc Search nwGUI.docEditor.docSearch.toggleProject.activate(QAction.Trigger) assert nwGUI.docEditor.docSearch.toggleProject.isChecked() assert nwGUI.docEditor.docSearch.doNextFile # Next Match nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) assert nwGUI.docEditor.theHandle == "2426c6f0ca922" # Next document nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3 nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) assert abs(nwGUI.docEditor.getCursorPosition() - 1127) < 3 # Toggle Replace nwGUI.docEditor._beginReplace() # MonkeyPatch the focus cycle. We can't really test this very well, other than # check that the tabs aren't captured when the main editor has focus monkeypatch.setattr(nwGUI.docEditor, "hasFocus", lambda: True) monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: False) monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: False) assert not nwGUI.docEditor.focusNextPrevChild(True) monkeypatch.setattr(nwGUI.docEditor, "hasFocus", lambda: False) monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: True) monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: False) assert nwGUI.docEditor.focusNextPrevChild(True) monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: False) monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: True) assert nwGUI.docEditor.focusNextPrevChild(True) # qtbot.stopForInteraction() # END Test testGuiEditor_Search