accounts
Version:
Tempo Accounts SDK
692 lines (565 loc) • 21.9 kB
text/typescript
import { Elysia } from 'elysia'
import express from 'express'
import { Hono } from 'hono'
import { describe, expect, test } from 'vp/test'
import { createServer } from '../../test/utils.js'
import * as Handler from './Handler.js'
describe('from', () => {
describe('cors', () => {
test('default: adds CORS headers', async () => {
const handler = Handler.from()
handler.get('/test', () => new Response('test'))
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(response.headers.get('Access-Control-Allow-Methods')).toBe(
'GET, POST, PUT, DELETE, OPTIONS',
)
expect(response.headers.get('Access-Control-Allow-Headers')).toBe('Content-Type')
})
test('behavior: cors = false disables CORS headers', async () => {
const handler = Handler.from({ cors: false })
handler.get('/test', () => new Response('test'))
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(response.headers.get('Access-Control-Allow-Origin')).toBeNull()
expect(response.headers.get('Access-Control-Allow-Methods')).toBeNull()
})
test('behavior: custom cors config', async () => {
const handler = Handler.from({
cors: {
origin: 'https://example.com',
methods: 'GET, POST',
headers: 'Content-Type, Authorization',
credentials: true,
maxAge: 86400,
},
})
handler.get('/test', () => new Response('test'))
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('https://example.com')
expect(response.headers.get('Access-Control-Allow-Methods')).toBe('GET, POST')
expect(response.headers.get('Access-Control-Allow-Headers')).toBe(
'Content-Type, Authorization',
)
expect(response.headers.get('Access-Control-Allow-Credentials')).toBe('true')
expect(response.headers.get('Access-Control-Max-Age')).toBe('86400')
})
test('behavior: cors with array of origins', async () => {
const handler = Handler.from({
cors: {
origin: ['https://example.com', 'https://other.com'],
},
})
handler.get('/test', () => new Response('test'))
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
'https://example.com, https://other.com',
)
})
test('behavior: OPTIONS preflight with default CORS', async () => {
const handler = Handler.from()
handler.get('/test', () => new Response('test'))
const response = await handler.fetch(
new Request('http://localhost/test', { method: 'OPTIONS' }),
)
expect(response.status).toBe(200)
expect(await response.text()).toBe('')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(response.headers.get('Access-Control-Allow-Methods')).toBe(
'GET, POST, PUT, DELETE, OPTIONS',
)
})
test('behavior: custom headers override CORS headers', async () => {
const handler = Handler.from({
cors: { origin: 'https://default.com' },
headers: { 'Access-Control-Allow-Origin': 'https://override.com' },
})
handler.get('/test', () => new Response('test'))
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('https://override.com')
})
})
})
describe('compose', () => {
test('default', async () => {
const handler1 = Handler.from()
handler1.get('/test', () => new Response('test'))
const handler2 = Handler.from()
handler2.get('/test2', () => new Response('test2'))
const handler = Handler.compose([handler1, handler2])
expect(handler).toBeDefined()
{
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test')
}
{
const response = await handler.fetch(new Request('http://localhost/test2'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test2')
}
})
test('behavior: path', async () => {
const handler1 = Handler.from()
handler1.get('/test', () => new Response('test'))
const handler2 = Handler.from()
handler2.get('/test2', () => new Response('test2'))
const handler = Handler.compose([handler1, handler2], {
path: '/api',
})
expect(handler).toBeDefined()
{
const response = await handler.fetch(new Request('http://localhost/api/test'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test')
}
{
const response = await handler.fetch(new Request('http://localhost/api/test2'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test2')
}
})
test('behavior: headers', async () => {
const handler1 = Handler.from()
handler1.get('/test', () => new Response('test'))
const handler2 = Handler.from()
handler2.get('/test2', () => new Response('test2'))
const headers = new Headers({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
})
const handler = Handler.compose([handler1, handler2], {
headers,
})
{
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(response.headers.get('Access-Control-Allow-Methods')).toBe('POST, OPTIONS')
expect(response.headers.get('Access-Control-Allow-Headers')).toBe(
'Content-Type, Authorization',
)
}
{
const response = await handler.fetch(new Request('http://localhost/test2'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test2')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
}
})
test('behavior: headers + path', async () => {
const handler1 = Handler.from()
handler1.get('/test', () => new Response('test'))
const handler2 = Handler.from()
handler2.get('/test2', () => new Response('test2'))
const headers = new Headers({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
})
const handler = Handler.compose([handler1, handler2], {
headers,
path: '/api',
})
{
const response = await handler.fetch(new Request('http://localhost/api/test'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(response.headers.get('Access-Control-Allow-Methods')).toBe('POST, OPTIONS')
}
{
const response = await handler.fetch(new Request('http://localhost/api/test2'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test2')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
}
})
test('behavior: headers + OPTIONS', async () => {
const handler1 = Handler.from()
handler1.get('/test', () => new Response('test'))
const headers = new Headers({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400',
})
const handler = Handler.compose([handler1], {
headers,
})
const response = await handler.fetch(
new Request('http://localhost/test', {
method: 'OPTIONS',
}),
)
expect(response.status).toBe(200)
expect(await response.text()).toBe('')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(response.headers.get('Access-Control-Allow-Methods')).toBe('POST, OPTIONS')
expect(response.headers.get('Access-Control-Allow-Headers')).toBe('Content-Type, Authorization')
expect(response.headers.get('Access-Control-Max-Age')).toBe('86400')
})
test('behavior: headers + 404', async () => {
const handler1 = Handler.from()
handler1.get('/test', () => new Response('test'))
const headers = new Headers({
'Access-Control-Allow-Origin': '*',
})
const handler = Handler.compose([handler1], {
headers,
})
const response = await handler.fetch(new Request('http://localhost/nonexistent'))
expect(response.status).toBe(404)
expect(await response.text()).toBe('Not Found')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
})
test('behavior: headers propagation from child handlers', async () => {
const handler1 = Handler.from()
handler1.get('/test', () => {
const response = new Response('test')
response.headers.set('X-Custom-Header', 'custom-value')
return response
})
const headers = new Headers({
'Access-Control-Allow-Origin': '*',
})
const handler = Handler.compose([handler1], {
headers,
})
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(response.headers.get('X-Custom-Header')).toBe('custom-value')
})
test('behavior: headers with child handler headers', async () => {
const childHeaders = new Headers({
'X-Child-Header': 'child-value',
})
const handler1 = Handler.from({ headers: childHeaders })
handler1.get('/test', () => new Response('test'))
const parentHeaders = new Headers({
'Access-Control-Allow-Origin': '*',
'X-Parent-Header': 'parent-value',
})
const handler = Handler.compose([handler1], {
headers: parentHeaders,
})
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test')
// Both parent and child headers should be present
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(response.headers.get('X-Parent-Header')).toBe('parent-value')
expect(response.headers.get('X-Child-Header')).toBe('child-value')
})
test('behavior: headers as object', async () => {
const handler1 = Handler.from()
handler1.get('/test', () => new Response('test'))
const handler = Handler.compose([handler1], {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
})
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(response.headers.get('Access-Control-Allow-Methods')).toBe('POST, OPTIONS')
expect(response.headers.get('Access-Control-Allow-Headers')).toBe('Content-Type, Authorization')
})
describe('integration', () => {
const handler1 = Handler.from()
handler1.get('/foo', () => new Response('foo'))
handler1.post('/bar', () => new Response('bar'))
const handler2 = Handler.from()
handler2.get('/baz', () => new Response('baz'))
handler2.post('/qux', () => new Response('qux'))
const handler = Handler.compose([handler1, handler2], {
path: '/api',
})
test('hono', async () => {
const app = new Hono()
app.all('*', (c) => handler.fetch(c.req.raw))
{
const response = await app.request('/api/foo')
expect(await response.text()).toBe('foo')
}
{
const response = await app.request('/api/bar', {
method: 'POST',
})
expect(await response.text()).toBe('bar')
}
{
const response = await app.request('/api/baz', {
method: 'GET',
})
expect(await response.text()).toBe('baz')
}
{
const response = await app.request('/api/qux', {
method: 'POST',
})
expect(await response.text()).toBe('qux')
}
})
test('elysia', async () => {
const app = new Elysia().all('*', ({ request }) => handler.fetch(request))
{
const response = await app.handle(new Request('http://localhost/api/foo'))
expect(await response.text()).toBe('foo')
}
{
const response = await app.handle(
new Request('http://localhost/api/bar', {
method: 'POST',
}),
)
expect(await response.text()).toBe('bar')
}
{
const response = await app.handle(
new Request('http://localhost/api/baz', {
method: 'GET',
}),
)
expect(await response.text()).toBe('baz')
}
{
const response = await app.handle(
new Request('http://localhost/api/qux', {
method: 'POST',
}),
)
expect(await response.text()).toBe('qux')
}
})
test('node.js', async () => {
const server = await createServer(handler.listener)
{
const response = await fetch(`${server.url}/api/foo`)
expect(await response.text()).toBe('foo')
}
{
const response = await fetch(`${server.url}/api/bar`, {
method: 'POST',
})
expect(await response.text()).toBe('bar')
}
{
const response = await fetch(`${server.url}/api/baz`, {
method: 'GET',
})
expect(await response.text()).toBe('baz')
}
{
const response = await fetch(`${server.url}/api/qux`, {
method: 'POST',
})
expect(await response.text()).toBe('qux')
}
await server.closeAsync()
})
test('express', async () => {
const app = express()
app.use(handler.listener)
const server = await createServer(app)
{
const response = await fetch(`${server.url}/api/foo`)
expect(await response.text()).toBe('foo')
}
{
const response = await fetch(`${server.url}/api/bar`, {
method: 'POST',
})
expect(await response.text()).toBe('bar')
}
{
const response = await fetch(`${server.url}/api/baz`, {
method: 'GET',
})
expect(await response.text()).toBe('baz')
}
{
const response = await fetch(`${server.url}/api/qux`, {
method: 'POST',
})
expect(await response.text()).toBe('qux')
}
await server.closeAsync()
})
})
})
describe('from', () => {
test('default', () => {
const handler = Handler.from()
expect(handler).toBeDefined()
})
test('.fetch', async () => {
const handler = Handler.from()
handler.get('/test', () => new Response('test'))
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test')
})
test('.listener', async () => {
const handler = Handler.from()
handler.get('/test', () => Response.json({ message: 'hello from listener' }))
const server = await createServer(handler.listener)
// Make a request to the server
const response = await fetch(`${server.url}/test`)
expect(response.status).toBe(200)
const data = await response.json()
expect(data).toEqual({ message: 'hello from listener' })
})
test('behavior: headers', async () => {
const headers = new Headers({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
})
const handler = Handler.from({ headers })
handler.get('/test', () => new Response('test'))
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(response.headers.get('Access-Control-Allow-Methods')).toBe('POST, OPTIONS')
expect(response.headers.get('Access-Control-Allow-Headers')).toBe('Content-Type, Authorization')
})
test('behavior: headers + OPTIONS', async () => {
const headers = new Headers({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400',
})
const handler = Handler.from({ headers })
handler.get('/test', () => new Response('test'))
const response = await handler.fetch(
new Request('http://localhost/test', {
method: 'OPTIONS',
}),
)
expect(response.status).toBe(200)
expect(await response.text()).toBe('')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(response.headers.get('Access-Control-Allow-Methods')).toBe('POST, OPTIONS')
expect(response.headers.get('Access-Control-Allow-Headers')).toBe('Content-Type, Authorization')
expect(response.headers.get('Access-Control-Max-Age')).toBe('86400')
})
test('behavior: headers + 404', async () => {
const headers = new Headers({
'Access-Control-Allow-Origin': '*',
})
const handler = Handler.from({ headers })
handler.get('/test', () => new Response('test'))
const response = await handler.fetch(new Request('http://localhost/nonexistent'))
expect(response.status).toBe(404)
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
})
test('behavior: headers propagation from routes', async () => {
const headers = new Headers({
'Access-Control-Allow-Origin': '*',
})
const handler = Handler.from({ headers })
handler.get('/test', () => {
const response = new Response('test')
response.headers.set('X-Custom-Header', 'custom-value')
response.headers.set('Content-Type', 'text/plain')
return response
})
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(response.headers.get('X-Custom-Header')).toBe('custom-value')
expect(response.headers.get('Content-Type')).toBe('text/plain')
})
test('behavior: headers as object', async () => {
const handler = Handler.from({
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
})
handler.get('/test', () => new Response('test'))
const response = await handler.fetch(new Request('http://localhost/test'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('test')
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*')
expect(response.headers.get('Access-Control-Allow-Methods')).toBe('POST, OPTIONS')
expect(response.headers.get('Access-Control-Allow-Headers')).toBe('Content-Type, Authorization')
})
describe('integration', () => {
const handler = Handler.from()
handler.get('/foo', () => new Response('foo'))
handler.post('/bar', () => new Response('bar'))
test('hono', async () => {
const app = new Hono()
app.all('*', (c) => handler.fetch(c.req.raw))
{
const response = await app.request('/foo')
expect(await response.text()).toBe('foo')
}
{
const response = await app.request('/bar', {
method: 'POST',
})
expect(await response.text()).toBe('bar')
}
})
test('elysia', async () => {
const app = new Elysia().all('*', ({ request }) => handler.fetch(request))
{
const response = await app.handle(new Request('http://localhost/foo'))
expect(await response.text()).toBe('foo')
}
{
const response = await app.handle(
new Request('http://localhost/bar', {
method: 'POST',
}),
)
expect(await response.text()).toBe('bar')
}
})
test('node.js', async () => {
const server = await createServer(handler.listener)
{
const response = await fetch(`${server.url}/foo`)
expect(await response.text()).toBe('foo')
}
{
const response = await fetch(`${server.url}/bar`, {
method: 'POST',
})
expect(await response.text()).toBe('bar')
}
await server.closeAsync()
})
test('express', async () => {
const app = express()
app.use(handler.listener)
const server = await createServer(app)
{
const response = await fetch(`${server.url}/foo`)
expect(await response.text()).toBe('foo')
}
{
const response = await fetch(`${server.url}/bar`, {
method: 'POST',
})
expect(await response.text()).toBe('bar')
}
await server.closeAsync()
})
})
})