Developer Tests - edmozley/freeitsm GitHub Wiki
FreeITSM ships a suite of PHP test scripts in tests/. They are developer
tooling, not part of the application β if you run FreeITSM rather than work on
it, you never need to touch them.
This page is the index. Each test has an entry on one of the pages below saying what it covers, how it works, how to run it, how to read its output and what to do when it goes red.
From the repository root, on the command line:
php tests/field-widths-agree.php
Most print one line per assertion and a count at the end:
ok the default is one of the permitted widths
FAIL form-logic agrees with the service β service=12,9,8,6,4,3 logic=12,9,6,4,3
============================================================
43 passed, 1 failed
The exit code is 0 when everything passed and 1 when anything failed, so a test can be used in a script or a CI job without parsing its output.
Every script starts with:
if (PHP_SAPI !== 'cli') { http_response_code(404); exit; }Do not remove it. FreeITSM is normally deployed by putting the repository in
the document root, so without that line a request to /tests/<anything>.php
would run the file β and these tests write to the real database, creating forms,
assets, documents and working analyst accounts. See
Test suite exposure for the whole story and the
three layers that now keep the directory closed.
A test that needs data creates its own, prefixed ZZ/zz, and deletes it in a
finally block. Several assert the cleanup rather than assume it. Even so:
run them against a development database, not a production one. A test that
dies part-way leaves its rows behind.
Each entry below says whether a test needs a database, needs the network, or needs nothing at all.
| Page | Covers |
|---|---|
| Forms | Field identity, conditional visibility, layout and widths, drafts, lookups, audiences, CSS class collisions |
| Assets & CMDB | Import, custom fields, physical disks, last-seen repair, typed CMDB fields, contract links, reconciliation, tags, labels, Proxmox and Cloud Director sync |
| Knowledge, search & documents | Article visibility and ACLs, gap analysis, the search corpus, text extraction, document permissions |
| Tickets & tasks | Ticket numbering, email threading, saved table views, folder counts for team members, task priority, recurrence, collaborators, calendar sync |
| Security & access | The security-findings suite, record previews, SSO/LDAP/OIDC, directory sync scopes |
| Integrations & external services | Jira and Azure DevOps, AI providers, CalDAV, mailbox folders, the inventory agent |
| System & infrastructure | Database verification indexes, config.php, container detection, UTC handling, the status portal |
| Test suite exposure | Why tests/ is unreachable over HTTP, and the guard that keeps it that way |
These recur throughout the suite and are worth knowing before you read or write one.
A test explains why it exists. The docblock names the failure it was written after, not just the behaviour it asserts. That is what makes a red result actionable years later.
Every negative assertion has a positive control. "The required field did not block submission" proves nothing on its own β it is equally true of a harness that never validated anything. So the suite pairs it with "β¦and this one DID block". If you add a check that something is refused, add the control too.
A checker must be able to fail. Several tests assert their own matcher works β that it sees a real match and does not see a near-miss. This is not belt-and-braces; it has caught real faults. One check was satisfied by its own explanatory comment and passed against the very bug it was written to catch.
A skip says so. A section that cannot run β no headless Chrome, a missing
table, no fixture server β prints SKIPPED and the reason. It never counts as a
pass. Chase a skip; a suite that is quietly skipping half of itself looks
exactly like a suite that is passing.
Green means what it says, and no more. Some tests carry an explicit warning
about what they cannot prove. tests/azure-openai/run.php ends with one: it
proves FreeITSM sends what Azure asks for, not that Azure accepts it.
- Start with the CLI guard.
php tests/web-exposure-guard.phpwill fail if you forget it, and it walks the directory rather than a list, so a new file is checked the moment it exists. - Write the docblock before the assertions: what has to hold, and what went wrong that made this worth writing.
- Use the
check(label, bool, detail)helper shape the rest of the suite uses, and end with the$pass/$failsummary andexit($fail === 0 ? 0 : 1). - Clean up in a
finally, and assert the cleanup. - Add a control.
- Add it to the right page here.