Para garantizar la fiabilidad en aplicaciones Vue.js, es esencial implementar pruebas efectivas. En este artículo, exploraremos cómo construir un store en Pinia que interactúe con una API externa y cómo realizar tests para validar su comportamiento y manejo de errores.
Primero, definimos un store de Pinia que maneje los datos de una API. Aquí tienes un ejemplo donde almacenamos información obtenida de una API externa:
import { defineStore } from "pinia";
export const useDataStore = defineStore({
id: "data",
state: () => ({
data: null,
error: {
message: "",
status: false
}
}),
actions: {
async fetchData(apiUrl: string) {
try {
if (this.data) {
return;
}
const { data } = await useAsyncData("data", () =>
$fetch(apiUrl)
);
if (data.value) {
this.data = data.value;
}
} catch (error) {
this.error.status = true;
this.error.message = "Error fetching data";
}
}
}
});
En este store, la función fetchData realiza una solicitud a una API externa y almacena los datos obtenidos en el estado.
Para las pruebas, utilizamos Vitest y creamos un mock de useAsyncData, la función que hace la solicitud a la API. Aquí te muestro cómo configurar los tests:
import { cleanup } from "@testing-library/vue";
import { vi, describe, it, expect, afterEach, beforeEach } from "vitest";
import { mockNuxtImport } from "@nuxt/test-utils/runtime";
import { setActivePinia, createPinia } from "pinia";
import { useDataStore } from "@/stores/data";
// Mock para useAsyncData
const useAsyncDataMock = vi.hoisted(() => vi.fn());
mockNuxtImport("useAsyncData", () => useAsyncDataMock);
const mockApiData = {
id: 1,
name: "Example",
detail: "This is an example"
};
// Mock para datos exitosos
const setupSuccessMock = () => {
useAsyncDataMock.mockImplementation(() => {
return {
data: ref(mockApiData),
error: ref(null),
};
});
};
afterEach(() => {
cleanup();
useAsyncDataMock.mockClear();
});
describe("Data Store", () => {
beforeEach(() => {
setActivePinia(createPinia());
});
describe("cuando los datos se obtienen con éxito", () => {
it("debería establecer los datos en el store", async () => {
const store = useDataStore();
setupSuccessMock();
await store.fetchData("https://api.example.com/data");
expect(store.data).toEqual(mockApiData);
});
});
describe("cuando los datos ya han sido obtenidos", () => {
it("no debería volver a hacer la solicitud", async () => {
const store = useDataStore();
setupSuccessMock();
await store.fetchData("https://api.example.com/data");
await store.fetchData("https://api.example.com/data");
expect(useAsyncDataMock).toHaveBeenCalledTimes(1);
});
});
describe("cuando la solicitud falla", () => {
it("debería establecer un mensaje de error", async () => {
const store = useDataStore();
useAsyncDataMock.mockImplementation(() => {
throw new Error("Error fetching data");
});
await store.fetchData("https://api.example.com/data");
expect(store.error.status).toBe(true);
expect(store.error.message).toBe("Error fetching data");
});
});
});
A continuación, desglosaremos cómo se realizan los tests clave para este store:
Mock de datos exitosos: Utilizamos setupSuccessMock para simular una respuesta exitosa de la API externa, asegurándonos de que el store guarde los datos de forma correcta
const setupSuccessMock = () => {
useAsyncDataMock.mockImplementation(() => {
return {
data: ref(mockApiData),
error: ref(null),
};
});
};
Verificación de almacenamiento de datos: Probamos que los datos obtenidos se guarden en el store tras una solicitud exitosa. Si la solicitud ya se ha hecho previamente, verificamos que no se vuelva a realizar.
describe("cuando los datos se obtienen con éxito", () => {
it("debería establecer los datos en el store", async () => {
const store = useDataStore();
setupSuccessMock();
await store.fetchData("https://api.example.com/data");
expect(store.data).toEqual(mockApiData);
});
});
Manejo de errores: Se simula un fallo en la solicitud para verificar que el store actualice su estado de error adecuadamente.
describe("cuando la solicitud falla", () => {
it("debería establecer un mensaje de error", async () => {
const store = useDataStore();
useAsyncDataMock.mockImplementation(() => {
throw new Error("Error fetching data");
});
await store.fetchData("https://api.example.com/data");
expect(store.error.status).toBe(true);
expect(store.error.message).toBe("Error fetching data");
});
});
Con esta configuración, puedes asegurarte de que tu store maneja los datos y errores de la API correctamente, lo cual es esencial para mantener la integridad y fiabilidad de las aplicaciones que dependen de datos externos.