-
-
Notifications
You must be signed in to change notification settings - Fork 28
Developer Tests Tickets
Part of Developer Tests. Ticket numbering, saved views, and the task engine: priority, recurrence, the people on a task, and what goes into a calendar.
| Test | Needs |
|---|---|
ticket-numbering.php |
Database |
table-views.php |
Database |
tasks-priority.php |
Nothing |
task-recurrence-dates.php |
Nothing |
task-recurrence-spawn.php |
Database |
task-collaborators/run.php |
Database |
calendar-sync-tasks.php |
Database |
test_email_thread.php |
The assertions that matter are not "it makes a number". They are:
- A number is never issued twice β including one a renumbered ticket used to have, because a reply quoting it must not land on a stranger's ticket.
- An old number keeps resolving forever, because the emails quoting it live in customers' inboxes and nobody can recall them.
- The reference parser recognises any format, because an install can change its format and every number it ever issued has to go on working.
- The padding is a minimum, never a limit.
Creates only ZZNUM-prefixed rows and sweeps them before and after. It
exercises the renumber path deliberately, because that is where a number can be
freed and handed out again.
php tests/ticket-numbering.php
A reissued number is the serious one. It routes a customer's reply onto somebody else's ticket, which is a data leak dressed as a filing error. Treat any red here as blocking a release.
Saved table views β specifically the visibility rules. There are three answers (mine, my team's, everyone's) and a fourth that must never happen: somebody else's private view.
Each is checked from the side that must be refused as well as the side that
must work, using a refuses() helper that asserts the call throws.
php tests/table-views.php
Creates ZZTV-named rows and removes them, including on failure.
A refuses() assertion going red means one analyst can load another's private
view β including its filters, which can describe data they cannot otherwise see.
This is a scan, not a behaviour test, and deliberately so.
The bug it guards is not a wrong output β it is a renderer deriving a colour from
a priority's display name. That produced class="priority-dot hoch" on a
German install, matched none of the four hardcoded English rules, and drew a
transparent circle: no error, no fallback, nothing on screen to suggest a
setting had not applied.
A behaviour test proves the renderer that exists today is right. It cannot stop the fifth renderer, written next year, from reaching for the name again because that is what its neighbours used to do. This is the same shape as the bug where every ticket intake path resolved its status by the word "Open", and the Watchtower counters before that. Three times, so the invariant gets a test rather than a comment:
- No stylesheet carries a per-priority-name rule.
- No renderer interpolates a priority into a class attribute.
- Every place that draws a priority goes through
TasksPriority. -
TasksPriorityvalidates the colour and escapes the name β both are admin-editable free text, and the name is stored exactly as typed.
php tests/tasks-priority.php
48 assertions. No database, no network, writes nothing.
Someone has added a renderer that builds a class from a priority name, or a
stylesheet rule keyed to one. Route it through TasksPriority instead. The test
names the file.
The recurrence date engine. Pure date arithmetic, no database β which is precisely why it is worth testing hard: every interesting bug in a recurrence feature is a calendar edge case, and none of them show up in a demo where everything falls on the 15th of a 31-day month.
The cases are the ones that break naive implementations:
- the 31st in a 30-day month, and in February
- "the last day of the month" across month lengths and a leap year
- "the 5th Tuesday" of a month that has only four
- "every 2 weeks on Mon and Thu" not collapsing into every week
- 29 February under a yearly rule
php tests/task-recurrence-dates.php
60 assertions, nothing required. Each line prints the date it produced, so a failure shows you the arithmetic rather than just a label.
The output gives got and wanted as real dates. Work out which rule the case
belongs to before changing anything β these cases interact, and "fixing" the 31st
commonly breaks the last-day-of-month rule.
The other half of recurrence: that completing a task actually produces the next one, carries across what the rule says to carry and nothing it should not, and fires from both ways a task can be completed.
π That last one is the point. TasksService::moveTask β dragging a card into
a closed column β is documented "No workflow event" and dispatches nothing. A
hook placed only on saveTask would give you a task that repeats when you tick it
and silently does not when you drag it. Dragging is the commoner action.
php tests/task-recurrence-spawn.php
ZZREC-prefixed, cleaned up including on failure.
If only the drag path is red, the hook has been attached to one completion route again. Both routes must spawn.
The other people on a task β the "Involved" list.
π΄ The first suite is the one that matters. A task you are on that fails to
appear in one list is indistinguishable, to the person looking, from your
never having been added to it β and there are four separate places that can hide
it. A single assertion against api/tasks/list.php would pass while the REST API
still hid the task, so every surface is asserted separately.
php tests/task-collaborators/run.php
Writes one task and two throwaway analysts, all removed in the teardown.
The label names the surface. Fix it there, then ask whether the other three share a helper that should have been used.
Tasks in a calendar β the decisions, not the network.
π Nothing here talks to Microsoft. What is worth testing is what the code decides: which of a task's two dates belongs in whose calendar, what an event looks like once built, and what happens at the edges. The provider is a network call and belongs behind a live run, not a unit test.
php tests/calendar-sync-tasks.php
ZZCAL-named rows, removed including on failure.
Read it as "we would now put the wrong thing in somebody's calendar". Since the network half is deliberately untested here, a green run does not mean sync works end to end β that still needs a live run against a real account.
It also had no authentication check of any kind β it called session_start()
and then printed that ticket's from_address and body_content to whoever asked.
Until tests/ was closed off it was fetchable over HTTP by anyone who knew the
path. See Test suite exposure.
It is recorded here so nobody goes looking for it, and so nobody mistakes its former existence for coverage of email threading. There is none β email threading has no automated test.
FreeITSM β an open-source IT Service Management platform Β· github.com/edmozley/freeitsm Β· MIT licence
- Installation
- β° Scheduled tasks (cron jobs)
- Architecture
- π§ͺ Developer tests
- AI Providers
- Internationalisation (i18n)
- Timezones & Time Handling
- π Date & Time Formats
- Theming & Dark Mode
- ποΈ Recent β getting back to what you were doing
- β¨οΈ Command palette (βK)
- π Searching inside tickets
- π Attached documents
-
MobileβFriendly
- β³ π« Mobile: Tickets
- β³ π» Mobile: Assets
- β³ π Mobile: Calendar
- β³ π Mobile: Knowledge
- β³ π¦ Mobile: Service Status
- β³ πΌ Mobile: Watchtower
- β³ π§© Mobile: Problem Management
- β³ π Mobile: Change Management
- β³ πΏ Mobile: Software
- β³ β Mobile: Tasks
- β³ π Mobile: Forms
- β³ π Mobile: Contracts
- β³ π Mobile: Domains
- β³ π Mobile: People
- β³ π Mobile: LMS
- β³ πΊοΈ Mobile: CMDB
- β³ πΊοΈ Mobile: Network Mapper
- β³ π§ Mobile: Process Mapper
- β³ βοΈ Mobile: Workflow
- β³ π₯οΈ Mobile: System
- β³ π Mobile: Reporting
- β³ π Mobile: System Wiki
- β³ π Mobile: Self-Service Portal
- β³ π§° Mobile: Techniques & Tricks
-
Security
- Layer 1 β which modules you can enter
- β³ π§© Module Access Control
- β³ π οΈ Module Access β Developer Guide
- Layer 2 β what you can administer
- β³ π Roles & Permissions
- β³ π οΈ Roles β Developer Guide
- β³ π€ Why capabilities are constants
- Layer 3 β the System module
- β³ π Admin Access Control
- Hardening
- β³ π Security review response 2026-08
- β³ π‘οΈ Security hardening 2026-08
- β³ π οΈ Security hardening 2026-08 β Developer Guide
- β³ π‘οΈ Round three β plain English
- β³ π οΈ Round three β Developer Guide
- β³ π‘οΈ CSRF protection (S4) β Developer Guide
- Single Sign-On (SSO)
- ποΈ LDAP & Active Directory
- π CardDAV contact sync
- Browser Extension
- API Reference
-
π REST API β how it works
- β³ π« REST API: Tickets
- β³ π» REST API: Assets
- β³ π΄ REST API: Problems
- β³ π REST API: Changes
- β³ π REST API: Knowledge
- β³ β REST API: Tasks
- β³ ποΈ REST API: CMDB
- β³ π REST API: Contracts
- β³ ποΈ REST API: Calendar
- β³ πΏ REST API: Software
- β³ π REST API: Domains
- β³ π¦ REST API: Service Status
- β³ βοΈ REST API: Morning Checks
- β³ π REST API: Forms
- β³ βοΈ REST API: Workflow
- β³ π·οΈ REST API: Cost centres
- β³ πΊοΈ REST API: Network Mapper
- β³ π§ Using the API docs page
- β³ π OpenAPI specification
- β³ β OpenAPI: kept correct
- β³ π οΈ Maintaining the catalogue
- Watchtower
-
Tickets
- β³ π Rota copy and paste β Developer Deep Dive
- β³ β Checklists & SOPs
- β³ βοΈ Mandatory fields
- β³ π·οΈ Ticket categories
- β³ π₯ Assigning tickets to a team, and escalation
- β³ π’ One board across every company
- β³ Mailbox Authentication
- β³ π€ Email send log
- β³ Basic IMAP mailboxes
- β³ Email rendering & images
- β³ SLA Management
- β³ WhatsApp channel
-
β³
βοΈ Telegram channel - β³ β CSAT company scope and filters β Developer Guide
- β³ π₯ Microsoft Teams channel
- β³ π¨οΈ Mattermost channel
- β³ π¬ Web chat channel
- β³ π£ Slack channel
- β³ π Linking tickets
- β³ β Record previews
- β³ π Ticket notes: internal or shared
- β³ ποΈ Canned responses
- β³ βοΈ Limiting replies to particular senders
- β³ π¨ Telling the analyst a ticket is theirs
- β³ βοΈ Email signatures
- β³ π The public web address
- β³ π’ Ticket numbering
- β³ π Raising a ticket for someone else
- β³ π Merging tickets
- β³ π Confidential tickets
- β³ π₯ Portal managers
- β³ π Who has seen a ticket
- β³ π Reading long tickets
- β³ β Splitting tickets
- β³ β Selecting several tickets
- β³ ποΈ The folder pane
- β³ π½ Just my tickets, or no closed ones
- β³ π οΈ Snoozing tickets β Developer Guide
- β³ π₯ Collision detection
- β³ β±οΈ Time tracking
- β³ π Scheduled work in your own calendar
- Problem Management
- Tasks
-
Assets
- β³ π’ Moving an asset between companies
- β³ π Shared asset locations
- β³ π§βπΌ Assigning assets to analysts
- β³ π Warranty and lease alerts
- β³ π Saved table views
- β³ π¨οΈ Recording anything, and importing it
- β³ π·οΈ QR asset labels
- β³ π Who holds what, and handover documents
- β³ π₯οΈ The inventory agent (PowerShell)
- β³ ποΈ Proxmox VE servers
- β³ βοΈ VMware Cloud Director servers
- β³ π Linking equipment to tickets
- β³ βοΈ Follow-up tasks on a ticket
- Knowledge
- Change Management
- Calendar
- Morning Checks
- Reporting
- Software
-
Forms
- β³ π¨ The form designer β Developer Guide
- β³ π Layout & the grid β Developer Guide
- β³ ποΈ Collections β grouping submissions
- β³ π Submissions as PDFs
- β³ β‘ What happens next β a form's own actions
- β³ π οΈ Sections & conditional logic β Developer Guide
- β³ π οΈ Lookup fields β Developer Guide
- β³ π‘οΈ Catalogue request approvals
- People
- Domains
- Contracts
- Service Status
- π Notifications
- π¨ War Room
- Self-Service Portal
- LMS
- Process Mapper
- CMDB
- Network Mapper
- Workflows
- Issue trackers (Jira, Azure DevOps)
- System
-
Overview
- β³ π Progress tracker
- β³ Concepts & vocabulary
- β³ Email routing & mailboxes
- β³ Settings: global vs per-company
- β³ Users & self-service
- β³ Staff cross-company access
- β³ π’ One board across every company
- β³ Worked examples
- β³ Pitfalls & gotchas
- β³ Scope: what it's for
- β³ π οΈ Developer Guide (make a module multi-company)
- β³ ποΈ Case study: CMDB (a linked graph)
- β³ π§ͺ Test harness (prove it's isolated)
- What this is
-
π Bugs resolved
- β³ π’ Chat tickets ignored your ticket numbering
- β³ π Dates shown as a dash, or in server time
- β³ π Assets β Users showed people from other companies
- β³ π Restricted analysts could read other modules' data
- β³ πΌοΈ Replies with a picture in the thread failed to send
- β³ π Reply attachments never reached the customer
- β³ π οΈ Outbound email attachments β Developer Guide
- β³ π A global SSO provider was missing from the portal
- β³ π Behind a proxy, the SSO redirect said http
- β³ βοΈ The portal tagline moved when you saved it
- β³ π¨ The portal settings screen forgot what you saved
- β³ π‘οΈ The approvals inbox said "Error" and nothing else
- β³ π A table's answers were missing from the PDF
- β³ β A single-select column let you tick every option
- β³ π The portal ignored a form's field widths
- β³ π The tasks board stopped taking clicks
- β³ ποΈ #121 The index list is out of date after upgrading
- β³ π #133 The calendar subscription was empty
- β³ π #131 Tasks always reopened on the board
- β³ π₯ #129 Every page returned HTTP 500 after upgrading
- β³ π³ #127 A PHP warning above the System page
- β³ π #126 Notes stamped with the server's clock
- β³ π Storing every date in UTC
- β³ πͺ The portal was down for everyone signed in
- β³ βοΈ #120 Workflow notes could never be written
- β³ βοΈ #123 Three errors when running Database Verification
- β³ π #122 The description box was a stub in the corner
- β³ π£ Demo data deleted real accounts
- β³ π #117 Sign-in redirected to the wrong address
- β³ π¨ #108 The priority dot was invisible
- β³ β±οΈ #116 Time logged from the right-click menu
- β³ π #114 API keys refused by our own guard
- β³ ποΈ #110 Assigning a task told nobody
- β³ πͺ #107 Signed out while still working
- β³ π #103 "Share with Requester" reached nobody
- β³ π #102 Search found nothing for hyphens
- β³ πͺ #101 Source code editor opened behind
- β³ βοΈ #88 Subtasks could not be ticked off
- β³ π» #84 Asset deep link selected nothing
- β³ π« #79 A new ticket arrived with no status
- β³ π§ #79 A ticket from email did not say so
- β³ π #78 Bell opened to nothing
- β³ π¬ #77 Mail only collected from Inbox
- β³ π #74 The default password could not be changed
- β³ π¦ #70 Renaming an impact level
- β³ π€ #67 App-only mailboxes could not send
- β³ π #45 Verify only ever worked for Microsoft
- β³ π #45 IMAP reported as not authenticated
- β³ βοΈ An email template stopped escaping itself
- β³ π The portal dashboard showed the wrong time
- β³ π’ The folder said 99 and the list showed 96