fix(cors): add default fallback for allowedMethods to prevent undefined.join() error
Some checks failed
armco-org/node-starter-kit/pipeline/head There was a failure building this commit

- Add DEFAULT_METHODS array with common REST methods when allowedMethods not configured
- Prevents crash on OPTIONS preflight requests when methods config is undefined
- Add unit tests for: default methods fallback, explicit method constraints, undefined handling
This commit is contained in:
2025-12-24 19:57:07 +05:30
parent acdd9b0eaa
commit 9c83023b5e
2 changed files with 72 additions and 1 deletions

View File

@@ -305,4 +305,71 @@ describe('CORS Middleware', () => {
expect(res.headers['access-control-allow-origin']).toBe('http://any-origin.com')
})
})
describe('Allowed Methods', () => {
it('should use default methods when allowedMethods not specified', async () => {
const app = await createAppWithCors({
arOptions: {
whitelist: ['http://localhost:3000'],
},
})
// OPTIONS preflight request should succeed and return allowed methods
const res = await request(app)
.options('/test')
.set('Origin', 'http://localhost:3000')
.set('Access-Control-Request-Method', 'POST')
expect(res.status).toBe(204)
expect(res.headers['access-control-allow-methods']).toBeDefined()
// Default methods should include common REST methods
const methods = res.headers['access-control-allow-methods']
expect(methods).toContain('GET')
expect(methods).toContain('POST')
expect(methods).toContain('PUT')
expect(methods).toContain('DELETE')
expect(methods).toContain('PATCH')
expect(methods).toContain('OPTIONS')
})
it('should constrain methods when allowedMethods is explicitly provided', async () => {
const app = await createAppWithCors({
allowedMethods: ['GET', 'POST'],
arOptions: {
whitelist: ['http://localhost:3000'],
},
})
const res = await request(app)
.options('/test')
.set('Origin', 'http://localhost:3000')
.set('Access-Control-Request-Method', 'POST')
expect(res.status).toBe(204)
const methods = res.headers['access-control-allow-methods']
expect(methods).toBe('GET,POST')
// Should NOT contain methods not in the explicit list
expect(methods).not.toContain('DELETE')
expect(methods).not.toContain('PUT')
})
it('should not crash on OPTIONS request when allowedMethods is undefined', async () => {
// This test ensures the fix for the undefined.join() error
const app = await createAppWithCors({
arOptions: {
whitelist: ['http://localhost:3000'],
},
// Explicitly NOT setting allowedMethods
})
// This should NOT throw "Cannot read properties of undefined (reading 'join')"
const res = await request(app)
.options('/test')
.set('Origin', 'http://localhost:3000')
.set('Access-Control-Request-Method', 'DELETE')
expect(res.status).toBe(204)
expect(res.headers['access-control-allow-methods']).toBeDefined()
})
})
})

View File

@@ -147,11 +147,15 @@ export async function initCors(app: Application, config: CorsConfig, logger?: Lo
return merged
}
// Default HTTP methods if not specified - allow common REST methods
// Not constraining by default as it may break existing apps; explicit config recommended
const DEFAULT_METHODS = ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE', 'OPTIONS']
const corsOptions: CorsOptions = {
...(config.libOptions || {}),
credentials: globalCredentials,
maxAge: config.maxAge,
methods: config.allowedMethods,
methods: config.allowedMethods ?? DEFAULT_METHODS,
allowedHeaders: config.allowedHeaders,
exposedHeaders: config.exposedHeaders,
}