Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7fbe2d4
add vs code system tests
seanbudd Nov 12, 2025
354d31b
Pre-commit auto-fix
pre-commit-ci[bot] Nov 12, 2025
e1757e4
register tests
seanbudd Nov 12, 2025
cc1c575
Merge remote-tracking branch 'origin/vsCodeTests' into vsCodeTests
seanbudd Nov 12, 2025
c4890f1
Fix types better
seanbudd Nov 12, 2025
4f76e0a
improve command pallette tests
seanbudd Nov 12, 2025
2f73988
improve search panel tests
seanbudd Nov 12, 2025
892f402
minor fixes, add extensions panel
seanbudd Nov 12, 2025
a8402bc
Pre-commit auto-fix
pre-commit-ci[bot] Nov 12, 2025
cd24529
add terminal panel tests
seanbudd Nov 12, 2025
7b8759d
Pre-commit auto-fix
pre-commit-ci[bot] Nov 12, 2025
75bb7de
minor fixes
seanbudd Nov 12, 2025
fc7c008
fix up extensions panel
seanbudd Nov 12, 2025
1b63038
test fixes
seanbudd Nov 12, 2025
10c89de
improve handling of tests
seanbudd Nov 13, 2025
0dec7bc
typo fix
seanbudd Nov 13, 2025
ef9d4ac
fix up dir
seanbudd Nov 13, 2025
aa66382
Apply suggestions from code review
seanbudd Nov 13, 2025
14bfdb9
fix terminal nav
seanbudd Nov 13, 2025
e818036
Merge remote-tracking branch 'origin/vsCodeTests' into vsCodeTests
seanbudd Nov 13, 2025
5aba130
minor test fixes
seanbudd Nov 13, 2025
2ab71c8
agree to overwrite file
seanbudd Nov 13, 2025
a99af47
fix wait for speech
seanbudd Nov 13, 2025
531c99b
remove broken tests
seanbudd Nov 13, 2025
767b461
Apply suggestions from code review
seanbudd Nov 13, 2025
02c3c98
fix up file nav
seanbudd Nov 13, 2025
079c173
Merge remote-tracking branch 'origin/vsCodeTests' into vsCodeTests
seanbudd Nov 13, 2025
5cb2a3e
fix up test
seanbudd Nov 13, 2025
2ac0e3a
change save confirmation key used
seanbudd Nov 13, 2025
b6d9d06
Update tests/system/robot/vscodeTests.py
SaschaCowley Nov 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions tests/manual/applications/IDEs/vsCodium.md
Original file line number Diff line number Diff line change
@@ -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
14 changes: 13 additions & 1 deletion tests/system/libraries/VSCodeLib.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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(
Expand Down
200 changes: 193 additions & 7 deletions tests/system/robot/vscodeTests.py
Original file line number Diff line number Diff line change
@@ -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-2025 NV Access Limited, Bill Dengler
Comment thread
SaschaCowley marked this conversation as resolved.
Outdated
# 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()
Comment thread
seanbudd marked this conversation as resolved.
_vscode = _getLib("VSCodeLib")
_vscode: "VSCodeLib" = _getLib("VSCodeLib")

_UNTITLED_FILE_FORMAT = "Untitled-{number}"


Comment thread
seanbudd marked this conversation as resolved.
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")
Comment thread
seanbudd marked this conversation as resolved.
_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")
Comment thread
seanbudd marked this conversation as resolved.
# 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")
Loading