- fromRow: extrae areaId y areaName (vía JOIN en getById) - toRow y updateEditable: incluyen area_id en escrituras a Supabase - getById: JOIN con areas!area_id(name) para obtener nombre en una query - Fixtures de tests actualizados con areaId: null (campo requerido) - 4 tests nuevos en tests/persistence/area-repo.test.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
95 lines
2.6 KiB
TypeScript
95 lines
2.6 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
import { supabaseAreaRepo } from '@/persistence/supabase/area-repo'
|
|
|
|
const { mockSingle, mockData } = vi.hoisted(() => ({
|
|
mockSingle: vi.fn(),
|
|
mockData: vi.fn(),
|
|
}))
|
|
|
|
vi.mock('@/lib/supabase', () => {
|
|
const buildChain = () => {
|
|
const chain: Record<string, unknown> = {}
|
|
chain.select = vi.fn().mockReturnValue(chain)
|
|
chain.insert = vi.fn().mockReturnValue(chain)
|
|
chain.update = vi.fn().mockReturnValue(chain)
|
|
chain.delete = vi.fn().mockReturnValue(chain)
|
|
chain.eq = vi.fn().mockReturnValue(chain)
|
|
chain.order = vi.fn().mockImplementation(() => mockData())
|
|
chain.single = mockSingle
|
|
return chain
|
|
}
|
|
|
|
return {
|
|
supabase: {
|
|
from: vi.fn().mockImplementation(() => buildChain()),
|
|
},
|
|
}
|
|
})
|
|
|
|
const AREA_ROW = {
|
|
id: 'area-uuid-1',
|
|
org_id: 'org-uuid-1',
|
|
name: 'Finanzas',
|
|
description: 'Área de finanzas',
|
|
created_at: '2026-07-07T00:00:00.000Z',
|
|
updated_at: '2026-07-07T00:00:00.000Z',
|
|
}
|
|
|
|
describe('supabaseAreaRepo', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
describe('getByOrg', () => {
|
|
it('devuelve lista de áreas mapeadas correctamente', async () => {
|
|
mockData.mockResolvedValue({ data: [AREA_ROW], error: null })
|
|
|
|
const result = await supabaseAreaRepo.getByOrg('org-uuid-1')
|
|
|
|
expect(result).toHaveLength(1)
|
|
expect(result[0]).toMatchObject({
|
|
id: 'area-uuid-1',
|
|
orgId: 'org-uuid-1',
|
|
name: 'Finanzas',
|
|
description: 'Área de finanzas',
|
|
createdAt: new Date('2026-07-07T00:00:00.000Z').getTime(),
|
|
})
|
|
})
|
|
|
|
it('devuelve array vacío si la org no tiene áreas', async () => {
|
|
mockData.mockResolvedValue({ data: [], error: null })
|
|
|
|
const result = await supabaseAreaRepo.getByOrg('org-sin-areas')
|
|
|
|
expect(result).toEqual([])
|
|
})
|
|
})
|
|
|
|
describe('create', () => {
|
|
it('inserta el área y retorna el registro mapeado', async () => {
|
|
mockSingle.mockResolvedValue({ data: AREA_ROW, error: null })
|
|
|
|
const result = await supabaseAreaRepo.create({
|
|
orgId: 'org-uuid-1',
|
|
name: 'Finanzas',
|
|
description: 'Área de finanzas',
|
|
})
|
|
|
|
expect(result).toMatchObject({
|
|
id: 'area-uuid-1',
|
|
orgId: 'org-uuid-1',
|
|
name: 'Finanzas',
|
|
description: 'Área de finanzas',
|
|
})
|
|
})
|
|
|
|
it('propaga el error de Supabase si el insert falla', async () => {
|
|
mockSingle.mockResolvedValue({ data: null, error: new Error('RLS violation') })
|
|
|
|
await expect(
|
|
supabaseAreaRepo.create({ orgId: 'org-1', name: 'Test' })
|
|
).rejects.toThrow('RLS violation')
|
|
})
|
|
})
|
|
})
|