Skip to content

Commit dc0f77e

Browse files
fix(product-pages): gate program certificate row on certificate_available
The program InfoBox rendered "Certificate: Program certificate on completion" unconditionally, claiming a certificate could be earned even for a program with no paid enrollment mode (free-only, or no modes). Gate the row on `program.certificate_available` — the API's own signal, computed server-side as `any(mode.requires_payment)` — the same flag MitxOnlineResourceCard already trusts. Visibility stays independent of product data: a paid mode with no purchasable product still shows its (odd) certificate card. That's a bad-data combination we deliberately don't police in the frontend. Pin the existing cert-row tests to certificate_available (the factory default is a random boolean). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 0d2f395 commit dc0f77e

3 files changed

Lines changed: 19 additions & 2 deletions

File tree

frontends/main/src/app-pages/ProductPages/InfoBoxProgram.test.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ describe("InfoBoxProgram — both offering", () => {
5353
makeMode({ requires_payment: true }),
5454
],
5555
products: [makeProduct()],
56+
certificate_available: true,
5657
})
5758

5859
renderWithProviders(<InfoBoxProgram program={program} />)
@@ -72,6 +73,7 @@ describe("InfoBoxProgram — paid-only offering", () => {
7273
const program = makeProgram({
7374
enrollment_modes: [makeMode({ requires_payment: true })],
7475
products: [makeProduct()],
76+
certificate_available: true,
7577
})
7678

7779
renderWithProviders(<InfoBoxProgram program={program} />)
@@ -161,9 +163,14 @@ describe("InfoBoxProgram — grid structure", () => {
161163
describe("InfoBoxProgram — no offering", () => {
162164
test("data-boxes=1 and no section divider when there's nothing to enroll in", async () => {
163165
setupAuth()
166+
// Paid mode but no purchasable product: nothing enrollable, so one box and
167+
// no divider. certificate_available tracks the paid mode independently of
168+
// products, so the certificate row still renders — we don't police this
169+
// bad-data combination.
164170
const program = makeProgram({
165171
enrollment_modes: [makeMode({ requires_payment: true })],
166172
products: [],
173+
certificate_available: true,
167174
})
168175

169176
renderWithProviders(<InfoBoxProgram program={program} />)

frontends/main/src/app-pages/ProductPages/ProductSummary.test.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,7 @@ describe("ProgramSummary", () => {
11091109
})
11101110

11111111
test("shows the certificate row and no price row", () => {
1112-
const program = factories.programs.program()
1112+
const program = factories.programs.program({ certificate_available: true })
11131113
renderWithProviders(<ProgramSummary tabletColumns={2} program={program} />)
11141114

11151115
expect(
@@ -1120,6 +1120,13 @@ describe("ProgramSummary", () => {
11201120
expect(screen.queryByTestId(TestIds.PriceRow)).not.toBeInTheDocument()
11211121
})
11221122

1123+
test("hides the certificate row when no certificate is available", () => {
1124+
const program = factories.programs.program({ certificate_available: false })
1125+
renderWithProviders(<ProgramSummary tabletColumns={2} program={program} />)
1126+
1127+
expect(screen.queryByTestId(TestIds.CertificateRow)).not.toBeInTheDocument()
1128+
})
1129+
11231130
test("orders metadata rows as requirements, format, duration, certificate", () => {
11241131
const requirements = new RequirementTreeBuilder()
11251132
const required = requirements.addOperator({ operator: "all_of" })
@@ -1137,6 +1144,7 @@ describe("ProgramSummary", () => {
11371144
programs: { required: [], electives: [] },
11381145
},
11391146
req_tree: requirements.serialize(),
1147+
certificate_available: true,
11401148
})
11411149
const course = makeCourse({
11421150
courseruns: [makeRun()],

frontends/main/src/app-pages/ProductPages/ProductSummary.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,9 @@ const ProgramSummary: React.FC<{
715715
/>
716716
<ProgramPaceRow courses={courses} data-testid={TestIds.PaceRow} />
717717
<ProgramDurationRow program={program} data-testid={TestIds.DurationRow} />
718-
<CertificateRow data-testid={TestIds.CertificateRow} />
718+
{program.certificate_available ? (
719+
<CertificateRow data-testid={TestIds.CertificateRow} />
720+
) : null}
719721
</SummaryRows>
720722
)
721723
}

0 commit comments

Comments
 (0)