Skip to content

Feature/475 Fix issue with PDF not generated - #476

Merged
junaidiqbalmoj merged 8 commits into
masterfrom
feature/475-PDF-generation-bug
May 8, 2026
Merged

Feature/475 Fix issue with PDF not generated#476
junaidiqbalmoj merged 8 commits into
masterfrom
feature/475-PDF-generation-bug

Conversation

@KianKwa

@KianKwa KianKwa commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

Jira link

#475

Change description

Fix issue with PDF not generated

Checklist

  • commit messages are meaningful and follow good commit message guidelines
  • README and other documentation has been updated / added (if needed)
  • tests have been updated / new tests has been added (if needed)
  • Does this PR introduce a breaking change

Summary by CodeRabbit

  • Bug Fixes

    • Resolved data-handling in the manual upload workflow so uploaded JSON is correctly processed.
    • Fixed persistence in non‑strategic uploads to ensure converted data is retained through the processing pipeline.
  • Tests

    • Added an end-to-end test validating PDF generation after a JSON publication upload.
    • Added a test helper to retrieve the latest artefact by location and list type to support the new test.
  • Chores

    • Updated E2E workflow step for schema collation.

@coderabbitai

coderabbitai Bot commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c914ecb0-bb40-4f1e-a545-6dd849ab3557

📥 Commits

Reviewing files that changed from the base of the PR and between 6192f06 and 57e0c94.

📒 Files selected for processing (1)
  • .github/workflows/e2e.yml

📝 Walkthrough

Walkthrough

Two handler fixes assign parsed/converted JSON to the shared jsonData variable so downstream processing receives the correct payload. A new nightly Playwright e2e test and helper verify PDF artefact generation after uploading an in-memory JSON publication. The E2E workflow command for Prisma schema collation was changed.

Changes

Upload Data Variable Scoping

Layer / File(s) Summary
Handler parse assignment
libs/admin-pages/src/pages/manual-upload-summary/index.ts
Replaces inner const JSON.parse assignment with jsonData = JSON.parse(...) so parsed payload is stored in the outer jsonData used later.
Excel→JSON assignment
libs/admin-pages/src/pages/non-strategic-upload-summary/index.ts
Uses jsonData (instead of local hearingsData) for Excel→JSON conversion output; persists jsonData to the artefact .json file and passes it to subsequent processing.
Regression surface
libs/admin-pages/src/pages/...
Scoping-only changes; no exported/public API changes.

PDF Generation E2E Test

Layer / File(s) Summary
Test helper
e2e-tests/utils/test-support-api.ts
Adds getLatestArtefactByLocationAndListType(locationId, listTypeId) to fetch the newest artefact matching location and list type.
Test data
e2e-tests/tests/admin/manual-upload.spec.ts
Introduces CIVIL_FAMILY_JSON inline JSON payload used by the test.
E2E scenario
e2e-tests/tests/admin/manual-upload.spec.ts
Adds nightly Playwright test that uploads the JSON publication via the manual-upload UI, confirms upload, retrieves the latest artefact, and asserts a non-empty .pdf exists in storage/temp/uploads.

CI Workflow Update

Layer / File(s) Summary
Workflow step
.github/workflows/e2e.yml
Replaces the Prisma schema collation command from yarn workspace @hmcts/postgres-prisma run collate to yarn tsx libs/postgres-prisma/src/collate-schema.ts.

Possibly related PRs

  • hmcts/cath-service#153: Related — also adjusts manual/non‑strategic upload handlers to ensure parsed/converted file data is assigned to the outer jsonData.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title describes fixing a PDF generation issue, which aligns with the core changes across multiple files refactoring variable scope and adding tests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/475-PDF-generation-bug

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0fc07e9d-f6f8-453a-9c30-34ae548546d8

📥 Commits

Reviewing files that changed from the base of the PR and between 055272e and 8d258fd.

📒 Files selected for processing (4)
  • e2e-tests/tests/manual-upload.spec.ts
  • e2e-tests/utils/notification-helpers.ts
  • libs/admin-pages/src/pages/manual-upload-summary/index.ts
  • libs/admin-pages/src/pages/non-strategic-upload-summary/index.ts

Comment thread e2e-tests/utils/notification-helpers.ts Outdated
Comment on lines +150 to +157
export async function getLatestArtefactByLocationAndListType(locationId: number, listTypeId: number) {
return await prisma.artefact.findFirst({
where: {
locationId: locationId.toString(),
listTypeId
},
orderBy: { lastReceivedDate: "desc" }
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Tighten this lookup to the current test run.

Filtering only by locationId and listTypeId is too broad for E2E assertions. A previous or concurrent upload for the same pair can be returned here, which makes the nightly PDF test flaky. Please add a discriminator from the current run, e.g. a createdAfter timestamp captured before submission.

Comment on lines 123 to 128
let jsonData: unknown;
if (!isFlatFile) {
try {
const jsonData = JSON.parse(uploadData.file.toString("utf-8"));
jsonData = JSON.parse(uploadData.file.toString("utf-8"));
await extractAndStoreArtefactSearch(artefactId, listTypeId, jsonData);
} catch (error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not swallow JSON parse failures here.

If JSON.parse() throws, jsonData stays undefined and processPublication() will skip PDF generation, but the request still carries on to the success page. Please fail the upload when the .json payload cannot be parsed, and only treat search extraction as non-fatal.

Suggested split between parse failure and search extraction failure
     let jsonData: unknown;
     if (!isFlatFile) {
       try {
         jsonData = JSON.parse(uploadData.file.toString("utf-8"));
-        await extractAndStoreArtefactSearch(artefactId, listTypeId, jsonData);
-      } catch (error) {
+      } catch {
+        throw new Error("Uploaded JSON could not be parsed");
+      }
+
+      try {
+        await extractAndStoreArtefactSearch(artefactId, listTypeId, jsonData);
+      } catch (error) {
         console.error("[Manual Upload] Failed to extract artefact search data", {
           artefactId,
           error: error instanceof Error ? error.message : String(error)
         });
       }

@github-actions

github-actions Bot commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

🎭 Playwright E2E Test Results

83 tests   50 ✅  5m 4s ⏱️
33 suites  33 💤
 1 files     0 ❌

Results for commit 57e0c94.

♻️ This comment has been updated with latest results.

…eration-bug

# Conflicts:
#	e2e-tests/tests/manual-upload.spec.ts
#	libs/admin-pages/src/pages/non-strategic-upload-summary/index.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
libs/admin-pages/src/pages/manual-upload-summary/index.ts (1)

132-140: ⚠️ Potential issue | 🟠 Major

Do not continue when JSON parsing fails.

JSON.parse() and extractAndStoreArtefactSearch() are still in the same try/catch. A parse failure leaves jsonData undefined, and the upload can still proceed to success without generating a PDF.

Suggested split: fail on parse, log-only on search extraction
     let jsonData: unknown;
     if (!isFlatFile) {
       try {
         jsonData = JSON.parse(uploadData.file.toString("utf-8"));
-        await extractAndStoreArtefactSearch(artefactId, listTypeId, jsonData);
-      } catch (error) {
+      } catch {
+        throw new Error("Uploaded JSON could not be parsed");
+      }
+
+      try {
+        await extractAndStoreArtefactSearch(artefactId, listTypeId, jsonData);
+      } catch (error) {
         console.error("[Manual Upload] Failed to extract artefact search data", {
           artefactId,
           error: error instanceof Error ? error.message : String(error)
         });
       }
e2e-tests/utils/notification-helpers.ts (1)

144-152: ⚠️ Potential issue | 🟠 Major

Tighten this lookup to the current test run to avoid flaky E2E assertions.

Filtering only by locationId and listTypeId can match an older or concurrent upload for the same pair.

Suggested shape
-export async function getLatestArtefactByLocationAndListType(locationId: number, listTypeId: number) {
+export async function getLatestArtefactByLocationAndListType(
+  locationId: number,
+  listTypeId: number,
+  createdAfter: Date
+) {
   return await prisma.artefact.findFirst({
     where: {
       locationId: locationId.toString(),
-      listTypeId
+      listTypeId,
+      lastReceivedDate: { gte: createdAfter }
     },
     orderBy: { lastReceivedDate: "desc" }
   });
 }
🧹 Nitpick comments (1)
e2e-tests/tests/admin/manual-upload.spec.ts (1)

505-541: Extend this nightly journey to include Welsh and accessibility checks inline.

The new test validates PDF generation, but it does not include inline Welsh/a11y assertions required for E2E journey coverage.

As per coding guidelines: e2e-tests/**/*.spec.ts: E2E tests in Playwright should minimise test count with one test per complete user journey, including validations, Welsh translations, and accessibility checks inline rather than in separate tests. As per coding guidelines: e2e-tests/**/*.spec.ts: Use AxeBuilder with Playwright to test accessibility inline within journey tests, not as separate tests.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 22e64a8d-bf7c-4f0f-a65f-13b525790d62

📥 Commits

Reviewing files that changed from the base of the PR and between 8d258fd and e5a7414.

📒 Files selected for processing (4)
  • e2e-tests/tests/admin/manual-upload.spec.ts
  • e2e-tests/utils/notification-helpers.ts
  • libs/admin-pages/src/pages/manual-upload-summary/index.ts
  • libs/admin-pages/src/pages/non-strategic-upload-summary/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/admin-pages/src/pages/non-strategic-upload-summary/index.ts

Comment thread e2e-tests/utils/notification-helpers.ts Outdated
@sonarqubecloud

Copy link
Copy Markdown

This reverts commit fdf2f29.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
e2e-tests/tests/admin/manual-upload.spec.ts (1)

504-537: Add inline accessibility and Welsh checks to keep this as a complete journey test.

This new journey test currently skips the inline a11y/Welsh assertions used elsewhere in this spec. Please include them here too so this path remains compliant and self-contained.

Suggested patch
   test("should generate a PDF after uploading a JSON publication `@nightly`", async ({ page }) => {
@@
     await page.getByRole("button", { name: "Confirm" }).click();
     await page.waitForURL("/manual-upload-success", { timeout: 30000 });
 
+    const accessibilityScanResults = await new AxeBuilder({ page })
+      .withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"])
+      .analyze();
+    expect(accessibilityScanResults.violations).toEqual([]);
+
+    await page.goto("/manual-upload-success?lng=cy");
+    await expect(page.getByRole("link", { name: "uwchlwytho ffeil arall" })).toBeVisible();
+
     const pdfPath = path.join(process.cwd(), "..", "storage", "temp", "uploads", `${artefact!.artefactId}.pdf`);
     expect(fs.existsSync(pdfPath)).toBe(true);
     expect(fs.statSync(pdfPath).size).toBeGreaterThan(0);
   });

As per coding guidelines: E2E tests in Playwright should minimize test count with one test per complete user journey, including validations, Welsh translations, and accessibility checks inline rather than in separate tests and Use AxeBuilder with Playwright to test accessibility inline within journey tests, not as separate tests.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f7d1d3f6-588b-4b0d-9fd5-bf711857e2d8

📥 Commits

Reviewing files that changed from the base of the PR and between e5a7414 and e2c976c.

📒 Files selected for processing (1)
  • e2e-tests/tests/admin/manual-upload.spec.ts

Comment thread e2e-tests/tests/admin/manual-upload.spec.ts Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@alao-daniel alao-daniel linked an issue May 1, 2026 that may be closed by this pull request

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
e2e-tests/tests/admin/manual-upload.spec.ts (1)

491-527: ⚡ Quick win

Missing inline accessibility scan — required by coding guidelines.

All journey tests should include an AxeBuilder accessibility check. The new @nightly test has no AxeBuilder call.

♻️ Suggested addition
  await page.waitForURL("/manual-upload-success", { timeout: 30000 });

+ const accessibilityScanResults = await new AxeBuilder({ page })
+   .withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"])
+   .disableRules(["target-size", "link-name"])
+   .analyze();
+ expect(accessibilityScanResults.violations).toEqual([]);
+
  const artefact = await getLatestArtefactByLocationAndListType(testLocationId, 8);

As per coding guidelines: "Use AxeBuilder with Playwright to test accessibility inline within journey tests, not as separate tests."


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 35f4ab4b-89a3-469a-a549-ed465b46e078

📥 Commits

Reviewing files that changed from the base of the PR and between e2c976c and 6192f06.

📒 Files selected for processing (2)
  • e2e-tests/tests/admin/manual-upload.spec.ts
  • e2e-tests/utils/test-support-api.ts

Comment on lines +521 to +526
const artefact = await getLatestArtefactByLocationAndListType(testLocationId, 8);
expect(artefact).toBeDefined();

const pdfPath = path.join(process.cwd(), "..", "storage", "temp", "uploads", `${artefact!.artefactId}.pdf`);
expect(fs.existsSync(pdfPath)).toBe(true);
expect(fs.statSync(pdfPath).size).toBeGreaterThan(0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

toBeDefined() passes for null — the artefact check will not fail cleanly.

getLatestArtefactByLocationAndListType returns null (not undefined) when no match is found. expect(null).toBeDefined() passes in Playwright/Jest because null !== undefined. The test will therefore proceed to line 524 where the runtime encounters null.artefactId and throws a TypeError rather than a clean assertion failure.

Use not.toBeNull() (or toBeTruthy()) instead.

🐛 Proposed fix
  const artefact = await getLatestArtefactByLocationAndListType(testLocationId, 8);
- expect(artefact).toBeDefined();
+ expect(artefact).not.toBeNull();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const artefact = await getLatestArtefactByLocationAndListType(testLocationId, 8);
expect(artefact).toBeDefined();
const pdfPath = path.join(process.cwd(), "..", "storage", "temp", "uploads", `${artefact!.artefactId}.pdf`);
expect(fs.existsSync(pdfPath)).toBe(true);
expect(fs.statSync(pdfPath).size).toBeGreaterThan(0);
const artefact = await getLatestArtefactByLocationAndListType(testLocationId, 8);
expect(artefact).not.toBeNull();
const pdfPath = path.join(process.cwd(), "..", "storage", "temp", "uploads", `${artefact!.artefactId}.pdf`);
expect(fs.existsSync(pdfPath)).toBe(true);
expect(fs.statSync(pdfPath).size).toBeGreaterThan(0);

@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@sonarqubecloud

sonarqubecloud Bot commented May 8, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@junaidiqbalmoj
junaidiqbalmoj merged commit 34f9a63 into master May 8, 2026
25 of 26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PDF not generated after publication upload

3 participants