import test from 'node:test'; import assert from 'node:assert/strict'; import { collect } from '../src/sources/google-places.mjs'; function fakeCtx() { const logs = []; return { emit: () => {}, log: (message) => logs.push(message), isCancelled: () => false, logs }; } // Antes, uma falha na pagina 2/3 (comum: o next_page_token do Google ainda // nao ativou apesar da espera de 2.5s entre paginas, ou uma falha transitoria // de rede) fazia search() lancar e descartar TODOS os leads ja obtidos nas // paginas anteriores bem-sucedidas, nao so a pagina que falhou. test('falha na pagina 2 nao descarta os leads ja obtidos na pagina 1', async () => { process.env.GOOGLE_PLACES_API_KEY = 'chave-teste'; const originalFetch = globalThis.fetch; let textsearchCalls = 0; globalThis.fetch = async (url) => { const href = url.toString(); if (href.includes('textsearch')) { textsearchCalls += 1; if (textsearchCalls === 1) { return new Response(JSON.stringify({ status: 'OK', results: [{ place_id: 'p1', name: 'Pizzaria Um' }], next_page_token: 'tok-pagina-2' })); } // Pagina 2: falha transitoria (token ainda nao ativo, erro do provedor, etc.) return new Response(JSON.stringify({ status: 'INVALID_REQUEST' })); } if (href.includes('details')) { return new Response(JSON.stringify({ result: { place_id: 'p1', name: 'Pizzaria Um' } })); } throw new Error(`fetch inesperado: ${href}`); }; try { const ctx = fakeCtx(); const params = { uf: 'BA', cities: ['Salvador'], segments: [{ name: 'restaurantes', queries: ['pizzaria'], interest: 'comida', pains: [] }], limits: { maxPerQuery: 10, googlePages: 3 } }; const batches = []; for await (const batch of collect(params, ctx)) batches.push(batch); assert.equal(batches.length, 1, JSON.stringify(batches)); assert.equal(batches[0].leads.length, 1); assert.equal(batches[0].leads[0].company.name, 'Pizzaria Um'); assert.ok(ctx.logs.some((message) => /pagina 2/.test(message)), ctx.logs.join(' | ')); } finally { globalThis.fetch = originalFetch; delete process.env.GOOGLE_PLACES_API_KEY; } }); // Uma falha logo na primeira pagina (nada acumulado ainda) continua // propagando e sendo tratada pelo chamador (loga e pula a query inteira) — // esse caminho nao muda. test('falha na primeira pagina ainda propaga e pula a query', async () => { process.env.GOOGLE_PLACES_API_KEY = 'chave-teste'; const originalFetch = globalThis.fetch; globalThis.fetch = async () => new Response(JSON.stringify({ status: 'INVALID_REQUEST' })); try { const ctx = fakeCtx(); const params = { uf: 'BA', cities: ['Salvador'], segments: [{ name: 'restaurantes', queries: ['pizzaria'], interest: 'comida', pains: [] }], limits: { maxPerQuery: 10, googlePages: 3 } }; const batches = []; for await (const batch of collect(params, ctx)) batches.push(batch); assert.equal(batches.length, 0); assert.ok(ctx.logs.some((message) => /falhou em/.test(message)), ctx.logs.join(' | ')); } finally { globalThis.fetch = originalFetch; delete process.env.GOOGLE_PLACES_API_KEY; } });