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