Files
don_confiao_frontend/tests/unit/components/provenance/provenance-graph.spec.js

177 lines
7.5 KiB
JavaScript

import { describe, expect, it } from 'vitest'
import {
buildProvenanceGraph,
hasAnySupplier,
} from '@/components/provenance/provenance-graph'
const ALL_KINDS = ['product', 'supplier', 'organization', 'municipality', 'department', 'country']
const singleRelation = [
{
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' },
organization: { id: 3, name: 'Red de Economía Solidaria' },
municipality: { id: 7, name: 'La Mesa' },
department: { id: 2, name: 'Cundinamarca' },
country: { id: 1, name: 'Colombia' },
},
],
},
]
function twoSuppliers (overrides = {}) {
return [
{
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(singleRelation)).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('buildProvenanceGraph', () => {
it('por defecto solo grafica productos y proveedores', () => {
const graph = buildProvenanceGraph(singleRelation)
expect(graph.nodes.map(n => n.kind)).toEqual(['product', 'supplier'])
expect(graph.edges).toEqual([{ from: 'product:1', to: 'supplier:5', certain: true }])
})
it('con todos los niveles grafica la cadena completa y la organización', () => {
const graph = buildProvenanceGraph(singleRelation, ALL_KINDS)
expect(edgeOf(graph, 'product:1', 'supplier:5')).toEqual({ from: 'product:1', to: 'supplier:5', certain: true })
expect(edgeOf(graph, 'supplier:5', 'organization:3').certain).toBe(true)
expect(edgeOf(graph, 'supplier:5', 'municipality:7')).toEqual({ from: 'supplier:5', 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('con varios proveedores crea el punto de disyunción y la duda se propaga', () => {
const graph = buildProvenanceGraph(twoSuppliers(), ALL_KINDS)
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').certain).toBe(false)
expect(edgeOf(graph, 'junction:1', 'supplier:6').certain).toBe(false)
expect(edgeOf(graph, 'supplier:5', 'municipality:7').certain).toBe(false)
expect(edgeOf(graph, 'municipality:7', 'department:2').certain).toBe(false)
expect(edgeOf(graph, 'department:2', 'country:1').certain).toBe(true)
expect(edgeOf(graph, 'supplier:5', 'organization:3').certain).toBe(true)
})
it('omite los niveles no solicitados conectando el nivel previo con el siguiente', () => {
const graph = buildProvenanceGraph(singleRelation, ['product', 'supplier', 'department'])
expect(graph.nodes.map(n => n.kind)).toEqual(['product', 'supplier', 'department'])
expect(edgeOf(graph, 'supplier:5', 'department:2')).toEqual({ from: 'supplier:5', to: 'department:2', certain: true })
expect(edgeOf(graph, 'supplier:5', 'municipality:7')).toBeUndefined()
})
it('sin proveedores activos conecta el producto con el siguiente nivel', () => {
const graph = buildProvenanceGraph(singleRelation, ['product', 'municipality', 'department'])
expect(edgeOf(graph, 'product:1', 'municipality:7')).toEqual({ from: 'product:1', to: 'municipality:7', certain: true })
expect(edgeOf(graph, 'municipality:7', 'department:2').certain).toBe(true)
})
it('sin productos activos los proveedores quedan como raíces sin junction', () => {
const graph = buildProvenanceGraph(twoSuppliers(), ['supplier', 'municipality'])
expect(graph.nodes.some(n => n.kind === 'product')).toBe(false)
expect(graph.nodes.some(n => n.kind === 'junction')).toBe(false)
expect(edgeOf(graph, 'supplier:5', 'municipality:7').certain).toBe(false)
})
it('con país activo crea el nodo país aunque se omitan niveles intermedios', () => {
const graph = buildProvenanceGraph(singleRelation, ['product', 'supplier', 'country'])
expect(graph.nodes.map(n => n.id)).toContain('country:1')
expect(edgeOf(graph, 'supplier:5', 'country:1').certain).toBe(true)
})
it('no crea nodos de país si no se solicita', () => {
const graph = buildProvenanceGraph(singleRelation, ['product', 'supplier', 'municipality'])
expect(graph.nodes.some(n => n.kind === 'country')).toBe(false)
})
it('no duplica aristas cuando varios productos comparten proveedor y municipio', () => {
const data = [
{ product: { id: 1, name: 'Panela' }, suppliers: [{ supplier: { id: 5, name: 'A' }, municipality: { id: 7, name: 'La Mesa' }, department: { id: 2, name: 'Cundinamarca' } }] },
{ product: { id: 2, name: 'Arroz' }, suppliers: [{ supplier: { id: 5, name: 'A' }, municipality: { id: 7, name: 'La Mesa' }, department: { id: 2, name: 'Cundinamarca' } }] },
]
const graph = buildProvenanceGraph(data, ['product', 'supplier', 'municipality'])
expect(graph.nodes.filter(n => n.id === 'municipality:7')).toHaveLength(1)
expect(graph.edges.filter(e => e.from === 'supplier:5' && e.to === 'municipality:7')).toHaveLength(1)
})
it('si el mismo par de nodos repite con distinta certeza, gana la duda', () => {
const data = [
{ product: { id: 1, name: 'Panela' }, suppliers: [{ supplier: { id: 5, name: 'A' }, organization: { id: 3, name: 'Red' } }] },
{ product: { id: 2, name: 'Arroz' }, suppliers: [{ supplier: { id: 5, name: 'A' }, organization: { id: 3, name: 'Red' } }, { supplier: { id: 6, name: 'B' }, organization: { id: 4, name: 'Coop' } }] },
]
const graph = buildProvenanceGraph(data, ['product', 'supplier', 'organization'])
expect(graph.edges.filter(e => e.from === 'supplier:5' && e.to === 'organization:3')).toHaveLength(1)
expect(edgeOf(graph, 'supplier:5', 'organization:3').certain).toBe(false)
})
it('incluye la imagen y el detalle de la entidad del producto', () => {
const graph = buildProvenanceGraph(singleRelation)
const product = graph.nodes.find(n => n.id === 'product:1')
expect(product.image).toBe('http://localhost/media/panela.jpg')
expect(product.entity.kind).toBe('product')
})
it('devuelve un grafo vacío cuando no hay provenance', () => {
const graph = buildProvenanceGraph([])
expect(graph.nodes).toEqual([])
expect(graph.edges).toEqual([])
})
})