visual-regression-tracker 5.0.0__tar.gz → 5.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 (35) hide show
  1. visual_regression_tracker-5.1.0/.coveragerc +3 -0
  2. visual_regression_tracker-5.1.0/.github/dependabot.yml +37 -0
  3. visual_regression_tracker-5.1.0/.github/workflows/release.yml +80 -0
  4. visual_regression_tracker-5.1.0/.github/workflows/workflow.yml +29 -0
  5. visual_regression_tracker-5.1.0/.gitignore +11 -0
  6. visual_regression_tracker-5.1.0/.releaserc.json +12 -0
  7. visual_regression_tracker-5.1.0/PKG-INFO +231 -0
  8. visual_regression_tracker-5.1.0/README.md +207 -0
  9. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/pyproject.toml +4 -2
  10. visual_regression_tracker-5.1.0/requirements.txt +5 -0
  11. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/tests/test_config.py +8 -0
  12. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/tests/test_playwright.py +16 -13
  13. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/tests/test_playwright_async.py +16 -13
  14. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/tests/test_visualRegressionTracker.py +198 -6
  15. visual_regression_tracker-5.1.0/tox.ini +28 -0
  16. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/visual_regression_tracker/config.py +2 -0
  17. visual_regression_tracker-5.1.0/visual_regression_tracker/playwright.py +140 -0
  18. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/visual_regression_tracker/types.py +6 -0
  19. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/visual_regression_tracker/visualRegressionTracker.py +81 -16
  20. visual_regression_tracker-5.1.0/visual_regression_tracker.egg-info/PKG-INFO +231 -0
  21. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/visual_regression_tracker.egg-info/SOURCES.txt +10 -0
  22. visual_regression_tracker-5.1.0/visual_regression_tracker.egg-info/scm_file_list.json +26 -0
  23. visual_regression_tracker-5.1.0/visual_regression_tracker.egg-info/scm_version.json +8 -0
  24. visual_regression_tracker-5.0.0/PKG-INFO +0 -312
  25. visual_regression_tracker-5.0.0/README.md +0 -288
  26. visual_regression_tracker-5.0.0/visual_regression_tracker/playwright.py +0 -154
  27. visual_regression_tracker-5.0.0/visual_regression_tracker.egg-info/PKG-INFO +0 -312
  28. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/LICENSE +0 -0
  29. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/setup.cfg +0 -0
  30. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/tests/test_types.py +0 -0
  31. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/visual_regression_tracker/__init__.py +0 -0
  32. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/visual_regression_tracker/exceptions.py +0 -0
  33. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/visual_regression_tracker.egg-info/dependency_links.txt +0 -0
  34. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/visual_regression_tracker.egg-info/requires.txt +0 -0
  35. {visual_regression_tracker-5.0.0 → visual_regression_tracker-5.1.0}/visual_regression_tracker.egg-info/top_level.txt +0 -0
@@ -0,0 +1,3 @@
1
+ [run]
2
+ concurrency = greenlet
3
+ branch = True
@@ -0,0 +1,37 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: pip
4
+ # requirements.txt pins the dev tools; pyproject.toml keeps ranges, raised only when a fix needs it
5
+ directory: "/"
6
+ schedule:
7
+ interval: weekly
8
+ open-pull-requests-limit: 5
9
+ versioning-strategy: increase-if-necessary
10
+ groups:
11
+ # one PR for all minor/patch bumps
12
+ pip-minor-patch:
13
+ patterns:
14
+ - "*"
15
+ update-types:
16
+ - minor
17
+ - patch
18
+ # majors usually need code changes, so they come apart from minor/patch
19
+ pip-major:
20
+ patterns:
21
+ - "*"
22
+ update-types:
23
+ - major
24
+ # security fixes in a single PR too
25
+ pip-security:
26
+ applies-to: security-updates
27
+ patterns:
28
+ - "*"
29
+
30
+ - package-ecosystem: github-actions
31
+ directory: "/"
32
+ schedule:
33
+ interval: weekly
34
+ groups:
35
+ github-actions:
36
+ patterns:
37
+ - "*"
@@ -0,0 +1,80 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ concurrency:
11
+ group: release
12
+
13
+ jobs:
14
+ release:
15
+ runs-on: ubuntu-latest
16
+ permissions:
17
+ contents: write
18
+ issues: write
19
+ outputs:
20
+ version: ${{ steps.semantic-release.outputs.version }}
21
+ steps:
22
+ - uses: actions/checkout@v7
23
+ with:
24
+ fetch-depth: 0
25
+ - uses: actions/setup-python@v7
26
+ with:
27
+ python-version: '3.14'
28
+ - name: Test
29
+ run: |
30
+ pip install build '.[playwright]' -r requirements.txt
31
+ python -m playwright install --with-deps chromium
32
+ python -m pytest tests
33
+ - uses: actions/setup-node@v7
34
+ with:
35
+ node-version: 24
36
+ - name: Build, tag and draft the GitHub release
37
+ id: semantic-release
38
+ env:
39
+ GITHUB_TOKEN: ${{ github.token }}
40
+ # Preset 10+ needs conventional-changelog-writer 9; semantic-release 25 bundles writer 8.
41
+ run: >
42
+ npx --yes
43
+ -p semantic-release@25.0.9
44
+ -p @semantic-release/exec@7.1.0
45
+ -p conventional-changelog-conventionalcommits@9.3.1
46
+ semantic-release
47
+ - uses: actions/upload-artifact@v7
48
+ if: steps.semantic-release.outputs.version
49
+ with:
50
+ name: dist
51
+ path: dist/
52
+ if-no-files-found: error
53
+
54
+ publish:
55
+ needs: release
56
+ if: needs.release.outputs.version
57
+ runs-on: ubuntu-latest
58
+ environment:
59
+ name: pypi
60
+ url: https://pypi.org/project/visual-regression-tracker/${{ needs.release.outputs.version }}/
61
+ permissions:
62
+ id-token: write
63
+ steps:
64
+ - uses: actions/download-artifact@v8
65
+ with:
66
+ name: dist
67
+ path: dist/
68
+ - uses: pypa/gh-action-pypi-publish@release/v1
69
+
70
+ github-release:
71
+ needs: [release, publish]
72
+ runs-on: ubuntu-latest
73
+ permissions:
74
+ contents: write
75
+ steps:
76
+ - name: Publish the GitHub release
77
+ env:
78
+ GH_TOKEN: ${{ github.token }}
79
+ VERSION: ${{ needs.release.outputs.version }}
80
+ run: gh release edit "$VERSION" --repo "$GITHUB_REPOSITORY" --draft=false
@@ -0,0 +1,29 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ build:
11
+
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
17
+
18
+ steps:
19
+ - uses: actions/checkout@v7
20
+ - name: Set up Python ${{ matrix.python-version }}
21
+ uses: actions/setup-python@v7
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+ - name: Install Tox
25
+ run: pip install tox tox-gh-actions
26
+ - name: Install Playwright system dependencies
27
+ run: pip install playwright && python -m playwright install-deps chromium
28
+ - name: Run Tox
29
+ run: tox
@@ -0,0 +1,11 @@
1
+ .coverage
2
+ junit
3
+ visual_regression_tracker.egg-info
4
+ htmlcov
5
+ build
6
+ .idea
7
+ dist
8
+ __pycache__
9
+ .tox
10
+ .vscode
11
+ .python-version
@@ -0,0 +1,12 @@
1
+ {
2
+ "tagFormat": "${version}",
3
+ "plugins": [
4
+ ["@semantic-release/commit-analyzer", { "preset": "conventionalcommits" }],
5
+ ["@semantic-release/release-notes-generator", { "preset": "conventionalcommits" }],
6
+ ["@semantic-release/exec", {
7
+ "prepareCmd": "SETUPTOOLS_SCM_PRETEND_VERSION=${nextRelease.version} python -m build",
8
+ "successCmd": "echo \"version=${nextRelease.version}\" >> \"$GITHUB_OUTPUT\""
9
+ }],
10
+ ["@semantic-release/github", { "draftRelease": true, "successCommentCondition": false }]
11
+ ]
12
+ }
@@ -0,0 +1,231 @@
1
+ Metadata-Version: 2.4
2
+ Name: visual_regression_tracker
3
+ Version: 5.1.0
4
+ Summary: Open source, self hosted solution for visual testing and managing results of visual testing.
5
+ License-Expression: Apache-2.0
6
+ Project-URL: Homepage, https://github.com/Visual-Regression-Tracker/Visual-Regression-Tracker
7
+ Project-URL: Source, https://github.com/Visual-Regression-Tracker/sdk-python
8
+ Project-URL: Issues, https://github.com/Visual-Regression-Tracker/sdk-python/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Topic :: Software Development :: Testing
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: requests>=2.32.4
20
+ Requires-Dist: dacite>=1.9
21
+ Provides-Extra: playwright
22
+ Requires-Dist: playwright>=1.50; extra == "playwright"
23
+ Dynamic: license-file
24
+
25
+ # Python SDK for [Visual Regression Tracker](https://github.com/Visual-Regression-Tracker/Visual-Regression-Tracker)
26
+
27
+ [![CI](https://github.com/Visual-Regression-Tracker/sdk-python/actions/workflows/workflow.yml/badge.svg)](https://github.com/Visual-Regression-Tracker/sdk-python/actions/workflows/workflow.yml)
28
+ [![PyPI](https://img.shields.io/pypi/v/visual-regression-tracker)](https://pypi.org/project/visual-regression-tracker/)
29
+
30
+ Requires Python 3.10 or later. Use 5.x of this SDK with VRT 6.0; image URLs in results need VRT server 5.0.10 or later.
31
+
32
+ ## Install
33
+
34
+ ```sh
35
+ pip install visual-regression-tracker
36
+
37
+ # or, with the Playwright integration
38
+ pip install "visual-regression-tracker[playwright]"
39
+ python -m playwright install
40
+ ```
41
+
42
+ ## Configuration
43
+
44
+ | Option | Environment variable | Default | Meaning |
45
+ |---|---|---|---|
46
+ | `apiUrl` | `VRT_APIURL` | `http://localhost:4200` | URL of the VRT API |
47
+ | `apiKey` | `VRT_APIKEY` | required | API key of a VRT user |
48
+ | `project` | `VRT_PROJECT` | required | Project name or ID |
49
+ | `branchName` | `VRT_BRANCHNAME` | required | Current git branch |
50
+ | `ciBuildId` | `VRT_CIBUILDID` | none | CI build ID, such as the commit SHA; runs with the same ID share a build |
51
+ | `enableSoftAssert` | `VRT_ENABLESOFTASSERT` | `false` | Log a failed check instead of raising `TestRunError` |
52
+ | `httpTimeoutInSeconds` | `VRT_HTTPTIMEOUTINSECONDS` | `360` | How long to wait for the server's answer, `0` for no limit. Connecting is limited to 10 s. |
53
+ | `sourceBranch` | `VRT_SOURCEBRANCH` | the project's main branch | Branch whose baselines `branchName` is compared with, such as the target branch of a pull request |
54
+
55
+ The server compares images while it answers `track()`. With VLM checks or a busy comparison queue that can
56
+ take minutes, so keep `httpTimeoutInSeconds` above 300.
57
+
58
+ A `Config` passed to the constructor is used as it is:
59
+
60
+ ```python
61
+ from visual_regression_tracker import VisualRegressionTracker, Config
62
+
63
+ vrt = VisualRegressionTracker(Config(
64
+ apiUrl='http://localhost:4200',
65
+ apiKey='tXZVHX0EA4YQM1MGDD',
66
+ project='Default project',
67
+ branchName='develop',
68
+ ciBuildId='commit_sha',
69
+ ))
70
+ ```
71
+
72
+ Without one, the SDK reads `vrt.json` from the current working directory, then lets environment variables
73
+ override it. `Config.default(path)` reads another file.
74
+
75
+ ```json
76
+ {
77
+ "apiUrl": "http://localhost:4200",
78
+ "apiKey": "tXZVHX0EA4YQM1MGDD",
79
+ "project": "Default project",
80
+ "branchName": "develop",
81
+ "ciBuildId": "commit_sha",
82
+ "enableSoftAssert": false,
83
+ "httpTimeoutInSeconds": 360,
84
+ "sourceBranch": "main"
85
+ }
86
+ ```
87
+
88
+ ```sh
89
+ VRT_APIURL="http://localhost:4200" \
90
+ VRT_APIKEY="tXZVHX0EA4YQM1MGDD" \
91
+ VRT_PROJECT="Default project" \
92
+ VRT_BRANCHNAME="develop" \
93
+ VRT_CIBUILDID="commit_sha" \
94
+ VRT_ENABLESOFTASSERT=true \
95
+ VRT_HTTPTIMEOUTINSECONDS=360 \
96
+ VRT_SOURCEBRANCH="main" \
97
+ python -m pytest
98
+ ```
99
+
100
+ Empty variables are ignored. `VRT_ENABLESOFTASSERT` is true for `true` or `1`.
101
+
102
+ ## Usage
103
+
104
+ ```python
105
+ from visual_regression_tracker import VisualRegressionTracker, TestRun, IgnoreArea
106
+
107
+ with VisualRegressionTracker() as vrt: # start() on enter, stop() on exit
108
+ result = vrt.track(TestRun(
109
+ name='Home page',
110
+ imageBase64=image_base64,
111
+ ))
112
+ ```
113
+
114
+ Without the context manager, call `build = vrt.start()` (returns `Build(id, projectId)`) and `vrt.stop()`.
115
+
116
+ `TestRun` fields:
117
+
118
+ | Field | Meaning |
119
+ |---|---|
120
+ | `name` | Required. Name of the image in VRT |
121
+ | `imageBase64` | The PNG image, base64 encoded, sent as JSON |
122
+ | `imagePath` | Or: path of a PNG file, sent as multipart |
123
+ | `imageBuffer` | Or: the PNG image as `bytes`, sent as multipart |
124
+ | `os`, `browser`, `viewport`, `device`, `customTags` | Optional. Together with `name` they pick the baseline |
125
+ | `diffTollerancePercent` | Optional. Allowed difference in %, default 0. The spelling is the API's. |
126
+ | `ignoreAreas` | Optional. List of `IgnoreArea(x, y, width, height)` in pixels |
127
+ | `comment` | Optional. Shown with the test run in the VRT app |
128
+ | `merge` | Optional. `True`: approving this run on a feature branch updates the baseline of the branch it was compared with |
129
+
130
+ Set exactly one of the image fields. Multipart avoids the server's JSON size limit (`BODY_PARSER_JSON_LIMIT`)
131
+ and the base64 overhead, so prefer it for large screenshots.
132
+
133
+ ### Playwright
134
+
135
+ ```python
136
+ from playwright.sync_api import sync_playwright
137
+ from visual_regression_tracker.playwright import PlaywrightVisualRegressionTracker, PageTrackOptions
138
+
139
+ with sync_playwright() as playwright:
140
+ browser_type = playwright.chromium
141
+ page = browser_type.launch().new_page()
142
+ page.goto('https://www.python.org/')
143
+
144
+ with PlaywrightVisualRegressionTracker(browser_type) as vrt:
145
+ vrt.trackPage(page, 'Home page')
146
+ vrt.trackElementHandle(page.query_selector('#touchnav-wrapper'), 'Navigation')
147
+ ```
148
+
149
+ The screenshot is sent as multipart. `browser` is the Playwright browser name and `viewport` the page's viewport size. The async API has
150
+ `trackPageAsync` and `trackElementHandleAsync`.
151
+
152
+ The last argument is optional: `PageTrackOptions` for `trackPage`, `ElementHandleTrackOptions` for
153
+ `trackElementHandle`. Both take:
154
+
155
+ - `diffTollerancePercent`, `ignoreAreas`, `customTags`, `comment` and `merge`, as in `TestRun`;
156
+ - `agent: Agent(os, device, viewport)`: baseline fields Playwright doesn't know. `viewport` is used for
157
+ element handles and for pages without a viewport size;
158
+ - `screenshotOptions`: arguments for Playwright's `screenshot()`. `PageScreenshotOptions` takes
159
+ `full_page`, `clip`, `omit_background`, `timeout`, `type`, `quality` and `path`.
160
+ `ElementHandleScreenshotOptions` takes the same, without `full_page` and `clip`.
161
+
162
+ ## Result and statuses
163
+
164
+ `track` and the Playwright methods return a `TestRunResult`:
165
+
166
+ - `testRunResponse`: `id`, `status`, `url` (the test run in the VRT app), `diffPercent`,
167
+ `diffTollerancePercent`, `pixelMisMatchCount`, `merge`;
168
+ - `imageUrl`, `diffUrl` and `baselineUrl`: the images, under `{apiUrl}/images/`. `diffUrl` and
169
+ `baselineUrl` are `None` when there is no diff or baseline.
170
+
171
+ | `TestRunStatus` | Server status | `track` |
172
+ |---|---|---|
173
+ | `OK` | `ok` | passes |
174
+ | `APPROVED` | `approved` | passes |
175
+ | `AUTO_APPROVED` | `autoApproved` | passes |
176
+ | `FAILED` | `failed` | passes, as in the other SDKs |
177
+ | `NEW` | `new` (no baseline yet) | raises `TestRunError` |
178
+ | `UNRESOLVED` | `unresolved` (difference found) | raises `TestRunError` |
179
+ | `UNKNOWN` | any other | passes, logs a warning |
180
+
181
+ With `enableSoftAssert`, `track` logs `new` and `unresolved` as errors instead of raising.
182
+
183
+ ## Errors
184
+
185
+ All errors derive from `VisualRegressionTrackerError`.
186
+
187
+ | Error | When |
188
+ |---|---|
189
+ | `ServerError` | The server answered with an HTTP error. `status_code` and the server's `message`; 413 and 422 add a hint about the server's size limits. |
190
+ | `RequestError` | No answer: connection refused, connect timeout, or read timeout after `httpTimeoutInSeconds`. Has the `url`. A read timeout on `track` doesn't mean the server dropped the test run: it may still be stored. |
191
+ | `TestRunError` | `track` got `new` or `unresolved`. Has the `status`. |
192
+ | `MissingConfigurationError` | A required option is not set. Has the `field`. |
193
+ | `InvalidConfigurationError` | An option has an invalid value. Has the `field`. |
194
+ | `VisualRegressionTrackerError` | `track` or `stop` before `start`. |
195
+ | `ValueError` | A `TestRun` with more than one image field. |
196
+
197
+ When the server answers 503 with a `Retry-After` of at most 60 seconds (the comparison queue is full, or the
198
+ server is restarting), the SDK waits that long and sends the request again, up to 3 times, logging a warning
199
+ each time. After that, or without a usable `Retry-After`, it raises `ServerError`.
200
+
201
+ ## Development
202
+
203
+ ```sh
204
+ pip install -e '.[playwright]' -r requirements.txt
205
+ python -m playwright install chromium
206
+ python -m pytest
207
+ ```
208
+
209
+ `tox` runs the tests on every supported Python.
210
+
211
+ ## Releasing
212
+
213
+ Merging to `master` releases. [semantic-release](https://semantic-release.gitbook.io/) reads the
214
+ [Conventional Commits](https://www.conventionalcommits.org/) since the last tag: `fix:`, `perf:` and `revert:` make a
215
+ patch, `feat:` a minor, and `!` after the type (`feat!:`) or a `BREAKING CHANGE:` footer a major release.
216
+ Other types (`chore:`, `ci:`, `docs:`, ...) release nothing. A squash merge takes the PR title (or, for a
217
+ single-commit PR, that commit's message) as its subject, so keep both conventional.
218
+
219
+ The `Release` workflow runs the tests, tags the commit (`5.1.0`, no `v`), publishes to PyPI and then
220
+ publishes the GitHub release with the generated notes. The package version comes from the tag
221
+ (setuptools-scm); nothing is committed back.
222
+
223
+ If publishing fails, the tag and a draft release already exist: re-run the failed jobs of that run
224
+ (not the whole run) before anything else is merged.
225
+
226
+ ## Links
227
+
228
+ - [Visual Regression Tracker](https://github.com/Visual-Regression-Tracker/Visual-Regression-Tracker): the server and how to run it
229
+ - [Python examples](https://github.com/Visual-Regression-Tracker/examples-python)
230
+ - [Other SDKs and agents](https://github.com/Visual-Regression-Tracker)
231
+ - [Licence: Apache-2.0](LICENSE)
@@ -0,0 +1,207 @@
1
+ # Python SDK for [Visual Regression Tracker](https://github.com/Visual-Regression-Tracker/Visual-Regression-Tracker)
2
+
3
+ [![CI](https://github.com/Visual-Regression-Tracker/sdk-python/actions/workflows/workflow.yml/badge.svg)](https://github.com/Visual-Regression-Tracker/sdk-python/actions/workflows/workflow.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/visual-regression-tracker)](https://pypi.org/project/visual-regression-tracker/)
5
+
6
+ Requires Python 3.10 or later. Use 5.x of this SDK with VRT 6.0; image URLs in results need VRT server 5.0.10 or later.
7
+
8
+ ## Install
9
+
10
+ ```sh
11
+ pip install visual-regression-tracker
12
+
13
+ # or, with the Playwright integration
14
+ pip install "visual-regression-tracker[playwright]"
15
+ python -m playwright install
16
+ ```
17
+
18
+ ## Configuration
19
+
20
+ | Option | Environment variable | Default | Meaning |
21
+ |---|---|---|---|
22
+ | `apiUrl` | `VRT_APIURL` | `http://localhost:4200` | URL of the VRT API |
23
+ | `apiKey` | `VRT_APIKEY` | required | API key of a VRT user |
24
+ | `project` | `VRT_PROJECT` | required | Project name or ID |
25
+ | `branchName` | `VRT_BRANCHNAME` | required | Current git branch |
26
+ | `ciBuildId` | `VRT_CIBUILDID` | none | CI build ID, such as the commit SHA; runs with the same ID share a build |
27
+ | `enableSoftAssert` | `VRT_ENABLESOFTASSERT` | `false` | Log a failed check instead of raising `TestRunError` |
28
+ | `httpTimeoutInSeconds` | `VRT_HTTPTIMEOUTINSECONDS` | `360` | How long to wait for the server's answer, `0` for no limit. Connecting is limited to 10 s. |
29
+ | `sourceBranch` | `VRT_SOURCEBRANCH` | the project's main branch | Branch whose baselines `branchName` is compared with, such as the target branch of a pull request |
30
+
31
+ The server compares images while it answers `track()`. With VLM checks or a busy comparison queue that can
32
+ take minutes, so keep `httpTimeoutInSeconds` above 300.
33
+
34
+ A `Config` passed to the constructor is used as it is:
35
+
36
+ ```python
37
+ from visual_regression_tracker import VisualRegressionTracker, Config
38
+
39
+ vrt = VisualRegressionTracker(Config(
40
+ apiUrl='http://localhost:4200',
41
+ apiKey='tXZVHX0EA4YQM1MGDD',
42
+ project='Default project',
43
+ branchName='develop',
44
+ ciBuildId='commit_sha',
45
+ ))
46
+ ```
47
+
48
+ Without one, the SDK reads `vrt.json` from the current working directory, then lets environment variables
49
+ override it. `Config.default(path)` reads another file.
50
+
51
+ ```json
52
+ {
53
+ "apiUrl": "http://localhost:4200",
54
+ "apiKey": "tXZVHX0EA4YQM1MGDD",
55
+ "project": "Default project",
56
+ "branchName": "develop",
57
+ "ciBuildId": "commit_sha",
58
+ "enableSoftAssert": false,
59
+ "httpTimeoutInSeconds": 360,
60
+ "sourceBranch": "main"
61
+ }
62
+ ```
63
+
64
+ ```sh
65
+ VRT_APIURL="http://localhost:4200" \
66
+ VRT_APIKEY="tXZVHX0EA4YQM1MGDD" \
67
+ VRT_PROJECT="Default project" \
68
+ VRT_BRANCHNAME="develop" \
69
+ VRT_CIBUILDID="commit_sha" \
70
+ VRT_ENABLESOFTASSERT=true \
71
+ VRT_HTTPTIMEOUTINSECONDS=360 \
72
+ VRT_SOURCEBRANCH="main" \
73
+ python -m pytest
74
+ ```
75
+
76
+ Empty variables are ignored. `VRT_ENABLESOFTASSERT` is true for `true` or `1`.
77
+
78
+ ## Usage
79
+
80
+ ```python
81
+ from visual_regression_tracker import VisualRegressionTracker, TestRun, IgnoreArea
82
+
83
+ with VisualRegressionTracker() as vrt: # start() on enter, stop() on exit
84
+ result = vrt.track(TestRun(
85
+ name='Home page',
86
+ imageBase64=image_base64,
87
+ ))
88
+ ```
89
+
90
+ Without the context manager, call `build = vrt.start()` (returns `Build(id, projectId)`) and `vrt.stop()`.
91
+
92
+ `TestRun` fields:
93
+
94
+ | Field | Meaning |
95
+ |---|---|
96
+ | `name` | Required. Name of the image in VRT |
97
+ | `imageBase64` | The PNG image, base64 encoded, sent as JSON |
98
+ | `imagePath` | Or: path of a PNG file, sent as multipart |
99
+ | `imageBuffer` | Or: the PNG image as `bytes`, sent as multipart |
100
+ | `os`, `browser`, `viewport`, `device`, `customTags` | Optional. Together with `name` they pick the baseline |
101
+ | `diffTollerancePercent` | Optional. Allowed difference in %, default 0. The spelling is the API's. |
102
+ | `ignoreAreas` | Optional. List of `IgnoreArea(x, y, width, height)` in pixels |
103
+ | `comment` | Optional. Shown with the test run in the VRT app |
104
+ | `merge` | Optional. `True`: approving this run on a feature branch updates the baseline of the branch it was compared with |
105
+
106
+ Set exactly one of the image fields. Multipart avoids the server's JSON size limit (`BODY_PARSER_JSON_LIMIT`)
107
+ and the base64 overhead, so prefer it for large screenshots.
108
+
109
+ ### Playwright
110
+
111
+ ```python
112
+ from playwright.sync_api import sync_playwright
113
+ from visual_regression_tracker.playwright import PlaywrightVisualRegressionTracker, PageTrackOptions
114
+
115
+ with sync_playwright() as playwright:
116
+ browser_type = playwright.chromium
117
+ page = browser_type.launch().new_page()
118
+ page.goto('https://www.python.org/')
119
+
120
+ with PlaywrightVisualRegressionTracker(browser_type) as vrt:
121
+ vrt.trackPage(page, 'Home page')
122
+ vrt.trackElementHandle(page.query_selector('#touchnav-wrapper'), 'Navigation')
123
+ ```
124
+
125
+ The screenshot is sent as multipart. `browser` is the Playwright browser name and `viewport` the page's viewport size. The async API has
126
+ `trackPageAsync` and `trackElementHandleAsync`.
127
+
128
+ The last argument is optional: `PageTrackOptions` for `trackPage`, `ElementHandleTrackOptions` for
129
+ `trackElementHandle`. Both take:
130
+
131
+ - `diffTollerancePercent`, `ignoreAreas`, `customTags`, `comment` and `merge`, as in `TestRun`;
132
+ - `agent: Agent(os, device, viewport)`: baseline fields Playwright doesn't know. `viewport` is used for
133
+ element handles and for pages without a viewport size;
134
+ - `screenshotOptions`: arguments for Playwright's `screenshot()`. `PageScreenshotOptions` takes
135
+ `full_page`, `clip`, `omit_background`, `timeout`, `type`, `quality` and `path`.
136
+ `ElementHandleScreenshotOptions` takes the same, without `full_page` and `clip`.
137
+
138
+ ## Result and statuses
139
+
140
+ `track` and the Playwright methods return a `TestRunResult`:
141
+
142
+ - `testRunResponse`: `id`, `status`, `url` (the test run in the VRT app), `diffPercent`,
143
+ `diffTollerancePercent`, `pixelMisMatchCount`, `merge`;
144
+ - `imageUrl`, `diffUrl` and `baselineUrl`: the images, under `{apiUrl}/images/`. `diffUrl` and
145
+ `baselineUrl` are `None` when there is no diff or baseline.
146
+
147
+ | `TestRunStatus` | Server status | `track` |
148
+ |---|---|---|
149
+ | `OK` | `ok` | passes |
150
+ | `APPROVED` | `approved` | passes |
151
+ | `AUTO_APPROVED` | `autoApproved` | passes |
152
+ | `FAILED` | `failed` | passes, as in the other SDKs |
153
+ | `NEW` | `new` (no baseline yet) | raises `TestRunError` |
154
+ | `UNRESOLVED` | `unresolved` (difference found) | raises `TestRunError` |
155
+ | `UNKNOWN` | any other | passes, logs a warning |
156
+
157
+ With `enableSoftAssert`, `track` logs `new` and `unresolved` as errors instead of raising.
158
+
159
+ ## Errors
160
+
161
+ All errors derive from `VisualRegressionTrackerError`.
162
+
163
+ | Error | When |
164
+ |---|---|
165
+ | `ServerError` | The server answered with an HTTP error. `status_code` and the server's `message`; 413 and 422 add a hint about the server's size limits. |
166
+ | `RequestError` | No answer: connection refused, connect timeout, or read timeout after `httpTimeoutInSeconds`. Has the `url`. A read timeout on `track` doesn't mean the server dropped the test run: it may still be stored. |
167
+ | `TestRunError` | `track` got `new` or `unresolved`. Has the `status`. |
168
+ | `MissingConfigurationError` | A required option is not set. Has the `field`. |
169
+ | `InvalidConfigurationError` | An option has an invalid value. Has the `field`. |
170
+ | `VisualRegressionTrackerError` | `track` or `stop` before `start`. |
171
+ | `ValueError` | A `TestRun` with more than one image field. |
172
+
173
+ When the server answers 503 with a `Retry-After` of at most 60 seconds (the comparison queue is full, or the
174
+ server is restarting), the SDK waits that long and sends the request again, up to 3 times, logging a warning
175
+ each time. After that, or without a usable `Retry-After`, it raises `ServerError`.
176
+
177
+ ## Development
178
+
179
+ ```sh
180
+ pip install -e '.[playwright]' -r requirements.txt
181
+ python -m playwright install chromium
182
+ python -m pytest
183
+ ```
184
+
185
+ `tox` runs the tests on every supported Python.
186
+
187
+ ## Releasing
188
+
189
+ Merging to `master` releases. [semantic-release](https://semantic-release.gitbook.io/) reads the
190
+ [Conventional Commits](https://www.conventionalcommits.org/) since the last tag: `fix:`, `perf:` and `revert:` make a
191
+ patch, `feat:` a minor, and `!` after the type (`feat!:`) or a `BREAKING CHANGE:` footer a major release.
192
+ Other types (`chore:`, `ci:`, `docs:`, ...) release nothing. A squash merge takes the PR title (or, for a
193
+ single-commit PR, that commit's message) as its subject, so keep both conventional.
194
+
195
+ The `Release` workflow runs the tests, tags the commit (`5.1.0`, no `v`), publishes to PyPI and then
196
+ publishes the GitHub release with the generated notes. The package version comes from the tag
197
+ (setuptools-scm); nothing is committed back.
198
+
199
+ If publishing fails, the tag and a draft release already exist: re-run the failed jobs of that run
200
+ (not the whole run) before anything else is merged.
201
+
202
+ ## Links
203
+
204
+ - [Visual Regression Tracker](https://github.com/Visual-Regression-Tracker/Visual-Regression-Tracker): the server and how to run it
205
+ - [Python examples](https://github.com/Visual-Regression-Tracker/examples-python)
206
+ - [Other SDKs and agents](https://github.com/Visual-Regression-Tracker)
207
+ - [Licence: Apache-2.0](LICENSE)
@@ -1,10 +1,10 @@
1
1
  [build-system]
2
- requires = ["setuptools>=77"]
2
+ requires = ["setuptools>=77", "setuptools-scm>=8"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "visual_regression_tracker"
7
- version = "5.0.0"
7
+ dynamic = ["version"]
8
8
  description = "Open source, self hosted solution for visual testing and managing results of visual testing."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -35,6 +35,8 @@ Issues = "https://github.com/Visual-Regression-Tracker/sdk-python/issues"
35
35
  [tool.setuptools]
36
36
  packages = ["visual_regression_tracker"]
37
37
 
38
+ [tool.setuptools_scm]
39
+
38
40
  [tool.pytest.ini_options]
39
41
  python_classes = "NoThanks"
40
42
  junit_family = "xunit2"
@@ -0,0 +1,5 @@
1
+ pytest==9.2.0
2
+ pytest-cov==7.1.0
3
+ pytest-mock==3.17.0
4
+ pytest-asyncio==1.4.1.post1
5
+ pylint==4.1.3