import { describe, expect, it } from 'vitest' import { buildEntityMaps, getApiEndpoint } from './DataApi.utils' import type { ProjectJsonSchemaPaths } from '@/data/docs/project-json-schema-query' import type { LoadBalancer } from '@/data/read-replicas/load-balancers-query' import type { Database } from '@/data/read-replicas/replicas-query' const makeDatabase = ( identifier: string, restUrl: string ): Pick => ({ identifier, restUrl }) const makeLoadBalancer = (endpoint: string): Pick => ({ endpoint }) describe('getApiEndpoint', () => { it('returns custom domain URL with /rest/v1/ when custom domain is active and primary database is selected', () => { expect( getApiEndpoint({ selectedDatabaseId: 'project-ref', projectRef: 'project-ref', resolvedEndpoint: 'https://api.example.com', loadBalancers: undefined, selectedDatabase: makeDatabase( 'project-ref', 'https://project-ref.supabase.co/rest/v1/' ) as Database, }) ).toBe('https://api.example.com/rest/v1/') }) it('returns database restUrl when custom domain is active but a replica is selected', () => { expect( getApiEndpoint({ selectedDatabaseId: 'replica-1', projectRef: 'project-ref', resolvedEndpoint: 'https://api.example.com', loadBalancers: undefined, selectedDatabase: makeDatabase( 'replica-1', 'https://replica-1.supabase.co/rest/v1/' ) as Database, }) ).toBe('https://replica-1.supabase.co/rest/v1/') }) it('normalizes a replica restUrl without a trailing slash', () => { expect( getApiEndpoint({ selectedDatabaseId: 'replica-1', projectRef: 'project-ref', resolvedEndpoint: undefined, loadBalancers: undefined, selectedDatabase: makeDatabase( 'replica-1', 'https://replica-1.supabase.co/rest/v1' ) as Database, }) ).toBe('https://replica-1.supabase.co/rest/v1/') }) it('returns load balancer endpoint with /rest/v1/ when load balancer is selected', () => { expect( getApiEndpoint({ selectedDatabaseId: 'load-balancer', projectRef: 'project-ref', resolvedEndpoint: 'https://project-ref.supabase.co', loadBalancers: [makeLoadBalancer('https://lb.supabase.co') as LoadBalancer], selectedDatabase: undefined, }) ).toBe('https://lb.supabase.co/rest/v1/') }) it('returns empty string when load balancer is selected but none exist', () => { expect( getApiEndpoint({ selectedDatabaseId: 'load-balancer', projectRef: 'project-ref', resolvedEndpoint: 'https://project-ref.supabase.co', loadBalancers: undefined, selectedDatabase: undefined, }) ).toBe('') }) it('returns database restUrl for a replica database selection', () => { expect( getApiEndpoint({ selectedDatabaseId: 'replica-2', projectRef: 'project-ref', resolvedEndpoint: 'https://project-ref.supabase.co', loadBalancers: undefined, selectedDatabase: makeDatabase( 'replica-2', 'https://replica-2.supabase.co/rest/v1/' ) as Database, }) ).toBe('https://replica-2.supabase.co/rest/v1/') }) }) describe('buildEntityMaps', () => { it('returns empty maps for undefined paths', () => { expect(buildEntityMaps(undefined)).toEqual({ resources: {}, rpcs: {} }) }) it('returns empty maps for empty paths', () => { expect(buildEntityMaps({})).toEqual({ resources: {}, rpcs: {} }) }) it('skips the root path', () => { const paths: ProjectJsonSchemaPaths = { '/': { get: {} as ProjectJsonSchemaPaths[string]['get'] }, } expect(buildEntityMaps(paths)).toEqual({ resources: {}, rpcs: {} }) }) it('classifies non-rpc paths as resources', () => { const paths: ProjectJsonSchemaPaths = { '/users': { get: {} as ProjectJsonSchemaPaths[string]['get'] }, '/posts': { get: {} as ProjectJsonSchemaPaths[string]['get'] }, } const result = buildEntityMaps(paths) expect(Object.keys(result.resources)).toEqual(['users', 'posts']) expect(result.rpcs).toEqual({}) }) it('classifies rpc/ paths as rpcs', () => { const paths: ProjectJsonSchemaPaths = { '/rpc/my_function': { post: {} as ProjectJsonSchemaPaths[string]['post'] }, } const result = buildEntityMaps(paths) expect(result.resources).toEqual({}) expect(Object.keys(result.rpcs)).toEqual(['my_function']) }) it('enriches entities with displayName and camelCase', () => { const paths: ProjectJsonSchemaPaths = { '/user_profiles': { get: {} as ProjectJsonSchemaPaths[string]['get'] }, '/rpc/get_user_count': { post: {} as ProjectJsonSchemaPaths[string]['post'] }, } const result = buildEntityMaps(paths) expect(result.resources['user_profiles']).toEqual({ id: 'user_profiles', displayName: 'user profiles', camelCase: 'userProfiles', }) expect(result.rpcs['get_user_count']).toEqual({ id: 'get_user_count', displayName: 'get user count', camelCase: 'getUserCount', }) }) it('handles mixed resources and rpcs', () => { const paths: ProjectJsonSchemaPaths = { '/': { get: {} as ProjectJsonSchemaPaths[string]['get'] }, '/users': { get: {} as ProjectJsonSchemaPaths[string]['get'] }, '/rpc/hello': { post: {} as ProjectJsonSchemaPaths[string]['post'] }, '/posts': { get: {} as ProjectJsonSchemaPaths[string]['get'] }, '/rpc/goodbye': { post: {} as ProjectJsonSchemaPaths[string]['post'] }, } const result = buildEntityMaps(paths) expect(Object.keys(result.resources)).toEqual(['users', 'posts']) expect(Object.keys(result.rpcs)).toEqual(['hello', 'goodbye']) }) })