14 servicios eliminados, 7 controllers local-only, crons locales, config sin MONDAY_*, frontend sin banners/avisos Monday. 552 tests API + 7 apps construidas.
121 lines
4.5 KiB
TypeScript
121 lines
4.5 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { cleanup, fireEvent, render, screen } from '@testing-library/react'
|
|
import AltaClientePage from './AltaClientePage'
|
|
import type { LeadResumen } from '../services/api'
|
|
|
|
type FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>
|
|
|
|
const LEAD: LeadResumen = {
|
|
id: 'lead-9',
|
|
nombre: 'María Fernanda López',
|
|
telefono: '4771234567',
|
|
email: 'maria@correo.com',
|
|
estado: 'NUEVO',
|
|
origen: 'Web',
|
|
fuente: 'lead',
|
|
}
|
|
|
|
const respuestaOk = (data: unknown) =>
|
|
new Response(JSON.stringify(data), { status: 200, headers: { 'Content-Type': 'application/json' } })
|
|
|
|
let fetchMock: ReturnType<typeof vi.fn<FetchFn>>
|
|
|
|
beforeEach(() => {
|
|
fetchMock = vi.fn<FetchFn>().mockImplementation((input) => {
|
|
const url = String(input)
|
|
if (url.includes('/borradores')) {
|
|
// Un borrador para que la pantalla inicial sea el picker
|
|
return Promise.resolve(
|
|
respuestaOk([{ id: 'b-1', nombre: 'Borrador previo', paso: 0, updatedAt: '2026-08-20T10:00:00Z' }]),
|
|
)
|
|
}
|
|
if (url.includes('/leads/buscar')) return Promise.resolve(respuestaOk([LEAD]))
|
|
return Promise.reject(new Error(`fetch inesperado: ${url}`))
|
|
})
|
|
vi.stubGlobal('fetch', fetchMock)
|
|
})
|
|
|
|
afterEach(() => {
|
|
cleanup()
|
|
vi.unstubAllGlobals()
|
|
})
|
|
|
|
describe('AltaClientePage — pantalla de entrada', () => {
|
|
it('muestra las dos opciones de alta', async () => {
|
|
render(<AltaClientePage />)
|
|
|
|
expect(await screen.findByRole('button', { name: /Alta Afluencia/ })).toBeTruthy()
|
|
expect(screen.getByRole('button', { name: /Alta de Cliente/ })).toBeTruthy()
|
|
})
|
|
|
|
it('"Alta de Cliente" navega al picker (borradores + búsqueda de lead)', async () => {
|
|
render(<AltaClientePage />)
|
|
|
|
fireEvent.click(await screen.findByRole('button', { name: /Alta de Cliente/ }))
|
|
|
|
expect(await screen.findByLabelText(/Buscar lead/)).toBeTruthy()
|
|
expect(screen.getByText('Borrador previo')).toBeTruthy()
|
|
})
|
|
|
|
it('"Alta Afluencia" muestra el formulario y "Volver" regresa a la entrada', async () => {
|
|
render(<AltaClientePage />)
|
|
|
|
fireEvent.click(await screen.findByRole('button', { name: /Alta Afluencia/ }))
|
|
expect(await screen.findByLabelText(/^Nombre/)).toBeTruthy()
|
|
|
|
fireEvent.click(screen.getByRole('button', { name: 'Volver' }))
|
|
expect(await screen.findByRole('button', { name: /Alta de Cliente/ })).toBeTruthy()
|
|
})
|
|
})
|
|
|
|
describe('AltaClientePage — alta desde lead capturado', () => {
|
|
it('al elegir un lead el wizard arranca con datosGenerales prellenados', async () => {
|
|
render(<AltaClientePage />)
|
|
|
|
// Entrada → Alta de Cliente → picker con la sección de búsqueda
|
|
fireEvent.click(await screen.findByRole('button', { name: /Alta de Cliente/ }))
|
|
const busqueda = await screen.findByLabelText(/Buscar lead/)
|
|
fireEvent.change(busqueda, { target: { value: 'maria' } })
|
|
fireEvent.click(await screen.findByText('María Fernanda López'))
|
|
|
|
// Wizard paso 1 con los campos del lead ya capturados
|
|
const nombre = (await screen.findByLabelText(/Nombre completo/)) as HTMLInputElement
|
|
expect(nombre.value).toBe('MARÍA FERNANDA LÓPEZ')
|
|
expect((screen.getByLabelText(/Correo electrónico|Email/i) as HTMLInputElement).value).toBe('maria@correo.com')
|
|
expect((screen.getByLabelText(/Celular/i) as HTMLInputElement).value).toBe('4771234567')
|
|
})
|
|
})
|
|
|
|
describe('AltaClientePage — alta desde cotización (?cotizacion=<id>)', () => {
|
|
it('se salta la entrada y va directo al wizard prellenado', async () => {
|
|
window.history.pushState({}, '', '/?cotizacion=cot-1')
|
|
fetchMock.mockImplementation((input) => {
|
|
const url = String(input)
|
|
if (url.includes('/cotizaciones/cot-1')) {
|
|
return Promise.resolve(
|
|
respuestaOk({
|
|
clienteNombre: 'Cliente Prueba',
|
|
clienteEmail: 'cliente@correo.com',
|
|
clienteTelefono: '6645550000',
|
|
desarrollo: 'SENDA',
|
|
unidadCodigo: 'U-101',
|
|
precioFinal: 1500000,
|
|
enganche: 150000,
|
|
}),
|
|
)
|
|
}
|
|
return Promise.reject(new Error(`fetch inesperado: ${url}`))
|
|
})
|
|
try {
|
|
render(<AltaClientePage />)
|
|
|
|
// Wizard directo, sin pasar por la entrada
|
|
const nombre = (await screen.findByLabelText(/Nombre completo/)) as HTMLInputElement
|
|
expect(nombre.value).toBe('CLIENTE PRUEBA')
|
|
expect(screen.queryByRole('button', { name: /Alta Afluencia/ })).toBeNull()
|
|
} finally {
|
|
window.history.pushState({}, '', '/')
|
|
}
|
|
})
|
|
})
|