Test Suite Create Edit Delete Refs 1852 - sebiboga/testlink-upgraded GitHub Wiki

Test Suite Create / Edit / Delete (modernized) — Refs #1852

One Dashio page replaces the three legacy modes of lib/testcases/containerEdit.php (new_testsuite, add_testsuite, edit_testsuite, update_testsuite, delete_testsuite).

  • Screen: gui/templates/testcases/suiteEdit.html
  • BFF: api/suiteedit/index.php
    • GET ?action=init&mode=create|edit|delete
    • POST ?action=create|update|delete

Why this screen had to be rebuilt

The api/suiteview inline "create/rename suite" modal was a bare name + details form. Against 1.9.20 that meant:

Legacy 1.9.20 the inline modal suiteEdit
html_table_of_custom_field_inputs() never rendered all types rendered from API data
design_values_to_db() on write never called called on create and update
keyword assignment absent dual picker, persisted
delete_executed_testcases gate (build_del_testsuite_warning_msg(), system_blocks_tsuite_delete_due_to_exec_tc) delete_deep() on a plain mgt_modify_tc re-checked at write time

So renaming a suite silently destroyed every design custom field of that suite, and a suite holding a linked and executed test case could be deleted without the right that legacy refused without.

Edit mode

Edit mode

  • Context meta grid: test project, prefix, container path, mode.
  • Name (pipe rejected, 100-char cap), details.
  • Custom fields: every type — string, numeric, email, checkbox, list, multiselection, date, textarea — with label, type name and possible values coming from the API as data (never innerHTML).
  • Keywords: available / assigned dual picker; an untouched save is a no-op.
  • The URL switches to the persisted identity without a reload, so the success message survives (the #1724 lesson).
  • The legacy actions 302 here, so a bookmarked/legacy link cannot reach the CF-dropping form any more.

Delete mode — the executed-case gate

Delete mode, executed case present

  • Blast radius first: how many nested suites and how many deep test cases go.
  • Per-case table with the link / execution status of every case (linked_and_executed, linked_but_not_executed, no_links).
  • With an executed case and no delete_executed_testcases right: the block warning is shown, the confirm dialog explains that the executions go too, and the Delete button stays disabled.
  • The gate is enforced server-side on the POST as well — the disabled button is a courtesy, the 409 suite_has_executed is the rule.
  • Only navigates away after the server confirms the write.

i18n

58 sued.* keys + footers.suiteEdit in all ten bundles, with a TLi18n locale switcher. Custom-field labels and type names stay in the language they were typed in: they are user data, not UI strings.

Bugs found while testing this screen

Issue What
#1853 (filed) cfield_mgr::_build_cfield() classifies a hash key as a DATE part by its _input suffix instead of the type, so a non-date field keeps an ARRAY cf_value and design_values_to_db() fatals (tlStringLen(): Argument #1 must be of type string, array given). Affects every CF write path, not only this screen.
#1854 (fixed) The BFF called check_string() with the wrong polarity (if (check_string(...)) -> bad_chars): the helper returns 1 = check ok, so no suite name was saveable at all while a name with a `

The CF silent-drop and the ungated delete in api/suiteview are deliberately not separate issues: they are exactly what Refs #1852 fixes.

Defects the browser pass caught (fixed in the same run)

  1. The CF block died on a multiselection field — cfInput() read a var declared in the checkbox branch, and since renderCfs() aborts, the keyword picker vanished too.
  2. Every save wiped the suite's keywords — the Assigned options were never selected, and only :selected options are posted (1 row -> 0 in the DB).
  3. The form could be saved exactly once per page load — BUSY was never released on the success path, so later clicks were swallowed silently.
  4. 33 E_WARNING per page load: $m[4..6] of a DATE-only value's optional time group.
  5. The legacy redirect dropped the suite/container identity when reached with suite_id/container_id instead of testsuiteID/objectID.
  6. Keyword writes were unvalidated: addKeywords() inserts raw ids, so a crafted payload could attach another project's keywords. Now 400 keyword_mismatch.

Class-API traps recorded for the next screen

  • testsuite::addKeywords() writes fk_table='nodes_hierarchy' (the node id is the suite id), not 'testsuite'.
  • testcase::get_exec_status() INNER JOINs testplan_tcversions — an "executed" case only exists through test plan -> testplan_tcversions -> tcversion -> executions; an executions row alone reads back no_links.
  • A stored DATE custom field is a UNIX timestamp, not a localized string.
  • nodes_hierarchy has no details column (2.0.1 schema drift).

Tests

tmp/TLU_Test_Cases.md → ## Issue #1852 — 51 PASS / 1 SKIPPED / 0 FAIL, including a 15-case real-browser pass. Fixture: tmp/fixtures_1852.php (re-runnable, prints the ids it created).