bunshine
Version:
A Bun HTTP & WebSocket server that is a little ray of sunshine.
190 lines (188 loc) • 6.73 kB
text/typescript
import type { Server } from 'bun';
import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
import HttpRouter from '../../HttpRouter/HttpRouter';
import { cors } from './cors';
describe('cors middleware', () => {
let server: Server;
let app: HttpRouter;
let fetchInit: RequestInit;
beforeEach(() => {
app = new HttpRouter();
server = app.listen({ port: 0 });
fetchInit = {
method: 'OPTIONS',
headers: {
Origin: 'google.com',
},
};
});
afterEach(() => {
server.stop(true);
});
it('should have proper defaults', async () => {
app.use(cors(), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.get('Access-Control-Allow-Origin')).toBe('*');
expect(resp.headers.get('Access-Control-Allow-Methods')).toBe(
'GET,HEAD,PUT,POST,PATCH,DELETE,OPTIONS'
);
});
it('should add specific origin', async () => {
const options = {
origin: 'example.com',
};
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.get('Access-Control-Allow-Origin')).toBe('example.com');
});
it('should add origin on RegExp', async () => {
const options = {
origin: /^google.(com|net)$/,
};
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.get('Access-Control-Allow-Origin')).toBe('google.com');
});
it('should add origin on Array<string | RegExp>', async () => {
const options = {
origin: ['dev.example.com', 'prod.example.com', /^google.(com|net)$/],
};
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.get('Access-Control-Allow-Origin')).toBe('google.com');
});
it('should parrot origin if true', async () => {
const options = {
origin: true,
};
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.get('Access-Control-Allow-Origin')).toBe('google.com');
});
it('should omit origin if false', async () => {
const options = {
origin: false,
};
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.get('Access-Control-Allow-Origin')).toBe(null);
});
it('should allow function that returns true', async () => {
const options = {
origin: () => true,
};
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.get('Access-Control-Allow-Origin')).toBe('google.com');
});
it('should allow function that returns false', async () => {
const options = {
origin: () => false,
};
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.get('Access-Control-Allow-Origin')).toBe(null);
});
it('should allow function that returns string', async () => {
const options = {
origin: () => 'google.com',
};
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.get('Access-Control-Allow-Origin')).toBe('google.com');
});
it('should ignore function that returns invalid value', async () => {
const options = {
origin: () => 123,
};
// @ts-expect-error - testing invalid input
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.get('Access-Control-Allow-Origin')).toBe(null);
});
it('should allow function-returning arrays (with match)', async () => {
const options = {
origin: () => ['example.com', 'google.com'],
};
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.get('Access-Control-Allow-Origin')).toBe('google.com');
});
it('should allow arrays (without match)', async () => {
const options = {
origin: ['some-other-thing'],
};
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.has('Access-Control-Allow-Origin')).toBe(false);
});
it('should add other headers', async () => {
const options = {
allowMethods: ['GET', 'POST'],
allowHeaders: ['Foo', 'Bar'],
exposeHeaders: ['Baz', 'Qux'],
maxAge: 60 * 30,
};
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, fetchInit);
const text = await resp.text();
expect(text).toBe('');
expect(resp.headers.get('Access-Control-Allow-Methods')).toBe('GET,POST');
expect(resp.headers.get('Access-Control-Allow-Headers')).toBe('Foo,Bar');
expect(resp.headers.get('Access-Control-Max-Age')).toBe('1800');
});
it('should add headers on GET', async () => {
const options = {
origin: '*',
allowMethods: ['GET', 'POST'],
allowHeaders: ['Foo', 'Bar'],
exposeHeaders: ['Baz', 'Qux'],
maxAge: 60 * 30,
};
app.use(cors(options), c => c.text('hello'));
const resp = await fetch(server.url, {
headers: {
Origin: 'google.com',
},
});
const text = await resp.text();
expect(text).toBe('hello');
expect(resp.headers.get('Access-Control-Allow-Origin')).toBe('*');
expect(resp.headers.has('Access-Control-Allow-Methods')).toBe(false);
expect(resp.headers.get('Access-Control-Expose-Headers')).toBe('Baz,Qux');
});
it('should throw on invalid origin option', async () => {
const thrower = () => {
const options = {
origin: new Date(),
};
// @ts-expect-error - testing invalid input
app.use(cors(options), c => c.text('hello'));
};
expect(thrower).toThrowError('Invalid cors origin option');
});
});