Skip to content

Commit 8fa511f

Browse files
Merge branch 'dev' into feat/migrate-export-to-playwright-v2
2 parents d60aeb1 + 39371f7 commit 8fa511f

43 files changed

Lines changed: 1731 additions & 388 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/context/backend.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
## Coding Rules
1515

1616
- Follow PEP 8, format with `black py` (v23.1.0), 80-char lines
17-
- Python >= 3.8 compatibility
17+
- Python >= 3.12 compatibility
1818
- Use `@pytorch_wrap` on all `Visdom` methods
1919
- Use `warn_once()` for deprecation warnings
2020

.agents/context/testing.md

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
11
# Testing Instructions
22

3-
Cypress 9 for E2E and visual regression. No Python unit tests — validation is via demo scripts and Cypress.
3+
Two layers: **pytest** for Python unit tests (pure functions, server utils, window/env lifecycle) and **Cypress 9** for E2E and visual regression. Demo scripts remain useful for manual/visual validation.
44

5-
## Run Tests
5+
## Run Python Tests (pytest)
6+
7+
```bash
8+
pip install -r test-requirements.txt # includes pytest, pytest-cov
9+
pytest # runs the tracked suite under py/tests/
10+
pytest -m "not server" # skip tests that need a live server (CI default)
11+
```
12+
13+
Config lives in `pyproject.toml` (`[tool.pytest.ini_options]`): discovery is scoped to
14+
`py/tests/` and `pythonpath = ["py"]` makes `import visdom` work without an editable install.
15+
Experimental `test_*.py` scripts in the repo root (and `test/`) are intentionally out of scope.
16+
17+
## Run E2E / Visual Tests (Cypress)
618

719
```bash
820
visdom -port 8098 -env_path /tmp # Always start fresh server first
@@ -24,9 +36,19 @@ Always use port `8098` and `-env_path /tmp` for isolation.
2436

2537
`basic.js` (connection), `pane.js` (CRUD), `text.js`, `image.js`, `properties.js`, `modal.js`, `misc.js`, `screenshots.init.js` (baseline), `screenshots.js` (comparison).
2638

39+
## Writing Python Tests
40+
41+
- Place in `py/tests/`, name files `test_*.py`, classes `Test*` (unittest `TestCase` or plain
42+
pytest functions both work — pytest auto-discovers unittest).
43+
- Keep them hermetic (no running server). A test that genuinely needs a live server must be
44+
marked `@pytest.mark.server` so CI can deselect it.
45+
- Start with simple hermetic tests (e.g., `test_smoke.py`) and add focused unit tests for
46+
server/window/env lifecycle code as coverage grows.
47+
2748
## CI
2849

29-
- Python 3.8, 3.9, 3.10 matrix, both WebSocket and polling modes
50+
- `python-tests.yml` runs `pytest -m "not server"` on a Python version matrix for every pull
51+
request (and on pushes to master/dev)
3052
- Visual regression compares PR screenshots against base branch
3153
- `update-js-build-files.yml` auto-compiles JS on master
3254
- `pypi.yml` publishes to PyPI when VERSION changes

.github/actions/prepare/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ inputs:
1212
python-version:
1313
description: 'Python version to use'
1414
required: false
15-
default: '3.10'
15+
default: '3.12'
1616

1717
runs:
1818
using: "composite"

.github/workflows/deploy-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,4 @@ jobs:
5252
steps:
5353
- name: Deploy to GitHub Pages
5454
id: deployment
55-
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e
55+
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128

.github/workflows/process-changes.yml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ jobs:
154154
needs: install-and-build
155155
strategy:
156156
matrix:
157-
python: ['3.10', '3.11', '3.12']
157+
python: ['3.12', '3.13']
158158
steps:
159159
- name: "Checkout Repository"
160160
uses: actions/checkout@v7.0.0
@@ -202,3 +202,27 @@ jobs:
202202
with:
203203
name: cypress-screenshots-functional-polling
204204
path: cypress/screenshots
205+
206+
playwright-test:
207+
name: "Playwright Functional Test"
208+
runs-on: ubuntu-latest
209+
needs: install-and-build
210+
steps:
211+
- name: "Checkout Repository"
212+
uses: actions/checkout@v7.0.0
213+
- uses: ./.github/actions/prepare
214+
215+
- name: Install Playwright Chromium
216+
run: npx playwright install --with-deps chromium
217+
218+
219+
220+
- name: Run Playwright tests
221+
run: npm run test:pw
222+
223+
- name: Upload Playwright Report
224+
uses: actions/upload-artifact@v7
225+
if: failure()
226+
with:
227+
name: playwright-report
228+
path: playwright/playwright-report/

.github/workflows/python-tests.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Python Tests
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- master
8+
- dev
9+
10+
jobs:
11+
pytest:
12+
name: "pytest (Python ${{ matrix.python-version }})"
13+
runs-on: ubuntu-latest
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
python-version: ["3.12", "3.13"]
18+
steps:
19+
- name: Checkout Repository
20+
uses: actions/checkout@v7.0.0
21+
- name: Set up Python
22+
uses: actions/setup-python@v6
23+
with:
24+
python-version: ${{ matrix.python-version }}
25+
- name: Install package and test dependencies
26+
run: |
27+
python -m pip install --upgrade pip
28+
python -m pip install -e .
29+
python -m pip install -r test-requirements.txt
30+
- name: Run pytest
31+
run: pytest -m "not server"

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,10 @@ website/.docusaurus
3030
venv
3131
test-bin
3232
bin
33+
34+
playwright/playwright-report/
35+
playwright/test-results/
36+
playwright/tmp/
37+
playwright-report/
38+
test-results/
39+
tmp/

AGENTS.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# AGENTS instructions
55

66
Visdom: Python client + Tornado server + React frontend for live data visualization.
7-
Version `0.2.4` · Python >= 3.8 · Apache 2.0
7+
Version `0.2.4` · Python >= 3.12 · Apache 2.0
88

99
## Setup
1010

@@ -38,14 +38,15 @@ Version `0.2.4` · Python >= 3.8 · Apache 2.0
3838

3939
## Testing
4040

41-
- Start server: `visdom -port 8098 -env_path /tmp`
41+
- Python unit tests: `pytest -m "not server"` (config in `pyproject.toml`, suite in `py/tests/`)
42+
- Start server (for Cypress): `visdom -port 8098 -env_path /tmp`
4243
- Baseline: `npm run test:init`
43-
- Run tests: `npm run test`
44+
- Run E2E tests: `npm run test`
4445
- Pre-commit: `pre-commit run --all-files`
4546

4647
## PR Checklist
4748

48-
- Branch from `master`, add Cypress tests for new code
49+
- Branch from `master`; add `pytest` tests in `py/tests/` for Python code and Cypress tests for frontend behavior
4950
- Update `README` for API changes, `__init__.pyi` for interface changes
5051
- Run linters, do not commit `py/visdom/static/`
5152

CONTRIBUTING.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,19 @@ To run the predefined tests
193193
5. run `npm run test:gui` (a new window should appear)
194194
6. click through the test spec-files and observe the tests done automatically in a newly opened browser instance
195195

196-
**as CLI tests**:
196+
**as CLI tests (Cypress)**:
197197
1. start a fresh visdom server instance on port `8098` , i.e. by just calling `visdom -port 8098` (Just to make sure another instance is not interfering with our test.)
198198
2. run `npm run test:init`. This generates screenshots of all plots for the visual regression testing.
199199
3. Adapt the code now to your needs.
200200
4. run `npm run build` *or* `npm run dev` (enables automatic building)
201201
5. run `npm run test`
202202

203+
**using Playwright (E2E tests)**:
204+
1. start a fresh visdom server instance on port `8098` using your environment's Python, i.e. `python -m visdom.server -port 8098 -env_path playwright/tmp` (make sure no other instances interfere).
205+
2. run `npx playwright install chromium` on first setup to install the browser.
206+
3. run `npm run build` *or* `npm run dev` to compile the frontend code.
207+
4. run the Playwright test suite: `npm run test:pw`
208+
203209
## Issues
204210
We use GitHub issues to track public bugs. Please ensure your description is
205211
clear and has sufficient instructions to be able to reproduce the issue.

README.md

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ The following API is currently supported:
287287
- [`vis.line`](#visline) : line plots
288288
- [`vis.stem`](#visstem) : stem plots
289289
- [`vis.heatmap`](#visheatmap) : heatmap plots
290+
- [`vis.confusion_matrix`](#visconfusion_matrix) : confusion matrix plots
290291
- [`vis.bar`](#visbar) : bar graphs
291292
- [`vis.histogram`](#vishistogram) : histograms
292293
- [`vis.histogram2d`](#vishistogram2d) : 2D histograms (density maps)
@@ -295,6 +296,8 @@ The following API is currently supported:
295296
- [`vis.pie`](#vispie) : pie charts
296297
- [`vis.surf`](#vissurf) : surface plots
297298
- [`vis.contour`](#viscontour) : contour plots
299+
- [`vis.roc_curve`](#visroc_curve) : ROC curves
300+
- [`vis.pr_curve`](#vispr_curve) : precision-recall curves
298301
- [`vis.quiver`](#visquiver) : quiver plots
299302
- [`vis.mesh`](#vismesh) : mesh plots
300303
- [`vis.sankey`](#vissankey) : sankey (flow) diagrams
@@ -549,6 +552,34 @@ The following `opts` are supported:
549552
- `opts.traceopts` : `dict` mapping trace names or indices to `dict`s of additional options that plot.ly accepts for a trace.
550553
- `opts.webgl` : use WebGL for plotting (`boolean`; default = `false`). It is faster if a plot contains too many points. Use sparingly as browsers won't allow more than a couple of WebGL contexts on a single page.
551554

555+
#### vis.roc_curve
556+
This function draws a ROC curve for binary classification.
557+
558+
It accepts either:
559+
- raw binary labels and scores via `y_true` and `y_score`, or
560+
- precomputed curve points via `fpr` and `tpr`.
561+
562+
The following `opts` are supported:
563+
- `opts.title` : plot title (`string`; default includes ROC-AUC)
564+
- `opts.legend` : two legend labels for curve and baseline (`list`)
565+
- `opts.xlabel` : x-axis label (`string`; default = `False Positive Rate`)
566+
- `opts.ylabel` : y-axis label (`string`; default = `True Positive Rate`)
567+
- `opts.layoutopts` : additional backend layout options (`dict`)
568+
569+
#### vis.pr_curve
570+
This function draws a precision-recall curve for binary classification.
571+
572+
It accepts either:
573+
- raw binary labels and scores via `y_true` and `y_score`, or
574+
- precomputed curve points via `precision` and `recall`.
575+
576+
The following `opts` are supported:
577+
- `opts.title` : plot title (`string`; default includes PR-AUC)
578+
- `opts.legend` : two legend labels for curve and baseline (`list`)
579+
- `opts.xlabel` : x-axis label (`string`; default = `Recall`)
580+
- `opts.ylabel` : y-axis label (`string`; default = `Precision`)
581+
- `opts.layoutopts` : additional backend layout options (`dict`)
582+
552583

553584
#### vis.stem
554585
This function draws a stem plot. It takes as input an `N` or `NxM` tensor
@@ -579,6 +610,32 @@ The following `opts` are supported:
579610
- `opts.layoutopts` : `dict` of any additional options that the graph backend accepts for a layout. For example `layoutopts = {'plotly': {'legend': {'x':0, 'y':0}}}`.
580611
- `opts.nancolor` : color for plotting `NaN`s. If this is `None`, `NaN`s will be plotted as transparent. (`string`; default = `None`)
581612

613+
#### vis.confusion_matrix
614+
This function draws a confusion matrix for classification evaluation.
615+
616+
It accepts either:
617+
- raw label vectors via `y_true` and `y_pred`, or
618+
- a precomputed confusion matrix via `cm`.
619+
620+
Optional normalization can be applied with the `normalize` parameter:
621+
- `'true'`: normalize by row (actual class)
622+
- `'pred'`: normalize by column (predicted class)
623+
- `'all'`: normalize by total count
624+
625+
An existing confusion matrix window can be modified with the `update` parameter:
626+
- `'replace'`: redraw the whole matrix in the window given by `win`
627+
- `'remove'`: delete the window given by `win`
628+
629+
The following `opts` are supported:
630+
631+
- `opts.title` : plot title (`string`; default = `Confusion Matrix`)
632+
- `opts.xlabel` : x-axis label (`string`; default = `Predicted`)
633+
- `opts.ylabel` : y-axis label (`string`; default = `Actual`)
634+
- `opts.colormap` : Plotly colorscale (`string`; default = `Blues`)
635+
- `opts.showCounts` : show raw counts in cells (`bool`; default = `True`)
636+
- `opts.showPercent` : show percentages in cells (`bool`; default = `True` when normalized, `False` otherwise)
637+
- `opts.layoutopts` : `dict` of any additional options that the graph backend accepts for a layout.
638+
582639
#### vis.bar
583640
This function draws a regular, stacked, or grouped bar plot. It takes as
584641
input an `N` or `NxM` tensor `X` that specifies the height of each of the
@@ -879,7 +936,7 @@ visdom is Apache 2.0 licensed, as found in the LICENSE file.
879936
Support for Lua Torch was deprecated following `v0.1.8.4`. If you'd like to use torch support, you'll need to download that release. You can follow the usage instructions there, but it is no longer officially supported.
880937

881938
## Contributing
882-
See guidelines for contributing [here.](./CONTRIBUTING.md)
939+
See guidelines for contributing and running E2E/visual tests (Cypress and Playwright) [here.](./CONTRIBUTING.md)
883940

884941
## Acknowledgments
885942
Visdom was inspired by tools like [display](https://github.com/szym/display) and relies on [Plotly](https://plot.ly/) as a plotting front-end.

0 commit comments

Comments
 (0)