import { describe, expect, it } from 'vitest' import { buildSupplierOrganizationGraph, buildTerritoryGraph, hasAnySupplier, hasAnyTerritory, } from '@/components/provenance/provenance-graph' const singleSupplier = [ { product: { id: 1, name: 'Panela regional por Kg', catalogue_images: ['http://localhost/media/panela.jpg'], }, suppliers: [ { supplier: { id: 5, name: 'Asociación Agropecuaria La Mesa', description: 'Cooperativa' }, organization: { id: 3, name: 'Red de Economía Solidaria', description: 'Red' }, municipality: { id: 7, name: 'La Mesa' }, department: { id: 2, name: 'Cundinamarca' }, country: { id: 1, name: 'Colombia', code: 'CO' }, }, ], }, ] const twoSuppliers = (overrides = {}) => [ { product: { id: 1, name: 'Panela' }, suppliers: [ { supplier: { id: 5, name: 'Asociación A' }, organization: { id: 3, name: 'Red' }, municipality: { id: 7, name: 'La Mesa' }, department: { id: 2, name: 'Cundinamarca' }, country: { id: 1, name: 'Colombia' }, ...(overrides.first || {}), }, { supplier: { id: 6, name: 'Asociación B' }, organization: { id: 3, name: 'Red' }, municipality: { id: 8, name: 'San Antonio' }, department: { id: 3, name: 'Antioquia' }, country: { id: 1, name: 'Colombia' }, ...(overrides.second || {}), }, ], }, ] function edgeOf (graph, from, to) { return graph.edges.find(edge => edge.from === from && edge.to === to) } describe('hasAnySupplier', () => { it('es true cuando algún producto tiene proveedores', () => { expect(hasAnySupplier(singleSupplier)).toBe(true) }) it('es false cuando todos los productos están sin proveedores', () => { const empty = [{ product: { id: 1, name: 'Panela' }, suppliers: [] }] expect(hasAnySupplier(empty)).toBe(false) }) it('es false cuando no hay provenance', () => { expect(hasAnySupplier([])).toBe(false) }) }) describe('hasAnyTerritory', () => { it('es true cuando algún proveedor tiene territorio', () => { expect(hasAnyTerritory(singleSupplier)).toBe(true) }) it('es false cuando todos los territorios vienen en null', () => { const noTerritory = [ { product: { id: 1, name: 'Panela' }, suppliers: [{ supplier: { id: 5, name: 'La Mesa' }, organization: null, municipality: null, department: null, country: null }], }, ] expect(hasAnyTerritory(noTerritory)).toBe(false) }) it('es false cuando no hay suppliers', () => { const noSuppliers = [{ product: { id: 1, name: 'Panela' }, suppliers: [] }] expect(hasAnyTerritory(noSuppliers)).toBe(false) }) }) describe('buildSupplierOrganizationGraph', () => { it('con un único proveedor conecta con arista cierta y sin junction', () => { const graph = buildSupplierOrganizationGraph(singleSupplier) expect(graph.nodes.map(n => n.id)).not.toContain('junction:1') expect(edgeOf(graph, 'product:1', 'supplier:5')).toEqual({ from: 'product:1', to: 'supplier:5', certain: true }) }) it('con varios proveedores crea un punto de disyunción: sólida hasta él y dudosa hacia cada proveedor', () => { const graph = buildSupplierOrganizationGraph(twoSuppliers()) expect(graph.nodes.map(n => n.id)).toContain('junction:1') expect(edgeOf(graph, 'product:1', 'junction:1')).toEqual({ from: 'product:1', to: 'junction:1', certain: true }) expect(edgeOf(graph, 'junction:1', 'supplier:5')).toEqual({ from: 'junction:1', to: 'supplier:5', certain: false }) expect(edgeOf(graph, 'junction:1', 'supplier:6')).toEqual({ from: 'junction:1', to: 'supplier:6', certain: false }) }) it('una organización compartida por todos los proveedores es cierta', () => { const graph = buildSupplierOrganizationGraph(twoSuppliers()) expect(edgeOf(graph, 'supplier:5', 'organization:3')).toEqual({ from: 'supplier:5', to: 'organization:3', certain: true }) expect(edgeOf(graph, 'supplier:6', 'organization:3')).toEqual({ from: 'supplier:6', to: 'organization:3', certain: true }) }) it('organizaciones distintas entre proveedores son dudosas', () => { const graph = buildSupplierOrganizationGraph(twoSuppliers({ first: { organization: { id: 3, name: 'Red' } }, second: { organization: { id: 4, name: 'Cooperativa' } }, })) expect(edgeOf(graph, 'supplier:5', 'organization:3').certain).toBe(false) expect(edgeOf(graph, 'supplier:6', 'organization:4').certain).toBe(false) }) it('incluye la imagen del producto y el detalle de la entidad', () => { const graph = buildSupplierOrganizationGraph(singleSupplier) const product = graph.nodes.find(n => n.id === 'product:1') expect(product.image).toBe('http://localhost/media/panela.jpg') expect(product.label).toBe('Panela regional por Kg') expect(product.entity.kind).toBe('product') expect(product.entity.name).toBe('Panela regional por Kg') }) it('omite el nodo de organización cuando la relación es null', () => { const data = [ { product: { id: 1, name: 'Panela' }, suppliers: [{ supplier: { id: 5, name: 'La Mesa' }, organization: null }], }, ] const graph = buildSupplierOrganizationGraph(data) expect(graph.nodes.map(n => n.id)).not.toContain('organization:') expect(graph.edges).toEqual([{ from: 'product:1', to: 'supplier:5', certain: true }]) }) it('no duplica nodos que se repiten entre productos', () => { const data = [ { product: { id: 1, name: 'Panela' }, suppliers: [{ supplier: { id: 5, name: 'La Mesa' }, organization: { id: 3, name: 'Red' } }] }, { product: { id: 2, name: 'Arroz' }, suppliers: [{ supplier: { id: 5, name: 'La Mesa' }, organization: { id: 3, name: 'Red' } }] }, ] const graph = buildSupplierOrganizationGraph(data) expect(graph.nodes.filter(n => n.id === 'supplier:5')).toHaveLength(1) expect(graph.nodes.filter(n => n.id === 'organization:3')).toHaveLength(1) expect(graph.edges).toHaveLength(4) }) it('no incluye posiciones de layout', () => { const graph = buildSupplierOrganizationGraph(singleSupplier) const product = graph.nodes.find(n => n.id === 'product:1') expect(product.x).toBeUndefined() expect(product.y).toBeUndefined() }) it('devuelve un grafo vacío cuando no hay provenance', () => { const graph = buildSupplierOrganizationGraph([]) expect(graph.nodes).toEqual([]) expect(graph.edges).toEqual([]) }) }) describe('buildTerritoryGraph', () => { it('con un único proveedor toda la cadena es cierta', () => { const graph = buildTerritoryGraph(singleSupplier) expect(edgeOf(graph, 'product:1', 'supplier:5')).toEqual({ from: 'product:1', to: 'supplier:5', certain: true }) expect(edgeOf(graph, 'supplier:5', 'municipality:7')).toEqual({ from: 'supplier:5', to: 'municipality:7', certain: true }) expect(edgeOf(graph, 'municipality:7', 'department:2')).toEqual({ from: 'municipality:7', to: 'department:2', certain: true }) expect(edgeOf(graph, 'department:2', 'country:1')).toEqual({ from: 'department:2', to: 'country:1', certain: true }) }) it('cuando los proveedores comparten municipio, el territorio es cierto desde allí', () => { const graph = buildTerritoryGraph(twoSuppliers({ second: { municipality: { id: 7, name: 'La Mesa' }, department: { id: 2, name: 'Cundinamarca' } }, })) expect(edgeOf(graph, 'product:1', 'junction:1').certain).toBe(true) expect(edgeOf(graph, 'junction:1', 'supplier:5').certain).toBe(false) expect(edgeOf(graph, 'supplier:5', 'municipality:7')).toEqual({ from: 'supplier:5', to: 'municipality:7', certain: true }) expect(edgeOf(graph, 'supplier:6', 'municipality:7')).toEqual({ from: 'supplier:6', to: 'municipality:7', certain: true }) expect(edgeOf(graph, 'municipality:7', 'department:2').certain).toBe(true) expect(edgeOf(graph, 'department:2', 'country:1').certain).toBe(true) }) it('municipios distintos pero mismo departamento: dudoso hasta el municipio y cierto desde el departamento', () => { const graph = buildTerritoryGraph(twoSuppliers({ second: { department: { id: 2, name: 'Cundinamarca' } }, })) expect(edgeOf(graph, 'supplier:5', 'municipality:7').certain).toBe(false) expect(edgeOf(graph, 'supplier:6', 'municipality:8').certain).toBe(false) expect(edgeOf(graph, 'municipality:7', 'department:2')).toEqual({ from: 'municipality:7', to: 'department:2', certain: true }) expect(edgeOf(graph, 'municipality:8', 'department:2')).toEqual({ from: 'municipality:8', to: 'department:2', certain: true }) expect(edgeOf(graph, 'department:2', 'country:1').certain).toBe(true) }) it('municipios y departamentos distintos mantienen la duda, y el país común es cierto', () => { const graph = buildTerritoryGraph(twoSuppliers()) expect(edgeOf(graph, 'supplier:5', 'municipality:7').certain).toBe(false) expect(edgeOf(graph, 'municipality:7', 'department:2').certain).toBe(false) expect(edgeOf(graph, 'supplier:6', 'municipality:8').certain).toBe(false) expect(edgeOf(graph, 'municipality:8', 'department:3').certain).toBe(false) expect(edgeOf(graph, 'department:2', 'country:1')).toEqual({ from: 'department:2', to: 'country:1', certain: true }) expect(edgeOf(graph, 'department:3', 'country:1')).toEqual({ from: 'department:3', to: 'country:1', certain: true }) }) it('no crea nodos de territorio cuando el proveedor no tiene municipio', () => { const data = [ { product: { id: 1, name: 'Panela' }, suppliers: [{ supplier: { id: 5, name: 'La Mesa' }, municipality: null, department: null, country: null }], }, ] const graph = buildTerritoryGraph(data) expect(graph.nodes.map(n => n.id)).toEqual(['product:1', 'supplier:5']) expect(graph.edges).toEqual([{ from: 'product:1', to: 'supplier:5', certain: true }]) }) })