Tengo un método para obtener datos de productos de una API. Uso Axios para llamar a la API. Dado que los datos del producto son independientes entre sí, llamo a todas las API a la vez y uso Promise.all para esperar a que se completen las llamadas antes de continuar. Por ejemplo, considere una función (no encerrada en una declaración de función) con líneas debajo.
const productIds = [ "SKU-1", "SKU-2" ]; const promises = productIds.map<Promise<Product>>(id => axios.get(`/products/${id}`)); Promise.all(promises).then(values => { // do some stuff here. });El caso de prueba de unidad escrito utiliza la implementación simulada de broma como se muestra a continuación.
import http from "axios"; import { sku1, sku2 } from "./test-product-data"; jest.mock("axios", () => ({ create: jest.fn(() => http), get: jest.fn(() => Promise.resolve()), })); const httpMock = http as jest.Mocked<typeof http>; describe("Update operations!", () => { beforeAll(() => { httpMock.get.mockImplementation(url => { // Call to Get product. if (url.endsWith("/SKU-1")) { mockedSuccessResponse.data = Object.assign({}, sku1); return Promise.resolve(mockedSuccessResponse); }; if (url.endsWith("/SKU-2")) { mockedSuccessResponse.data = Object.assign({}, sku2); return Promise.resolve(mockedSuccessResponse); }; }); }); }); Jest devuelve la respuesta de la última llamada API, es decir, la respuesta de SKU-2 incluso para el producto con id SKU-1 . ¿Me estoy perdiendo de algo?
Dado que está modificando la misma referencia de objeto ( mockedSuccessResponse.data ), los cambios posteriores sobrescribirán los anteriores. Esto significa que el objeto simulado ( sku2 ) para la url que termina con /SKU-2 anulará el mockedSuccessResponse.data . Cuando llamas a axios.get() en promise.all , ambos resolvieron los datos simulados de sku2 .
Solución: Cree diferentes objetos simulados para diferentes ramas condicionales.
P.ej
index.ts :
import axios from 'axios'; interface Product { id: string; } export function main() { const productIds = ['SKU-1', 'SKU-2']; const promises = productIds.map<Promise<Product>>((id) => axios.get(`/products/${id}`)); return Promise.all(promises); } index.test.ts :
import http from 'axios'; import { main } from './'; jest.mock('axios', () => ({ create: jest.fn(() => http), get: jest.fn(), })); const httpMock = http as jest.Mocked<typeof http>; describe('Update operations!', () => { const sku1 = { id: 'sku-1' }; const sku2 = { id: 'sku-2' }; beforeAll(() => { httpMock.get.mockImplementation((url: string): any => { if (url.endsWith('/SKU-1')) { return Promise.resolve({ data: Object.assign({}, sku1) }); } if (url.endsWith('/SKU-2')) { return Promise.resolve({ data: Object.assign({}, sku2) }); } }); }); test('should pass', async () => { const actual = await main(); expect(actual).toEqual([{ data: { id: 'sku-1' } }, { data: { id: 'sku-2' } }]); }); });Resultado de la prueba:
PASS examples/70599956/index.test.ts (9.178 s) Update operations! ✓ should pass (2 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 9.216 s