Skip to content

Commit 53d4fe0

Browse files
Merge branch 'main' into refactor/DTOSS-ExceptionResponse
2 parents fa76d72 + c3f3fff commit 53d4fe0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+965
-1199
lines changed

.github/workflows/ci-ui-tests.yaml

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,48 +21,29 @@ jobs:
2121
- name: Setup Node.js
2222
uses: actions/setup-node@v4
2323
with:
24-
node-version: "22"
24+
node-version: "lts/*"
25+
check-latest: true
2526
cache: "npm"
2627
cache-dependency-path: application/CohortManager/src/Web/package-lock.json
2728

2829
- name: Install dependencies
2930
run: npm ci
3031

32+
- name: Run Unit tests
33+
run: npm run test:unit
34+
3135
- name: Install Playwright browsers
3236
run: npx playwright install --with-deps
3337

34-
- name: Start application and run tests
35-
env:
36-
AUTH_SECRET: ${{ secrets.AUTH_SECRET }}
37-
SERVICE_NAME: ${{ vars.SERVICE_NAME }}
38-
NEXTAUTH_URL: ${{ vars.NEXTAUTH_URL }}
39-
EXCEPTIONS_API_URL: ${{ vars.EXCEPTIONS_API_URL }}
40-
COHORT_MANAGER_RBAC_CODE: ${{ vars.COHORT_MANAGER_USERS }}
41-
run: |
42-
# Start the app in background
43-
npm run dev:secure &
44-
45-
# Wait for the app to be ready
46-
while ! curl -s https://localhost:3000 > /dev/null; do
47-
echo "Waiting for app to start..."
48-
sleep 5
49-
done
50-
51-
# Run the tests
52-
npm run test:e2e
53-
54-
- name: run epic 4a tests
38+
- name: Run E2E tests
5539
env:
56-
AUTH_SECRET: ${{ secrets.AUTH_SECRET }}
5740
SERVICE_NAME: ${{ vars.SERVICE_NAME }}
41+
APP_ENV: ${{ vars.APP_ENV }}
5842
NEXTAUTH_URL: ${{ vars.NEXTAUTH_URL }}
5943
EXCEPTIONS_API_URL: ${{ vars.EXCEPTIONS_API_URL }}
60-
COHORT_MANAGER_RBAC_CODE: ${{ vars.COHORT_MANAGER_USERS }}
61-
run: |
62-
63-
64-
# Run the tests
65-
npm run test:e2e:epic_4a
44+
COHORT_MANAGER_RBAC_CODE: ${{ vars.COHORT_MANAGER_RBAC_CODE }}
45+
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
46+
run: npm run test:e2e
6647

6748
- name: Upload test results
6849
if: always()

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,6 @@ application/CohortManager/src/Functions/*.json
117117
# Explicitly include test JSON files
118118
!**/playwright-tests/src/tests/e2e/testFiles/**/*.json
119119

120-
120+
# Act
121+
.act.secrets
122+
.act.vars

application/CohortManager/src/Web/.env.tests

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
# Default
2-
NEXT_PUBLIC_BASE_URL=http://localhost:3000
3-
APP_ENV=development
42
SERVICE_NAME="Cohort Manager"
3+
APP_ENV=development
54

65
# Next Auth
7-
NEXTAUTH_SECRET= # Random non secret string
6+
NEXTAUTH_URL=http://localhost:3000/api/auth
87

98
# API
109
EXCEPTIONS_API_URL=http://localhost:3000

application/CohortManager/src/Web/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ next-env.d.ts
4242
/playwright-report/
4343
/blob-report/
4444
/playwright/.cache/
45+
/.features-gen
46+
/screenshots
4547

4648
# Env
4749
.env
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import mockDataStore from "@/app/data/mockDataStore";
3+
4+
interface UpdateExceptionRequest {
5+
ExceptionId: string;
6+
ServiceNowNumber?: string;
7+
}
8+
export async function PUT(request: NextRequest) {
9+
try {
10+
// 1. Read and validate request body
11+
let requestBody: string;
12+
try {
13+
requestBody = await request.text();
14+
} catch (error) {
15+
console.error("Error reading request body:", error);
16+
return NextResponse.json(
17+
{ error: "Invalid request body" },
18+
{ status: 400 }
19+
);
20+
}
21+
22+
if (!requestBody || requestBody.trim() === "") {
23+
console.warn("Request body is empty.");
24+
return NextResponse.json(
25+
{ message: "Request body is empty" },
26+
{ status: 204 }
27+
);
28+
}
29+
30+
// 2. Deserialize request
31+
let updateRequest: UpdateExceptionRequest;
32+
try {
33+
updateRequest = JSON.parse(requestBody);
34+
} catch (error) {
35+
console.error("Error parsing JSON:", error);
36+
return NextResponse.json(
37+
{ error: "Invalid JSON format" },
38+
{ status: 400 }
39+
);
40+
}
41+
42+
// 3. Validate ExceptionId
43+
if (!updateRequest.ExceptionId) {
44+
console.warn("ExceptionId is missing.");
45+
return NextResponse.json(
46+
{ error: "ExceptionId is required" },
47+
{ status: 400 }
48+
);
49+
}
50+
51+
const exceptionId = parseInt(updateRequest.ExceptionId, 10);
52+
if (isNaN(exceptionId) || exceptionId === 0) {
53+
console.warn("Invalid ExceptionId provided:", updateRequest.ExceptionId);
54+
return NextResponse.json(
55+
{ error: "Invalid ExceptionId provided" },
56+
{ status: 400 }
57+
);
58+
}
59+
60+
// 4. Check & Fetch Exception Record from shared data store
61+
const exceptionData = mockDataStore.getException(exceptionId);
62+
if (!exceptionData) {
63+
console.warn(`No exception found with ID: ${exceptionId}`);
64+
return NextResponse.json(
65+
{ message: `No exception found with ID: ${exceptionId}` },
66+
{ status: 204 }
67+
);
68+
}
69+
70+
// 5. Update Exception Record with ServiceNow number using the data store
71+
const originalServiceNowId = exceptionData.ServiceNowId;
72+
const newServiceNowId = updateRequest.ServiceNowNumber || "";
73+
74+
// Use the data store's update method to ensure consistency across both APIs
75+
const updateSuccess = mockDataStore.updateExceptionServiceNow(
76+
exceptionId,
77+
newServiceNowId
78+
);
79+
80+
// 6. Check if update was successful and return appropriate response
81+
if (!updateSuccess) {
82+
console.error("Failed to update exception:", exceptionId);
83+
return NextResponse.json(
84+
{ error: "Failed to update exception record" },
85+
{ status: 500 }
86+
);
87+
}
88+
89+
// Get the updated exception to return current values
90+
const updatedException = mockDataStore.getException(exceptionId);
91+
92+
return NextResponse.json(
93+
{
94+
message: "Exception record updated with ServiceNow number successfully",
95+
exceptionId: exceptionId,
96+
previousServiceNowId: originalServiceNowId,
97+
newServiceNowId: newServiceNowId,
98+
updatedAt: updatedException?.RecordUpdatedDate,
99+
},
100+
{ status: 200 }
101+
);
102+
} catch (error) {
103+
console.error("An unexpected error occurred:", error);
104+
return NextResponse.json(
105+
{ error: "An unexpected error occurred" },
106+
{ status: 500 }
107+
);
108+
}
109+
}

application/CohortManager/src/Web/app/components/header.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ export default async function Header({
4040
</div>
4141

4242
{session?.user && (
43-
<nav className="nhsuk-header__account" aria-label="Account">
43+
<nav
44+
className="nhsuk-header__account"
45+
aria-label="Account"
46+
data-testid="header-account-navigation"
47+
>
4448
<ul className="nhsuk-header__account-list">
4549
<li className="nhsuk-header__account-item">
4650
<svg

application/CohortManager/src/Web/app/components/pagination.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ interface PaginationProps {
1616

1717
export default function Pagination({ items, previous, next }: PaginationProps) {
1818
return (
19-
<nav className="app-pagination" aria-label="Pagination">
19+
<nav
20+
className="app-pagination"
21+
aria-label="Pagination"
22+
data-testid="pagination"
23+
>
2024
{previous && (
2125
<div className="app-pagination__prev">
2226
<a

application/CohortManager/src/Web/app/components/participantInformationPanel.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,17 @@ export default function ParticipantInformationPanel({
8686
</dd>
8787
</div>
8888
{exceptionDetails.supersededByNhsNumber && (
89-
<div className="nhsuk-summary-list__row">
89+
<div
90+
className="nhsuk-summary-list__row"
91+
data-testid="superseded-by-row"
92+
>
9093
<dt className="nhsuk-summary-list__key">
9194
Superseded by NHS number
9295
</dt>
93-
<dd className="nhsuk-summary-list__value">
96+
<dd
97+
className="nhsuk-summary-list__value"
98+
data-testid="superseded-by-value"
99+
>
94100
{formatNhsNumber(exceptionDetails.supersededByNhsNumber ?? "")}
95101
</dd>
96102
</div>

application/CohortManager/src/Web/app/components/reportsInformationTable.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export default function ReportsInformationTable({
6666
>
6767
Date of Birth{" "}
6868
</span>
69-
{formatCompactDate(d.DateOfBirth)}
69+
{formatCompactDate(d?.DateOfBirth ?? "")}
7070
</td>
7171
{isConfusion ? (
7272
<td className="nhsuk-table__cell app-u-no-wrap">
@@ -96,7 +96,7 @@ export default function ReportsInformationTable({
9696
>
9797
Superseded by NHS number{" "}
9898
</span>
99-
{formatNhsNumber(d.SupersededByNhsNumber ?? "")}
99+
{formatNhsNumber(d?.SupersededByNhsNumber ?? "")}
100100
</td>
101101
</>
102102
)}

application/CohortManager/src/Web/app/components/signIn.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export default function SignIn({
7878
<>
7979
<hr />
8080
<form
81+
data-testid="test-account-form"
8182
action={async (formData) => {
8283
"use server";
8384
await signIn("credentials", formData);

0 commit comments

Comments
 (0)