mirror of
https://github.com/supabase/supabase.git
synced 2026-05-08 15:57:47 +08:00
260 lines
7.6 KiB
TypeScript
260 lines
7.6 KiB
TypeScript
import type { IncomingHttpHeaders } from 'node:http'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import {
|
|
commaSeparatedStringIntoArray,
|
|
constructHeaders,
|
|
fromNodeHeaders,
|
|
toSnakeCase,
|
|
zBooleanString,
|
|
} from './apiHelpers'
|
|
|
|
vi.mock('@/lib/constants', () => ({
|
|
IS_PLATFORM: false,
|
|
}))
|
|
|
|
describe('apiHelpers', () => {
|
|
describe('constructHeaders', () => {
|
|
beforeEach(() => {
|
|
process.env.SUPABASE_SERVICE_KEY = 'test-service-key'
|
|
})
|
|
|
|
it('should return default headers when no headers are provided', () => {
|
|
const result = constructHeaders(null as any)
|
|
expect(result).toEqual({
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json',
|
|
})
|
|
})
|
|
|
|
it('should clean and include only allowed headers', () => {
|
|
const inputHeaders = {
|
|
Accept: 'application/json',
|
|
Authorization: 'Bearer token',
|
|
'Content-Type': 'application/json',
|
|
'x-connection-encrypted': 'true',
|
|
cookie: 'test-cookie',
|
|
'User-Agent': 'test-agent',
|
|
Referer: 'test-referer',
|
|
}
|
|
|
|
const result = constructHeaders(inputHeaders)
|
|
expect(result).toEqual({
|
|
Accept: 'application/json',
|
|
Authorization: 'Bearer token',
|
|
'Content-Type': 'application/json',
|
|
'x-connection-encrypted': 'true',
|
|
cookie: 'test-cookie',
|
|
apiKey: 'test-service-key',
|
|
})
|
|
})
|
|
|
|
it('should remove undefined values from headers', () => {
|
|
const inputHeaders = {
|
|
Accept: undefined,
|
|
Authorization: 'Bearer token',
|
|
'Content-Type': 'application/json',
|
|
cookie: undefined,
|
|
}
|
|
|
|
const result = constructHeaders(inputHeaders)
|
|
expect(result).toEqual({
|
|
Authorization: 'Bearer token',
|
|
'Content-Type': 'application/json',
|
|
apiKey: 'test-service-key',
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('toSnakeCase', () => {
|
|
it('should return null for null input', () => {
|
|
expect(toSnakeCase(null)).toBeNull()
|
|
})
|
|
|
|
it('should convert object keys to snake case', () => {
|
|
const input = {
|
|
firstName: 'John',
|
|
lastName: 'Doe',
|
|
contactInfo: {
|
|
emailAddress: 'john@example.com',
|
|
phoneNumber: '1234567890',
|
|
},
|
|
}
|
|
|
|
const expected = {
|
|
first_name: 'John',
|
|
last_name: 'Doe',
|
|
contact_info: {
|
|
email_address: 'john@example.com',
|
|
phone_number: '1234567890',
|
|
},
|
|
}
|
|
|
|
expect(toSnakeCase(input)).toEqual(expected)
|
|
})
|
|
|
|
it('should handle arrays of objects', () => {
|
|
const input = [
|
|
{ firstName: 'John', lastName: 'Doe' },
|
|
{ firstName: 'Jane', lastName: 'Smith' },
|
|
]
|
|
|
|
const expected = [
|
|
{ first_name: 'John', last_name: 'Doe' },
|
|
{ first_name: 'Jane', last_name: 'Smith' },
|
|
]
|
|
|
|
expect(toSnakeCase(input)).toEqual(expected)
|
|
})
|
|
|
|
it('should handle arrays of primitive values', () => {
|
|
const input = [1, 'test', true]
|
|
expect(toSnakeCase(input)).toEqual([1, 'test', true])
|
|
})
|
|
|
|
it('should handle nested arrays', () => {
|
|
const input = {
|
|
users: [
|
|
{ firstName: 'John', contactInfo: { emailAddress: 'john@example.com' } },
|
|
{ firstName: 'Jane', contactInfo: { emailAddress: 'jane@example.com' } },
|
|
],
|
|
}
|
|
|
|
const expected = {
|
|
users: [
|
|
{ first_name: 'John', contact_info: { email_address: 'john@example.com' } },
|
|
{ first_name: 'Jane', contact_info: { email_address: 'jane@example.com' } },
|
|
],
|
|
}
|
|
|
|
expect(toSnakeCase(input)).toEqual(expected)
|
|
})
|
|
|
|
it('should handle primitive values', () => {
|
|
expect(toSnakeCase('test')).toBe('test')
|
|
expect(toSnakeCase(123)).toBe(123)
|
|
expect(toSnakeCase(true)).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('zBooleanString', () => {
|
|
it('should transform "true" string to boolean true', () => {
|
|
const schema = zBooleanString()
|
|
const result = schema.parse('true')
|
|
expect(result).toBe(true)
|
|
})
|
|
|
|
it('should transform "false" string to boolean false', () => {
|
|
const schema = zBooleanString()
|
|
const result = schema.parse('false')
|
|
expect(result).toBe(false)
|
|
})
|
|
|
|
it('should throw error for invalid boolean string', () => {
|
|
const schema = zBooleanString()
|
|
expect(() => schema.parse('invalid')).toThrow('must be a boolean string')
|
|
})
|
|
|
|
it('should throw custom error message when provided', () => {
|
|
const customError = 'Custom boolean error'
|
|
const schema = zBooleanString(customError)
|
|
expect(() => schema.parse('invalid')).toThrow(customError)
|
|
})
|
|
|
|
it('should throw error for empty string', () => {
|
|
const schema = zBooleanString()
|
|
expect(() => schema.parse('')).toThrow('must be a boolean string')
|
|
})
|
|
|
|
it('should throw error for non-string input', () => {
|
|
const schema = zBooleanString()
|
|
expect(() => schema.parse(true)).toThrow()
|
|
expect(() => schema.parse(false)).toThrow()
|
|
expect(() => schema.parse(123)).toThrow()
|
|
})
|
|
})
|
|
|
|
describe('commaSeparatedStringIntoArray', () => {
|
|
it('should split comma-separated string into array', () => {
|
|
const result = commaSeparatedStringIntoArray('a,b,c')
|
|
expect(result).toEqual(['a', 'b', 'c'])
|
|
})
|
|
|
|
it('should trim whitespace from values', () => {
|
|
const result = commaSeparatedStringIntoArray('a, b , c')
|
|
expect(result).toEqual(['a', 'b', 'c'])
|
|
})
|
|
|
|
it('should filter out empty values', () => {
|
|
const result = commaSeparatedStringIntoArray('a,,b,')
|
|
expect(result).toEqual(['a', 'b'])
|
|
})
|
|
|
|
it('should handle single value', () => {
|
|
const result = commaSeparatedStringIntoArray('single')
|
|
expect(result).toEqual(['single'])
|
|
})
|
|
|
|
it('should handle empty string', () => {
|
|
const result = commaSeparatedStringIntoArray('')
|
|
expect(result).toEqual([])
|
|
})
|
|
|
|
it('should handle string with only commas', () => {
|
|
const result = commaSeparatedStringIntoArray(',,,')
|
|
expect(result).toEqual([])
|
|
})
|
|
})
|
|
|
|
describe('fromNodeHeaders', () => {
|
|
it('should convert simple node headers to fetch headers', () => {
|
|
const nodeHeaders: IncomingHttpHeaders = {
|
|
'content-type': 'application/json',
|
|
authorization: 'Bearer token',
|
|
}
|
|
|
|
const result = fromNodeHeaders(nodeHeaders)
|
|
|
|
expect(result.get('content-type')).toBe('application/json')
|
|
expect(result.get('authorization')).toBe('Bearer token')
|
|
})
|
|
|
|
it('should skip undefined values', () => {
|
|
const nodeHeaders: IncomingHttpHeaders = {
|
|
'content-type': 'application/json',
|
|
authorization: undefined,
|
|
accept: 'application/json',
|
|
}
|
|
|
|
const result = fromNodeHeaders(nodeHeaders)
|
|
|
|
expect(result.get('content-type')).toBe('application/json')
|
|
expect(result.get('authorization')).toBeNull()
|
|
expect(result.get('accept')).toBe('application/json')
|
|
})
|
|
|
|
it('should handle empty headers object', () => {
|
|
const nodeHeaders: IncomingHttpHeaders = {}
|
|
const result = fromNodeHeaders(nodeHeaders)
|
|
|
|
expect(Array.from(result.keys())).toEqual([])
|
|
})
|
|
|
|
it('should handle mixed array and string values', () => {
|
|
const nodeHeaders: IncomingHttpHeaders = {
|
|
'content-type': 'application/json',
|
|
'x-custom': ['value1', 'value2'],
|
|
authorization: 'Bearer token',
|
|
'x-empty': undefined,
|
|
}
|
|
|
|
const result = fromNodeHeaders(nodeHeaders)
|
|
|
|
expect(result.get('content-type')).toBe('application/json')
|
|
expect(result.get('authorization')).toBe('Bearer token')
|
|
expect(result.get('x-empty')).toBeNull()
|
|
expect(result.get('x-custom')).toBe('value1, value2')
|
|
})
|
|
})
|
|
})
|