You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tracking issue capturing a design discussion (June 2026) on maturing our testing setup. We started writing tests for the first time a few days ago (see #1267); the suite now lives in website/tests.py (~1,580 lines) with a solid two-tier design — SimpleTestCase + MagicMock for pure logic, DatabaseTestCase for the DB/view/template layer. The tests exist; nothing runs them automatically.
The core gap
We auto-deploy master to the test server on every push:
push to master → live on makeabilitylab-test.cs.washington.edu, with no checks in between.
So the regression tests we just wrote only protect us if a contributor remembers to run manage.py test in the container before pushing. With rotating student contributors and push-to-deploy, that honor-system gate is exactly what continuous integration (CI) removes.
Mechanics / cost (for the record)
GitHub Actions is free and unlimited for public repos (this repo is public). No billing, no minute caps. A run of our suite is ~1–3 min.
A failing test is a signal, not a gate: it shows a red ✗ on the commit and emails the author. It does not block, revert, or alter pushed code. Merge-blocking only happens if we opt into branch protection later.
4. Coverage measurement — coverage.py (stay on Django's runner; no pytest). Report in CI, don't gate on a number yet — use it to target backfill.
5. Backfill high-risk untested code — ranked: delete_unused_files.py (runs every container start, deletes files, two latent crashes already found); a parametrized view smoke-sweep (GET every public URL → 200, catches the NoReverseMatch/AttributeError template bug class); Person.save() side effects; pure utils (timeutils, ml_utils, fileutils).
6. Pa11y in CI — we already have the service + .pa11yci.json; CONTRIBUTING requires it on UI changes but nothing enforces it. Wire into the workflow.
7. JS unit tests — deferred. ~2,633 lines of vanilla JS (incl. a11y-critical lightbox.js), but a Jest/node harness adds the build step we deliberately avoid. Let Pa11y cover rendered a11y for now; revisit only if we want unit-level JS coverage.
First PR
Items 1 + 2 + 3 shipped together in #1279 / PR #1280 (merged 2026-06-15) — CI now runs the suite on every push to master and every PR.
Remaining work: items 4, 5, 6 (item 7 deferred). Each is a good standalone PR.
Summary
Tracking issue capturing a design discussion (June 2026) on maturing our testing setup. We started writing tests for the first time a few days ago (see #1267); the suite now lives in
website/tests.py(~1,580 lines) with a solid two-tier design —SimpleTestCase+MagicMockfor pure logic,DatabaseTestCasefor the DB/view/template layer. The tests exist; nothing runs them automatically.The core gap
We auto-deploy
masterto the test server on every push:So the regression tests we just wrote only protect us if a contributor remembers to run
manage.py testin the container before pushing. With rotating student contributors and push-to-deploy, that honor-system gate is exactly what continuous integration (CI) removes.Mechanics / cost (for the record)
Prioritized roadmap
manage.py test websiteon PRs (and optionally pushes tomaster) against a Postgres 16 service container. Highest leverage. ✅ Done in Add CI + test-settings shim + split tests into a package (#1279) #1280.makeabilitylab/settings_test.pywithMIGRATION_MODULES = {'website': None}+--run-syncdbso the runner builds schema from models, bypassing the gitignored per-env migration history. Durable fix for thecolumn already existsflakiness (Need much better testing infracture on local host #1267). Prerequisite for CI. ✅ Done in Add CI + test-settings shim + split tests into a package (#1279) #1280.tests.pyinto atests/package —tests/base.py(sharedDatabaseTestCase+ fixtures) plustest_*.pyby concern. Django auto-discovers; pure move, no config. ✅ Done in Add CI + test-settings shim + split tests into a package (#1279) #1280.coverage.py(stay on Django's runner; no pytest). Report in CI, don't gate on a number yet — use it to target backfill.delete_unused_files.py(runs every container start, deletes files, two latent crashes already found); a parametrized view smoke-sweep (GETevery public URL → 200, catches the NoReverseMatch/AttributeError template bug class);Person.save()side effects; pure utils (timeutils,ml_utils,fileutils)..pa11yci.json; CONTRIBUTING requires it on UI changes but nothing enforces it. Wire into the workflow.lightbox.js), but a Jest/node harness adds the build step we deliberately avoid. Let Pa11y cover rendered a11y for now; revisit only if we want unit-level JS coverage.First PR
Items 1 + 2 + 3 shipped together in #1279 / PR #1280 (merged 2026-06-15) — CI now runs the suite on every push to
masterand every PR.Remaining work: items 4, 5, 6 (item 7 deferred). Each is a good standalone PR.
Related