Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
96 changes: 81 additions & 15 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
branches: [main]

jobs:
test:
test-setup:
runs-on: ${{ matrix.os }}
strategy:
matrix:
Expand All @@ -23,7 +23,7 @@ jobs:
windows-11-arm,
]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
Expand All @@ -35,13 +35,13 @@ jobs:
name: artifacts-test-${{ matrix.os }}
path: |
**/recordings/**/*
test-ignore-tcc-db:
test-setup-ignore-tcc-db:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
Expand All @@ -53,22 +53,88 @@ jobs:
name: artifacts-test-ignore-tcc-db-${{ matrix.os }}
path: |
**/recordings/**/*
test-nvda-install-dir:

test-install:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-2022, windows-2025, windows-11-arm]
os:
[
macos-14,
macos-15,
macos-15-intel,
macos-26,
macos-26-intel,
windows-2022,
windows-2025,
windows-11-arm,
ubuntu-latest,
]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
- run: yarn install --frozen-lockfile
- run: yarn ci:nvda-install-dir
- run: Get-ChildItem $env:USERPROFILE\nvda
- uses: actions/upload-artifact@v4
if: always()
with:
name: artifacts-test-nvda-install-dir-${{ matrix.os }}
path: |
**/recordings/**/*
- run: yarn build
- shell: bash
run: |
tmpdir=$(mktemp -d)
cd "$tmpdir"
npm init -y
npm install @guidepup/guidepup
npm install -g "${GITHUB_WORKSPACE}"
export PATH="$(npm bin -g):$PATH"

cat > node_modules/@guidepup/guidepup/manifest.json <<'EOF'
{
"version": 1,
"screenReaders": [
{
"id": "nvda",
"name": "NVDA",
"platforms": ["win32"],
"defaultDownload": true,
"assets": [
{
"version": "0.2.1-2026.1.1",
"repository": "guidepup/nvda",
"asset": "guidepup-nvda-0.2.1-2026.1.1.zip",
"sha256": "b6fdfde86190c7c14132d459f2f88995da6251ded431e23947d676ffb152f963"
}
]
},
{
"id": "voiceover",
"name": "VoiceOver",
"platforms": ["darwin"],
"defaultDownload": true,
"assets": [
{
"version": "0.0.1",
"platformVersion": "23",
"repository": "guidepup/voiceover",
"asset": "guidepup-voiceover-preferences-macos-14.dmg",
"sha256": "c6595f5ca50440e8553cde278936a46eff58d4c904e19c87e7d0e25950617ee1"
},
{
"version": "0.0.1",
"platformVersion": "24",
"repository": "guidepup/voiceover",
"asset": "guidepup-voiceover-preferences-macos-15.dmg",
"sha256": "8bdc3a11c45a19cc876a859bfbd64529469a8b7d4ad41fd7e00a0729ebdbcb25"
},
{
"version": "0.0.1",
"platformVersion": "25",
"repository": "guidepup/voiceover",
"asset": "guidepup-voiceover-preferences-macos-26.dmg",
"sha256": "9af2a3af7c9bffae1b2af26f1970548ecd62f33965fd30f4e43f21b9f57ce5ca"
}
]
}
]
}
EOF

guidepup install
83 changes: 48 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@

## [Documentation](https://www.guidepup.dev/docs/guides/automated-environment-setup)

[![MacOS Sonoma Support](https://img.shields.io/badge/macos-Somona-blue.svg?logo=apple)](https://apps.apple.com/us/app/macos-sonoma/id6450717509)
[![MacOS Sequoia Support](https://img.shields.io/badge/macos-Sequoia-blue.svg?logo=apple)](https://apps.apple.com/us/app/macos-sequoia/id6596773750)
[![MacOS Tahoe Support](https://img.shields.io/badge/macos-Tahoe-blue.svg?logo=apple)](https://www.apple.com/uk/os/macos/)
[![macOS Sonoma Support](https://img.shields.io/badge/macos-Somona-blue.svg?logo=apple)](https://apps.apple.com/us/app/macos-sonoma/id6450717509)
[![macOS Sequoia Support](https://img.shields.io/badge/macos-Sequoia-blue.svg?logo=apple)](https://apps.apple.com/us/app/macos-sequoia/id6596773750)
[![macOS Tahoe Support](https://img.shields.io/badge/macos-Tahoe-blue.svg?logo=apple)](https://www.apple.com/uk/os/macos/)
[![Windows Server 2022 Support](https://img.shields.io/badge/windows_server-2022-blue.svg?logo=windows)](https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2022)
[![Windows Server 2025 Support](https://img.shields.io/badge/windows_server-2025-blue.svg?logo=windows)](https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2025)

This package sets up your environment for screen reader automation.

It enables automation for <a href="https://www.guidepup.dev/docs/api/class-voiceover"><b>VoiceOver on MacOS</b></a> and <a href="https://www.guidepup.dev/docs/api/class-nvda"><b>NVDA on Windows</b></a>.
It enables automation for <a href="https://www.guidepup.dev/docs/api/class-voiceover"><b>VoiceOver on macOS</b></a> and <a href="https://www.guidepup.dev/docs/api/class-nvda"><b>NVDA on Windows</b></a>.

## Getting Started

Expand All @@ -28,79 +28,92 @@ And get cracking with your screen reader automation code!

## Usage

### GitHub Actions
### Setup

If you are using GitHub Actions, check out the dedicated [`guidepup/setup-action`](https://github.com/marketplace/actions/guidepup-setup):
This subcommand allows you to setup an OS environment ready for screen reader automation.

```yaml
- name: Setup Environment
uses: guidepup/setup-action
```console
npx @guidepup/setup setup
```

### MacOS

If you are running this command locally you may need to take some manual steps to complete setup by following the [manual VoiceOver setup documentation](https://www.guidepup.dev/docs/guides/manual-voiceover-setup).

#### CI

If you are running this command in CI/CD, it is recommended to add the `--ci` flag to prevent interactive prompts:
If you are running this command in CI/CD, it is recommended to add the `--ci` flag to prevent prompts for manual interaction:

```console
npx @guidepup/setup --ci
npx @guidepup/setup setup --ci
```

#### Ignore TCC.db Updates
#### macOS

If updating the TCC.db is not possible (due to SIP) or required you can skip the database update step by using the `--ignore-tcc-db` flag:
If you are running this command locally you may need to take some manual steps to complete setup by following the [manual VoiceOver setup documentation](https://www.guidepup.dev/docs/guides/manual-voiceover-setup).

##### Ignore TCC Database Updates

If updating the `TCC.db` is not possible (due to enabled SIP) or not required for your macOS setup, you can skip the database update step by using the `--macos-ignore-tcc-db` flag:

```console
npx @guidepup/setup --ignore-tcc-db
npx @guidepup/setup setup --macos-ignore-tcc-db
```

> [!NOTE]
> If the necessary permissions have not been granted by other means, using this flag may result in your environment not being set up for reliable screen reader automation.

#### Recording
##### Recording

If you are encountering errors in CI for MacOS you can pass a `--record` flag to the command which will output a screen-recording of the setup to a `./recordings/` directory:
If you are encountering errors in CI for macOS you can pass a `--macos-record` flag to the command which will output a screen-recording of the setup to a `./recordings/` directory:

```console
npx @guidepup/setup --ci --record
npx @guidepup/setup --ci --macos-record
```

### Windows
### Install

#### NVDA Installation
This subcommand allows you to install screen readers and their assets to use in screen reader automation with [Guidepup](https://www.guidepup.dev/).

When running on windows a portable NVDA instance compatible with Guidepup will be installed to a temporary directory by default. The location of this installation directory is stored in the Windows registry under the key `HKCU\Software\Guidepup\Nvda`.
```console
npx @guidepup/setup install
```

If you want to specify the directory that NVDA is installed to you can pass a `--nvda-install-dir` flag to the command:
By default VoiceOver is installed on macOS, and NVDA is installed on Windows.

To install a specific screen reader you can pass it to the command as an argument:

```console
npx @guidepup/setup --nvda-install-dir <NVDA_INSTALLATION_DIRECTORY>
npx @guidepup/setup install voiceover
npx @guidepup/setup install nvda
```

##### Using HTTP / HTTPS Proxy for Installation
Screen reader options include:

- `voiceover` on macOS (default)
- `nvda` on Windows (default)

#### Using HTTP / HTTPS Proxy for Installation

If you are using a proxy connection, you must define the proxy URL in an env variable. You can use any of the following variables:

- `HTTPS_PROXY`
- `https_proxy`
- `HTTP_PROXY`
- `http_proxy`
- `NO_PROXY`
- `no_proxy`

#### Foreground Timeout Lock

Modern versions of Windows have a setting which prevents new application instances launching in front of other applications in quick succession, requiring over 3 minutes between activations before it will actually show the window - in the interim it launches the window minimized.
### Global Install

Many test automation frameworks will completely close down a browser after a test has finished and then launch a new instance for the next test - on Windows this suffers from the timeout lock on foreground windows. This impacts on screen reader automation which need the window to activate and focus to be able to drive the screen reader on the application.
You can also install the CLI globally:

To mitigate this the setup script updates two keys in the Windows registry under `HKCU\Control Panel\Desktop`:
```console
npm install -g @guidepup/setup
```

- `ForegroundLockTimeout` - Specifies the time in milliseconds, following user input, during which the system will not allow applications to force themselves into the foreground. Defaults to `200000`.
- `ForegroundFlashCount` - Determines the number of times the taskbar button will flash to notify the user that a background window has been activated by the system. If the time elapsed since the last user input exceeds the value of ForegroundLockTimeout, the window will automatically be brought to the foreground. Defaults to `3`.
After which you can access the CLI through the `guidepup` command:

Both of these are set to `0` by the setup script.
```console
guidepup setup
guidepup install
```

## Powerful Tooling

Expand Down
File renamed without changes.
24 changes: 11 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "@guidepup/setup",
"version": "0.23.0",
"description": "Setup your environment for screen-reader automation.",
"version": "0.24.0",
"description": "Configure your environment and manage screen readers for Guidepup.",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
"bin": {
"setup": "bin/setup"
"guidepup": "bin/guidepup"
},
"author": "Craig Morten <craig.morten@hotmail.co.uk>",
"license": "MIT",
Expand All @@ -26,16 +26,15 @@
],
"scripts": {
"build": "yarn clean && yarn compile",
"ci": "yarn clean && yarn lint && yarn build && yarn resolutionFix && yarn start --ci --record",
"ci:nvda-install-dir": "yarn clean && yarn lint && yarn build && yarn resolutionFix && yarn start --ci --record --nvda-install-dir %userprofile%\\nvda",
"ci:ignore-tcc-db": "yarn clean && yarn lint && yarn build && yarn resolutionFix && yarn start --ci --record --ignore-tcc-db",
"ci": "yarn clean && yarn lint && yarn build && yarn resolutionFix && yarn start:setup --ci --macos-record",
"ci:ignore-tcc-db": "yarn clean && yarn lint && yarn build && yarn resolutionFix && yarn start:setup --ci --macos-record --macos-ignore-tcc-db",
"clean": "rimraf lib",
"compile": "tsc",
"dev": "ts-node ./src/index.ts",
"resolutionFix": "ts-node ./.github/workflows/resolutionFix.ts",
"lint": "eslint . --ext .ts",
"lint:fix": "yarn lint --fix",
"start": "node ./bin/setup",
"start:setup": "node ./bin/guidepup setup",
"prepublish": "yarn build"
},
"devDependencies": {
Expand All @@ -53,10 +52,9 @@
},
"dependencies": {
"chalk": "^4.0.0",
"decompress": "^4.2.1",
"https-proxy-agent": "^7.0.5",
"regedit": "5.0.1",
"semver": "^7.5.4"
},
"guidepupNvdaVersion": "0.2.0-2026.1.1"
"commander": "^15.0.0",
"extract-zip": "^2.0.1",
"semver": "^7.5.4",
"undici": "^8.7.0"
}
}
13 changes: 13 additions & 0 deletions src/commands/install/delete-asset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { rm } from "node:fs/promises";
import { handleInfoWithPath } from "../../logging";

export async function deleteAsset(assetPath: string): Promise<void> {
handleInfoWithPath("Removing", assetPath);

try {
await rm(assetPath, { force: true, recursive: true });
} catch {
// Ignore cleanup failures, preferring to expose the error that triggered
// cleanup.
}
}
32 changes: 32 additions & 0 deletions src/commands/install/download-asset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";
import { EnvHttpProxyAgent, fetch } from "undici";
import type { Asset } from "./types";
import { ERR_INSTALL_FAILED_TO_DOWNLOAD_ASSET } from "../../errors";

const dispatcher = new EnvHttpProxyAgent();

export async function downloadAsset(
asset: Asset,
source: string,
destination: string,
): Promise<void> {
const response = await fetch(source, {
dispatcher,
});

if (!response.ok || !response.body) {
throw new Error(
`${ERR_INSTALL_FAILED_TO_DOWNLOAD_ASSET}: ${asset.asset} (${response.status} ${response.statusText})`,
);
}

try {
await pipeline(response.body, createWriteStream(destination));
} catch (cause) {
throw new Error(
`${ERR_INSTALL_FAILED_TO_DOWNLOAD_ASSET}: ${asset.asset} (${response.status} ${response.statusText})`,
{ cause },
);
}
}
Loading
Loading