Set Test Urgency - sebiboga/testlink-upgraded GitHub Wiki
The modernized Set Test Urgency screen replaces the legacy
lib/plan/planUrgency.php + planUrgency.tpl page (launched through the
test_urgency frmWorkArea feature from the execution tree). It assigns
urgency to the test cases linked to a test plan: per test suite with one click
or per test case version with radio buttons, computing the same execution
priority as TestLink 1.9.20 (priority = importance × urgency, thresholds
from urgencyImportance config via priority_to_level()).
Path: Test Plan Management > Set Test Urgency (visible when a test plan is active in context)
URL: gui/templates/plans/testUrgency.html?tproject_id=<id>&tplan_id=<id>
BFF API: api/plans/index.php (routes /urgency, /urgency/suite, /urgency/tcases)
Prerequisite: testplan_planning right enforced server-side on every route;
menu visibility gated by testplan_set_urgent_testcases (legacy parity).

-
Toolbar — test project name, test plan selector (accessible plans),
build selector, platform selector (only when the plan links platforms),
a Help button that opens the legacy
test_urgencyinstructions in a modal, and a reload button; bare deep-links recover the first accessible project. -
Suites pane (left) — every suite of the plan holding DIRECTLY linked
test cases, with TC count and a colored urgency badge (
High/Medium/Low/mixed). Click a suite to load its table. -
Suite urgency buttons —
High/Medium/Lowapply the chosen urgency to all test case versions directly under the selected suite (setSuiteUrgency()semantics) and refresh both badges and table. -
Test case table — external id + name, assigned testers, importance,
High/Medium/Low radios preselected with the current urgency and a colored
priority tag showing the level and numeric value (e.g.
High (9)). -
Row links — pen icon opens the modern Test Case viewer
(
tcView.html), clock icon opens Execution History (execHistory.html) in new tabs (replaces the legacy popups). - Save button — “Set Urgency for Test Cases” posts every radio value (legacy form parity); an unsaved-changes hint appears on edits.
-
Help button — the question-mark button in the toolbar opens the legacy
show_instructions('test_urgency')page (“Specify tests with high or low urgency”: Purpose + Get Started) in a Bootstrap modal, fetched live from the ported instructions viewer (api/staticpage/index.php), localized to the active locale. A modal footer link opens the full standalone page (documentation/staticPage.html?key=test_urgency). The modal does not navigate, so unsaved radio changes are preserved.



| Value | Constant | Meaning |
|---|---|---|
| 1 | LOW | low urgency |
| 2 | MEDIUM | medium urgency |
| 3 | HIGH | high urgency |
Priority = importance × urgency; levels via legacy thresholds
(>= 6 HIGH, < 3 LOW, otherwise MEDIUM). Suite badges show mixed
whenever the linked test case versions of that suite carry different
urgencies.
Legacy planUrgency.php used rightsAnd = ["testplan_planning"] for the
page and all mutations — the BFF enforces exactly that on every route
(401 unauthenticated, 403 without the right). The aside menu entry keeps the
legacy testplan_set_urgent_testcases grant gate.
All routes under /api/plans/index.php, session auth + CSRF guard:
| Route | Method | Purpose |
|---|---|---|
/urgency?tproject_id=&tplan_id=[&build_id=][&platform_id=] |
GET | context: accessible plans selector, active plan, suites w/ TC counts + urgency summary, plan builds + default/current build, plan platforms + default/current platform |
/urgency/suite?tplan_id=&tsuite_id=[&platform_id=][&build_id=] |
GET | test cases under one suite: ids, names, importance, urgency, computed priority, assigned testers (for the selected build) |
/urgency/suite |
POST |
{tplan_id, tsuite_id, urgency} → setSuiteUrgency()
|
/urgency/tcases |
POST |
{tplan_id, items:{tcversion_id:urgency}} → setTestUrgency() loop |
The Assigned To column is resolved from user_assignments for a particular
build. Legacy (lib/plan/planUrgency.php:114 +
tlTestCaseFilterControl::init_setting_build) used the navigator's
setting_build session value; the port initially hard-coded the
alphabetically-first active build. The toolbar now has a Build selector
(#buildSel):
- all builds of the plan are listed (inactive/closed included, closed ones
labelled
(closed)— legacyplan_modekeeps them in the list); - choosing a build re-fetches the current suite with
&build_id=and the column reflects that build's assignments; the choice is persisted in the URL (build_id); - server default order: navigator-stored
<tplan_id>_stored_setting_buildsession value → alphabetically-first active+open build (pre-#1140 behaviour) → first build; an invalidbuild_idfalls back to the default; - a plan with no builds shows the
-placeholder and an empty Assigned To column.

The legacy urgency grid was scoped by the navigator's platform setting
(lib/plan/planUrgency.php:46,112-115 → $context->platform_id;
lib/functions/testPlanUrgency.class.php:163-166 appends
AND TPTCV.platform_id=<n> when set). The port merged every platform of a
test case version into a single row with no way to isolate one. The toolbar now
has a Platform selector (#platformSel):
- options are the plan's linked platforms (
testplan::getPlatforms()) plus an All platforms entry (0); - choosing a platform re-fetches the current suite with
&platform_id=and the grid shows only that platform's urgency/assignment rows (e.g. a version linked to Linux at urgency 3 and Windows at 1 showsHighfor All/Linux andLowfor Windows); the choice is persisted in the URL (platform_id); - server default order: navigator-stored
<tplan_id>_stored_setting_platformsession value →0(all platforms); an explicitplatform_id=0selects all, an unlinked positive id falls back to the default; - a plan that links no platforms hides the selector (
#platformCtx), matching legacyinit_setting_platform()whengetLinkedToTestplanAsMap()is empty; - like legacy, the write paths (
setSuiteUrgency()/setTestUrgency()) are NOT platform-scoped — saving a per-TC urgency updates that tcversion's rows on every platform. Only the read/display path is filtered.


All labels live under the turg.* namespace in all ten locale bundles
(en, ro, de, es, fr, it, ja, pt, ru, zh): header, column headers,
urgency/importance/priority level labels, feedback messages, description
text, empty states, and the Build / Platform selector labels
(turg.build, turg.buildTitle, turg.platform, turg.platformAll,
turg.platformTitle).

- The ExtJS execution-tree navigation is replaced by the suites pane; the
tree-session build/platform filters are gone. Dedicated Build (Issue
#1140) and Platform (Issue #1141) selectors now reproduce the legacy
setting_build(Assigned To column) andsetting_platform(urgency grid scope) semantics that lived in the tree session. - Exec-history / design popups became links to the modern standalone screens.
- Per-platform rows are merged into one row per test case version when All platforms is selected (the write path always updated all platform rows of a tcversion anyway, exactly like legacy).
Suite 58 in the repository test-case document — 12/12 PASS including permission paths (401/403), deep-link recovery, locale switch, DB-level verification of both write paths and an Event Viewer check (zero new Error/Warning entries). Tracking issue: #605.
-
Gap: legacy
getSuiteUrgency()orders rows withORDER BY NHB.node_order(lib/functions/testPlanUrgency.class.php:179) so the urgency grid renders test cases in suite tree order (drag-drop reorders included). The modern BFF merged the same legacy rows but then re-sorted them bytcversion_id(insertion order) —api/plans/index.php— so a case inserted later but placed earlier in the tree rendered in the wrong position, diverging from both the legacy grid and the suite tree. -
Fix: the
GET /urgency/suitemerge loop now carriesnode_order(already present in every raw row via the legacy SQL) into each item payload and sorts by[node_order, tcversion_id]—node_orderascending mirrors legacyORDER BY NHB.node_order;tcversion_idis only a deterministic tie-breaker. No front-end change was needed (renderRows()renders payload order). No new i18n keys (no new user-visible strings). -
Testing: fixture
tmp/fixtures_1144.php(projectURG1144, suiteURG1 Suite Order: Case B created first / lower tcversion_id but tree- reordered to node_order 2, Case A created later / node_order 1; plus a natural-order suite and an empty suite). Verified API + in-browser: reordered suite renders Case A before Case B (pre-fix: reversed); natural order unchanged; empty suite returnsitems: []; suite-button and per-TC writes keep the order on refresh; Event Viewer clean (0 Error/Warning). SuiteTask — Issue #1144intmp/TLU_Test_Cases.md; gateTLU_REQUIRE_SUITE="Issue #1144" bash ai/verify_test_suites.shPASS.
-
Gap: legacy
lib/plan/planUrgency.php:27-30rendered theshow_instructions('test_urgency')help page (title “Specify tests with high or low urgency”, body fromlocale/*/texts.phpwith Purpose and Get Started). The modern screen only had a one-line.descand no button/link to reach the instructions viewer that was already ported under #1501. -
Fix: added a
#btnHelpquestion-mark button to the toolbar and a Bootstrap modal (gui/templates/plans/testUrgency.html) that fetchesapi/staticpage/index.php?action=show&key=test_urgencyin the active locale (TLi18n.getLocale()), showing the legacy title/body; a footer link opens the standalonedocumentation/staticPage.html?key=test_urgency. No BFF change was needed — #1501 already servestest_urgency. i18nturg.help/helpTooltip/helpOpenFulladded to all 10 bundles. -
Testing: fixture
tmp/fixtures_1143.php(projectTURG1143, plan, suite, 3 linked TCs). Verified in-browser: en modal “Purpose/Get Started”;&locale=de→ title “Dringlichkeit der Tests bestimmen”, body “Zweck:”, localized footer; unsaved radio survives open/close; BFF 200 authenticated / 401 anonymous; 0 console messages; Event Viewer clean. SuiteTask — Issue #1143intmp/TLU_Test_Cases.md— 11/11 PASS;ai/verify_i18n_coverage.sh9/9 PASS.
-
Gap: legacy scoped the urgency grid to the navigator's platform setting
(
setting_platform); the modern screen had no platform control and merged all platforms into one row, so urgency/assignment could not be isolated per platform. -
Fix:
GET /urgencynow returnsplatforms,default_platform_idandplatform_id(newurgencyPlatforms()helper,api/plans/index.php, honours the legacy<tplan_id>_stored_setting_platformsession key); the toolbar got a Platform selector (gui/templates/plans/testUrgency.html) that passesplatform_idtoGET /urgency/suite, persists it in the URL and resets on plan change; the selector hides for plans with no linked platforms. The BFFplatform_idfilter onGET /urgency/suitealready existed. -
Testing: fixture
tmp/fixtures_1141.sql(plan 2010, Linux/Windows, PLT-1 urgency 3 vs 1). Verified in-browser: All/Linux →High (6), Windows →Low (2); write path stays global (both platform rows updated), matching legacy. Added test suiteTask — Issue #1141totmp/TLU_Test_Cases.md.
-
Symptom: Accessing
lib/plan/planUrgency.phpwith missing/zero/invalidtplan_idanswered HTTP 200 but wrote 5-7 E_WARNING rows to events (undefined keys, null array access ininit_args,initializeGui/foreach path, and missingpageTitlein template context). -
Root cause: Unchecked array/session accesses (
$_SESSION['testplanName'/'testprojectID'/'testplanID']), unchecked results fromget_node_hierarchy_info()andgetSuiteUrgency(), unsafe access to$session_datakeys, andpageTitlenot set on$gui. -
Fix: Added defensive guards in
lib/plan/planUrgency.php:-
init_args(): guard session fallback values withisset(); guard$session_dataaccess fortestcases_to_show,setting_build,setting_platform. -
initializeGui(): guard$ni = $treeMgr->get_node_hierarchy_info(...)result; set$guiObj->pageTitle = lang_get('plan_urgency')with optional plan name suffix. - Main flow: treat falsy
getSuiteUrgency()result as empty array beforeforeach.
-
-
Verification:
curl -s -b <cookies> -L "http://localhost:8082/lib/plan/planUrgency.php?tplan_id=0"produces 0 new E_WARNING events (confirmed by DB query ofeventstable). Same for missing/empty/non-numeric params. -
Regression test: Added "Regression — Issue #1884" suite to
tmp/TLU_Test_Cases.md;TLU_REQUIRE_SUITE="Issue #1884" bash ai/verify_test_suites.sh→ PASS. -
Files changed:
lib/plan/planUrgency.php(+14/-7)
-
Symptom: opening the screen with only
tproject_idin the URL (?tproject_id=N, notplan_id) selected the default plan and populated the suite list, but the test-case table stayed empty and the console logged one400 (Bad Request). Measured:window.tplanId === 0while#tplanSel.value === "<plan>", andGET /urgency/suite?tplan_id=0…→{"error_code":"NO_TPLAN"}. -
Root cause: the BFF correctly normalizes a bare project link to the project's first
accessible plan (
api/plans/index.phpGET /urgency,$tplan_id = $tplans[0]['id']) and returns it asr.tplan, butrender()(gui/templates/plans/testUrgency.html:251) only mirrored that id into the<select>and never assigned the module-leveltplanId— so the auto-selected suite was fetched withtplan_id=0. -
Fix: one line in the branch that already trusts the server's choice —
tplanId = parseInt(r.tplan.id, 10);before$sel.val(String(r.tplan.id)). No user-facing string changed; the no-planelsefallback is untouched. -
Blast radius: this screen only.
planUpdateTC.html/platformsAssign.htmlshare the code shape but their servers returntplan: nullfor a bare link, so they are not affected (checked, no sibling issue filed). -
Testing: fixture
tmp/fixtures_1926.sql(projectURG Project, plansURG Plan Adefault /URG Plan B, suite A with 2 linked TCs, suite B with 1, build). Verified in-browser: bare link now rendersURG Plan A/URG Suite Awith 2 rows; suite click, plan switch, build selector, invalidtplan_idfallback and the radio save (urgency1 → 3 intestplan_tcversions) all pass; console clean, Event Viewer clean. Regression suiteRegression — Issue #1926(10 cases) PASS; CHANGELOG gate 13 PASS / 0 FAIL.
Before — empty table, 400 NO_TPLAN
|
After — default plan's suite rendered |
|---|---|
![]() |
![]() |

