Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/modules/creator/creator.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ router.get(
),
listCreators
);
// 405 handler for CREATORS_ROOT
router.all(CREATORS_ROOT, (_req, res) => {
res.set('Allow', 'GET').sendStatus(405);
});

/**
* @route GET /api/v1/creators/:creatorId/profile
Expand All @@ -61,5 +65,9 @@ router.put(
requireCreatorProfileOwnership('creatorId'),
upsertCreatorProfileHandler
);
// 405 handler for /:creatorId/profile
router.all('/:creatorId/profile', (_req, res) => {
res.set('Allow', 'GET, PUT').sendStatus(405);
});

export default router;
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Integration test: creator route Method Not Allowed (405) validation
//
// Creator routes should return a 405 Method Not Allowed response when called with an
// unsupported HTTP method, and include an Allow header listing supported methods.

// Mock chalk first to avoid ESM issues
jest.mock('chalk', () => ({
red: (text: string) => text,
green: (text: string) => text,
magenta: (text: string) => text,
cyan: (text: string) => text,
}));

// Mock tspec to prevent hanging
jest.mock('tspec', () => ({
TspecDocsMiddleware: jest.fn().mockResolvedValue([]),
}));

import supertest from 'supertest';
import app from '../../app';

// Mock all the things so we don't need a real database
jest.mock('../../utils/prisma.utils');
jest.mock('../../utils/logger.utils', () => ({
logger: {
error: jest.fn(),
warn: jest.fn(),
info: jest.fn(),
}
}));
jest.mock('../../config', () => ({
envConfig: { MODE: 'test', PORT: 3000, ENABLE_REQUEST_LOGGING: false },
appConfig: { allowedOrigins: [] }
}));

describe('Creator routes — Method Not Allowed (405) validation', () => {
describe('POST /api/v1/creators (unsupported method)', () => {
it('returns 405 status code', async () => {
const res = await supertest(app).post('/api/v1/creators');
expect(res.status).toBe(405);
});

it('includes Allow header with GET', async () => {
const res = await supertest(app).post('/api/v1/creators');
expect(res.headers.allow).toBe('GET');
});
});

describe('POST /api/v1/creators/test-id/stats (unsupported method)', () => {
it('returns 405 status code', async () => {
const res = await supertest(app).post('/api/v1/creators/test-id/stats');
expect(res.status).toBe(405);
});

it('includes Allow header with GET', async () => {
const res = await supertest(app).post('/api/v1/creators/test-id/stats');
expect(res.headers.allow).toBe('GET');
});
});
});
8 changes: 8 additions & 0 deletions src/modules/creators/creators.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ creatorsRouter.get(
cacheControl(CREATOR_PUBLIC_ROUTE_CACHE_PRESETS[CREATOR_PUBLIC_ROUTE_NAMES.LIST]),
httpListCreators
);
// 405 handler for /
creatorsRouter.all('/', (_req, res) => {
res.set('Allow', 'GET').sendStatus(405);
});

/**
* GET /api/v1/creators/:id/stats
Expand All @@ -38,5 +42,9 @@ creatorsRouter.get(
cacheControl(CREATOR_PUBLIC_ROUTE_CACHE_PRESETS[CREATOR_PUBLIC_ROUTE_NAMES.GET_STATS]),
httpGetCreatorStats
);
// 405 handler for /:id/stats
creatorsRouter.all('/:id/stats', (_req, res) => {
res.set('Allow', 'GET').sendStatus(405);
});

export default creatorsRouter;
Loading