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.
Files changed (101) hide show
  1. nvda_addon_testkit-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +77 -0
  2. nvda_addon_testkit-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  3. nvda_addon_testkit-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +38 -0
  4. nvda_addon_testkit-0.1.0/.github/pull_request_template.md +15 -0
  5. nvda_addon_testkit-0.1.0/.github/release-drafter.yml +36 -0
  6. nvda_addon_testkit-0.1.0/.github/workflows/ci.yml +74 -0
  7. nvda_addon_testkit-0.1.0/.github/workflows/publish.yml +40 -0
  8. nvda_addon_testkit-0.1.0/.github/workflows/release-drafter.yml +23 -0
  9. nvda_addon_testkit-0.1.0/.github/workflows/sonar.yml +98 -0
  10. nvda_addon_testkit-0.1.0/.gitignore +13 -0
  11. nvda_addon_testkit-0.1.0/CONTRIBUTING.md +64 -0
  12. nvda_addon_testkit-0.1.0/LICENSE +338 -0
  13. nvda_addon_testkit-0.1.0/PKG-INFO +109 -0
  14. nvda_addon_testkit-0.1.0/README.md +85 -0
  15. nvda_addon_testkit-0.1.0/action.yml +27 -0
  16. nvda_addon_testkit-0.1.0/examples/demo-addon/build.py +30 -0
  17. nvda_addon_testkit-0.1.0/examples/demo-addon/globalPlugins/testkit_demo.py +33 -0
  18. nvda_addon_testkit-0.1.0/examples/demo-addon/manifest.ini +8 -0
  19. nvda_addon_testkit-0.1.0/pyproject.toml +63 -0
  20. nvda_addon_testkit-0.1.0/renovate.json +4 -0
  21. nvda_addon_testkit-0.1.0/ruff.toml +8 -0
  22. nvda_addon_testkit-0.1.0/sonar-project.properties +24 -0
  23. nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/__init__.py +78 -0
  24. nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/addons_api.py +108 -0
  25. nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/braille_tap.py +100 -0
  26. nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/config_api.py +107 -0
  27. nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/eval_api.py +35 -0
  28. nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/input_api.py +63 -0
  29. nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/log_tap.py +74 -0
  30. nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/mainthread.py +50 -0
  31. nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/registry.py +46 -0
  32. nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/serialise.py +47 -0
  33. nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/server.py +113 -0
  34. nvda_addon_testkit-0.1.0/spy/globalPlugins/nvda_testkit_spy/speech_tap.py +112 -0
  35. nvda_addon_testkit-0.1.0/spy/manifest.ini +8 -0
  36. nvda_addon_testkit-0.1.0/src/nvda_testkit/__init__.py +5 -0
  37. nvda_addon_testkit-0.1.0/src/nvda_testkit/_version.py +24 -0
  38. nvda_addon_testkit-0.1.0/src/nvda_testkit/cli.py +92 -0
  39. nvda_addon_testkit-0.1.0/src/nvda_testkit/client.py +114 -0
  40. nvda_addon_testkit-0.1.0/src/nvda_testkit/download.py +73 -0
  41. nvda_addon_testkit-0.1.0/src/nvda_testkit/errors.py +59 -0
  42. nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/__init__.py +1 -0
  43. nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/addons.py +58 -0
  44. nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/braille.py +57 -0
  45. nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/config.py +30 -0
  46. nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/keys.py +30 -0
  47. nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/log.py +95 -0
  48. nvda_addon_testkit-0.1.0/src/nvda_testkit/namespaces/speech.py +76 -0
  49. nvda_addon_testkit-0.1.0/src/nvda_testkit/plugin.py +137 -0
  50. nvda_addon_testkit-0.1.0/src/nvda_testkit/portable.py +161 -0
  51. nvda_addon_testkit-0.1.0/src/nvda_testkit/process.py +287 -0
  52. nvda_addon_testkit-0.1.0/src/nvda_testkit/provisioning.py +106 -0
  53. nvda_addon_testkit-0.1.0/src/nvda_testkit/resolve.py +126 -0
  54. nvda_addon_testkit-0.1.0/src/nvda_testkit/rpcclient.py +122 -0
  55. nvda_addon_testkit-0.1.0/src/nvda_testkit/settings.py +68 -0
  56. nvda_addon_testkit-0.1.0/src/nvda_testkit/speechtypes.py +74 -0
  57. nvda_addon_testkit-0.1.0/src/nvda_testkit/spybundle.py +24 -0
  58. nvda_addon_testkit-0.1.0/tests/conftest.py +55 -0
  59. nvda_addon_testkit-0.1.0/tests/fake_nvda.py +332 -0
  60. nvda_addon_testkit-0.1.0/tests/fixtures/snapshot_index_alpha.html +1901 -0
  61. nvda_addon_testkit-0.1.0/tests/fixtures/update_check_stable.txt +5 -0
  62. nvda_addon_testkit-0.1.0/tests/test_addons_namespace.py +111 -0
  63. nvda_addon_testkit-0.1.0/tests/test_braille_namespace.py +60 -0
  64. nvda_addon_testkit-0.1.0/tests/test_build_spy.py +18 -0
  65. nvda_addon_testkit-0.1.0/tests/test_cli.py +162 -0
  66. nvda_addon_testkit-0.1.0/tests/test_client.py +129 -0
  67. nvda_addon_testkit-0.1.0/tests/test_config_namespace.py +35 -0
  68. nvda_addon_testkit-0.1.0/tests/test_download.py +95 -0
  69. nvda_addon_testkit-0.1.0/tests/test_e2e_conftest.py +84 -0
  70. nvda_addon_testkit-0.1.0/tests/test_errors.py +56 -0
  71. nvda_addon_testkit-0.1.0/tests/test_fake_nvda.py +162 -0
  72. nvda_addon_testkit-0.1.0/tests/test_keys_namespace.py +38 -0
  73. nvda_addon_testkit-0.1.0/tests/test_log_namespace.py +75 -0
  74. nvda_addon_testkit-0.1.0/tests/test_plugin.py +305 -0
  75. nvda_addon_testkit-0.1.0/tests/test_portable.py +115 -0
  76. nvda_addon_testkit-0.1.0/tests/test_process.py +198 -0
  77. nvda_addon_testkit-0.1.0/tests/test_provisioning.py +49 -0
  78. nvda_addon_testkit-0.1.0/tests/test_resolve.py +93 -0
  79. nvda_addon_testkit-0.1.0/tests/test_rpcclient.py +127 -0
  80. nvda_addon_testkit-0.1.0/tests/test_settings.py +58 -0
  81. nvda_addon_testkit-0.1.0/tests/test_speech_namespace.py +103 -0
  82. nvda_addon_testkit-0.1.0/tests/test_speechtypes.py +86 -0
  83. nvda_addon_testkit-0.1.0/tests_e2e/conftest.py +73 -0
  84. nvda_addon_testkit-0.1.0/tests_e2e/test_demo_addon.py +71 -0
  85. nvda_addon_testkit-0.1.0/tests_e2e/test_smoke.py +42 -0
  86. nvda_addon_testkit-0.1.0/tests_spy/__init__.py +0 -0
  87. nvda_addon_testkit-0.1.0/tests_spy/conftest.py +27 -0
  88. nvda_addon_testkit-0.1.0/tests_spy/nvda_stubs.py +367 -0
  89. nvda_addon_testkit-0.1.0/tests_spy/test_addons_api.py +89 -0
  90. nvda_addon_testkit-0.1.0/tests_spy/test_braille_tap.py +65 -0
  91. nvda_addon_testkit-0.1.0/tests_spy/test_config_api.py +108 -0
  92. nvda_addon_testkit-0.1.0/tests_spy/test_eval_api.py +47 -0
  93. nvda_addon_testkit-0.1.0/tests_spy/test_input_api.py +63 -0
  94. nvda_addon_testkit-0.1.0/tests_spy/test_log_tap.py +57 -0
  95. nvda_addon_testkit-0.1.0/tests_spy/test_mainthread.py +65 -0
  96. nvda_addon_testkit-0.1.0/tests_spy/test_plugin.py +208 -0
  97. nvda_addon_testkit-0.1.0/tests_spy/test_registry.py +58 -0
  98. nvda_addon_testkit-0.1.0/tests_spy/test_serialise.py +83 -0
  99. nvda_addon_testkit-0.1.0/tests_spy/test_server.py +88 -0
  100. nvda_addon_testkit-0.1.0/tests_spy/test_speech_tap.py +70 -0
  101. 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,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Usage / configuration help
4
+ url: https://github.com/ZirekHQ/nvda-addon-testkit/blob/main/README.md
5
+ about: Start here for install, configuration, and fixture reference.
@@ -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,13 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ dist/
5
+ build/
6
+ *.egg-info/
7
+ testOutput/
8
+ src/nvda_testkit/_spy/
9
+ src/nvda_testkit/_version.py
10
+ examples/demo-addon.nvda-addon
11
+ .pytest_cache/
12
+ .ruff_cache/
13
+ .idea/
@@ -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.