diff --git a/frontend/src/services/api.test.js b/frontend/src/services/api.test.js new file mode 100644 index 0000000..d5c67b0 --- /dev/null +++ b/frontend/src/services/api.test.js @@ -0,0 +1,123 @@ +/* +CI/CD Workshop +Copyright (C) 2025 OpenBokeron + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { getMenu, getPrices, getCiStatus, getBuildHistory } from './api'; + +describe('API services', () => { + beforeEach(() => { + vi.stubGlobal('fetch', vi.fn()); + }); + + afterEach(() => { + vi.unstubAllGlobals(); + }); + + describe('getMenu', () => { + it('devuelve datos del menu cuando la API responde correctamente', async () => { + const mockMenu = { + starters: ['Sopa'], + mains: ['Pescado al vapor'], + desserts: ['Fruta'], + }; + + fetch.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockMenu), + }); + + const result = await getMenu(); + + expect(fetch).toHaveBeenCalledWith('/taller/api/menu'); + expect(result).toEqual(mockMenu); + }); + + it('lanza error cuando la API falla', async () => { + fetch.mockResolvedValueOnce({ + ok: false, + status: 500, + }); + + await expect(getMenu()).rejects.toThrow('Respuesta no valida del servidor'); + }); + }); + + describe('getPrices', () => { + it('devuelve array de items cuando la API responde', async () => { + const mockResponse = { + items: [ + { item: 'cafe', price: 1.2 }, + { item: 'tostada', price: 2.0 }, + ], + }; + + fetch.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockResponse), + }); + + const result = await getPrices(); + + expect(fetch).toHaveBeenCalledWith('/taller/api/prices'); + expect(result).toEqual(mockResponse.items); + }); + + it('devuelve array vacio si no hay items', async () => { + fetch.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve({}), + }); + + const result = await getPrices(); + + expect(result).toEqual([]); + }); + }); + + describe('getCiStatus', () => { + it('llama al endpoint /health', async () => { + const mockHealth = { status: 'ok', build: 42 }; + + fetch.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockHealth), + }); + + const result = await getCiStatus(); + + expect(fetch).toHaveBeenCalledWith('/taller/api/health'); + expect(result).toEqual(mockHealth); + }); + }); + + describe('getBuildHistory', () => { + it('llama al endpoint /builds', async () => { + const mockBuilds = { builds: [{ number: 1 }, { number: 2 }] }; + + fetch.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(mockBuilds), + }); + + const result = await getBuildHistory(); + + expect(fetch).toHaveBeenCalledWith('/taller/api/builds'); + expect(result).toEqual(mockBuilds); + }); + }); +});