Skip to content

Developer Tests Tickets

Ed Mozley edited this page Sep 21, 2026 · 2 revisions

πŸ§ͺ Developer Tests β€” Tickets & tasks

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 ⚠️ Not a test β€” see below

tests/ticket-numbering.php

What it tests

The assertions that matter are not "it makes a number". They are:

  1. 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.
  2. An old number keeps resolving forever, because the emails quoting it live in customers' inboxes and nobody can recall them.
  3. The reference parser recognises any format, because an install can change its format and every number it ever issued has to go on working.
  4. The padding is a minimum, never a limit.

How it works

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.

Run it

php tests/ticket-numbering.php

If it fails

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.


tests/table-views.php

What it tests

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.

Run it

php tests/table-views.php

Creates ZZTV-named rows and removes them, including on failure.

If it fails

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.


tests/tasks-priority.php

What it tests

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:

  1. No stylesheet carries a per-priority-name rule.
  2. No renderer interpolates a priority into a class attribute.
  3. Every place that draws a priority goes through TasksPriority.
  4. TasksPriority validates the colour and escapes the name β€” both are admin-editable free text, and the name is stored exactly as typed.

Run it

php tests/tasks-priority.php

48 assertions. No database, no network, writes nothing.

If it fails

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.


tests/task-recurrence-dates.php

What it tests

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

Run it

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.

If it fails

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.


tests/task-recurrence-spawn.php

What it tests

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.

Run it

php tests/task-recurrence-spawn.php

ZZREC-prefixed, cleaned up including on failure.

If it fails

If only the drag path is red, the hook has been attached to one completion route again. Both routes must spawn.


tests/task-collaborators/run.php

What it tests

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.

⚠️ Every "it works" assertion is paired with a control proving the check can actually fail. A filter test that passes because the query returns everything is not evidence of anything.

Run it

php tests/task-collaborators/run.php

Writes one task and two throwaway analysts, all removed in the teardown.

If it fails

The label names the surface. Fix it there, then ask whether the other three share a helper that should have been used.


tests/calendar-sync-tasks.php

What it tests

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.

Run it

php tests/calendar-sync-tasks.php

ZZCAL-named rows, removed including on failure.

If it fails

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.


tests/test_email_thread.php β€” deleted in 2.3.1

⚠️ It was never a test. It was a leftover scratch page: it rendered the email thread of ticket #45, hardcoded, as an HTML page, with no assertions and no pass/fail count. It was written to look at thread formatting.

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

Getting Started

Modules

Multi-tenancy (planned)

Blue sky thinking

Bugs resolved

Links

Clone this wiki locally