tests(middleware-cors): add configureHeaders specs
ADD
packages/middleware-cors/src/configureHeader.spec.ts
+import {
+ configureAllowedOrigin,
+ configureAllowedHeaders,
+ configureAllowedMethods,
+ applyHeaders,
+ configureCredentials,
+ configureHeaders,
+} from './configureHeaders';
+import { createMockResponse, createMockRequest } from './middleware.spec';
+import { CORSOptions } from './middleware';
+
+const origin = 'fake-origin';
+
+describe('configureAllowedOrigin', () => {
+ test('return an empty array if no match', done => {
+ const configured = configureAllowedOrigin(origin, []);
+ expect(configured).toHaveLength(0);
+ done();
+ });
+
+ test('handle wildcard correctly', done => {
+ const configured = configureAllowedOrigin(origin, '*');
+ expect(configured).toHaveLength(1);
+ expect(configured[0].key).toEqual('Access-Control-Allow-Origin');
+ expect(configured[0].value).toEqual('*');
+ done();
+ });
+
+ test('handle wildcard correctly', done => {
+ const configured = configureAllowedOrigin(origin, 'fake-origin');
+ expect(configured).toHaveLength(1);
+ expect(configured[0].key).toEqual('Access-Control-Allow-Origin');
+ expect(configured[0].value).toEqual('fake-origin');
+ done();
+ });
+
+ test('handle array correctly', done => {
+ const configured = configureAllowedOrigin(origin, ['fake-origin']);
+ expect(configured).toHaveLength(1);
+ expect(configured[0].key).toEqual('Access-Control-Allow-Origin');
+ expect(configured[0].value).toEqual('fake-origin');
+ done();
+ });
+
+ test('handle regexp correctly', done => {
+ const configured = configureAllowedOrigin(origin, /[aZ-]/);
+ expect(configured).toHaveLength(1);
+ expect(configured[0].key).toEqual('Access-Control-Allow-Origin');
+ expect(configured[0].value).toEqual('fake-origin');
+ done();
+ });
+});
+
+describe('configureAllowedHeaders', () => {
+ test('handle wildcard correctly', done => {
+ const configured = configureAllowedHeaders('*');
+ expect(configured).toHaveLength(1);
+ expect(configured[0].key).toEqual('Access-Control-Allow-Headers');
+ expect(configured[0].value).toEqual('*');
+ done();
+ });
+
+ test('handle many headers correctly', done => {
+ const configured = configureAllowedHeaders([
+ 'x-custom-tag',
+ 'x-custom-timestamp',
+ ]);
+ expect(configured).toHaveLength(1);
+ expect(configured[0].key).toEqual('Access-Control-Allow-Headers');
+ expect(configured[0].value).toEqual('X-Custom-Tag, X-Custom-Timestamp');
+ done();
+ });
+});
+
+describe('configureAllowedMethods', () => {
+ test('handle many methods correctly', done => {
+ const configured = configureAllowedMethods('POST', ['POST', 'GET']);
+ expect(configured).toHaveLength(1);
+ expect(configured[0].key).toEqual('Access-Control-Allow-Methods');
+ expect(configured[0].value).toEqual('POST, GET');
+ done();
+ });
+});
+
+describe('configureCredentials', () => {
+ test('handle credentials correctly', done => {
+ const configured = configureCredentials(true);
+ expect(configured).toHaveLength(1);
+ expect(configured[0].key).toEqual('Access-Control-Allow-Credentials');
+ expect(configured[0].value).toEqual('true');
+ done();
+ });
+});
+
+describe('applyHeaders', () => {
+ test('handle many methods correctly', done => {
+ const configured = [{ key: 'Foo', value: 'Bar' }];
+ const res = createMockResponse();
+
+ applyHeaders(configured, res);
+
+ expect(res.setHeader).toBeCalledWith('Foo', 'Bar');
+ done();
+ });
+});
+
+describe('configureHeaders', () => {
+ test('should configure headers correctly', done => {
+ const res = createMockResponse();
+ const req = createMockRequest('OPTIONS');
+ const options: CORSOptions = {
+ origin: '*',
+ methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
+ withCredentials: false,
+ optionsSuccessStatus: 204,
+ allowHeaders: '*',
+ };
+
+ configureHeaders(req.headers.origin as string, req.method, res, options);
+
+ expect(res.setHeader).toBeCalledTimes(4);
+ expect(res.statusCode).toEqual(options.optionsSuccessStatus);
+ done();
+ });
+});

MODIFY
packages/middleware-cors/src/configureHeaders.ts
packages/middleware-cors/src/configureHeaders.ts
-import { HttpRequest, HttpResponse } from '@marblejs/core';
+import { HttpMethod, HttpResponse } from '@marblejs/core';
-import { capitalize, isNotEmptyArray, isString } from './util';
import { CORSOptions } from './middleware';
+import { capitalize, isNotEmptyArray, isString } from './util';
interface ConfiguredHeader {
key: string;
@@ -15,12 +15,11 @@ enum AccessControlAllow {
Credentials = 'Access-Control-Allow-Credentials',
}
-const configureAllowedOrigin = (
- req: HttpRequest,
+export const configureAllowedOrigin = (
+ origin: string,
allowedOrigin: string | string[] | RegExp,
): ConfiguredHeader[] => {
const headers: ConfiguredHeader[] = [];
- const origin = req.headers.origin as string;
if (isString(allowedOrigin) && allowedOrigin === '*') {
headers.push({ key: AccessControlAllow.Origin, value: '*' });
@@ -42,13 +41,13 @@ const configureAllowedOrigin = (
return headers;
};
-const configureAllowedMethods = (
- req: HttpRequest,
+export const configureAllowedMethods = (
+ method: HttpMethod,
methods: string[],
): ConfiguredHeader[] => {
const headers: ConfiguredHeader[] = [];
- if (isNotEmptyArray(methods) && methods.includes(req.method)) {
+ if (isNotEmptyArray(methods) && methods.includes(method)) {
headers.push({
key: AccessControlAllow.Methods,
value: methods.join(', '),
@@ -58,7 +57,7 @@ const configureAllowedMethods = (
return headers;
};
-const configureAllowedHeaders = (
+export const configureAllowedHeaders = (
allowedHeaders: string | string[],
): ConfiguredHeader[] => {
const headers: ConfiguredHeader[] = [];
@@ -80,7 +79,9 @@ const configureAllowedHeaders = (
return headers;
};
-const configureCredentials = (withCredentials: boolean): ConfiguredHeader[] => {
+export const configureCredentials = (
+ withCredentials: boolean,
+): ConfiguredHeader[] => {
if (withCredentials) {
return [{ key: AccessControlAllow.Credentials, value: 'true' }];
}
@@ -88,27 +89,31 @@ const configureCredentials = (withCredentials: boolean): ConfiguredHeader[] => {
return [];
};
-const applyHeaders = (headers: ConfiguredHeader[], res: HttpResponse): void => {
+export const applyHeaders = (
+ headers: ConfiguredHeader[],
+ res: HttpResponse,
+): void => {
headers.forEach(({ key, value }) => {
res.setHeader(key, value);
});
};
export function configureHeaders(
- req: HttpRequest,
+ origin: string,
+ method: HttpMethod,
res: HttpResponse,
options: CORSOptions,
): void {
// @todo add exposed headers
const headers = [
- ...configureAllowedOrigin(req, options.origin!),
+ ...configureAllowedOrigin(origin, options.origin!),
...configureCredentials(options.withCredentials!),
];
- if (req.method === 'OPTIONS') {
+ if (method === 'OPTIONS') {
// @todo add max age header, exposed headers
const preflightHeaders = [
- ...configureAllowedMethods(req, options.methods!),
+ ...configureAllowedMethods(method, options.methods!),
...configureAllowedHeaders(options.allowHeaders!),
{ key: 'Content-Length', value: '0' },
];

MODIFY
packages/middleware-cors/src/middleware.spec.ts
packages/middleware-cors/src/middleware.spec.ts
@@ -3,8 +3,7 @@ import { of } from 'rxjs';
import { cors$ } from './middleware';
-describe('CORS middleware', () => {
- const createMockResponse = () =>
+export const createMockResponse = () =>
(({
writeHead: jest.fn(),
setHeader: jest.fn(),
@@ -12,7 +11,7 @@ describe('CORS middleware', () => {
end: jest.fn(),
} as unknown) as HttpResponse);
- const createMockRequest = (
+export const createMockRequest = (
method: HttpMethod = 'GET',
headers: any = { origin: 'fake-origin' },
) =>
@@ -21,6 +20,7 @@ describe('CORS middleware', () => {
headers: { ...headers },
} as unknown) as HttpRequest);
+describe('CORS middleware', () => {
describe('Access-Control-Allow-Origin', () => {
describe('String arg', () => {
test('should allow wildcard', done => {

MODIFY
packages/middleware-cors/src/middleware.ts
packages/middleware-cors/src/middleware.ts
@@ -25,7 +25,7 @@ export const cors$ = (options: CORSOptions = {}): Middleware => (req$, res) => {
return req$.pipe(
tap(req => {
- configureHeaders(req, res, options);
+ configureHeaders(req.headers.origin as string, req.method, res, options);
if (req.method === 'OPTIONS') {
res.end();

tests(middleware-cors): add configureHeaders specs