Frontend redesign in progress: updated styles, layout, and components across all pages to align with new design system. Includes Jira API compliance specs, property tests, and load test script.
10 KiB
Implementation Plan
-
1. Write bug condition exploration test
- Property 1: Bug Condition — Jira API Compliance Violations
- CRITICAL: This test MUST FAIL on unfixed code — failure confirms the bugs exist
- DO NOT attempt to fix the test or the code when it fails
- NOTE: This test encodes the expected behavior — it will validate the fix when it passes after implementation
- GOAL: Surface counterexamples that demonstrate the three compliance violations
- Scoped PBT Approach: Scope properties to the three concrete bug conditions:
searchIssues()sends POST instead of GET — generate random JQL strings and assert the HTTP method captured isGETand the request path starts with/rest/api/2/search?with query parameters (not a JSON body)getIssue()sends a single-issue GET to/rest/api/2/issue/{key}— generate random issue keys and assert the request path contains/rest/api/2/search(not/rest/api/2/issue/)searchIssuesByKeys()builds JQL withoutproject =— generate random arrays of issue keys and assert the JQL string passed to the search containsproject =
- Mock
jiraRequestto capture HTTP method, URL path, and body arguments without making real HTTP calls - Use
fast-checkarbitraries to generate JQL strings, issue keys (e.g.,fc.tuple(fc.stringMatching(/^[A-Z]{2,6}$/), fc.integer({ min: 1, max: 99999 }))forKEY-123patterns), and key arrays - Test file:
backend/__tests__/jira-api-compliance.property.test.js - Run test on UNFIXED code
- EXPECTED OUTCOME: Test FAILS (this is correct — it proves the bugs exist)
- Document counterexamples found:
searchIssues()uses POST,getIssue()hits/rest/api/2/issue/{key},searchIssuesByKeys()JQL lacksproject = - Mark task complete when test is written, run, and failure is documented
- Requirements: 1.1, 1.2, 1.3
-
2. Write preservation property tests (BEFORE implementing fix)
- Property 2: Preservation — Unchanged Jira API Functions
- IMPORTANT: Follow observation-first methodology
- Observe behavior on UNFIXED code for non-buggy functions:
createIssue({ project: { key: 'TEST' }, summary: 'x', issuetype: { name: 'Task' } })sendsPOSTto/rest/api/2/issuewith JSON body containing{ fields: {...} }updateIssue('TEST-1', { summary: 'y' })sendsPUTto/rest/api/2/issue/TEST-1with JSON body containing{ fields: {...} }addComment('TEST-1', 'comment text')sendsPOSTto/rest/api/2/issue/TEST-1/commentwith JSON body containing{ body: 'comment text' }transitionIssue('TEST-1', '5')sendsPOSTto/rest/api/2/issue/TEST-1/transitionswith JSON body containing{ transition: { id: '5' } }getTransitions('TEST-1')sendsGETto/rest/api/2/issue/TEST-1/transitionstestConnection()sendsGETto/rest/api/2/myself
- Write property-based tests using
fast-checkthat verify for all generated inputs:createIssue()always sendsPOST /rest/api/2/issuewith{ fields }body — generate random field objectsupdateIssue()always sendsPUT /rest/api/2/issue/{key}with{ fields }body — generate random keys and field objectsaddComment()always sendsPOST /rest/api/2/issue/{key}/commentwith{ body }— generate random keys and comment stringstransitionIssue()always sendsPOST /rest/api/2/issue/{key}/transitionswith{ transition: { id } }— generate random keys and transition IDsgetTransitions()always sendsGET /rest/api/2/issue/{key}/transitions— generate random keystestConnection()always sendsGET /rest/api/2/myself- Response shape:
searchIssues()returns{ ok, data: { total, issues } }andgetIssue()returns{ ok, data: <issue> }— verify shape is preserved
- Mock
jiraRequestto capture method, path, body and return appropriate mock responses - Test file:
backend/__tests__/jira-api-preservation.property.test.js - Verify tests pass on UNFIXED code
- EXPECTED OUTCOME: Tests PASS (this confirms baseline behavior to preserve)
- Mark task complete when tests are written, run, and passing on unfixed code
- Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10
-
3. Fix the core API helper (
backend/helpers/jiraApi.js)-
3.1 Convert
searchIssues()from POST to GET with query parameters- Replace
jiraPost('/rest/api/2/search', body)withjiraGet('/rest/api/2/search?jql=...&fields=...&maxResults=...&startAt=...') - URL-encode JQL string with
encodeURIComponent(jql) - Comma-join and encode fields array with
encodeURIComponent(fields.join(',')) - Encode
maxResultsandstartAtas query parameters - Remove the JSON body object
{ jql, startAt, maxResults, fields } - Preserve the
res.status === 200check andJSON.parse(res.body)response parsing - Preserve the
{ ok, data }return shape - Bug_Condition: searchIssues uses POST /rest/api/2/search with JSON body
- Expected_Behavior: searchIssues uses GET /rest/api/2/search?jql=&fields=&maxResults=&startAt=
- Preservation: Response shape { ok, data: { total, issues } } unchanged
- Requirements: 2.1
- Replace
-
3.2 Add project scoping to
searchIssuesByKeys()JQL- Change JQL from
key in (${keyList}) AND updated >= -24htokey in (${keyList}) AND updated >= -24h AND project = ${JIRA_PROJECT_KEY} JIRA_PROJECT_KEYis already available in module scope- Bug_Condition: searchIssuesByKeys JQL lacks project = clause
- Expected_Behavior: JQL includes project = JIRA_PROJECT_KEY
- Preservation: Return shape and searchIssues delegation unchanged
- Requirements: 2.2
- Change JQL from
-
3.3 Refactor
getIssue()to delegate tosearchIssues()via JQL- Replace
jiraGet('/rest/api/2/issue/${encodeURIComponent(issueKey)}?fields=...')with a call tosearchIssues()using JQLkey = "${issueKey}" AND project = ${JIRA_PROJECT_KEY}andmaxResults: 1 - Extract
data.issues[0]from search results to return as{ ok: true, data: <issue> } - Return
{ ok: false, status: 404, body: 'Issue not found' }when search returns empty results - Preserve the
{ ok, data: <single-issue> }return shape for callers - Bug_Condition: getIssue sends GET /rest/api/2/issue/{key} (single-issue GET)
- Expected_Behavior: getIssue delegates to searchIssues with JQL key = "{key}" AND project = KEY
- Preservation: Return shape { ok, data: { key, fields } } unchanged
- Requirements: 2.3
- Replace
-
3.4 Verify bug condition exploration test now passes
- Property 1: Expected Behavior — Jira API Compliance Violations
- IMPORTANT: Re-run the SAME test from task 1 — do NOT write a new test
- The test from task 1 encodes the expected behavior
- When this test passes, it confirms the expected behavior is satisfied
- Run
npx jest backend/__tests__/jira-api-compliance.property.test.js --no-cache - EXPECTED OUTCOME: Test PASSES (confirms bugs are fixed)
- Requirements: 2.1, 2.2, 2.3
-
3.5 Verify preservation tests still pass
- Property 2: Preservation — Unchanged Jira API Functions
- IMPORTANT: Re-run the SAME tests from task 2 — do NOT write new tests
- Run
npx jest backend/__tests__/jira-api-preservation.property.test.js --no-cache - EXPECTED OUTCOME: Tests PASS (confirms no regressions)
- Confirm all unchanged functions still produce the same HTTP method, path, and body
-
-
4. Update the UAT test script (
backend/scripts/jira-uat-test.js)-
4.1 Update test case 3 name to reflect JQL-based pattern
- Change
'3. Get Single Issue (GET /issue/{key})'to'3. Get Single Issue (JQL search)' - The test body calls
jiraApi.getIssue()which now delegates to JQL search — no logic change needed in the test function itself - Requirements: 2.4
- Change
-
4.2 Update test case 8 name to reflect GET method
- Change
'8. JQL Search (POST /search)'to'8. JQL Search (GET /search)' - Add project-scoped JQL to the test: include
AND project = ${jiraApi.JIRA_PROJECT_KEY}in the JQL string passed tosearchIssues() - Requirements: 2.5
- Change
-
4.3 Update test case 9 to verify project scoping
- Add a log entry or assertion that the bulk key search includes project scoping
- The underlying
searchIssuesByKeys()now includesproject = <KEY>— the test validates the function works correctly with the compliant JQL - Requirements: 2.5
-
-
5. Update the API documentation (
docs/jira-api-use-cases.md)-
5.1 Update compliance summary table
- Change "Bulk reads via JQL" row endpoint from
POST /rest/api/2/searchtoGET /rest/api/2/search - Add a row for "Single-issue fetch" describing JQL-based lookup via
GET /rest/api/2/search?jql=key="KEY"&... - Requirements: 2.6, 2.7
- Change "Bulk reads via JQL" row endpoint from
-
5.2 Update Use Case 3 (Get Single Issue)
- Change endpoint from
GET /rest/api/2/issue/{issueKey}?fields=...toGET /rest/api/2/search?jql=key="ISSUE-KEY" AND project=<KEY>&fields=...&maxResults=1 - Update the description to explain the JQL-based pattern
- Requirements: 2.7
- Change endpoint from
-
5.3 Update Use Case 8 (JQL Search / Bulk Sync)
- Change endpoint from
POST /rest/api/2/searchtoGET /rest/api/2/search?jql=...&fields=...&maxResults=...&startAt=... - Update JQL pattern to include
project = <KEY>scoping - Requirements: 2.6
- Change endpoint from
-
5.4 Update Use Case 9 (Issue Lookup)
- Change endpoint from
GET /rest/api/2/issue/{issueKey}?fields=...toGET /rest/api/2/search?jql=key="ISSUE-KEY" AND project=<KEY>&fields=...&maxResults=1 - Update the description to match the JQL-based lookup pattern
- Requirements: 2.7
- Change endpoint from
-
-
6. Checkpoint — Ensure all tests pass
- Run
npx jest backend/__tests__/jira-api-compliance.property.test.js --no-cache— all bug condition tests pass - Run
npx jest backend/__tests__/jira-api-preservation.property.test.js --no-cache— all preservation tests pass - Run
npx jest --no-cache— all existing tests in the project still pass - Ensure all tests pass, ask the user if questions arise.
- Run