Repository: nvaccess/nvda

Issue:
Lots of intermittent errors while using Microsoft Edge with NVDA
<!-- Please read the text in this edit field before filling it in.
Please thoroughly read NVDA's wiki article on how to fill in this template, including how to provide the required files.
Issues may be closed if the required information is not present.
https://github.com/nvaccess/nvda/wiki/Github-issue-template-explanation-and-examples
Please also note that the NVDA project has a Citizen and Contributor Code of Conduct which can be found at https://github.com/nvaccess/nvda/blob/master/CODE_OF_CONDUCT.md. NV Access expects that all contributors and other community members read and abide by the rules set out in this document while participating or contributing to this project. This includes creating or commenting on issues and pull requests. 
-->

### Steps to reproduce:
1. Install edge beta/dev/caneri
2. Install NVDA latest snapshot
3. Turn on NVDA
4. Open edge
5. Navigate casually and observe
### Actual behavior:
Whenever we navigate the web or open the edge or go to the address bar, we get tons of errors and error sounds
### Expected behavior:
No errors should be thrown
### System configuration
#### NVDA installed/portable/running from source:
Installed
#### NVDA version:
Latest alpha snapshot
#### Windows version:
Win 10 21332
#### Name and version of other software in use when reproducing the issue:
Edge
#### Other information about your system:
I'm attaching the logs which I got while browsing the web, opening edge and going to address bar.
### Other questions
#### Does the issue still occur after restarting your computer?
yes, always
#### Have you tried any other versions of NVDA? If so, please report their behaviors.
No
#### If add-ons are disabled, is your problem still occurring?
Yes
#### Did you try to run the COM registry fixing tool in NVDA menu / tools?
Yes
[edge.txt](https://github.com/nvaccess/nvda/files/6158389/edge.txt)
[Log1.txt](https://github.com/nvaccess/nvda/files/6158450/Log1.txt)
[Log2.txt](https://github.com/nvaccess/nvda/files/6158453/Log2.txt)




Discussion:
@akash07k can you still reproduce this?
Yes, It still reproduces

On 5/28/21, Leonard de Ruijter ***@***.***> wrote:
> @akash07k can you still reproduce this?
>
> --
> You are receiving this because you were mentioned.
> Reply to this email directly or view it on GitHub:
> https://github.com/nvaccess/nvda/issues/12189#issuecomment-850193710

Could you test the try build for #12475?
Sure, please give me some time.

On 5/28/21, Leonard de Ruijter ***@***.***> wrote:
> Could you test the try build for #12475?
>
> --
> You are receiving this because you were mentioned.
> Reply to this email directly or view it on GitHub:
> https://github.com/nvaccess/nvda/issues/12189#issuecomment-850262880

Hi, I can't find the link to download the try build, can you please
let me know that where do I find that?

On 5/28/21, Akash Kakkar ***@***.***> wrote:
> Sure, please give me some time.
>
> On 5/28/21, Leonard de Ruijter ***@***.***> wrote:
>> Could you test the try build for #12475?
>>
>> --
>> You are receiving this because you were mentioned.
>> Reply to this email directly or view it on GitHub:
>> https://github.com/nvaccess/nvda/issues/12189#issuecomment-850262880
>

Here it is:
[nvda_snapshot_pr12475-22946,37f5649f.exe](https://ci.appveyor.com/api/buildjobs/xohn2wgijbs21s34/artifacts/output%2Fnvda_snapshot_pr12475-22946%2C37f5649f.exe)



Yes, the issue is fixed with this try build.
thanks a lot for your work

On 5/29/21, Cyrille Bougot ***@***.***> wrote:
> Here it is:
> [nvda_snapshot_pr12475-22946,37f5649f.exe](https://ci.appveyor.com/api/buildjobs/xohn2wgijbs21s34/artifacts/output%2Fnvda_snapshot_pr12475-22946%2C37f5649f.exe)
>
>
>
>
> --
> You are receiving this because you were mentioned.
> Reply to this email directly or view it on GitHub:
> https://github.com/nvaccess/nvda/issues/12189#issuecomment-850662831


Resolving patch:
diff --git a/source/NVDAObjects/UIA/__init__.py b/source/NVDAObjects/UIA/__init__.py
--- a/source/NVDAObjects/UIA/__init__.py
+++ b/source/NVDAObjects/UIA/__init__.py
@@ -940,6 +940,9 @@ def findOverlayClasses(self,clsList):
 				clsList.append(spartanEdge.EdgeList)
 			else:
 				clsList.append(spartanEdge.EdgeNode)
+		elif self.windowClassName == "Chrome_WidgetWin_1" and self.UIATextPattern:
+			from . import chromium
+			clsList.append(chromium.ChromiumUIA)
 		elif self.windowClassName == "Chrome_RenderWidgetHostHWND":
 			from . import chromium
 			from . import web
@@ -1264,9 +1267,12 @@ def _get_UIALegacyIAccessiblePattern(self):
 		return self.UIALegacyIAccessiblePattern
 
 	_TextInfo=UIATextInfo
+	_cache_TextInfo = False
+
 	def _get_TextInfo(self):
-		if self.UIATextPattern: return self._TextInfo
-		textInfo=super(UIA,self).TextInfo
+		if self.UIATextPattern:
+			return self._TextInfo
+		textInfo = super(UIA, self).TextInfo
 		if textInfo is NVDAObjectTextInfo and self.UIAIsWindowElement and self.role==controlTypes.ROLE_WINDOW:
 			import displayModel
 			return displayModel.DisplayModelTextInfo
diff --git a/source/NVDAObjects/UIA/chromium.py b/source/NVDAObjects/UIA/chromium.py
--- a/source/NVDAObjects/UIA/chromium.py
+++ b/source/NVDAObjects/UIA/chromium.py
@@ -1,7 +1,7 @@
 # A part of NonVisual Desktop Access (NVDA)
 # This file is covered by the GNU General Public License.
 # See the file COPYING for more details.
-# Copyright (C) 2020 NV Access limited, Leonard de Ruijter
+# Copyright (C) 2020-2021 NV Access limited, Leonard de Ruijter
 
 import UIAHandler
 from . import web
@@ -16,6 +16,15 @@
 
 class ChromiumUIATextInfo(web.UIAWebTextInfo):
 
+	def expand(self, unit):
+		# #12474: Expanding to line breaks when the underlying text range is empty.
+		if (
+			UIAHandler.NVDAUnitsToUIAUnits.get(unit) == UIAHandler.UIA.TextUnit_Line
+			and self.obj.UIATextPattern.documentRange.GetText(1) == ""
+		):
+			return
+		super().expand(unit)
+
 	def _getFormatFieldAtRange(self, textRange, formatConfig, ignoreMixedValues=False):
 		formatField = super()._getFormatFieldAtRange(textRange, formatConfig, ignoreMixedValues=ignoreMixedValues)
 		# Headings are also exposed in the element tree,
diff --git a/source/core.py b/source/core.py
--- a/source/core.py
+++ b/source/core.py
@@ -232,7 +232,9 @@ def getWxLangOrNone() -> Optional['wx.LanguageInfo']:
 
 
 def triggerNVDAExit():
-	preNVDAExit.notifyOnce()
+	import queueHandler
+	# queue this so that the calling process can exit safely (eg a Popup menu)
+	queueHandler.queueFunction(queueHandler.eventQueue, preNVDAExit.notifyOnce)
 
 
 def _closeAllWindows():


Test patch:
diff --git a/tests/system/nvdaSettingsFiles/standard-dontShowExitDialog.ini b/tests/system/nvdaSettingsFiles/standard-dontShowExitDialog.ini
new file mode 100644
--- /dev/null
+++ b/tests/system/nvdaSettingsFiles/standard-dontShowExitDialog.ini
@@ -0,0 +1,18 @@
+schemaVersion = 2
+[general]
+	showWelcomeDialogAtStartup = True
+	askToExit = False
+[update]
+	askedAllowUsageStats = True
+	autoCheck = False
+	startupNotification = False
+	allowUsageStats = False
+[speech]
+	synth = speechSpySynthDriver
+[development]
+	enableScratchpadDir = True
+[virtualBuffers]
+	autoSayAllOnPageLoad = False
+	passThroughAudioIndication = False
+[annotations]
+	reportDetails = True
diff --git a/tests/system/robot/startupShutdownNVDA.py b/tests/system/robot/startupShutdownNVDA.py
--- a/tests/system/robot/startupShutdownNVDA.py
+++ b/tests/system/robot/startupShutdownNVDA.py
@@ -32,6 +32,33 @@ def NVDA_Starts():
 	_process.process_should_be_running(_nvdaProcessAlias)
 
 
+def quits_from_menu(showExitDialog=True):
+	"""Ensure NVDA can be quit from menu."""
+	spy = _nvdaLib.getSpyLib()
+	_builtIn.sleep(1)
+	spy.emulateKeyPress("NVDA+n")
+	spy.emulateKeyPress("x", blockUntilProcessed=False)  # don't block so NVDA can exit
+	if showExitDialog:
+		exitTitleIndex = spy.wait_for_specific_speech("Exit NVDA")
+
+		spy.wait_for_speech_to_finish()
+		actualSpeech = spy.get_speech_at_index_until_now(exitTitleIndex)
+
+		_asserts.strings_match(
+			actualSpeech,
+			"\n".join([
+				"Exit NVDA  dialog",
+				"What would you like to do?  combo box  Exit  collapsed  Alt plus d"
+			])
+		)
+		_builtIn.sleep(1)  # the dialog is not always receiving the enter keypress, wait a little for it
+		spy.emulateKeyPress("enter", blockUntilProcessed=False)  # don't block so NVDA can exit
+
+	_process.wait_for_process(_nvdaProcessAlias, timeout="10 sec")
+	_process.process_should_be_stopped(_nvdaProcessAlias)
+
+
+
 def quits_from_keyboard():
 	"""Ensure NVDA can be quit from keyboard."""
 	spy = _nvdaLib.getSpyLib()
@@ -40,7 +67,7 @@ def quits_from_keyboard():
 	_builtIn.sleep(1)  # the dialog is not always receiving the enter keypress, wait a little longer for it
 	spy.emulateKeyPress("enter")
 
-	spy.emulateKeyPress("insert+q")
+	spy.emulateKeyPress("NVDA+q")
 	exitTitleIndex = spy.wait_for_specific_speech("Exit NVDA")
 
 	spy.wait_for_speech_to_finish()
@@ -54,7 +81,7 @@ def quits_from_keyboard():
 		])
 	)
 	_builtIn.sleep(1)  # the dialog is not always receiving the enter keypress, wait a little longer for it
-	spy.emulateKeyPress("enter", blockUntilProcessed=False)
+	spy.emulateKeyPress("enter", blockUntilProcessed=False)  # don't block so NVDA can exit
 	_process.wait_for_process(_nvdaProcessAlias, timeout="10 sec")
 	_process.process_should_be_stopped(_nvdaProcessAlias)
 
diff --git a/tests/system/robot/startupShutdownNVDA.robot b/tests/system/robot/startupShutdownNVDA.robot
--- a/tests/system/robot/startupShutdownNVDA.robot
+++ b/tests/system/robot/startupShutdownNVDA.robot
@@ -30,6 +30,11 @@ Quits from keyboard
 	[Setup]	start NVDA	standard-doShowWelcomeDialog.ini
 	quits_from_keyboard	# run test
 
+Quits from menu
+	[Documentation]	Starts NVDA and ensures that it can be quit using the keyboard
+	[Setup]	start NVDA	standard-dontShowExitDialog.ini
+	quits from menu	False	# run test
+
 Read welcome dialog
 	[Documentation]	Ensure that the welcome dialog can be read in full
 	[Setup]	start NVDA	standard-doShowWelcomeDialog.ini