mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
* update gh action, update vitest config * debug * debug cov * idk try something different * test2 * test3 * add base path * rm debug * add apiAuthenticate tests * supabaseClient tests * apiWrappers tests * add apiHelpers tests * add configcat tests * add formatSql tests * add github tests * add cloudprovider utils tests * add helpers tests * fix typeerr * add missing readonly err * fix typeerrrs * fix type errors in apiWrapper tests * fix apiHelpers test * add packages/ui tests * add coveralls flags * try coveralls parallel config * fix coveralls parallel config --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
319 lines
9.6 KiB
TypeScript
319 lines
9.6 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
import { apiAuthenticate } from './apiAuthenticate'
|
|
import { readOnly } from './supabaseClient'
|
|
|
|
const mocks = vi.hoisted(() => {
|
|
return {
|
|
getAuthUser: vi.fn().mockResolvedValue({
|
|
user: {
|
|
id: 'test-gotrue-id',
|
|
email: 'test@example.com',
|
|
},
|
|
error: null,
|
|
}),
|
|
getIdentity: vi.fn().mockReturnValue({
|
|
identity: null,
|
|
error: null,
|
|
}),
|
|
getAuth0Id: vi.fn(),
|
|
}
|
|
})
|
|
|
|
// Mock dependencies
|
|
vi.mock('./supabaseClient', () => ({
|
|
readOnly: {
|
|
from: vi.fn(),
|
|
},
|
|
}))
|
|
|
|
vi.mock('lib/gotrue', () => ({
|
|
getAuthUser: mocks.getAuthUser,
|
|
getIdentity: mocks.getIdentity,
|
|
getAuth0Id: mocks.getAuth0Id,
|
|
}))
|
|
|
|
describe('apiAuthenticate', () => {
|
|
const mockReq = {
|
|
headers: {
|
|
authorization: 'Bearer test-token',
|
|
},
|
|
query: {},
|
|
} as any
|
|
|
|
const mockRes = {} as any
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
mocks.getAuthUser.mockResolvedValue({
|
|
user: {
|
|
id: 'test-gotrue-id',
|
|
email: 'test@example.com',
|
|
},
|
|
error: null,
|
|
})
|
|
mocks.getIdentity.mockReturnValue({
|
|
identity: null,
|
|
error: null,
|
|
})
|
|
})
|
|
|
|
it('should return error when request is not available', async () => {
|
|
const result = await apiAuthenticate(null as any, mockRes)
|
|
expect(result).toStrictEqual({ error: new Error('Request is not available') })
|
|
})
|
|
|
|
it('should return error when response is not available', async () => {
|
|
const result = await apiAuthenticate(mockReq, null as any)
|
|
expect(result).toStrictEqual({ error: new Error('Response is not available') })
|
|
})
|
|
|
|
it('should return error when authorization token is missing', async () => {
|
|
const reqWithoutToken = { ...mockReq, headers: {} }
|
|
const result = await apiAuthenticate(reqWithoutToken, mockRes)
|
|
expect(result).toStrictEqual({ error: { name: 'Error', message: 'missing access token' } })
|
|
})
|
|
|
|
it('should return error when auth user fetch fails', async () => {
|
|
mocks.getAuthUser.mockResolvedValue({
|
|
user: null,
|
|
error: new Error('Auth failed'),
|
|
})
|
|
|
|
const result = await apiAuthenticate(mockReq, mockRes)
|
|
expect(result).toStrictEqual({ error: { name: 'Error', message: 'Auth failed' } })
|
|
})
|
|
|
|
it('should handle identity error', async () => {
|
|
mocks.getIdentity.mockReturnValue({
|
|
identity: null,
|
|
error: new Error('Identity error'),
|
|
})
|
|
|
|
const result = await apiAuthenticate(mockReq, mockRes)
|
|
expect(result).toStrictEqual({ error: { name: 'Error', message: 'Identity error' } })
|
|
})
|
|
|
|
it('should set auth0 id when identity provider is present', async () => {
|
|
mocks.getIdentity.mockReturnValue({
|
|
identity: {
|
|
provider: 'auth0',
|
|
id: 'auth0-id',
|
|
},
|
|
error: null,
|
|
})
|
|
mocks.getAuth0Id.mockReturnValue('auth0-user-id')
|
|
|
|
// Mock user query
|
|
vi.mocked(readOnly.from).mockReturnValue({
|
|
select: vi.fn().mockReturnThis(),
|
|
eq: vi.fn().mockReturnThis(),
|
|
single: vi
|
|
.fn()
|
|
.mockResolvedValue({ data: { id: 'test-user-id', primary_email: 'test@example.com' } }),
|
|
} as any)
|
|
|
|
const result = await apiAuthenticate(mockReq, mockRes)
|
|
expect(result).toStrictEqual({
|
|
id: 'test-user-id',
|
|
primary_email: 'test@example.com',
|
|
})
|
|
expect(mocks.getAuth0Id).toHaveBeenCalledWith('auth0', 'auth0-id')
|
|
})
|
|
|
|
it('should return user when user_id_supabase is present', async () => {
|
|
// Mock identity to return auth0 provider
|
|
mocks.getIdentity.mockReturnValue({
|
|
identity: {
|
|
provider: 'auth0',
|
|
id: 'auth0-id',
|
|
},
|
|
error: null,
|
|
})
|
|
mocks.getAuth0Id.mockReturnValue('auth0-user-id')
|
|
|
|
// Mock user query to return a user with auth0_id
|
|
vi.mocked(readOnly.from).mockReturnValue({
|
|
select: vi.fn().mockReturnThis(),
|
|
eq: vi.fn().mockReturnThis(),
|
|
single: vi.fn().mockResolvedValue({
|
|
data: {
|
|
id: 'supabase-user-id',
|
|
auth0_id: 'auth0-user-id',
|
|
primary_email: 'test@example.com',
|
|
},
|
|
}),
|
|
} as any)
|
|
|
|
const result = await apiAuthenticate(mockReq, mockRes)
|
|
expect(result).toStrictEqual({
|
|
id: 'supabase-user-id',
|
|
auth0_id: 'auth0-user-id',
|
|
primary_email: 'test@example.com',
|
|
})
|
|
})
|
|
|
|
it('should return error when user does not exist', async () => {
|
|
vi.mocked(readOnly.from).mockReturnValue({
|
|
select: vi.fn().mockReturnThis(),
|
|
eq: vi.fn().mockReturnThis(),
|
|
single: vi.fn().mockResolvedValue({ data: null }),
|
|
} as any)
|
|
|
|
const result = await apiAuthenticate(mockReq, mockRes)
|
|
expect(result).toStrictEqual({ error: new Error('The user does not exist') })
|
|
})
|
|
|
|
it('should check organization permissions when orgSlug is provided', async () => {
|
|
const reqWithOrg = {
|
|
...mockReq,
|
|
query: { slug: 'test-org' },
|
|
}
|
|
|
|
// Mock user query
|
|
vi.mocked(readOnly.from).mockReturnValueOnce({
|
|
select: vi.fn().mockReturnThis(),
|
|
eq: vi.fn().mockReturnThis(),
|
|
single: vi
|
|
.fn()
|
|
.mockResolvedValue({ data: { id: 'test-user-id', primary_email: 'test@example.com' } }),
|
|
} as any)
|
|
|
|
// Mock organization query
|
|
vi.mocked(readOnly.from).mockReturnValueOnce({
|
|
select: vi.fn().mockReturnThis(),
|
|
match: vi.fn().mockReturnThis(),
|
|
single: vi.fn().mockResolvedValue({ data: { id: 'org-id' } }),
|
|
} as any)
|
|
|
|
// Mock member check
|
|
vi.mocked(readOnly.from).mockReturnValueOnce({
|
|
select: vi.fn().mockReturnThis(),
|
|
match: vi.fn().mockReturnThis(),
|
|
single: vi.fn().mockResolvedValue({ data: { id: 'member-id' }, status: 200 }),
|
|
} as any)
|
|
|
|
const result = await apiAuthenticate(reqWithOrg, mockRes)
|
|
expect(result).toStrictEqual({
|
|
id: 'test-user-id',
|
|
primary_email: 'test@example.com',
|
|
})
|
|
})
|
|
|
|
it('should return error when user lacks organization permissions', async () => {
|
|
const reqWithOrg = {
|
|
...mockReq,
|
|
query: { slug: 'test-org' },
|
|
}
|
|
|
|
// Mock user query
|
|
vi.mocked(readOnly.from).mockReturnValueOnce({
|
|
select: vi.fn().mockReturnThis(),
|
|
eq: vi.fn().mockReturnThis(),
|
|
single: vi
|
|
.fn()
|
|
.mockResolvedValue({ data: { id: 'test-user-id', primary_email: 'test@example.com' } }),
|
|
} as any)
|
|
|
|
// Mock organization query
|
|
vi.mocked(readOnly.from).mockReturnValueOnce({
|
|
select: vi.fn().mockReturnThis(),
|
|
match: vi.fn().mockReturnThis(),
|
|
single: vi.fn().mockResolvedValue({ data: { id: 'org-id' } }),
|
|
} as any)
|
|
|
|
// Mock member check failure
|
|
vi.mocked(readOnly.from).mockReturnValueOnce({
|
|
select: vi.fn().mockReturnThis(),
|
|
match: vi.fn().mockReturnThis(),
|
|
single: vi.fn().mockRejectedValue(new Error('Permission denied')),
|
|
} as any)
|
|
|
|
const result = await apiAuthenticate(reqWithOrg, mockRes)
|
|
expect(result).toStrictEqual({
|
|
error: { name: 'Error', message: 'The user does not have permission' },
|
|
})
|
|
})
|
|
|
|
it('should handle unknown errors gracefully', async () => {
|
|
mocks.getAuthUser.mockRejectedValue(new Error('Unexpected error'))
|
|
|
|
const result = await apiAuthenticate(mockReq, mockRes)
|
|
expect(result).toStrictEqual({ error: { name: 'Error', message: 'Unexpected error' } })
|
|
})
|
|
|
|
it('should get organization from project reference', async () => {
|
|
const reqWithProject = {
|
|
...mockReq,
|
|
query: { ref: 'test-project' },
|
|
}
|
|
|
|
// Mock user query
|
|
vi.mocked(readOnly.from).mockReturnValueOnce({
|
|
select: vi.fn().mockReturnThis(),
|
|
eq: vi.fn().mockReturnThis(),
|
|
single: vi
|
|
.fn()
|
|
.mockResolvedValue({ data: { id: 'test-user-id', primary_email: 'test@example.com' } }),
|
|
} as any)
|
|
|
|
// Mock project query
|
|
vi.mocked(readOnly.from).mockReturnValueOnce({
|
|
select: vi.fn().mockReturnThis(),
|
|
match: vi.fn().mockReturnThis(),
|
|
single: vi.fn().mockResolvedValue({ data: { organization_id: 'org-id' } }),
|
|
} as any)
|
|
|
|
// Mock member check
|
|
vi.mocked(readOnly.from).mockReturnValueOnce({
|
|
select: vi.fn().mockReturnThis(),
|
|
match: vi.fn().mockReturnThis(),
|
|
single: vi.fn().mockResolvedValue({ data: { id: 'member-id' }, status: 200 }),
|
|
} as any)
|
|
|
|
const result = await apiAuthenticate(reqWithProject, mockRes)
|
|
expect(result).toStrictEqual({
|
|
id: 'test-user-id',
|
|
primary_email: 'test@example.com',
|
|
})
|
|
})
|
|
|
|
it('should use organization_id from projectRef in member check', async () => {
|
|
const reqWithProject = {
|
|
...mockReq,
|
|
query: { ref: 'project-xyz' },
|
|
}
|
|
|
|
// Mock user query
|
|
vi.mocked(readOnly.from).mockReturnValueOnce({
|
|
select: vi.fn().mockReturnThis(),
|
|
eq: vi.fn().mockReturnThis(),
|
|
single: vi
|
|
.fn()
|
|
.mockResolvedValue({ data: { id: 'user-123', primary_email: 'user@example.com' } }),
|
|
} as any)
|
|
|
|
// Mock project query to return a specific organization_id
|
|
vi.mocked(readOnly.from).mockReturnValueOnce({
|
|
select: vi.fn().mockReturnThis(),
|
|
match: vi.fn().mockReturnThis(),
|
|
single: vi.fn().mockResolvedValue({ data: { organization_id: 'org-abc' } }),
|
|
} as any)
|
|
|
|
// Spy on the match function for the member check
|
|
const matchSpy = vi.fn().mockReturnThis()
|
|
vi.mocked(readOnly.from).mockReturnValueOnce({
|
|
select: vi.fn().mockReturnThis(),
|
|
match: matchSpy,
|
|
single: vi.fn().mockResolvedValue({ data: { id: 'member-1' }, status: 200 }),
|
|
} as any)
|
|
|
|
const result = await apiAuthenticate(reqWithProject, mockRes)
|
|
expect(result).toStrictEqual({
|
|
id: 'user-123',
|
|
primary_email: 'user@example.com',
|
|
})
|
|
// Ensure the member check used the org id from the project lookup
|
|
expect(matchSpy).toHaveBeenCalledWith({ organization_id: 'org-abc', user_id: 'user-123' })
|
|
})
|
|
})
|