Skip to content

Commit

Permalink
Merge pull request #415 from NYPL/SCC-3762/patron-eligibility-errors
Browse files Browse the repository at this point in the history
SCC-3762 - Patron Eligibility Errors
  • Loading branch information
dgcohen authored Dec 17, 2024
2 parents 4dba074 + ca74cf4 commit 429a2eb
Show file tree
Hide file tree
Showing 17 changed files with 736 additions and 328 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Added and integrated hold confirmation details fetcher function (SCC-3762)
- Added server-side auth redirect to hold confirmation page (SCC-3762)
- Added fetchPatronEligibility server function that requests a patron's hold request eligibility status from Discovery API (SCC-3762)
- Added patron ineligibility error messaging to HoldRequestErrorBanner component (SCC-3762)
- Added eligibility checks to EDD and on-site request hold pages and API routes (SCC-3762)

### Updated

Expand Down
151 changes: 115 additions & 36 deletions __test__/pages/hold/eddRequestPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ import {
BASE_URL,
PATHS,
EDD_FORM_FIELD_COPY,
HOLD_PAGE_ERROR_HEADINGS,
} from "../../../src/config/constants"
import { fetchDeliveryLocations } from "../../../src/server/api/hold"
import { EDDPageStatusMessages } from "../../../src/utils/holdPageUtils"

jest.mock("../../../src/server/auth")
jest.mock("../../../src/server/api/bib")
Expand All @@ -44,6 +44,26 @@ const mockReq = {
},
}

const fillRequiredEDDFormFields = async () => {
// Fill in all required form fields
await userEvent.type(
screen.getByPlaceholderText(EDD_FORM_FIELD_COPY.emailAddress.placeholder),
EDD_FORM_FIELD_COPY.emailAddress.placeholder
)
await userEvent.type(
screen.getByPlaceholderText(EDD_FORM_FIELD_COPY.startPage.placeholder),
EDD_FORM_FIELD_COPY.startPage.placeholder
)
await userEvent.type(
screen.getByPlaceholderText(EDD_FORM_FIELD_COPY.endPage.placeholder),
EDD_FORM_FIELD_COPY.endPage.placeholder
)
await userEvent.type(
screen.getByPlaceholderText(EDD_FORM_FIELD_COPY.chapterTitle.placeholder),
EDD_FORM_FIELD_COPY.chapterTitle.placeholder
)
}

describe("EDD Request page", () => {
describe("logout redirect handling", () => {
beforeEach(() => {
Expand Down Expand Up @@ -74,14 +94,12 @@ describe("EDD Request page", () => {
params: { id },
req: mockReq,
res: mockRes,
query: {},
})
expect(responseWithZeroRedirects.redirect).toBeDefined()
const responseWithTwoRedirects = await getServerSideProps({
params: { id: "123-456" },
req: { ...mockReq, cookies: { nyplAccountRedirects: 2 } },
res: mockRes,
query: {},
})
expect(responseWithTwoRedirects.redirect).toBeDefined()
})
Expand All @@ -98,7 +116,6 @@ describe("EDD Request page", () => {
params: { id },
req: mockReq,
res: mockRes,
query: {},
})
expect(responseWithoutRedirect.redirect).not.toBeDefined()
})
Expand All @@ -107,7 +124,6 @@ describe("EDD Request page", () => {
params: { id },
req: mockReq,
res: mockRes,
query: {},
})
expect(response.redirect).toBeUndefined()
})
Expand All @@ -123,7 +139,6 @@ describe("EDD Request page", () => {
params: { id },
res: mockRes,
req: mockReq,
query: {},
})
expect(mockRes.setHeader.mock.calls[0]).toStrictEqual([
"Set-Cookie",
Expand All @@ -149,7 +164,6 @@ describe("EDD Request page", () => {
params: { id },
res: mockRes,
req: mockReq,
query: {},
})
expect(responseWithAeonRedirect.redirect).toStrictEqual({
destination: bibWithSingleAeonItem.resource.items[0].aeonUrl[0],
Expand Down Expand Up @@ -204,32 +218,12 @@ describe("EDD Request page", () => {

global.fetch = jest.fn().mockImplementationOnce(() =>
Promise.resolve({
status: 404,
status: 500,
json: () => Promise.resolve({ success: true }),
})
)

// Fill in all required form fields
await userEvent.type(
screen.getByPlaceholderText(
EDD_FORM_FIELD_COPY.emailAddress.placeholder
),
EDD_FORM_FIELD_COPY.emailAddress.placeholder
)
await userEvent.type(
screen.getByPlaceholderText(EDD_FORM_FIELD_COPY.startPage.placeholder),
EDD_FORM_FIELD_COPY.startPage.placeholder
)
await userEvent.type(
screen.getByPlaceholderText(EDD_FORM_FIELD_COPY.endPage.placeholder),
EDD_FORM_FIELD_COPY.endPage.placeholder
)
await userEvent.type(
screen.getByPlaceholderText(
EDD_FORM_FIELD_COPY.chapterTitle.placeholder
),
EDD_FORM_FIELD_COPY.chapterTitle.placeholder
)
await fillRequiredEDDFormFields()
})

it("shows an error when the request fails", async () => {
Expand All @@ -238,7 +232,9 @@ describe("EDD Request page", () => {
expect(screen.getByTestId("hold-request-error")).toBeInTheDocument()
})

expect(screen.getByText("Request failed")).toBeInTheDocument()
expect(
screen.getByText("Request failed.", { exact: false })
).toBeInTheDocument()

expect(
screen.queryByText(
Expand Down Expand Up @@ -307,11 +303,11 @@ describe("EDD Request page", () => {
discoveryItemResult={bibWithItems.resource.items[0]}
patronId="123"
isAuthenticated={true}
pageStatus="unavailable"
errorStatus="eddUnavailable"
/>
)
expect(
screen.getByText(EDDPageStatusMessages.unavailable.heading)
screen.getByText(HOLD_PAGE_ERROR_HEADINGS.eddUnavailable)
).toBeInTheDocument()
})
it("shows a failed error message when the page loads with an failed status", async () => {
Expand All @@ -321,11 +317,11 @@ describe("EDD Request page", () => {
discoveryItemResult={bibWithItems.resource.items[0]}
patronId="123"
isAuthenticated={true}
pageStatus="failed"
errorStatus="failed"
/>
)
expect(
screen.getByText(EDDPageStatusMessages.failed.heading)
screen.getByText(HOLD_PAGE_ERROR_HEADINGS.failed)
).toBeInTheDocument()
})
it("shows an invalid error message when the page loads with an invalid status", async () => {
Expand All @@ -335,11 +331,94 @@ describe("EDD Request page", () => {
discoveryItemResult={bibWithItems.resource.items[0]}
patronId="123"
isAuthenticated={true}
pageStatus="invalid"
errorStatus="invalid"
/>
)
expect(
screen.getByText(EDDPageStatusMessages.invalid.message)
screen.getByText(
"Some fields contain errors. Please correct and submit again."
)
).toBeInTheDocument()
})
})
describe("EDD Request patron ineligibility messaging", () => {
beforeEach(async () => {
render(
<EDDRequestPage
discoveryBibResult={bibWithItems.resource}
discoveryItemResult={bibWithItems.resource.items[0]}
patronId="123"
isAuthenticated={true}
/>
)

global.fetch = jest.fn().mockImplementationOnce(() =>
Promise.resolve({
status: 401,
json: () =>
Promise.resolve({
success: false,
patronEligibilityStatus: {
eligibility: false,
expired: true,
moneyOwed: true,
ptypeDisallowsHolds: true,
reachedHoldLimit: true,
},
}),
})
)

await fillRequiredEDDFormFields()

await fireEvent(
screen.getByText("Submit request"),
new MouseEvent("click")
)
})

it("shows an error listing ineligibility reasons when the patron is ineligibile to place holds", async () => {
await waitFor(() => {
expect(screen.getByTestId("hold-request-error")).toBeInTheDocument()
})

expect(
screen.getByText(HOLD_PAGE_ERROR_HEADINGS.patronIneligible, {
exact: false,
})
).toBeInTheDocument()

expect(
screen.getByText("This is because:", {
exact: false,
})
).toBeInTheDocument()

expect(
screen.getByText("Your account has expired", {
exact: false,
})
).toBeInTheDocument()

expect(
screen.getByText("Your fines have exceeded the limit", {
exact: false,
})
).toBeInTheDocument()

expect(
screen.getByText(
"Your card does not permit placing holds on ReCAP materials.",
{
exact: false,
}
)
).toBeInTheDocument()

expect(
screen.getByText("You have reached the allowed number of holds.", {
exact: false,
})
).toBeInTheDocument()
})
})
Expand Down
Loading

0 comments on commit 429a2eb

Please sign in to comment.