Files
don_confiao_frontend/tests/unit/components/provenance/ProvenanceMap.spec.js

225 lines
6.9 KiB
JavaScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
import { flushPromises, mount } from '@vue/test-utils'
import { nextTick } from 'vue'
import { createPinia, setActivePinia } from 'pinia'
import ProvenanceMap from '@/components/provenance/ProvenanceMap.vue'
import vuetify from '@/plugins/vuetify'
const leaflet = vi.hoisted(() => {
const markers = []
const polylines = []
const layers = []
function makeLayer (type) {
const layer = {
type,
addTo: vi.fn(function () { return this }),
on: vi.fn(),
bindTooltip: vi.fn(function () { return this }),
remove: vi.fn(),
}
layers.push(layer)
return layer
}
const map = {
setView: vi.fn(function () { return this }),
fitBounds: vi.fn(),
remove: vi.fn(),
invalidateSize: vi.fn(),
on: vi.fn(),
}
const bounds = { extend: vi.fn(), isValid: vi.fn(() => true) }
return {
markers,
polylines,
layers,
map,
bounds,
L: {
map: vi.fn(() => map),
tileLayer: vi.fn(() => makeLayer('tileLayer')),
marker: vi.fn((pos, opts) => {
const marker = makeLayer('marker')
marker.pos = pos
marker.opts = opts
markers.push(marker)
return marker
}),
divIcon: vi.fn(opts => opts),
polyline: vi.fn((points, opts) => {
const polyline = makeLayer('polyline')
polyline.points = points
polyline.opts = opts
polylines.push(polyline)
return polyline
}),
latLngBounds: vi.fn(() => bounds),
},
}
})
vi.mock('leaflet', () => ({ default: leaflet.L }))
const settings = { latitude: 4.6, longitude: -74.08, address: 'Cra 1 #2-3' }
const provenance = [
{
product: { id: 1, name: 'Panela regional', catalogue_images: ['http://localhost/media/panela.jpg'] },
suppliers: [
{
supplier: { id: 5, name: 'Asociación La Mesa' },
organization: { id: 3, name: 'Red de Economía Solidaria' },
municipality: { id: 7, name: 'Santa Bárbara', latitude: 6.23, longitude: -75.56 },
},
],
},
{
product: { id: 2, name: 'Arroz blanco', catalogue_images: [] },
suppliers: [
{ supplier: { id: 6, name: 'Campesinos del Oriente' }, municipality: { id: 8, name: 'La Mesa', latitude: 4.86, longitude: -74.63 } },
{ supplier: { id: 7, name: 'Finca El Paraíso' }, municipality: { id: 9, name: 'San Antonio', latitude: 6.22, longitude: -75.57 } },
],
},
]
function mountMap (props = {}) {
const api = { getStoreSettings: vi.fn().mockResolvedValue(settings) }
const pinia = createPinia()
setActivePinia(pinia)
const wrapper = mount(ProvenanceMap, {
props: { provenance, ...props },
global: {
plugins: [pinia, vuetify],
provide: { api },
},
})
return { api, wrapper }
}
function handlerOf (marker, event) {
return marker.on.mock.calls.find(args => args[0] === event)[1]
}
beforeEach(() => {
vi.clearAllMocks()
leaflet.markers.length = 0
leaflet.polylines.length = 0
leaflet.layers.length = 0
document.body.innerHTML = ''
})
describe('ProvenanceMap', () => {
it('carga la configuración de la tienda al montarse', async () => {
const { api } = mountMap()
await flushPromises()
expect(api.getStoreSettings).toHaveBeenCalled()
})
it('crea el mapa con la tienda y un marcador por municipio de origen', async () => {
mountMap()
await flushPromises()
expect(leaflet.L.map).toHaveBeenCalledTimes(1)
expect(leaflet.L.tileLayer).toHaveBeenCalledTimes(1)
expect(leaflet.markers).toHaveLength(4)
expect(leaflet.map.fitBounds).toHaveBeenCalled()
expect(leaflet.markers[0].bindTooltip).toHaveBeenCalled()
})
it('al pasar sobre un producto dibuja una línea hasta la tienda', async () => {
mountMap()
await flushPromises()
handlerOf(leaflet.markers[1], 'mouseover')()
expect(leaflet.L.polyline).toHaveBeenCalledTimes(1)
expect(leaflet.L.polyline.mock.calls[0][0]).toEqual([[6.23, -75.56], [4.6, -74.08]])
expect(leaflet.polylines[0].addTo).toHaveBeenCalled()
})
it('al pasar sobre la tienda dibuja las líneas de todos los productos', async () => {
mountMap()
await flushPromises()
handlerOf(leaflet.markers[0], 'mouseover')()
expect(leaflet.L.polyline).toHaveBeenCalledTimes(3)
})
it('al salir del marcador se limpian las líneas', async () => {
mountMap()
await flushPromises()
handlerOf(leaflet.markers[1], 'mouseover')()
expect(leaflet.polylines).toHaveLength(1)
handlerOf(leaflet.markers[1], 'mouseout')()
expect(leaflet.polylines[0].remove).toHaveBeenCalled()
})
it('al hacer clic en un producto abre el diálogo con el proveedor', async () => {
mountMap()
await flushPromises()
handlerOf(leaflet.markers[1], 'click')()
await nextTick()
expect(document.body.textContent).toContain('Asociación La Mesa')
expect(document.body.textContent).toContain('Panela regional')
})
it('no dibuja la línea de la tienda cuando la tienda no tiene coordenadas', async () => {
const api = { getStoreSettings: vi.fn().mockResolvedValue({ address: 'Cra 1' }) }
const pinia = createPinia()
setActivePinia(pinia)
mount(ProvenanceMap, {
props: { provenance },
global: {
plugins: [pinia, vuetify],
provide: { api },
},
})
await flushPromises()
expect(leaflet.markers).toHaveLength(3)
handlerOf(leaflet.markers[0], 'mouseover')()
expect(leaflet.L.polyline).not.toHaveBeenCalled()
})
it('muestra un aviso cuando ningún municipio tiene coordenadas', async () => {
const noCoords = [
{ product: { id: 1, name: 'Panela' }, suppliers: [{ supplier: { id: 5, name: 'A' }, municipality: { id: 7, name: 'M' } }] },
]
const { wrapper } = mountMap({ provenance: noCoords })
await flushPromises()
expect(leaflet.L.map).not.toHaveBeenCalled()
expect(wrapper.text()).toContain('coordenadas')
})
it('lee las coordenadas string del backend y da fondo visible al producto sin imagen', async () => {
const backendProvenance = [
{
product: { id: 110, name: 'Panela condimentada 150 grs', catalogue_images: [] },
suppliers: [
{
supplier: { id: 4, name: 'Asociación Agropecuaria La Mesa' },
organization: null,
municipality: { id: 2653, name: 'LA MESA', latitude: '4.6310280', longitude: '-74.4615880' },
department: { id: 91, name: 'Cundinamarca' },
country: { id: 3, name: 'Colombia', code: 'CO' },
},
],
},
]
mountMap({ provenance: backendProvenance })
await flushPromises()
expect(leaflet.L.map).toHaveBeenCalledTimes(1)
expect(leaflet.markers).toHaveLength(2)
expect(leaflet.markers[1].pos).toEqual([4.631028, -74.461588])
const productIcon = leaflet.L.divIcon.mock.calls.find(args => args[0].html.includes('provenance-product-fallback'))
expect(productIcon).toBeDefined()
})
})