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.
140 lines
10 KiB
Markdown
140 lines
10 KiB
Markdown
# Implementation Plan
|
|
|
|
- [x] 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:
|
|
1. `searchIssues()` sends POST instead of GET — generate random JQL strings and assert the HTTP method captured is `GET` and the request path starts with `/rest/api/2/search?` with query parameters (not a JSON body)
|
|
2. `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/`)
|
|
3. `searchIssuesByKeys()` builds JQL without `project =` — generate random arrays of issue keys and assert the JQL string passed to the search contains `project =`
|
|
- Mock `jiraRequest` to capture HTTP method, URL path, and body arguments without making real HTTP calls
|
|
- Use `fast-check` arbitraries to generate JQL strings, issue keys (e.g., `fc.tuple(fc.stringMatching(/^[A-Z]{2,6}$/), fc.integer({ min: 1, max: 99999 }))` for `KEY-123` patterns), 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 lacks `project =`
|
|
- Mark task complete when test is written, run, and failure is documented
|
|
- _Requirements: 1.1, 1.2, 1.3_
|
|
|
|
- [x] 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' } })` sends `POST` to `/rest/api/2/issue` with JSON body containing `{ fields: {...} }`
|
|
- `updateIssue('TEST-1', { summary: 'y' })` sends `PUT` to `/rest/api/2/issue/TEST-1` with JSON body containing `{ fields: {...} }`
|
|
- `addComment('TEST-1', 'comment text')` sends `POST` to `/rest/api/2/issue/TEST-1/comment` with JSON body containing `{ body: 'comment text' }`
|
|
- `transitionIssue('TEST-1', '5')` sends `POST` to `/rest/api/2/issue/TEST-1/transitions` with JSON body containing `{ transition: { id: '5' } }`
|
|
- `getTransitions('TEST-1')` sends `GET` to `/rest/api/2/issue/TEST-1/transitions`
|
|
- `testConnection()` sends `GET` to `/rest/api/2/myself`
|
|
- Write property-based tests using `fast-check` that verify for all generated inputs:
|
|
1. `createIssue()` always sends `POST /rest/api/2/issue` with `{ fields }` body — generate random field objects
|
|
2. `updateIssue()` always sends `PUT /rest/api/2/issue/{key}` with `{ fields }` body — generate random keys and field objects
|
|
3. `addComment()` always sends `POST /rest/api/2/issue/{key}/comment` with `{ body }` — generate random keys and comment strings
|
|
4. `transitionIssue()` always sends `POST /rest/api/2/issue/{key}/transitions` with `{ transition: { id } }` — generate random keys and transition IDs
|
|
5. `getTransitions()` always sends `GET /rest/api/2/issue/{key}/transitions` — generate random keys
|
|
6. `testConnection()` always sends `GET /rest/api/2/myself`
|
|
7. Response shape: `searchIssues()` returns `{ ok, data: { total, issues } }` and `getIssue()` returns `{ ok, data: <issue> }` — verify shape is preserved
|
|
- Mock `jiraRequest` to 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_
|
|
|
|
- [x] 3. Fix the core API helper (`backend/helpers/jiraApi.js`)
|
|
|
|
- [x] 3.1 Convert `searchIssues()` from POST to GET with query parameters
|
|
- Replace `jiraPost('/rest/api/2/search', body)` with `jiraGet('/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 `maxResults` and `startAt` as query parameters
|
|
- Remove the JSON body object `{ jql, startAt, maxResults, fields }`
|
|
- Preserve the `res.status === 200` check and `JSON.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_
|
|
|
|
- [x] 3.2 Add project scoping to `searchIssuesByKeys()` JQL
|
|
- Change JQL from `` key in (${keyList}) AND updated >= -24h `` to `` key in (${keyList}) AND updated >= -24h AND project = ${JIRA_PROJECT_KEY} ``
|
|
- `JIRA_PROJECT_KEY` is 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_
|
|
|
|
- [x] 3.3 Refactor `getIssue()` to delegate to `searchIssues()` via JQL
|
|
- Replace `jiraGet('/rest/api/2/issue/${encodeURIComponent(issueKey)}?fields=...')` with a call to `searchIssues()` using JQL `key = "${issueKey}" AND project = ${JIRA_PROJECT_KEY}` and `maxResults: 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_
|
|
|
|
- [x] 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_
|
|
|
|
- [x] 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
|
|
|
|
- [x] 4. Update the UAT test script (`backend/scripts/jira-uat-test.js`)
|
|
|
|
- [x] 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_
|
|
|
|
- [x] 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 to `searchIssues()`
|
|
- _Requirements: 2.5_
|
|
|
|
- [x] 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 includes `project = <KEY>` — the test validates the function works correctly with the compliant JQL
|
|
- _Requirements: 2.5_
|
|
|
|
- [x] 5. Update the API documentation (`docs/jira-api-use-cases.md`)
|
|
|
|
- [x] 5.1 Update compliance summary table
|
|
- Change "Bulk reads via JQL" row endpoint from `POST /rest/api/2/search` to `GET /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_
|
|
|
|
- [x] 5.2 Update Use Case 3 (Get Single Issue)
|
|
- Change endpoint from `GET /rest/api/2/issue/{issueKey}?fields=...` to `GET /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_
|
|
|
|
- [x] 5.3 Update Use Case 8 (JQL Search / Bulk Sync)
|
|
- Change endpoint from `POST /rest/api/2/search` to `GET /rest/api/2/search?jql=...&fields=...&maxResults=...&startAt=...`
|
|
- Update JQL pattern to include `project = <KEY>` scoping
|
|
- _Requirements: 2.6_
|
|
|
|
- [x] 5.4 Update Use Case 9 (Issue Lookup)
|
|
- Change endpoint from `GET /rest/api/2/issue/{issueKey}?fields=...` to `GET /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_
|
|
|
|
- [x] 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.
|