Open source test case management platform — a free alternative to TestRail, Qase.io, and Zephyr. Built from TestForge PRD v1.0 (see docs/DOCUMENTATION.md Part II for the audit of that document).
- Test case management — suite → section → case hierarchy with steps, tags, custom fields, shared steps, versioning and full-text search.
- Test runs — build a run from a filter, execute it with keyboard shortcuts and a live timer, rerun only what failed, compare two runs.
- Automation integration — upload JUnit/TRX/NUnit/xUnit/Cucumber/Mocha results, or stream live runs from Playwright, Cypress, pytest and the CLI.
- CI quality gates — a per-project pass-rate policy your pipeline can block on, plus an embeddable live quality badge.
- Cases as code — sync a
tests/folder of YAML with the server so test cases get reviewed in pull requests like the rest of your code. - Self-hosted and free — one
docker compose up, SQLite or PostgreSQL, unlimited users, no per-seat pricing, MIT licensed.
Full feature list (45)
- Multi-project workspace — create, archive, namespace tests per project
- Test case management — all standard PRD §4.2.1 fields, dynamic steps,
clone, bulk edit, tags, soft delete, automatic ID
TC-[SLUG]-[NUM]; bulk select → drag onto a suite to move or onto another row to reorder, or "Copy to project…" to duplicate into another project you belong to (fresh IDs, flattened shared steps, duplicated attachments) - Suite → section → case hierarchy (PRD §4.1.2)
- Test run & execution — select cases via filter, 7-color status (§4.3.2),
keyboard shortcuts
P/F/B/S/R+J/K(US-002), automatic timer, partial run, rerun failed only, milestone - Automation integration — upload results from JUnit, TRX (MSTest), NUnit3,
xUnit.net v2, Cucumber JSON or Mocha JSON via
POST /api/v1/results(format auto-detected, orPOST /api/v1/junitfor the original JUnit-only alias), auto-matching to test cases viaTC-WEB-001annotation in test name or exact title (US-010) - REST API v1 — Bearer API key (hashed), cursor pagination, filtering
- Import/Export CSV — with preview & validation before import (US-004)
- Reports — pass rate trend, flaky test detection, bug correlation, automation coverage (§4.5)
- Live quality badge — public shields.io-style SVG (
/badge/<token>.svg) showing the latest pass rate / automation coverage / case count, embeddable in a README; opt-in per project, revocable token (L-01) - Real-time collaborative run execution — presence avatars, live result updates over SSE, soft claims ("Ana is on this case") and last-write-wins conflict toasts with Undo; degrades gracefully when the stream is blocked (L-04, single-instance scope)
- CI quality gates — per-project policy (min pass rate, max new failures
vs the previous run, block-on-untested, required tags); CI asks
testforge-cli gate --wait 600orGET /api/v1/projects/<slug>/gateand gets a deterministic, mute-aware verdict with exit code (L-02) - Test cases as code (GitOps) —
testforge-cli cases pull|status|pushsyncs atests/folder of canonical YAML with the server, so cases get reviewed in PRs like code; 3-way merge against a committed.testforge.lock, conflicts exit 1 with a report instead of overwriting (L-03 — see docs/CASES-AS-CODE.md) - Basic auth & RBAC — register/login JWT, brute force lockout (§8), audit log (§5.5)
- SSO & two-factor auth — OpenID Connect single sign-on (any OIDC provider
via
TF_OIDC_ISSUER; covers Google Workspace/Azure AD/Okta/Keycloak), plus optional per-account TOTP 2FA with single-use recovery codes.TF_DISABLE_PASSWORD_LOGIN=1makes an instance SSO/social-only. - LDAP / Active Directory — self-hosted instances can authenticate against a
corporate directory (
TF_LDAP_URL+TF_LDAP_BASE_DN; OpenLDAP and AD both work out of the box). Users sign in on the normal login form with their directory username or email;TF_LDAP_AUTO_PROVISION=1creates the TestForge account on first login. Local accounts keep working as a fallback, so a directory outage can't lock the admin out. Supportsldaps://and StartTLS (TF_LDAP_START_TLS=1); TOTP 2FA still applies on top of a directory bind. - Attachments — drag-drop/paste screenshots & files on test cases and run
results (evidence), sha256-deduplicated storage in the
/datavolume, per-file limit viaTF_MAX_UPLOAD_MB(default 10 MB) - Markdown — GFM in descriptions, preconditions, steps, expected results and run notes (sanitized rendering); paste a screenshot into the editor to attach & embed it
- Global search —
⌘K/Ctrl+Kcommand palette across cases, runs, suites and milestones (exactTC-…id lookup ranks first), scoped to your projects - Saved views — save case-table filter combos as named views (personal or shared with the project), star one as your default
- Custom fields — define per-project fields on cases & run results
(9 types incl. dropdown, multi-select, user, date); enforced in forms,
CSV import/export (
cf_<key>columns), and the REST API - Shared steps — reusable step blocks ("Log in as admin") inserted into any case; edit once and every case updates, delete only when unused
- Case history & versioning — every change becomes a numbered revision (author, per-field diff) with one-click restore; run results remember which revision they executed and flag stale ones
- Test plans & configurations — bundle runs generated from one case selection × a configuration matrix (e.g. Browser × OS → 4 runs, max 50), with aggregate progress, a per-combo result matrix, and one-click complete-plan; configuration axes are managed under Fields
- Issue tracker integration — connect Jira, GitHub or GitLab per project; file an issue straight from a failed result (steps, expected vs actual and a backlink are pre-filled), link existing issues by key or URL, and see live status badges refreshed by a sync job. Tokens are encrypted at rest and never returned to the browser
- Notifications — push run/case events to Slack, Discord, Microsoft Teams
or email per project (event subscriptions, test button, failure-burst
aggregation); links use
TF_BASE_URL, chat webhook URLs are stored encrypted (TF_SECRET, falls back toAUTH_SECRET), and non-standard webhook hosts requireTF_ALLOW_ANY_WEBHOOK_HOST=1 - In-app help center —
/docs/help, a guide per feature area (test cases, runs, plans, automation, integrations, notifications, reports, team & roles) for end users, separate from the developer-facing/docs/api - Parameters / datasets —
{{var}}placeholders in a case's steps, substituted per named dataset row; a run seeds one result per row instead of one per case, each tagged with its dataset name - Environments — tag runs with where they executed (Staging, Prod, …);
&env=<name>on an automation upload auto-creates one; filter runs and reports by environment - Mute / quarantine flaky tests — quarantine a known-flaky case (reason required) from the Reports Flaky panel; its results still record but are excluded from pass-rate math everywhere, shown as a separate grey segment
- Importers — bring cases in from TestRail (XML), Qase (JSON), or TestLink (XML) in addition to CSV; suites are created by path with a preview step (counts, sample rows, warnings) before anything is saved
- Run comparison — pick any two runs and see them side by side
(
runs/compare?a=…&b=…): a per-case table with status in each run and a delta arrow, plus a summary of regressions (pass → fail) and fixes - Dashboards — build a per-project grid of report widgets (pass-rate trend, status distribution, automation coverage, flaky tests, run velocity, Markdown notes); position them on a 4-column grid
- Public share links — hand a stakeholder a read-only run or dashboard
report at
/share/<token>— no sign-in, no way back into the app,noindex; create with an optional expiry, copy, or revoke from the run/dashboard page - Public project sharing (portfolio mode) — publish a whole project
read-only at
/public/<project-slug>: overview, suite folders and every test case, no sign-in, no way back into the app. Toggle the Test Cases section and search-engine indexing (noindexby default) from Settings → Public sharing (F-38) - Scheduled reports — email a KPI summary (pass rate, executions, top
failures, link to the full report) daily or weekly to a list of recipients;
managed under Notifications, sent by the
/api/cron/send-reportsjob - Exploratory / session-based testing — run a timeboxed session against a
charter with a live timer and quick-add notes (
N/B/Q/Ihotkeys for Note/Bug/Question/Idea, attachments per note); convert an Idea into a draft case or file a Bug straight to your connected issue tracker (F-25) - Built-in defects — a lightweight internal defect tracker (
DF-<SLUG>-<n>, severity, status board OPEN→CONFIRMED→FIXED/WON'T FIX→CLOSED) for teams without Jira/GitHub/GitLab; link or report one straight from a failed run result, no external tracker required (F-26) - BDD / Gherkin — a case's whole scenario can be authored as one
Given/When/Then block instead of steps, with syntax-highlighted display;
import/export
.featurefiles (oneScenario:per case, tags → tags, Feature name → suite), and Cucumber JSON results match by scenario name like any other case (F-27) - Suite baselines — snapshot a suite tree (case content + F-05 revision) as a named baseline to test an older release in parallel with current work; "compare to current" flags what changed, moved, or was deleted; a run created "from baseline" pins and renders each case's pinned content, not today's edits (F-28)
- XLSX & JSON export — export cases/runs as
.xlsxor full-fidelity.json(custom fields, steps, datasets; optional per-case revision history) alongside the existing CSV/.featureexports, all from one Export menu; CSV import remembers a per-project column mapping so a CSV with different header names only needs mapping once (F-30) - My Work —
/my-work, a cross-project queue of everything assigned to you: results waiting for you in active runs, cases you own, and case reviews requested from you; a sidebar badge shows the total (F-31) - Case dependencies — mark a case as requiring another to pass first (cycles rejected); in a run, a dependent whose prerequisite just failed gets a one-click "Accept — mark BLOCKED" suggestion — never applied automatically (F-32)
- Print & PDF views — dedicated
/print/*routes render a clean, paginated document (cover with provenance, clickable TOC, cases with fully-expanded steps or a run report with pass-rate summary + stacked bar); "Save as PDF" comes straight from the browser's print dialog, so there's no server-side PDF dependency. Scope the catalog to a suite, a saved view, or a single case (F-35) - Mobile execution PWA — installable (manifest, icons, offline fallback page via a hand-rolled service worker) with a single-card, thumb-zone executor layout on phones. Record results with no signal: they queue in IndexedDB and sync automatically when you're back online, with a last-write-wins conflict notice so nothing is silently lost (F-36)
- AI assist (bring your own key) — point an org at any Anthropic-compatible endpoint (key stored encrypted) to draft test cases from a pasted requirement, suggest edge-case steps on a case, and flag near-duplicate cases (the duplicate detector is a local title match and needs no key). Every AI action is opt-in per click and the features stay hidden until a key is configured (F-29)
docker compose upnpm install
npx prisma db push # create SQLite database
npm run seed # demo data + admin account
npm run devDemo login: admin@testforge.local / admin12345
Default database is SQLite for out-of-the-box setup. For production per PRD (§5.1, PostgreSQL): change
providerinprisma/schema.prismatopostgresqland setDATABASE_URL.
Your entire instance (users, projects, cases, runs, API keys, audit log, …) lives in a single database. To back it up or move to your own server if the hosted site goes away, see docs/SELF-HOSTED-MIGRATION.md.
# Create a WRITE-scoped API key in Settings → API Keys, then:
curl -X POST "http://localhost:3000/api/v1/results?project=web&name=CI%20Run" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/xml" \
--data-binary @results/junit.xml
# format is auto-detected (junit/trx/nunit3/xunit2/cucumber/mocha); pass
# &format=trx etc. to be explicit. POST /api/v1/junit still works unchanged.npm workspaces + a Python package under packages/:
testforge-cli—testforge upload <file> --project <slug>(wraps the results API; envTESTFORGE_URL/TESTFORGE_TOKEN).testforge-playwright-reporter/testforge-cypress-reporter— stream a live run as tests finish (create → per-test result → complete), matchingTC-<SLUG>-<n>in the test title.pytest-testforge— the same, as a pytest plugin.
Each package has a README with copy-paste setup and is publishable to npm/PyPI (publishing is a manual step).
src/app/(app)/— application pages (dashboard, projects, runs, reports, settings)src/app/actions/— server actions (data mutations)src/app/api/— REST API v1, CSV import/export, JUnit uploadprisma/schema.prisma— data model (including ERD gap fixes from the audit)
Do not commit or push directly to remote main. Every push/merge to
main triggers auto-deploy to production (testforge.emha.space via
.github/workflows/deploy.yml).
Expected workflow:
- Create a branch from
main(feat/...,fix/..., etc.). - Push the branch to remote and open a Pull Request to
main. - Wait for CI (
prisma generate+next build) to pass. - Merge the PR — production deploy runs automatically after merge.
git checkout main && git pull
git checkout -b fix/short-description
# ... work ...
git push -u origin fix/short-description
# open PR on GitHub → review → mergeApplies to Cursor, Claude Code, Copilot, and other coding agents in this repo. Follow these rules before changing code, git, or deploy.
- Do not commit or push directly to remote
main(automatic production deploy — see § Git & deploy). - Required workflow: branch (
feat/...,fix/...) → push branch → PR tomain→ CI green → merge. - Do not commit unless the user explicitly asks. Do not push to remote unless the user explicitly asks.
- Do not force-push to
main/master. Do not commit.env, secrets, or*.db.
- Minimal diff — only change what the task requires; do not refactor unrelated code.
- Follow repo conventions: Next.js 14 App Router, server actions
(
src/app/actions/), Prisma + SQLite dev, Tailwind, i18n EN/ID. - Do not add
.mddocumentation files unless the user asks.
- Production:
testforge.emha.space· VPS/opt/testforge·docker-compose.prod.yml· deploy via.github/workflows/deploy.yml. NEXT_PUBLIC_*variables are baked at Docker build time — change them indocker-compose.prod.yml(and rebuild), not only as fallbacks in TSX code.- GitHub links for visitors (clone, Star on GitHub) now point at the real
repo
mansyur007/testforge, same as dev/CI. The former decoymansyur007/test-forgestill exists on GitHub but is no longer referenced from this source tree.
docs/DOCUMENTATION.md— the consolidated project documentation: application audit (architecture, auth, user flows), PRD audit, competitor comparison, and the full implementation work orders for all 42 shipped features.- EMHA estate deploy skill (VPS, Caddy):
.claude/skills/— local, gitignored; brief guide in § Git & deploy and the deploy workflow.
License: MIT


