Skip to content

Releases

v1.6.0

Choose a tag to compare

@arieleven arieleven released this 05 Nov 09:47
66b052c

Install: pip install qasight==1.6.0 (team server and web UI: pip install "qasight[api]==1.6.0")

Testosterone is now QASight. The package is qasight, the command is qasight and the config file is qasight.yaml. Nothing old stops working: pip install -U testo-core upgrades you (it now installs qasight), and the testo command, testosterone.yaml, pytest --testo and every TESTO_* setting still work. The repository moved to arieleven/qasight; old links forward. Details: Rename to QASight.

Highlights: qasight init sets a project up in one command; a Report page and qasight export pdf|pptx|xlsx for managers; qasight demo and qasight try to see it on sample or local results; qasight mcp for coding agents; qasight export-site publishes a read-only history site to GitHub Pages; quarantine from the UI; releases and environments on runs; stop or delete runs from the UI; storage limits, backups and token rotation for the team server.

Upgrade note: the team server compose file now keeps backups in their own testo_backups volume at /backups. Copy any backups you want to keep out of /data/backups after updating the compose file.

Renamed

  • Testosterone is now QASight. The package is qasight (pip install qasight), the command is qasight, the Python modules are qasight and qasight_api, the config file is qasight.yaml, the pytest flags are --qasight..., plugin entry points are qasight.frameworks / qasight.reporters, and the Docker images are qasight-runner, qasight-server and qasight-runner-service. Everything from before keeps working: the testo command, testosterone.yaml / testosterone.yml and [tool.testosterone], pytest --testo..., the testo.* entry point groups, and every TESTO_* setting (which QASIGHT_* can now also set). testo-core is still released at the same version: it installs qasight and keeps import testo_core / import testo_api working with a deprecation warning, so pip install -U testo-core upgrades too. Files the tool writes keep their names (.testo/, testo_history.db, testo-summary.md), and the team server's Postgres user and database stay testo. See Rename to QASight

Added

  • Storage limits: report archives (qasight report list) now follow history.retention like runs, and qasight report delete --id removes them by hand. TESTO_RETENTION_DAYS and TESTO_RETENTION_RUNS_PER_CYCLE set (or override) the limits without a qasight.yaml, so the Docker team server can be limited by its environment. history.max_file_mb / TESTO_HISTORY_MAX_FILE_MB leaves big files (videos, traces) out of a run's history copy and report archive. qasight server init sets 180 days and 100 MB for new servers; existing servers keep everything until a limit is set
  • Storage visibility: the Runs page shows how many runs there are, the database and file sizes, report archives and free disk, and warns when the disk is getting full (GET /api/v1/storage, TESTO_LOW_DISK_PCT). /api/v1/health/ready has a disk check, and qasight doctor prints Disk and History size rows
  • A run that dies mid-way (kill -9, out of memory, a crashed server) is recorded as a failed run ("stopped without finishing") when its cycle next runs or the API server starts, instead of leaving no trace
  • Token rotation: TESTO_API_TOKEN_PREVIOUS is accepted next to a new TESTO_API_TOKEN while CI secrets are updated, and TESTO_SESSION_KEY signs sign-in cookies instead of the token so a new token keeps people signed in. qasight server init generates a session key
  • qasight export-site writes the web UI and recent runs as a read-only static site for GitHub Pages or any file host, and the GitHub Action's static-site: "true" uploads it for an actions/deploy-pages job. The UI bundled in the wheel now works under any path, so one build serves qasight ui and the site. The api extra adds httpx
  • Delete chosen runs: the Runs page has Select runs, then a checkbox per finished run and Delete selected (with a confirm). The CLI does it with qasight clean --history --run ID (repeatable), and the API with POST /api/v1/runs:delete ({"run_ids": [...]}; an admin's call in accounts mode). Like retention, a run's row, its per-test rows and its report copy go together, and a running run is skipped
  • Stop a run: the cycle page and Quick run show a Stop button while a run is going (press again to kill stages that ignore the first stop). Only that run's stages are stopped, the rest of its stages are skipped, and it is still recorded, as stopped. A queued run is dropped before it starts. API: POST /api/v1/cycle-executions/{id}/cancel; the execution's status becomes cancelled
  • The Runs page says how long runs are kept (history.retention) and the default stage time limit (timeout_s), from GET /api/v1/run-settings
  • Report: where failures concentrate (the few tests behind most failures, the most repeated errors), retry rate and line coverage by day, tests with unstable timing, when failures happen (by hour, weekday and environment, with a sentence when one fails far more often), and tests that caught real bugs against tests that only raised false alarms. The test page shows each test's slowest-runs time and flags unstable timing
  • Report: a By team table (each CODEOWNERS owner or owner label: tests, failing, open failures and the oldest, time to fix, flaky tests and their cost) and the suite's size against the period before with the tests added and removed, tests skipped in every run, and slow tests that never failed
  • Report: why runs were red and what flakiness costs. The /report page counts the period's red runs by cause (real bug, bug in the test, environment, flaky tests, crash or setup, not marked yet) from the causes marked on failures and the flaky classification, with the share that was noise, and shows the CI minutes flaky tests cost (their retries plus the red runs only they caused), the branches they held up and the most costly tests. The cycle page's flaky tests show their cost and are sorted most costly first
  • Report and dashboard: how long failing tests stay red and what the suite costs. The /report page has a Speed and stability section (median time to fix failing tests, open failures by age with the oldest listed, the share of the period the default branch was red and its longest red spell, CI minutes, first-try green rate of pull request commits), a Suite time by day chart, and a per-cycle table with suite time, slowest 10% and the stage that grew most. The dashboard has a Last 7 days card with the same numbers (GET /api/v1/dashboard/delivery). Flaky tests and reruns of the same commit are left out of time to fix
  • Issues with red tests: the cycle page's new "Issues" card groups tests by the issue they point at (issue links and issue labels from N1's labels and links) and lists the issues with a failing test first, with links to the tracker and to the failing tests. API: GET /api/v1/analytics/issues?cycle=
  • Releases: record the release a run tests with qasight run --release 2.3 (also qasight ingest --release, TESTO_RELEASE, and the GitHub Action's release input). A new Releases page lists every release with its pass rate, and each release's page shows its cycles, failing tests (with the ones new since the release before), flaky tests and what it fixed. API: GET /api/v1/releases and GET /api/v1/releases/{release}; release on run items and the run detail
  • Run a chosen set of tests: qasight run --test NAME (repeatable) and qasight run --rerun-failed RUN_ID, with pytest node ids or -k, Playwright --grep and Behave --name, plus Allure's test plan file (ALLURE_TESTPLAN_PATH) for other runners. The run page has "Run these tests again", and the cycle page's label filter has "Run these". API: tests and rerun_failed on POST /api/v1/cycles/{cycle}/executions
  • Environments: qasight run --env browser=firefox --env os=linux (also qasight ingest, the TESTO_ENV variable, Allure's environment.properties, and the GitHub Action's new environment input) records what a run tested on. Flaky detection and failing streaks keep environments apart, so a test that always fails on one browser is a failure there, not flaky. The run page and runs list show the environment, and the test page has a "By environment" card ("Fails only on browser=firefox")
  • Test labels and issue links: each test keeps what it is about (feature, story, epic, severity, owner, tags and custom labels) and its issue links, read from Allure results, allure-pytest markers, Playwright tags and annotations, Behave tags and a JUnit test case's own <properties> (record_property("feature", "Checkout")). The run page and the test page show them as chips; the cycle page has a "By label" card ("Checkout: 12 tests, 3 failing") and filters its tests with ?label=. API: GET /api/v1/analytics/labels?cycle=, and label= on GET /api/v1/analytics/tests. Migration 0006 adds the labels and links columns to test_result, run automatically
  • qasight export pdf|pptx|xlsx|png|html|csv|json writes the manager report as a file, and the Report page's Download menu gets the same files from the server (GET /api/v1/report/export). PowerPoint has six slides with native, editable charts and tables; Excel has Summary, Trend (with a chart), Cycles, Tests and Findings sheets; HTML is one file that opens offline; PDF and PNG are drawn by headless Chromium. PDF, PNG, PowerPoint and Excel need the new export extra (pip install 'qasight[export]', then playwright install chromium for PDF and PNG). The team server image includes PowerPoint and Excel, and PDF with `--build-arg TESTO_REPORT_PDF=1...
Read more

v1.5.0

Choose a tag to compare

@arieleven arieleven released this 01 Nov 21:56
8a78225

Install: pip install testo-core==1.5.0 (OpenTelemetry export: pip install "testo-core[otel]==1.5.0")

Highlights: send runs to OpenTelemetry as traces; run only the tests a change can affect (testo affected, pytest --testo-affected); and manage VM pools with testo pool status, add, remove and sweep, dry run by default and every command logged.

Added

  • OpenTelemetry export: a run, its stages and its tests as one trace over OTLP, so test runs show up in Datadog, Grafana Tempo, Honeycomb, Jaeger or any other OTLP backend. Tests keep their real start and stop times; failures are error spans with the message. The otel reporter sends it after testo run, and testo otel --cycle/--run-id sends any recorded run (--dry-run prints the spans). Configured with the standard OTEL_EXPORTER_OTLP_* variables; off unless configured. Needs the new [otel] extra (pip install 'testo-core[otel]')
  • Affected-test selection, off unless asked: testo affected lists the tests the changes since the baseline branch can affect, each with why it was picked (--json, or --list for any runner's command line), and pytest --testo-affected runs only those. Changed files map to tests through affected.rules globs in testosterone.yaml, changed test files, and a coverage.py report with test contexts; a change nothing maps, a lockfile or conftest.py, or a git problem runs everything and says why
  • testo pool add, remove and sweep run a pool's own provider.create / provider.destroy commands, when a person types them: dry run unless --apply (which asks unless --yes), only verbs listed under provider.allow, at most 5 keys per command, max_items and name_prefix limits, never a key in items or one someone holds, and TESTO_PROVIDER_ACTIONS=0 turns them off. Every command run is logged with who, where and how it went: testo pool log, a "Provider commands" card on the Resources page, GET/POST /api/v1/resources/actions. New table resource_action
  • testo pool status: compare each resource pool with the keys that really exist. A pool's new provider.list is your own read-only command that prints them; the report shows keys that are missing, VMs outside the pool (leftovers) and, with --check, free keys that fail on_check. Exits 1 when something needs a look. Testosterone never creates or deletes a key on its own: only testo pool, typed by a person, runs provider commands, and a test checks that runs, leases, stages and the API never reach them

Changed

  • The PyPI page's Documentation link goes to the docs site instead of the GitHub wiki, and README links to guides open the rendered docs site pages

Full changelog: v1.4.0...v1.5.0

v1.4.0

Choose a tag to compare

@arieleven arieleven released this 31 Oct 09:22
9530fd0

Install: pip install testo-core==1.4.0 (the web UI: pip install "testo-core[api]==1.4.0" && testo ui)

Highlights: testo ingest reads Jest, Vitest, .NET, Go, Robot, Allure, RSpec, k6 and Xcode results as they are; pytest --testo; a dashboard that leads with what needs attention and a Project health score; triage memory; screenshots, traces and flakiness over time on the test page; resource pools and time-based shards for parallel runs; testo badge; a try-it page; and the GitHub Action at uses: taltal-beep/testosterone@v1.

Added

  • The GitHub Action at the repository root, ready for the GitHub Marketplace: uses: taltal-beep/testosterone@v1 (name "Testosterone Test History", with an icon). taltal-beep/testosterone/integrations/github-action@v1 keeps working; a test keeps the two copies the same
  • testo badge: a README badge for a cycle's latest run ("tests | 412 passed · 2 flaky", green, yellow or red), as an SVG or a shields.io endpoint JSON. A team server serves it live at GET /api/v1/badge.svg and GET /api/v1/badge.json (?cycle=)
  • testo lease demo fills the Resources page with made-up pools, holders, a disabled key and a queue, to try it out (--clear undoes it); the live demo shows them too.
  • testo ingest, junit_xml globs and POST /api/v1/ingest also read RSpec JSON (rspec --format json), k6 summaries (--summary-export or handleSummary JSON: each check and threshold is one result) and Xcode test results exported by xcrun xcresulttool get test-results tests (XCTest and Swift Testing, retries flagged flaky). Android instrumentation JUnit XML (Espresso, connectedAndroidTest) is labelled android with its device. "Rerun these tests" adds rspec <files> -e and ./gradlew connectedAndroidTest with the failing classes and methods
  • Resource pools: an on_check hook (run after on_take; a key that fails it is taken out of the pool and another is tried), TESTO_RESOURCE_CLEAN=1 when the last holder gave the key back after a successful on_release (or testo lease release --clean), so on_take can skip a reset it doesn't need, and reuse_delay (default lease_ttl / 3): an expired lease keeps its key out of the pool that much longer, so a frozen holder notices before anyone else gets it. testo lease list and the Resources page show such keys as expired. New columns resource_item.clean and resource_lease.reuse_delay_s, added to existing databases automatically
  • "Rerun these tests" covers more runners: Jest and Vitest (-t on the describe path), go test -run, dotnet test --filter, robot --test, and Maven (-Dtest=Class#method) or Gradle (--tests) for JUnit XML from a JVM build whose pom.xml or Gradle build is in the run's target repo. Dotted JUnit names are only offered as pytest tests when they point at a test_*.py or *_test.py file
  • Equipment jest, vitest and cypress: args go to npx jest, npx vitest run or npx cypress run, and the stage adds the report Testosterone reads (Jest's and Vitest's own JSON, Cypress's built-in JUnit reporter) with no extra package. Jest and Vitest take --maxWorkers from workers
  • testo ingest, junit_xml globs and POST /api/v1/ingest read runners' own result files, recognised by content, so these suites need no JUnit reporter package: Jest and Vitest JSON (jest --json, vitest --reporter=json; describe blocks, retried tests flagged flaky, files that failed to load), .NET TRX (dotnet test --logger trx), go test -json output (subtests, build failures), Robot Framework output.xml (tags, messages) and Allure results (testo ingest allure-results/, with attachments). A folder argument stands for the files in it
  • Shards by time: pytest --testo-shard I/N (or TESTO_SHARD=I/N testo run ...) runs one of N shards that take about the same time, from the recorded test times; testo split prints a shard's tests for other runners. testo run sets TESTO_CYCLE and TESTO_STAGE for each stage.
  • Stages can ask for keys: resources: POOL on a stage gives each pytest worker (per: worker), each test (per: test) or the stage (per: stage) its own key, and workers: auto starts one worker per free key. In plain pytest: --testo-resource POOL and the testo_resource fixture.
  • Resource pools for parallel runs: list keys (VMs, devices, test accounts, seats) under resources: in testosterone.yaml, and testo lease run POOL -- CMD gives each worker its own key in TESTO_RESOURCE_ID. Leases are rows with a heartbeat and a TTL, so a crashed worker frees its key; requests wait in a fair queue; failing on_take/on_release hooks take a key out of the pool. With TESTO_SERVER_URL the leases live on the team server, so developers on different laptops share one pool. Also testo lease take/heartbeat/release/list/disable/enable/free, /api/v1/resources and a Resources page in the UI. New tables resource_item, resource_lease, resource_waiter
  • A Project health page (/health): a 0-100 test health score for the project you test, from pass rate, green builds, flaky tests, tests that got slower, skipped and quarantined tests and the test pyramid, with what to fix first and a score per cycle. An optional AI review scores the tests with checks you switch on and off (why tests are flaky, related failures, test strategy gaps, test debt, slow tests, test churn, test names), each expandable to what it checks and reads. It uses your AI provider, never reads source code and is labelled an AI estimate. New endpoints GET /api/v1/project-health, GET /api/v1/project-health/skills and GET/POST /api/v1/project-health/ai-review. On the read-only demo the checks are listed but the review can't be run
  • A cycle's run history: the cycle page has a "Recent runs" card (pass rate, one square per run, the latest three), and Runs filters by cycle (/runs?cycle=web, backed by GET /api/v1/runs?cycle=) with the same pass-rate line
  • Docs: "Compared with other tools", where Testosterone fits next to Allure, ReportPortal, Currents, Trunk and Datadog, and when to pick one of them instead
  • Triage memory: on a failed run's page, "Mark the cause" of a failing test (bug in the product, bug in the test, environment, flaky, other, plus a note). Later failures in the same cycle with the same message (numbers, ids and quoted values aside) show that cause too, with where it was marked. New table failure_triage, endpoints GET/PUT/DELETE /api/v1/triage, and a triage field on each test of GET /api/v1/runs/{run_id}/failures
  • "Flakiness over time" on the test page: the share of outcome changes over the five runs ending at each run, and how it compares with five runs before. Test-history points add flip_rate
  • The test page shows what the last failing run kept: screenshots and videos in place, the Playwright trace as a download with the command that opens it. GET /api/v1/analytics/test-history adds last_failure_attachments
  • pytest --testo (or --testo-cycle NAME): a pytest plugin, installed with testo-core and inert without the flag, that records each session as a run the way testo ingest does, with the checkout's branch and commit. --testo-server uploads to a team server instead
  • The dashboard leads with "Needs attention": red cycles (failing and new-failure counts, red for how many runs), tests that just started flaking and tests that got slower, each linking to its page. New endpoint GET /api/v1/dashboard/attention. The rollup and quick-links cards and the KPI icons are gone, and the no-runs page explains testo ingest, testo config init / testo run and the try-it page
  • The run page has a "Rerun these tests" command per runner (pytest node ids, npx playwright test --grep, behave --name) with a Copy button, from the new rerun_commands field of GET /api/v1/runs/{run_id}/failures
  • Compare opens on the latest run against the one before it in its cycle, and each run in the pickers shows its branch (GET /api/v1/runs adds branch)
  • The run page shows the branch, pull request target and commit the run tested (linked on GitHub), and GET /api/v1/runs/{run_id} returns them
  • Cycles recorded with testo ingest (or by another machine) have a cycle page: GET /api/v1/cycles lists them after the config's cycles with source: "history", and their page shows the test search, slowest tests and flaky card without a Run panel. testo ui in a folder with no testosterone.yaml lists recorded cycles instead of an error
  • Docs: second pass of the product review (docs/product-review.md): 6.5 to 7.5, what a 10 needs in each area, and new findings, chiefly that cycles created by testo ingest have no cycle page
  • A try-it page (/try, "Try a file" under Tools, also on the static demo): drop JUnit XML files, or use the sample, and see the run the way Testosterone shows one (verdict, failing tests with shared causes grouped, slowest tests), read in the browser with nothing uploaded

Changed

  • Claude Code on the web sessions install .[dev] into .venv at startup (.claude/hooks/session-start.sh), since the container's system pip can't build csscompressor
  • One health score: the dashboard's Health card now shows the Project health score (same number as /health) and opens that page. A run's own pass percentage is labelled "Pass rate" on the run page and in Compare, and "passed" in the dashboard's recent runs
  • The test page's duration chart shows its scale (longest run and zero); slowdown percentages read the same on the dashboard and the cycle page; the dashboard says "All 3 cycles are red." when none passed; Runs says "Every recorded run" instead of "archived cycle run"
  • Charts have text alternatives: the test page's duration chart reads its values, and the flaky card's outcome strip is announced
  • UI accessibility and copy: the skip link is i...
Read more

v1.3.0

Choose a tag to compare

@arieleven arieleven released this 25 Oct 06:00
c3d582e

Install: pip install testo-core==1.3.0 (the web UI: pip install "testo-core[api]==1.3.0" && testo ui)

Highlights: failing tests first on the run page, testo ui, a page per test with search and slowest tests, PR comments judged against the target branch, owners and issue links for flaky tests, and opt-in team-server features (accounts, persistent queue, parallel stages, throwaway runner containers).

Added

  • Flaky tests and the per-test page show the test's owners from CODEOWNERS and an "Open an issue" link (GitHub's new-issue form, prefilled with the test, cycle, last failure and owners). Runs record their repository (owner/name) from CI variables or a github.com origin remote
  • A page for each test (/cycles/<cycle>/test?key=): pass rate, flaky or not, last failure, duration per run and every run with its branch. The cycle page can search its tests and lists the slowest tests and the ones that got slower. New endpoints GET /api/v1/analytics/tests and GET /api/v1/analytics/test-history
  • Pull request comments and testo report markdown compare a PR's run with the latest run on its target branch (new --baseline-branch overrides), not with whichever run came before, and say which baseline they used. Runs record the PR's target branch (ci_base_ref, also accepted by testo ingest), the PR's own branch on GitHub, and the local git branch and commit outside CI
  • testo ui: the web UI ships inside the wheel, so pip install 'testo-core[api]' && testo ui opens the dashboard on this machine's run history (http://127.0.0.1:8000) with no checkout or Node. testo-api also serves the bundled UI when TESTO_UI_DIR isn't set
  • UI accessibility and copy pass: stronger primary-button contrast, a visible keyboard focus ring, a skip link, h1 → h2 headings, a 44px mobile menu button, AI settings fits a phone, load errors say what to check, sentence-case titles, "Advanced" is now "Tools" with a plain Docs link, and the dashboard hides unknown trends and missing reports. testo --help has the README's tagline and no RST double backticks
  • The run page leads with its failing tests: each with its failure message, stage, "New" or "Failing for N runs", and a flaky badge, and failures that share a message are grouped ("2 tests: ConnectionRefusedError ..."). A one-line verdict sits under the title; the run id, exit code (now explained, e.g. "1 (tests failed)") and duration moved to a Details card. New endpoint GET /api/v1/runs/{run_id}/failures
  • Compare and the dashboard ignore timing noise: a duration change under 5% of the baseline, or under 100 ms (5 ms for the per-test average), is "Within noise" instead of a red regression or a green improvement
  • Docs: a product review (docs/product-review.md) scoring positioning, onboarding, the red-build workflow, design, accessibility and copy against Allure, ReportPortal, Currents and Trunk, with a Now / Next / Later roadmap
  • Opt-in throwaway containers for runs started on a team server: with TESTO_RUNNER=container each stage runs in a fresh container started by a separate runner service (testo-runner-service, Dockerfile.testo-runner-service, deploy/server/docker-compose.runner.yml), with no Linux capabilities, a process limit, fixed mounts and only the stage's own variables. The API never gets the Docker socket. Default host (unchanged)
  • Sign-in throttling with TESTO_AUTH=accounts: after TESTO_LOGIN_MAX_FAILURES (default 5) wrong passwords for a name in 15 minutes, or four times that from one address, /login answers 429 until the window slides
  • TESTO_REPORTS_ORIGIN serves report pages from a second hostname, so script in a report can't act with the viewer's session on the API's origin. Off by default
  • Per-user accounts for the team server, off by default: with TESTO_AUTH=accounts people sign in with their own username and password, roles viewer / runner / admin decide who can start runs or change settings, every write and sign-in is in an audit log (GET /api/v1/audit), and testo users manages accounts. The UI shows who is signed in. The API token keeps working as an admin for CI
  • TESTO_RUN_QUEUE=db keeps API runs that are waiting for a worker in the database, and the server queues them again on startup, so a restart or upgrade no longer drops them. Default memory (unchanged)
  • Opt-in parallel stages: a cycle with max_parallel_stages: N runs up to N stages at once (default 1, unchanged). Events and the renderer stay on one thread, results keep config order, fail_fast starts no new stages after a failure, and stage names must be unique in a parallel cycle
  • The API runs at most TESTO_MAX_CONCURRENT_RUNS executions at once (default 2) on a fixed worker pool; further runs wait as queued instead of each starting its own thread
  • Team server sign-in: TESTO_PROTECT_READS=1 makes every read (API, /history report files, the UI, the live run stream) need the API token, and a /login page trades the token for an HttpOnly session cookie that also authorizes writes. On in deploy/server/docker-compose.yml; the UI it serves redirects to /login when the session is missing. Off by default elsewhere, so local use is unchanged
  • Frontend lint: ESLint with typescript-eslint and the React hook rules (frontend/eslint.config.js, npm --prefix frontend run lint), blocking in CI's frontend job
  • Unit tests for the TestBeats and ReportPortal reporter payloads, the Anthropic provider, and the testo config and testo report commands (coverage 80% to 83%)
  • Frontend tests for the loading, error and empty states of the run detail and Compare pages
  • Unit tests for the Allure report wrapper, the local report server, the Behave adapter's argument building, the BehaveX-to-Allure export and testo watch's debounced re-runs (each module now at 92% or more; total coverage 84% to 86%)

Changed

  • Internal split of the three largest modules: run event streaming moved to testo_api/execution_events.py, config section parsing to testo_core/config/sections.py, and testo report list / open to testo_core/cli/commands/report_archive.py. No behaviour change
  • The release workflow's "Verify install from PyPI" step retries for up to five minutes instead of one 30-second wait, so a slow PyPI index no longer marks a published release as failed
  • The testo-server image sets TESTO_PROTECT_READS=1, so a plain docker run protects reads too, not only deploy/server/docker-compose.yml. Set it to 0 to open reads on a trusted network
  • Frontend on React 19 (react, react-dom and their types together), @testing-library/jest-dom 7 and the latest TanStack Query and PostCSS patches; replaces Dependabot #132, #133 and #135, which bumped react without react-dom
  • The pixel mascot's frame source moved from testo_core/mascot/ to scripts/mascot/, so it no longer ships in the wheel; the UI animations are unchanged. Play it with python -m scripts.mascot flex, regenerate the frontend frames with python -m scripts.mascot.export_ts
  • Frontend toolchain: Vite 8 (Rolldown) and Vitest 5, replacing Vite 5 and Vitest 2; clears the six dev-only npm audit advisories (esbuild dev server, Vitest mocker, tinypool). vite.config.ts takes defineConfig from vitest/config, and the EventSource test mocks are constructor functions, which Vitest 4+ requires

Fixed

  • An API run that raised SystemExit (say, a reporter plugin calling sys.exit()) took its worker thread down for good, shrinking the pool until queued runs never started; the worker now survives it and dead workers are replaced
  • The API sends X-Content-Type-Options: nosniff and frame-ancestors 'self' on every response, and serves report attachments under /history with Content-Security-Policy: sandbox, so an uploaded HTML attachment can no longer run script on the team server's origin
  • test_python_build_module_available skips when build is not installed, and the pytest rootdir test runs python -P -m pytest with the suite's own interpreter, so a contributor's first local run is green
  • testo config init generates a smoke-test cycle that runs ordinary pytest tests in tests/ without a marker filter. Marker-based pytest and BehaveX configurations remain as commented-out examples, so a new pytest project does not require smoke markers or BDD features (#100, thanks @evidentart)

Full changelog: v1.2.0...v1.3.0

v1.2.0

Choose a tag to compare

@arieleven arieleven released this 24 Oct 10:23
e3ea0f9

Install: pip install testo-core==1.2.0

If a cycle has behave or behavex stages, install testo-core[bdd] (Behave is now an extra).

Added

  • testo ingest: record JUnit XML that any runner already wrote (Jest, Vitest, go test, JUnit5, ...) as a run of a cycle, with no testosterone.yaml needed. Ingested runs get the same history, Compare, testo flaky, reporters and PR comment as testo run. Backed by a new equipment: junit that runs no process and fails the stage when a test failed or no report matched

  • Team server: POST /api/v1/ingest records uploaded JUnit XML, and testo ingest --server URL --token uploads with the CI job's provenance (provider, pipeline, job, commit, branch, repository). The API serves the built web UI when TESTO_UI_DIR is set. New testo-server Docker image (Dockerfile.testo-server, published with testo-runner) and deploy/server/docker-compose.yml with Postgres. Guide: docs/Processes & Guides/Team Server.md

  • Playwright JSON reports: testo ingest results.json (and any junit_xml glob that matches a .json file) reads Playwright's json reporter output, keeping what JUnit loses: every retry as a step with its own error, flaky tests (passed on retry) flagged, and traces, screenshots, videos and testInfo.attach() files copied as Allure attachments. testo ingest --server uploads .json reports too. See docs/Specs & ADRs/Playwright JSON Import - 2026-10-22.md

  • Unit tests for the Extent, ReportPortal and TestBeats reporters, the reporter factory, reporter config parsing and Docker results collection (recovered from an old branch)

  • AI failure summaries without a paid key: an openai_compatible provider with a base URL, so Gemini, Groq, OpenRouter (free keys) or a local Ollama (no key) work. The settings page offers presets for them

  • Flaky test detection: testo flaky --cycle <name> (--window, --json, --fail-on-flaky), GET /api/v1/analytics/flaky and a Flaky tests card on the cycle page (also in the Pages demo). A test is flaky when it both passed and failed and flipped at least twice in the cycle's last runs (testo_core/services/flaky_service.py)

  • GitHub Action run summary: after a persisted run the action writes the results, failing tests and per-test changes since the previous run to the job summary, and with comment-on-pr: "true" keeps one comment per cycle on the pull request (edited in place). New inputs job-summary, comment-on-pr, github-token and package. The text comes from the new testo report markdown command. This repository's CI runs the action on its own checkout and comments on its own pull requests

  • Plugin API: a package can add a test runner or a reporter through the testo.frameworks and testo.reporters entry point groups (testo_core/plugins.py), with no change to Testosterone. testo plugins lists built-ins and installed plugins (--check imports and verifies them, --json), and examples/plugin/ is a complete plugin with a unittest adapter and a json-summary reporter

  • equipment: playwright: runs npx playwright test with its JUnit and HTML reporters wired in, so Playwright tests count in summaries, diffs and the UI with no junit_xml setup, the HTML report is kept per run as the native report, and workers becomes --workers. Also offered on the Quick Run page

  • Docs site: the docs/ vault built with MkDocs Material (mkdocs.yml, scripts/mkdocs_hooks.py, [docs] extra) and published at https://taltal-beep.github.io/testosterone/docs/ by the Pages demo workflow. A new docs_site CI job builds it with --strict

  • JSON Schema for testosterone.yaml (schema/testosterone.schema.json, generated by scripts/export_config_schema.py and checked in CI) so VS Code and other editors autocomplete and validate the config. testo config init and testo init add the # yaml-language-server: $schema=... line

  • Flaky test quarantine: a quarantine: list in testosterone.yaml (top-level and per cycle; test name globs, optional reason and owner). A stage that exits 1 passes when every failed test is quarantined; the failures are still reported everywhere and recorded per stage as quarantined (CLI summary, --ci NDJSON, run record, testo report markdown). testo flaky marks quarantined tests, prints a snippet for the rest, and --fail-on-flaky ignores quarantined ones (testo_core/engine/quarantine.py)

  • docs/project-review.md: a whole-repo review scorecard (architecture, code quality, tests, security, docs, CI) with findings and a remediation plan, linked from the docs index and site nav

  • docs/Getting Started.md: from pip install testo-core to a regression in testo summary and the GitHub Action, with the same project in examples/getting-started/. A new getting_started CI job runs that example through the GitHub Action

  • Alerts where developers look: slack and teams reporters and a testo notify --to slack|teams command post a run's failing tests, new regressions, newly flaky tests and fixes to an incoming webhook (URL from TESTO_SLACK_WEBHOOK_URL / TESTO_TEAMS_WEBHOOK_URL or a ${env:…} option; --when failure|change|always). testo report annotations prints failing tests as GitHub ::error annotations on their file and line, and testo flaky --new lists tests the latest run made flaky. The GitHub Action gains annotations (on by default), slack-webhook, teams-webhook, notify-when and flaky-issues (opens one issue per newly flaky test)

Changed

  • testo-api refuses to start on a non-loopback host without TESTO_API_TOKEN (exit 2) instead of only warning; set TESTO_ALLOW_UNAUTHENTICATED=1 to start anyway on a trusted network
  • The ?config_path= on read routes (GET /api/v1/cycles, /cycles/{cycle}, /runs/{run_id}/pyramid) only loads files named testosterone.yaml, testosterone.yml or pyproject.toml and returns 400 for anything else. Reads need no token, so an arbitrary path let anyone probe the server's files and read fragments of them in parse errors
  • The API reports the installed package version instead of a hard-coded one
  • CI: a test (python 3.12) / test (python 3.13) job runs the fast suite on the other Python versions pyproject.toml lists; BehaveX tests skip without the bdd extra
  • CI: trivy-action and claude-code-base-action pinned to commit SHAs instead of @master / @beta; commitlint, pr-heavy and release-gate workflows get a read-only permissions: block
  • AI settings (never the key) are saved to artifacts/ai_settings.json and survive an API restart (TESTO_AI_SETTINGS_PATH moves it; empty keeps them in memory). The settings page resets the model when the provider changes, names the missing environment variable and refuses a key pasted as a variable name. The summary prompt asks for a short plain-text What failed / Likely cause / Next steps reply, and the Run Details card shows provider errors in words
  • equipment: playwright uses Playwright's json reporter instead of junit (--reporter=list,json,html, written to test-results/testo-results.json), so testo run gets the same retries, flaky flags and traces. A stage that sets its own --reporter=junit is still imported from test-results/testo-junit.xml
  • Behave and BehaveX are now an extra. pip install testo-core no longer installs behave, behavex and allure-behave (35 packages instead of 47). Migration: if a cycle has behave or behavex stages, install testo-core[bdd]; in the GitHub Action pass package: "testo-core[bdd]", and in the GitLab template set TESTO_PACKAGE: "testo-core[bdd]" (new variable). The testo-runner image and the dev extra include it. Without it a Behave stage fails with exit 3 and the stage error names the extra, which the CLI stage panel now shows (the --ci stream keeps it in the artifact event mirror, as before)
  • README and PyPI description lead with what the project answers on every run (what broke, what's flaky, what got slower) and with testo ingest for any runner, next to running cycles; new PyPI keywords
  • Web UI restyled after the Vision UI dashboard look: navy palette, glass cards over a blue glow, Plus Jakarta Sans, a desktop sidebar with icon tiles and a docs card, and icon tiles on the Dashboard KPI cards. Faint line art of the testosterone molecule and of vials with a syringe sits behind the pages. Phones keep the top bar and menu. See docs/Specs & ADRs/UI Restyle - 2026-10-19.md
  • publish.yml publishes straight to PyPI (the Test PyPI step is gone; the build, metadata and clean-install checks still run before the upload) and can be run by hand for an existing release tag
  • Runner image: Dockerfile.testo-runner uses the floating python:3.11-slim-bookworm base (the 3.11.9 pin carried 9 fixable CRITICAL Debian CVEs that failed the v1.1.1 image scan), and docker-publish.yml scans and smoke-runs the image before pushing it and can be run by hand for an existing release tag
  • Setup prompts install testo-core from PyPI instead of the GitHub zip
  • move-major-tag.yml keeps the moving v1 tag on the latest stable release (and can be run by hand for an existing tag)
  • README: a "What's new" section for the changes since 1.1.1, new screenshots and UI walkthrough of the restyled UI on real self-test and fake-api runs (including the flaky tests card), a terminal recording of testo flaky, testo report markdown and testo plugins, and the Playwright equipment, plugins, testo report markdown, testo summary and PR comments in the reference sections

Fixed

  • BehaveX stages get BehaveX's own HTML report again. The adapter passed BehaveX's Allure --formatter, and BehaveX skips report.html whenever a formatter is set, so the report Testo showed was re-rendered afterwards without scenario logs. BehaveX now runs plain and the executor converts its report.json to Allure results after the stage...
Read more

v1.1.1

Choose a tag to compare

@arieleven arieleven released this 19 Oct 18:20
11ac429

Install: pip install testo-core==1.1.1

First release meant for PyPI (pip install testo-core).

Added

  • Open-source community files: SECURITY.md (private vulnerability reporting), CODE_OF_CONDUCT.md (Contributor Covenant 2.1), CITATION.cff, issue forms (.github/ISSUE_TEMPLATE/*.yml, blank issues off, links to Discussions and the security form) and .github/dependabot.yml (weekly grouped updates for pip, npm and GitHub Actions, chore(deps) commits with the no-changelog label; commitlint.config.js skips Dependabot's long commit bodies). CONTRIBUTING.md gains "Finding something to work on" and a note on the AI-agent files, and its Quickstart link is fixed
  • README: animated walkthroughs of the web UI and of the CLI (docs/assets/demo/)
  • docs/Prompts & Snippets/Setup Prompts.md: copy-paste prompts for an AI coding assistant to install Testosterone in another project, write its testosterone.yaml, run it in GitHub Actions or GitLab CI, open the web UI and troubleshoot. Command Reference no longer calls doctor, clean, watch and init unimplemented

Fixed

  • pip install testo-core followed by testo run crashed with ModuleNotFoundError: No module named 'sqlalchemy': run history is always saved (SQLite by default) but sqlmodel was only in the [db] extra. It is now a core dependency; [db] keeps the Postgres driver and tomli-w. A new package CI job (scripts/package_smoke.sh) installs the built wheel with no extras and runs a cycle, and the publish workflow runs the same check before uploading
  • Compare showed "n/a" / "Unknown" for "Test time (sum)" and "Avg per test" on every run because nothing stored them. Both persistence backends now write metrics_duration_ms and avg_case_ms, plus test_time_ms per stage. Runs saved earlier still show "n/a"

Changed

  • Package metadata for PyPI: description, MIT license expression, author, keywords, classifiers and project links. The README shown on PyPI has its relative images and links rewritten to GitHub URLs at build time, and the sdist now carries only the Python package, its tests and the top-level docs (about 260 KB instead of 3.5 MB)
  • publish.yml fails before uploading when the release tag does not match pyproject.toml's version, and runs twine check --strict
  • README: PyPI badge and a pip install testo-core quickstart
  • Pages demo: the read-only notice is now a dismissible alert, and a "Read-only demo" badge in the header reopens it
  • Detailed architecture diagram showing CycleRunService, the history/ read side and the repository, in the README and docs/Architecture/System Diagram.md

Full changelog: CHANGELOG.md