diff --git a/tests/manual/applications/IDEs/vsCodium.md b/tests/manual/applications/IDEs/vsCodium.md new file mode 100644 index 00000000000..45cc0183c91 --- /dev/null +++ b/tests/manual/applications/IDEs/vsCodium.md @@ -0,0 +1,124 @@ +# VSCodium Smoke Testing Plan + +## Objective + +To ensure NVDA functions correctly with VS Code or other VSCodium derivatives across typical user workflows. +This plan focuses on basic navigation, file operations, editor accessibility, and common development tasks. +VSCodium is based on Electron and as such smoke testing can reveal issues with the framework. + +## Areas Covered + +* Application launch and window navigation +* File operations (open, save, close) +* Editor accessibility +* Command palette and search +* Extensions +* Terminal + +## Application Launch and Window Navigation + +### Steps + +1. Launch VSCodium +1. Verify NVDA announces the VSCodium window title +1. Use `control+shift+p` to open the command palette +1. Use `f1` to open the command palette (alternative) +1. Use `control+b` to toggle the sidebar +1. Use `control+shift+f` to focus the Search panel +1. Use `f6` to navigate between sections of the window + +### Expected Results + +* NVDA announces window title and major UI regions +* Navigation between panels and tabs is clear and consistent + +## File Operations + +### Steps + +1. Use `control+n` to create a new file +1. Use `control+s` to save, enter a filename, and confirm +1. Use `control+o` to open an existing file +1. Use `control+w` to close the current file +1. Use `control+shift+t` to reopen a closed file +1. Use `control+n` to create another new file +1. Use `control+tab` to switch between open files/tabs +1. Use `control+shift+e` to focus the File Explorer + +### Expected Results + +* NVDA announces file dialogs and file actions +* File operations are accessible and confirmed by speech + +## Editor Operations + +### Steps + +1. Type and navigate text in the editor using arrow keys +1. Use `control+home` and `control+end` to jump to start/end of file +1. Use `control+f` to open the find bar and search for text +1. Use `control+h` to open the replace bar +1. Use `control+z` and `control+y` to undo/redo +1. Use `control+shift+\` to jump to matching bracket +1. Use `alt+upArrow` and `alt+downArrow` to move lines up/down + +### Expected Results + +* NVDA announces text and search results +* Editing and navigation are accessible + +## Command Palette + +### Steps + +1. Use `control+shift+p` or `f1` to open the command palette +1. Type to search for commands (e.g., "toggle word wrap") +1. Use arrow keys to navigate results +1. Press `enter` to execute a command + +### Expected Results + +* NVDA announces command palette, search results, and command execution +* All command palette features are accessible + +## Search Panel + +### Steps + +1. Use `control+shift+f` to open the search panel +1. Fill out each field (find, replace, include, exclude) +1. Review results with `f4` + +### Expected Results + +* NVDA announces search results and search fields + +## Extensions + +### Steps + +1. Use `control+shift+x` to open the Extensions panel +1. Use arrow keys to navigate available extensions +1. Use the search panel to search for extensions +1. Use `tab` to move between extension details and actions +1. Use `enter` to install or enable an extension + +### Expected Results + +* NVDA announces extension names, details, and actions +* Installing and managing extensions is accessible + +## Terminal + +### Steps + +1. Use ``control+` `` to open the integrated terminal +1. Type commands e.g. `ls` +1. Review output with accessible view using `alt+f2` +1. Use ``control+shift+` `` to create a new terminal +1. Use `control+pageUp/pageDown` to switch between terminals + +### Expected Results + +* NVDA announces terminal focus and output +* Terminal operations are accessible diff --git a/tests/system/libraries/VSCodeLib.py b/tests/system/libraries/VSCodeLib.py index 7a421998a15..8f18c927d12 100644 --- a/tests/system/libraries/VSCodeLib.py +++ b/tests/system/libraries/VSCodeLib.py @@ -55,13 +55,24 @@ def _findCodeLauncher() -> str: return f'"{resolved}"' raise AssertionError("Visual Studio Code launcher not found. Is it installed?") - def start_vscode(self) -> _Window: + def start_vscode(self, targetPath: str | None = None) -> _Window: + """Start Visual Studio Code. + + :param targetPath: The path to the folder or file to open, defaults to a temporary directory. + :return: The window object for the started Visual Studio Code instance + """ launcher = self._findCodeLauncher() if VSCodeLib._testTempDir is None: VSCodeLib._testTempDir = _tempfile.mkdtemp(prefix="nvdatest") userDataDir = _os.path.join(VSCodeLib._testTempDir, "vscodeUserData") _os.makedirs(userDataDir, exist_ok=True) + if targetPath is None: + targetPath = _os.path.join(VSCodeLib._testTempDir, "testDirectory") + + if not _os.path.exists(targetPath): + _os.makedirs(targetPath, exist_ok=True) + # Prepare user settings to suppress welcome/startup screen userSettingsDir = _os.path.join(userDataDir, "User") _os.makedirs(userSettingsDir, exist_ok=True) @@ -97,6 +108,7 @@ def start_vscode(self) -> _Window: f"--skip-add-to-recently-opened " f"-n " f"--wait" + f' "{targetPath}"' ) _builtIn.log(f"Starting Visual Studio Code: {cmd}", level="DEBUG") VSCodeLib._processRFHandleForStart = _process.start_process( diff --git a/tests/system/robot/vscodeTests.py b/tests/system/robot/vscodeTests.py index c9ef1153b74..4dc915797f4 100644 --- a/tests/system/robot/vscodeTests.py +++ b/tests/system/robot/vscodeTests.py @@ -1,19 +1,205 @@ # A part of NonVisual Desktop Access (NVDA) -# Copyright (C) 2025 Bill Dengler -# This file is covered by the GNU General Public License. -# See the file COPYING for more details. - +# Copyright (C) 2025 NV Access Limited, Bill Dengler +# This file may be used under the terms of the GNU General Public License, version 2 or later, as modified by the NVDA license. +# For full terms and any additional permissions, see the NVDA license file: https://github.com/nvaccess/nvda/blob/master/copying.txt from robot.libraries.BuiltIn import BuiltIn from SystemTestSpy import _getLib import NvdaLib as _NvdaLib +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from VSCodeLib import VSCodeLib _builtIn: BuiltIn = BuiltIn() -_vscode = _getLib("VSCodeLib") +_vscode: "VSCodeLib" = _getLib("VSCodeLib") + +_UNTITLED_FILE_FORMAT = "Untitled-{number}" -def vs_code_status_line_is_available(): - """Start Visual Studio Code and ensure NVDA+end does not report "no status line found".""" +def status_line_is_available(): + """Ensure NVDA+end does not report "no status line found".""" _vscode.start_vscode() speech = _NvdaLib.getSpeechAfterKey("NVDA+end") _builtIn.should_not_contain(speech, "no status line found") + + +def sidebar_toggle_announced(): + """Ensure control+b announces sidebar shown/hidden.""" + _vscode.start_vscode() + speech = _NvdaLib.getSpeechAfterKey("control+b") + _builtIn.should_contain(speech, "Side Bar hidden") + speech = _NvdaLib.getSpeechAfterKey("control+b") + _builtIn.should_contain(speech, "Side Bar shown") + + +def command_palette(): + """Ensure the command palette is announced when activated and can be navigated.""" + _vscode.start_vscode() + spy = _NvdaLib.getSpyLib() + speech = _NvdaLib.getSpeechAfterKey("control+shift+p") + _builtIn.should_contain(speech, "Type the name of a command") + spy.emulateKeyPress("escape") + speech = _NvdaLib.getSpeechAfterKey("f1") + _builtIn.should_contain(speech, "Type the name of a command") + newFileActionName = "Create: New File" + for c in newFileActionName: + spy.emulateKeyPress(c) + speech = _NvdaLib.getSpeechAfterKey("downArrow") + _builtIn.should_not_contain(speech, newFileActionName) + speech = _NvdaLib.getSpeechAfterKey("upArrow") + _builtIn.should_contain(speech, newFileActionName) + spy.emulateKeyPress("enter") + speech = _NvdaLib.getSpeechAfterKey("enter") + _builtIn.should_contain(speech, _UNTITLED_FILE_FORMAT.format(number=1)) + + +def file_navigation(): + """Ensure file navigation works correctly.""" + _vscode.start_vscode() + spy = _NvdaLib.getSpyLib() + # create 2 new files + spy.emulateKeyPress("control+n") + spy.emulateKeyPress("enter") + # Create second file + spy.emulateKeyPress("control+n") + # Save second file + spy.emulateKeyPress("control+s") + spy.emulateKeyPress("alt+s") + # Close second file + spy.emulateKeyPress("control+w") + # Save first file + spy.emulateKeyPress("control+s") + spy.emulateKeyPress("alt+s") + # Go to file explorer + speech = _NvdaLib.getSpeechAfterKey("control+shift+e") + _builtIn.should_contain(speech, "Files Explorer") + + +def search_panel(): + """Ensure the search panel is announced when activated and can be navigated.""" + _vscode.start_vscode() + spy = _NvdaLib.getSpyLib() + # Create file and text + spy.emulateKeyPress("control+n") + for c in "hello world": + spy.emulateKeyPress(c) + # Open search panel + speech = _NvdaLib.getSpeechAfterKey("control+shift+f") + _builtIn.should_contain(speech, "Search") + # Type search query + for c in "hello": + spy.emulateKeyPress(c) + # Confirm search + spy.emulateKeyPress("enter") + speech = _NvdaLib.getSpeechAfterKey("enter") + # TODO: report grammar issue to codium + _builtIn.should_contain(speech, "1 results in 1 files") + # Navigate search results + speech = _NvdaLib.getSpeechAfterKey("f4") + _builtIn.should_contain(speech, "hello world") + + +def file_editor_operations(): + """Ensure file editor operations such as navigation, undo, and redo work correctly.""" + _vscode.start_vscode() + spy = _NvdaLib.getSpyLib() + # create new file + spy.emulateKeyPress("control+n") + # type some text + for c in "hello": + spy.emulateKeyPress(c) + # navigate with arrow keys + speech = _NvdaLib.getSpeechAfterKey("leftArrow") + _builtIn.should_contain(speech, "o") + speech = _NvdaLib.getSpeechAfterKey("rightArrow") + _builtIn.should_contain(speech, "blank") + # jump to start of file + spy.emulateKeyPress("control+home") + speech = _NvdaLib.getSpeechAfterKey("NVDA+upArrow") + _builtIn.should_contain(speech, "hello") + # jump to end of file + spy.emulateKeyPress("control+end") + speech = _NvdaLib.getSpeechAfterKey("leftArrow") + _builtIn.should_contain(speech, "o") + # open find bar and search + spy.emulateKeyPress("control+f") + spy.emulateKeyPress("h") + spy.emulateKeyPress("e") + speech = _NvdaLib.getSpeechAfterKey("l") + _builtIn.should_contain(speech, "1 of 1") + spy.emulateKeyPress("escape") + # open replace bar + speech = _NvdaLib.getSpeechAfterKey("control+h") + _builtIn.should_contain(speech, "Replace") + spy.emulateKeyPress("escape") + # type bracket for bracket matching test + spy.emulateKeyPress("control+end") + spy.emulateKeyPress("enter") + for c in "(a)": + spy.emulateKeyPress(c) + # jump to matching bracket + spy.emulateKeyPress("control+shift+\\") + speech = _NvdaLib.getSpeechAfterKey("numpad2") + _builtIn.should_contain(speech, "left paren") + # move line down + spy.emulateKeyPress("control+home") + speech = _NvdaLib.getSpeechAfterKey("alt+downArrow") + _builtIn.should_contain(speech, "hello") + # move line up + speech = _NvdaLib.getSpeechAfterKey("alt+upArrow") + _builtIn.should_contain(speech, "hello") + # undo + spy.emulateKeyPress("control+z") + speech = _NvdaLib.getSpeechAfterKey("NVDA+upArrow") + _builtIn.should_contain(speech, "hello") + # redo + spy.emulateKeyPress("control+y") + speech = _NvdaLib.getSpeechAfterKey("NVDA+downArrow") + _builtIn.should_contain(speech, "(a)") + + +def extensions_panel(): + """Ensure extensions panel is accessible.""" + _vscode.start_vscode() + spy = _NvdaLib.getSpyLib() + speech = _NvdaLib.getSpeechAfterKey("control+shift+x") + _builtIn.should_contain(speech, "Extensions") + for c in 'publisher:"Microsoft"': + spy.emulateKeyPress(c) + spy.emulateKeyPress("enter") + # Tab to clear search button + spy.emulateKeyPress("tab") + # Tab to search results + speech = _NvdaLib.getSpeechAfterKey("tab") + _builtIn.should_contain(speech, "Extensions list") + speech = _NvdaLib.getSpeechAfterKey("downArrow") + _builtIn.should_contain(speech, "Microsoft") + speech = _NvdaLib.getSpeechAfterKey("tab") + _builtIn.should_contain(speech, "Install") + + +def terminal_panel(): + """Ensure terminal panel is accessible.""" + _vscode.start_vscode() + spy = _NvdaLib.getSpyLib() + speech = _NvdaLib.getSpeechAfterKey("control+`") + _builtIn.should_contain(speech, "Terminal 1") + for c in "echo foo": + spy.emulateKeyPress(c) + spy.emulateKeyPress("enter") + spy.wait_for_speech_to_finish() + # Enter accessible view of terminal output + speech = _NvdaLib.getSpeechAfterKey("alt+f2") + # Read bottom of terminal output + speech = _NvdaLib.getSpeechAfterKey("upArrow") + _builtIn.should_contain(speech, "foo") + spy.emulateKeyPress("escape") + # Create new terminal + speech = _NvdaLib.getSpeechAfterKey("control+shift+`") + _builtIn.should_contain(speech, "Terminal 2") + # Navigate between terminals + speech = _NvdaLib.getSpeechAfterKey("control+pageUp") + _builtIn.should_contain(speech, "Terminal 1") + speech = _NvdaLib.getSpeechAfterKey("control+pageDown") + _builtIn.should_contain(speech, "Terminal 2") diff --git a/tests/system/robot/vscodeTests.robot b/tests/system/robot/vscodeTests.robot index 45052e45bab..452a80089e9 100644 --- a/tests/system/robot/vscodeTests.robot +++ b/tests/system/robot/vscodeTests.robot @@ -32,6 +32,35 @@ default teardown quit NVDA *** Test Cases *** -VS Code status line is available - [Documentation] Start Visual Studio Code and ensure NVDA+end does not report "no status line found". - vs_code_status_line_is_available + +status line is available + [Documentation] Ensure NVDA+end does not report "no status line found". + status_line_is_available + +sidebar toggle announced + [Documentation] Ensure control+b announces sidebar shown/hidden. + sidebar_toggle_announced + +command palette + [Documentation] Ensure the command palette is announced when activated and can be navigated. + command_palette + +file navigation + [Documentation] Ensure file navigation works correctly. + file_navigation + +search panel + [Documentation] Ensure the search panel is announced when activated and can be navigated. + search_panel + +file editor operations + [Documentation] Ensure file editor operations such as navigation, undo, and redo work correctly. + file_editor_operations + +extensions panel + [Documentation] Ensure extensions panel is accessible + extensions_panel + +terminal panel + [Documentation] Ensure terminal panel is accessible. + terminal_panel