diff --git a/api-server/src/server/boot/certificate.js b/api-server/src/server/boot/certificate.js index 8dcc4f6a4ce..11a5fab310f 100644 --- a/api-server/src/server/boot/certificate.js +++ b/api-server/src/server/boot/certificate.js @@ -14,7 +14,9 @@ import { certIds, oldDataVizId, currentCertifications, - upcomingCertifications + upcomingCertifications, + legacyCertifications, + legacyFullStackCertification } from '../../../../shared/config/certification-settings'; import { reportError } from '../middlewares/sentry-error-handler.js'; @@ -77,10 +79,15 @@ export function getFallbackFullStackDate(completedChallenges, completedDate) { return latestCertDate ? latestCertDate : completedDate; } -function ifNoCertification404(req, res, next) { +export function ifNoCertification404(req, res, next) { const { certSlug } = req.body; if (!certSlug) return res.status(404).end(); - if (currentCertifications.includes(certSlug)) return next(); + if ( + currentCertifications.includes(certSlug) || + legacyCertifications.includes(certSlug) || + legacyFullStackCertification.includes(certSlug) + ) + return next(); if ( process.env.SHOW_UPCOMING_CHANGES === 'true' && upcomingCertifications.includes(certSlug) diff --git a/api-server/src/server/boot_tests/certificate.test.js b/api-server/src/server/boot_tests/certificate.test.js index 4c511b6c929..556696be76c 100644 --- a/api-server/src/server/boot_tests/certificate.test.js +++ b/api-server/src/server/boot_tests/certificate.test.js @@ -1,10 +1,94 @@ -import { getFallbackFullStackDate } from '../boot/certificate'; +import { + getFallbackFullStackDate, + ifNoCertification404 +} from '../boot/certificate'; import { fullStackChallenges } from './fixtures'; +export const mockReq = opts => { + const req = {}; + return { ...req, ...opts }; +}; + +export const mockRes = opts => { + const res = {}; + res.status = jest.fn().mockReturnValue(res); + res.end = jest.fn().mockReturnValue(res); + res.json = jest.fn().mockReturnValue(res); + res.redirect = jest.fn().mockReturnValue(res); + res.set = jest.fn().mockReturnValue(res); + res.clearCookie = jest.fn().mockReturnValue(res); + res.cookie = jest.fn().mockReturnValue(res); + return { ...res, ...opts }; +}; + describe('boot/certificate', () => { describe('getFallbackFullStackDate', () => { it('should return the date of the latest completed challenge', () => { expect(getFallbackFullStackDate(fullStackChallenges)).toBe(1685210952511); }); }); + + describe('ifNoCertification404', () => { + it('declares a 404 when there is no certSlug in the body', () => { + const req = mockReq({ + body: {} + }); + const res = mockRes(); + const next = jest.fn(); + + ifNoCertification404(req, res, next); + + expect(res.status).toHaveBeenCalledWith(404); + expect(next).not.toHaveBeenCalled(); + }); + + it('declares a 404 for an invalid certSlug in the body', () => { + const req = mockReq({ + body: { certSlug: 'not-a-real-certSlug' } + }); + const res = mockRes(); + const next = jest.fn(); + + ifNoCertification404(req, res, next); + + expect(res.status).toHaveBeenCalledWith(404); + expect(next).not.toHaveBeenCalled(); + }); + + it('calls next for a valid certSlug of a current certification', () => { + const req = mockReq({ + body: { certSlug: 'responsive-web-design' } + }); + const res = mockRes(); + const next = jest.fn(); + + ifNoCertification404(req, res, next); + + expect(next).toHaveBeenCalled(); + }); + + it('calls next for a valid certSlug of a legacy certification', () => { + const req = mockReq({ + body: { certSlug: 'legacy-front-end' } + }); + const res = mockRes(); + const next = jest.fn(); + + ifNoCertification404(req, res, next); + + expect(next).toHaveBeenCalled(); + }); + + it('calls next for a valid certSlug of the legacy full stack certification', () => { + const req = mockReq({ + body: { certSlug: 'full-stack' } + }); + const res = mockRes(); + const next = jest.fn(); + + ifNoCertification404(req, res, next); + + expect(next).toHaveBeenCalled(); + }); + }); }); diff --git a/shared/config/certification-settings.ts b/shared/config/certification-settings.ts index 0d5ecbf3925..13475ca94f3 100644 --- a/shared/config/certification-settings.ts +++ b/shared/config/certification-settings.ts @@ -62,6 +62,12 @@ export const legacyCertifications = [ Certification.LegacyInfoSecQa ] as const; +// The Legacy Full Stack certification can only be claimed when specific +// "current" and "legacy" certifications have been claimed. +export const legacyFullStackCertification = [ + Certification.LegacyFullStack +] as const; + // "Upcoming" certifications are standard certifications that are not live unless // showUpcomingChanges is true. export const upcomingCertifications = [Certification.UpcomingPython] as const;