177 lines
7.5 KiB
JavaScript
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([])
|
|
})
|
|
})
|