nvda-addon-testkit 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nvda_addon_testkit-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +77 -0
- nvda_addon_testkit-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- nvda_addon_testkit-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +38 -0
- nvda_addon_testkit-0.1.0/.github/pull_request_template.md +15 -0
- nvda_addon_testkit-0.1.0/.github/release-drafter.yml +36 -0
- nvda_addon_testkit-0.1.0/.github/workflows/ci.yml +74 -0
- nvda_addon_testkit-0.1.0/.github/workflows/publish.yml +40 -0
- nvda_addon_testkit-0.1.0/.github/workflows/release-drafter.yml +23 -0
- nvda_addon_testkit-0.1.0/.github/workflows/sonar.yml +98 -0
- nvda_addon_testkit-0.1.0/.gitignore +13 -0
- nvda_addon_testkit-0.1.0/CONTRIBUTING.md +64 -0
- nvda_addon_testkit-0.1.0/LICENSE +338 -0
- nvda_addon_testkit-0.1.0/PKG-INFO +109 -0
- nvda_addon_testkit-0.1.0/README.md +85 -0
- nvda_addon_testkit-0.1.0/action.yml +27 -0
- nvda_addon_testkit-0.1.0/examples/demo-addon/build.py +30 -0
- nvda_addon_testkit-0.1.0/examples/demo-addon/globalPlugins/testkit_demo.py +33 -0
- nvda_addon_testkit-0.1.0/examples/demo-addon/manifest.ini +8 -0
- nvda_addon_testkit-0.1.0/pyproject.toml +63 -0
- nvda_addon_testkit-0.1.0/renovate.json +4 -0
- nvda_addon_testkit-0.1.0/ruff.toml +8 -0
- nvda_addon_testkit-0.1.0/sonar-project.properties +24 -0
- nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/__init__.py +78 -0
- nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/addons_api.py +108 -0
- nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/braille_tap.py +100 -0
- nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/config_api.py +107 -0
- nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/eval_api.py +35 -0
- nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/input_api.py +63 -0
- nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/log_tap.py +74 -0
- nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/mainthread.py +50 -0
- nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/registry.py +46 -0
- nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/serialise.py +47 -0
- nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/server.py +113 -0
- nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/speech_tap.py +112 -0
- nvda_addon_testkit-0.1.0/spy/manifest.ini +8 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/__init__.py +5 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/_version.py +24 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/cli.py +92 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/client.py +114 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/download.py +73 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/errors.py +59 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/__init__.py +1 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/addons.py +58 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/braille.py +57 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/config.py +30 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/keys.py +30 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/log.py +95 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/speech.py +76 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/plugin.py +137 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/portable.py +161 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/process.py +287 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/provisioning.py +106 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/resolve.py +126 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/rpcclient.py +122 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/settings.py +68 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/speechtypes.py +74 -0
- nvda_addon_testkit-0.1.0/src/nvda_testkit/spybundle.py +24 -0
- nvda_addon_testkit-0.1.0/tests/conftest.py +55 -0
- nvda_addon_testkit-0.1.0/tests/fake_nvda.py +332 -0
- nvda_addon_testkit-0.1.0/tests/fixtures/snapshot_index_alpha.html +1901 -0
- nvda_addon_testkit-0.1.0/tests/fixtures/update_check_stable.txt +5 -0
- nvda_addon_testkit-0.1.0/tests/test_addons_namespace.py +111 -0
- nvda_addon_testkit-0.1.0/tests/test_braille_namespace.py +60 -0
- nvda_addon_testkit-0.1.0/tests/test_build_spy.py +18 -0
- nvda_addon_testkit-0.1.0/tests/test_cli.py +162 -0
- nvda_addon_testkit-0.1.0/tests/test_client.py +129 -0
- nvda_addon_testkit-0.1.0/tests/test_config_namespace.py +35 -0
- nvda_addon_testkit-0.1.0/tests/test_download.py +95 -0
- nvda_addon_testkit-0.1.0/tests/test_e2e_conftest.py +84 -0
- nvda_addon_testkit-0.1.0/tests/test_errors.py +56 -0
- nvda_addon_testkit-0.1.0/tests/test_fake_nvda.py +162 -0
- nvda_addon_testkit-0.1.0/tests/test_keys_namespace.py +38 -0
- nvda_addon_testkit-0.1.0/tests/test_log_namespace.py +75 -0
- nvda_addon_testkit-0.1.0/tests/test_plugin.py +305 -0
- nvda_addon_testkit-0.1.0/tests/test_portable.py +115 -0
- nvda_addon_testkit-0.1.0/tests/test_process.py +198 -0
- nvda_addon_testkit-0.1.0/tests/test_provisioning.py +49 -0
- nvda_addon_testkit-0.1.0/tests/test_resolve.py +93 -0
- nvda_addon_testkit-0.1.0/tests/test_rpcclient.py +127 -0
- nvda_addon_testkit-0.1.0/tests/test_settings.py +58 -0
- nvda_addon_testkit-0.1.0/tests/test_speech_namespace.py +103 -0
- nvda_addon_testkit-0.1.0/tests/test_speechtypes.py +86 -0
- nvda_addon_testkit-0.1.0/tests_e2e/conftest.py +73 -0
- nvda_addon_testkit-0.1.0/tests_e2e/test_demo_addon.py +71 -0
- nvda_addon_testkit-0.1.0/tests_e2e/test_smoke.py +42 -0
- nvda_addon_testkit-0.1.0/tests_spy/__init__.py +0 -0
- nvda_addon_testkit-0.1.0/tests_spy/conftest.py +27 -0
- nvda_addon_testkit-0.1.0/tests_spy/nvda_stubs.py +367 -0
- nvda_addon_testkit-0.1.0/tests_spy/test_addons_api.py +89 -0
- nvda_addon_testkit-0.1.0/tests_spy/test_braille_tap.py +65 -0
- nvda_addon_testkit-0.1.0/tests_spy/test_config_api.py +108 -0
- nvda_addon_testkit-0.1.0/tests_spy/test_eval_api.py +47 -0
- nvda_addon_testkit-0.1.0/tests_spy/test_input_api.py +63 -0
- nvda_addon_testkit-0.1.0/tests_spy/test_log_tap.py +57 -0
- nvda_addon_testkit-0.1.0/tests_spy/test_mainthread.py +65 -0
- nvda_addon_testkit-0.1.0/tests_spy/test_plugin.py +208 -0
- nvda_addon_testkit-0.1.0/tests_spy/test_registry.py +58 -0
- nvda_addon_testkit-0.1.0/tests_spy/test_serialise.py +83 -0
- nvda_addon_testkit-0.1.0/tests_spy/test_server.py +88 -0
- nvda_addon_testkit-0.1.0/tests_spy/test_speech_tap.py +70 -0
- nvda_addon_testkit-0.1.0/tools/build_spy.py +47 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something in the testkit isn't behaving the way it should.
|
|
3
|
+
title: "[Bug] "
|
|
4
|
+
labels: ["bug"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thanks for taking the time to report a bug. The fields below help reproduce and diagnose the problem quickly — please fill in as much as you can.
|
|
10
|
+
|
|
11
|
+
- type: input
|
|
12
|
+
id: testkit-version
|
|
13
|
+
attributes:
|
|
14
|
+
label: nvda-addon-testkit version
|
|
15
|
+
description: Output of `nvda-testkit --version`, or the version pinned in your requirements.
|
|
16
|
+
placeholder: e.g. 0.1.0
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
|
|
20
|
+
- type: input
|
|
21
|
+
id: nvda-channel
|
|
22
|
+
attributes:
|
|
23
|
+
label: NVDA channel / version under test
|
|
24
|
+
description: Whatever you passed as `nvda-channel`, or the resolved version from `nvda-testkit doctor`.
|
|
25
|
+
placeholder: e.g. stable / alpha / 2026.1.1
|
|
26
|
+
validations:
|
|
27
|
+
required: true
|
|
28
|
+
|
|
29
|
+
- type: input
|
|
30
|
+
id: os
|
|
31
|
+
attributes:
|
|
32
|
+
label: OS
|
|
33
|
+
description: The e2e suite only runs on Windows; host/spy tests run anywhere. Note which you were running.
|
|
34
|
+
placeholder: e.g. Windows 11 24H2 (x64) / Ubuntu 24.04 (host tests only)
|
|
35
|
+
validations:
|
|
36
|
+
required: true
|
|
37
|
+
|
|
38
|
+
- type: textarea
|
|
39
|
+
id: steps
|
|
40
|
+
attributes:
|
|
41
|
+
label: Steps to reproduce
|
|
42
|
+
description: What did you run, step by step? A minimal failing test or `pytest` invocation is ideal.
|
|
43
|
+
placeholder: |
|
|
44
|
+
1. pip install -e ".[dev]"
|
|
45
|
+
2. pytest tests_e2e/test_smoke.py -v
|
|
46
|
+
3. ...
|
|
47
|
+
validations:
|
|
48
|
+
required: true
|
|
49
|
+
|
|
50
|
+
- type: textarea
|
|
51
|
+
id: expected
|
|
52
|
+
attributes:
|
|
53
|
+
label: Expected behavior
|
|
54
|
+
placeholder: What you thought would happen.
|
|
55
|
+
validations:
|
|
56
|
+
required: true
|
|
57
|
+
|
|
58
|
+
- type: textarea
|
|
59
|
+
id: actual
|
|
60
|
+
attributes:
|
|
61
|
+
label: Actual behavior
|
|
62
|
+
placeholder: What actually happened. Include the pytest failure/traceback verbatim.
|
|
63
|
+
validations:
|
|
64
|
+
required: true
|
|
65
|
+
|
|
66
|
+
- type: textarea
|
|
67
|
+
id: logs
|
|
68
|
+
attributes:
|
|
69
|
+
label: Relevant output
|
|
70
|
+
description: Full traceback, `nvda.log` records around the failure, or `nvda-testkit doctor` output.
|
|
71
|
+
render: text
|
|
72
|
+
|
|
73
|
+
- type: textarea
|
|
74
|
+
id: extra
|
|
75
|
+
attributes:
|
|
76
|
+
label: Anything else?
|
|
77
|
+
description: Workarounds you tried, related issues, your `[tool.nvda-testkit]` config, etc.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest a new fixture, namespace, or improvement to existing behavior.
|
|
3
|
+
title: "[Feature] "
|
|
4
|
+
labels: ["enhancement"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thanks for the suggestion. A bit of context helps decide whether and how to prioritize it.
|
|
10
|
+
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: problem
|
|
13
|
+
attributes:
|
|
14
|
+
label: What problem does this solve?
|
|
15
|
+
description: Describe what you're trying to test or automate, not just the API you have in mind. This often suggests a simpler fixture or a better fit with an existing namespace.
|
|
16
|
+
placeholder: e.g. "I want to assert on the content of a specific braille cell range, not just the full display buffer..."
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: proposal
|
|
22
|
+
attributes:
|
|
23
|
+
label: Proposed behavior
|
|
24
|
+
description: What should change? If you have a specific fixture/API shape in mind, sketch it.
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
|
|
28
|
+
- type: textarea
|
|
29
|
+
id: alternatives
|
|
30
|
+
attributes:
|
|
31
|
+
label: Alternatives considered
|
|
32
|
+
description: Other approaches you tried, or existing workarounds using the current fixtures.
|
|
33
|
+
|
|
34
|
+
- type: textarea
|
|
35
|
+
id: extra
|
|
36
|
+
attributes:
|
|
37
|
+
label: Anything else?
|
|
38
|
+
description: Links to similar testing APIs elsewhere, example add-on code this would help test, etc.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Closes #<!-- issue number, or remove this line if no issue -->.
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
<!-- 1-3 sentences on what this PR does and why. -->
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
<!-- Concrete list of changes. File paths and line refs help reviewers. -->
|
|
10
|
+
|
|
11
|
+
## Test plan
|
|
12
|
+
|
|
13
|
+
- [ ] `pytest` passes (host + spy suites).
|
|
14
|
+
- [ ] `ruff check .` / `ruff format --check .` pass.
|
|
15
|
+
- [ ] `tests_e2e/` verified on Windows, if this touches the wire protocol or fixtures. <!-- remove if not applicable -->
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Release Drafter config. Maintains a draft release on GitHub that auto-updates
|
|
2
|
+
# as PRs merge into main. At release time, open the draft, confirm/adjust the
|
|
3
|
+
# tag (vX.Y.Z), and publish -- that `release: published` event is what
|
|
4
|
+
# publish.yml uses to build and upload to PyPI. See CONTRIBUTING.md.
|
|
5
|
+
|
|
6
|
+
name-template: 'v$RESOLVED_VERSION'
|
|
7
|
+
tag-template: 'v$RESOLVED_VERSION'
|
|
8
|
+
template: |
|
|
9
|
+
$CHANGES
|
|
10
|
+
|
|
11
|
+
categories:
|
|
12
|
+
- title: '🐛 Fixes'
|
|
13
|
+
labels:
|
|
14
|
+
- bug
|
|
15
|
+
- title: '✨ Features'
|
|
16
|
+
labels:
|
|
17
|
+
- enhancement
|
|
18
|
+
- title: '📚 Documentation'
|
|
19
|
+
labels:
|
|
20
|
+
- documentation
|
|
21
|
+
- title: '🧹 Maintenance'
|
|
22
|
+
labels:
|
|
23
|
+
- chore
|
|
24
|
+
- dependencies
|
|
25
|
+
|
|
26
|
+
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
|
|
27
|
+
change-title-escapes: '\<*_&'
|
|
28
|
+
|
|
29
|
+
# We tag manually, so don't try to auto-bump versions based on labels.
|
|
30
|
+
# Leave $RESOLVED_VERSION as a placeholder the maintainer overrides at
|
|
31
|
+
# release time.
|
|
32
|
+
version-resolver:
|
|
33
|
+
default: patch
|
|
34
|
+
|
|
35
|
+
exclude-labels:
|
|
36
|
+
- skip-changelog
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
lint:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v5
|
|
17
|
+
with:
|
|
18
|
+
persist-credentials: false
|
|
19
|
+
- uses: actions/setup-python@v6
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.13"
|
|
22
|
+
- run: 'pip install --only-binary :all: ruff'
|
|
23
|
+
- run: ruff check .
|
|
24
|
+
- run: ruff format --check .
|
|
25
|
+
|
|
26
|
+
unit:
|
|
27
|
+
runs-on: ${{ matrix.os }}
|
|
28
|
+
strategy:
|
|
29
|
+
fail-fast: false
|
|
30
|
+
matrix:
|
|
31
|
+
os: [ubuntu-latest, windows-2025]
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v5
|
|
34
|
+
with:
|
|
35
|
+
persist-credentials: false
|
|
36
|
+
- uses: actions/setup-python@v6
|
|
37
|
+
with:
|
|
38
|
+
python-version: "3.13"
|
|
39
|
+
- run: 'pip install --only-binary :all: -e ".[dev]"'
|
|
40
|
+
- run: python tools/build_spy.py
|
|
41
|
+
# Bare `pytest` so testpaths picks up tests_spy/ too. An explicit
|
|
42
|
+
# `pytest tests/` silently skips every spy test in CI.
|
|
43
|
+
- run: pytest -v
|
|
44
|
+
|
|
45
|
+
e2e:
|
|
46
|
+
runs-on: windows-2025
|
|
47
|
+
strategy:
|
|
48
|
+
fail-fast: false
|
|
49
|
+
matrix:
|
|
50
|
+
channel: [stable, alpha]
|
|
51
|
+
continue-on-error: ${{ matrix.channel == 'alpha' }}
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/checkout@v5
|
|
54
|
+
with:
|
|
55
|
+
persist-credentials: false
|
|
56
|
+
- uses: actions/setup-python@v6
|
|
57
|
+
with:
|
|
58
|
+
python-version: "3.13"
|
|
59
|
+
- run: pip install -e ".[dev]"
|
|
60
|
+
- run: python tools/build_spy.py
|
|
61
|
+
- name: Cache NVDA launchers
|
|
62
|
+
uses: actions/cache@v4
|
|
63
|
+
with:
|
|
64
|
+
path: ~/.cache/nvda-testkit
|
|
65
|
+
key: nvda-launcher-${{ matrix.channel }}-${{ github.run_id }}
|
|
66
|
+
restore-keys: nvda-launcher-${{ matrix.channel }}-
|
|
67
|
+
- run: nvda-testkit doctor
|
|
68
|
+
- run: pytest tests_e2e/ -v --nvda-channel=${{ matrix.channel }}
|
|
69
|
+
- if: failure()
|
|
70
|
+
uses: actions/upload-artifact@v5
|
|
71
|
+
with:
|
|
72
|
+
name: e2e-${{ matrix.channel }}-artifacts
|
|
73
|
+
path: testOutput/
|
|
74
|
+
if-no-files-found: warn
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v5
|
|
15
|
+
with:
|
|
16
|
+
persist-credentials: false
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
- uses: actions/setup-python@v6
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.13"
|
|
21
|
+
- run: "pip install --only-binary :all: build twine"
|
|
22
|
+
- run: python -m build
|
|
23
|
+
- run: twine check dist/*
|
|
24
|
+
- uses: actions/upload-artifact@v5
|
|
25
|
+
with:
|
|
26
|
+
name: dist
|
|
27
|
+
path: dist/
|
|
28
|
+
|
|
29
|
+
publish:
|
|
30
|
+
needs: build
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
environment: pypi
|
|
33
|
+
permissions:
|
|
34
|
+
id-token: write
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/download-artifact@v6
|
|
37
|
+
with:
|
|
38
|
+
name: dist
|
|
39
|
+
path: dist/
|
|
40
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Release Drafter
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
# Re-run when a PR is opened/edited so label changes are reflected without
|
|
8
|
+
# waiting for the next merge.
|
|
9
|
+
pull_request:
|
|
10
|
+
types: [opened, reopened, synchronize, edited, labeled, unlabeled]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
update_release_draft:
|
|
14
|
+
permissions:
|
|
15
|
+
contents: write
|
|
16
|
+
pull-requests: write
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: release-drafter/release-drafter@6a93d829887aa2e0748befe2e808c66c0ec6e4c7 # v6.4.0
|
|
20
|
+
with:
|
|
21
|
+
config-name: release-drafter.yml
|
|
22
|
+
env:
|
|
23
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
name: Sonar
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
# SonarCloud keeps whichever report finishes processing last, not the newest
|
|
10
|
+
# commit, so overlapping scans can leave main showing an older analysis.
|
|
11
|
+
concurrency:
|
|
12
|
+
group: sonar-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
# windows_only-marked tests only run on Windows, so a ubuntu-only coverage
|
|
17
|
+
# run would show them as permanently uncovered. This job measures that leg
|
|
18
|
+
# and hands the raw data to the scan job to merge.
|
|
19
|
+
windows_coverage:
|
|
20
|
+
name: Windows coverage
|
|
21
|
+
runs-on: windows-2025
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
# Matches the scan job's guard: nothing consumes this artifact on fork PRs.
|
|
25
|
+
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
|
26
|
+
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v5
|
|
29
|
+
with:
|
|
30
|
+
persist-credentials: false
|
|
31
|
+
|
|
32
|
+
- uses: actions/setup-python@v6
|
|
33
|
+
with:
|
|
34
|
+
python-version: "3.13"
|
|
35
|
+
|
|
36
|
+
- run: 'pip install --only-binary :all: -e ".[dev]"'
|
|
37
|
+
- run: python tools/build_spy.py
|
|
38
|
+
|
|
39
|
+
- name: Run tests with coverage
|
|
40
|
+
env:
|
|
41
|
+
COVERAGE_FILE: .coverage.windows.tests
|
|
42
|
+
# `coverage run -m pytest`, not `pytest --cov`: this package registers
|
|
43
|
+
# itself as a pytest11 entry-point plugin, so pytest's own plugin
|
|
44
|
+
# loader imports nvda_testkit's modules before pytest-cov's --cov
|
|
45
|
+
# flag would start tracing, permanently miscounting every top-level
|
|
46
|
+
# def/class line in them as uncovered.
|
|
47
|
+
run: coverage run -m pytest -v
|
|
48
|
+
|
|
49
|
+
- uses: actions/upload-artifact@v5
|
|
50
|
+
with:
|
|
51
|
+
name: windows-coverage-data
|
|
52
|
+
path: .coverage.windows.*
|
|
53
|
+
include-hidden-files: true # coverage data files start with a dot
|
|
54
|
+
retention-days: 1
|
|
55
|
+
|
|
56
|
+
sonar:
|
|
57
|
+
name: Sonar
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
needs: ["windows_coverage"]
|
|
60
|
+
permissions:
|
|
61
|
+
contents: read
|
|
62
|
+
# Fork PRs are never given repository secrets, so SONAR_TOKEN would be
|
|
63
|
+
# empty and the scan would fail with a red X the contributor can't clear.
|
|
64
|
+
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
|
65
|
+
env:
|
|
66
|
+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
67
|
+
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v5
|
|
70
|
+
with:
|
|
71
|
+
fetch-depth: 0 # Sonar needs full history for new-code detection and blame
|
|
72
|
+
persist-credentials: false
|
|
73
|
+
|
|
74
|
+
- uses: actions/setup-python@v6
|
|
75
|
+
with:
|
|
76
|
+
python-version: "3.13"
|
|
77
|
+
|
|
78
|
+
- run: 'pip install --only-binary :all: -e ".[dev]"'
|
|
79
|
+
- run: python tools/build_spy.py
|
|
80
|
+
|
|
81
|
+
- name: Run tests with coverage
|
|
82
|
+
run: coverage run -m pytest -v
|
|
83
|
+
|
|
84
|
+
# After the run above, never before: `coverage run` erases any
|
|
85
|
+
# .coverage.* data files already sitting in the workspace.
|
|
86
|
+
- name: Download the Windows leg's coverage
|
|
87
|
+
uses: actions/download-artifact@v6
|
|
88
|
+
with:
|
|
89
|
+
name: windows-coverage-data
|
|
90
|
+
|
|
91
|
+
- name: Merge into one coverage report
|
|
92
|
+
run: |
|
|
93
|
+
python -m coverage combine --append
|
|
94
|
+
python -m coverage xml
|
|
95
|
+
|
|
96
|
+
- name: SonarQube scan
|
|
97
|
+
if: env.SONAR_TOKEN != ''
|
|
98
|
+
uses: SonarSource/sonarqube-scan-action@22918119ff8e1ca75a623e15c8296b6ea4fbe28f # v8.2.1
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Contributing to nvda-addon-testkit
|
|
2
|
+
|
|
3
|
+
Contributions are welcome — bug reports, feature suggestions, and PRs alike.
|
|
4
|
+
|
|
5
|
+
## Reporting a bug
|
|
6
|
+
|
|
7
|
+
Use the **Bug report** template at <https://github.com/ZirekHQ/nvda-addon-testkit/issues/new/choose>. It asks for the testkit version, NVDA channel, OS, and enough of a repro to run — fill in what you can, especially a minimal failing test or command.
|
|
8
|
+
|
|
9
|
+
## Suggesting a feature
|
|
10
|
+
|
|
11
|
+
Use the **Feature request** template. Describe the *problem* you're hitting, not just the API you imagine — that often surfaces a simpler fixture or a better name than the first idea.
|
|
12
|
+
|
|
13
|
+
## Development setup
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install -e ".[dev]"
|
|
17
|
+
python tools/build_spy.py
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`build_spy.py` packages `spy/` (the scriptable NVDA double) into the `.nvda-addon` the host-side tests install. Rerun it whenever you change anything under `spy/`.
|
|
21
|
+
|
|
22
|
+
## Running tests
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pytest # host and spy unit tests -- any platform
|
|
26
|
+
pytest tests_e2e/ -v # real NVDA -- Windows only
|
|
27
|
+
nvda-testkit doctor # check this machine
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
| Tree | Exercises | Runs on |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| `tests/` | the host-side library, against `tests/fake_nvda.py` | Linux + Windows |
|
|
33
|
+
| `tests_spy/` | `spy/`, the in-NVDA agent, against stubbed NVDA modules (`tests_spy/nvda_stubs.py`) | Linux + Windows |
|
|
34
|
+
| `tests_e2e/` | both halves together, against a real provisioned NVDA | Windows only |
|
|
35
|
+
|
|
36
|
+
`tests_e2e/` tests run serially — only one NVDA can own a desktop session, so `pytest-xdist` with more than one worker refuses to start rather than silently corrupting results.
|
|
37
|
+
|
|
38
|
+
## Linting
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
ruff check .
|
|
42
|
+
ruff format --check .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Submitting a PR
|
|
46
|
+
|
|
47
|
+
Use the pull request template. Link the issue with `Closes #N` in the PR body where one exists.
|
|
48
|
+
|
|
49
|
+
- **Commit messages**: short imperative subject, optionally prefixed `fix:` / `feat:` / `ci:` / `chore:` / `docs:` when it clarifies the kind of change. Don't append the `(#NNNNN)` PR-number suffix — GitHub's squash-merge adds it automatically.
|
|
50
|
+
- **Branch naming**: `<type>/<slug>`, e.g. `fix/rpc-race`, `feature/braille-namespace`.
|
|
51
|
+
- **No `Co-Authored-By` trailers.**
|
|
52
|
+
|
|
53
|
+
## Cutting a release
|
|
54
|
+
|
|
55
|
+
Releases are tag-driven, not version-bumped by hand — `pyproject.toml` has no `version` field. The `hatch-vcs` build hook derives the package version from the git tag at build time.
|
|
56
|
+
|
|
57
|
+
1. Publish a GitHub Release from `main` with a `vX.Y.Z` tag (semver; pre-1.0 minor bumps may break the fixture API).
|
|
58
|
+
2. `.github/workflows/publish.yml` picks up the `release: published` event, builds the sdist/wheel, and uploads to PyPI via Trusted Publishing — no token to rotate.
|
|
59
|
+
|
|
60
|
+
No separate changelog file to update — Release Drafter maintains a draft release from merged PR titles/labels as you go; open the draft, set the tag, and publish it to trigger the step above.
|
|
61
|
+
|
|
62
|
+
### Why not fully automate this (conventional commits + semantic-release)?
|
|
63
|
+
|
|
64
|
+
Considered and deliberately skipped. PRs are squash-merged, so main's history is already one commit per PR — parsing commit prefixes to categorize a release would just be a stricter, easier-to-typo restatement of what PR labels already give Release Drafter for free. More importantly, auto-bumping the version and auto-publishing on merge removes the last human checkpoint before something goes to PyPI, and pre-1.0 semver bumps (does this `feat:` deserve a minor, or does it actually break the fixture API?) are judgment calls a bot applies too mechanically at this stage. Worth revisiting if release volume ever makes the manual tag-and-publish step the actual bottleneck.
|