feat: ecosistema FRASA — apps Cotizador, Alta Clientes, Cobranza y Landing
- Cotizador (/quote): 4 propuestas con formulas validadas del Excel, comparador, combobox de unidades, vigencia, PDF ANEXO A - Alta Clientes (/client): wizard 8 pasos, validacion CURP RENAPO, OCR de INE, checklist de expediente, firma digital, 5 PDFs legales - Cobranza (/pay): planes de enganche, mora, vista cobranza del dia, recibos PDF, bitacora, dashboard con filtros - Landing (/): entrada al ecosistema - Design system StudioBlank (monocromo, acento #1B4332) en las 4 apps - 123 tests vitest
This commit is contained in:
173
apps/alta-clientes/src/lib/schemas.test.ts
Normal file
173
apps/alta-clientes/src/lib/schemas.test.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import {
|
||||
datosGeneralesSchema,
|
||||
coacreditadoSchema,
|
||||
referenciasSchema,
|
||||
REGEX_CURP,
|
||||
REGEX_RFC,
|
||||
} from './schemas'
|
||||
import type { DatosGenerales } from '../types'
|
||||
|
||||
// Datos válidos base con el fixture del cliente del PDF de referencia
|
||||
const generalesValidos: DatosGenerales = {
|
||||
campaniaVenta: '',
|
||||
fecha: '2026-07-19',
|
||||
nombreCompleto: 'PASCUAL MARTIN TELLEZ CHIGUINDO',
|
||||
nacionalidad: 'MEXICANA',
|
||||
nivelEstudios: 'MAESTRIA',
|
||||
curp: 'TECP891124HBCLHS07',
|
||||
rfc: 'TECP8911246B4',
|
||||
nss: '',
|
||||
delegacionMunicipio: 'TIJUANA',
|
||||
direccion: 'RIO EUFRATES EDIF 1 7145 203',
|
||||
codigoPostal: '22223',
|
||||
antiguedadDomicilio: '2',
|
||||
fechaNacimiento: '1989-11-24',
|
||||
lugarNacimiento: 'TIJUANA',
|
||||
estadoCivil: 'SOLTERO',
|
||||
regimenBienes: '',
|
||||
peso: '87',
|
||||
estatura: '1.78',
|
||||
email: 'dantemartinchi@gmail.com',
|
||||
telCasa: '',
|
||||
celular: '6646935924',
|
||||
viviendaAnios: '2',
|
||||
tipoVivienda: 'PROPIA',
|
||||
tipoCompra: 'VIVIR_AHI',
|
||||
actividadOcupacion: 'AGENTE DEL MINISTERIO PUBLICO FEDERAL',
|
||||
}
|
||||
|
||||
describe('regex de identificadores', () => {
|
||||
it('acepta CURP válida', () => {
|
||||
expect(REGEX_CURP.test('TECP891124HBCLHS07')).toBe(true)
|
||||
})
|
||||
|
||||
it('rechaza CURP inválida', () => {
|
||||
expect(REGEX_CURP.test('TECP891124HBCLHS0')).toBe(false) // corta
|
||||
expect(REGEX_CURP.test('tecp891124hbclhs07')).toBe(false) // minúsculas
|
||||
expect(REGEX_CURP.test('TECP89112XHBCLHS07')).toBe(false) // fecha inválida
|
||||
})
|
||||
|
||||
it('acepta RFC válido', () => {
|
||||
expect(REGEX_RFC.test('TECP8911246B4')).toBe(true)
|
||||
})
|
||||
|
||||
it('rechaza RFC inválido', () => {
|
||||
expect(REGEX_RFC.test('TECP8911246B')).toBe(false) // corto
|
||||
expect(REGEX_RFC.test('TECP891124!B4')).toBe(false)
|
||||
expect(REGEX_RFC.test('tecp8911246b4')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('datosGeneralesSchema', () => {
|
||||
it('acepta los datos del fixture', () => {
|
||||
expect(datosGeneralesSchema.safeParse(generalesValidos).success).toBe(true)
|
||||
})
|
||||
|
||||
it('rechaza CURP inválida', () => {
|
||||
const r = datosGeneralesSchema.safeParse({ ...generalesValidos, curp: 'XXXX000000XXXXXXX0' })
|
||||
expect(r.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rechaza RFC inválido', () => {
|
||||
const r = datosGeneralesSchema.safeParse({ ...generalesValidos, rfc: '123' })
|
||||
expect(r.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rechaza email inválido', () => {
|
||||
const r = datosGeneralesSchema.safeParse({ ...generalesValidos, email: 'no-es-correo' })
|
||||
expect(r.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rechaza código postal que no tenga 5 dígitos', () => {
|
||||
const r = datosGeneralesSchema.safeParse({ ...generalesValidos, codigoPostal: '2223' })
|
||||
expect(r.success).toBe(false)
|
||||
})
|
||||
|
||||
it('exige régimen de bienes solo cuando el estado civil es CASADO', () => {
|
||||
const casado = datosGeneralesSchema.safeParse({ ...generalesValidos, estadoCivil: 'CASADO' })
|
||||
expect(casado.success).toBe(false)
|
||||
const casadoConRegimen = datosGeneralesSchema.safeParse({
|
||||
...generalesValidos,
|
||||
estadoCivil: 'CASADO',
|
||||
regimenBienes: 'SEPARACION_BIENES',
|
||||
})
|
||||
expect(casadoConRegimen.success).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('coacreditadoSchema', () => {
|
||||
const base = {
|
||||
generales: { ...generalesValidos, nombreCompleto: '', curp: '', rfc: '', email: '', fechaNacimiento: '', celular: '' },
|
||||
empleo: {
|
||||
tipoEmpleo: '' as const,
|
||||
tipoEconomia: '' as const,
|
||||
compania: '',
|
||||
antiguedadAnios: '',
|
||||
antiguedadMeses: '',
|
||||
direccion: '',
|
||||
colonia: '',
|
||||
numero: '',
|
||||
codigoPostal: '',
|
||||
puesto: '',
|
||||
telefono: '',
|
||||
ext: '',
|
||||
delegacion: '',
|
||||
},
|
||||
economicos: {
|
||||
ingresosMensuales: 0,
|
||||
otrosIngresos: 0,
|
||||
gastosLuz: 0,
|
||||
gastosOtros: 0,
|
||||
dependientes: { personas: '', parentesco: '', edad: '' },
|
||||
},
|
||||
}
|
||||
|
||||
it('no exige datos del co-acreditado cuando el toggle está apagado', () => {
|
||||
const r = coacreditadoSchema.safeParse({ ...base, tieneCoacreditado: false })
|
||||
expect(r.success).toBe(true)
|
||||
})
|
||||
|
||||
it('exige el nombre del co-acreditado cuando el toggle está activo', () => {
|
||||
const r = coacreditadoSchema.safeParse({ ...base, tieneCoacreditado: true })
|
||||
expect(r.success).toBe(false)
|
||||
})
|
||||
|
||||
it('acepta co-acreditado con nombre cuando el toggle está activo', () => {
|
||||
const r = coacreditadoSchema.safeParse({
|
||||
...base,
|
||||
tieneCoacreditado: true,
|
||||
generales: { ...base.generales, nombreCompleto: 'MARIA LOPEZ PEREZ' },
|
||||
})
|
||||
expect(r.success).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('referenciasSchema', () => {
|
||||
const vacia = { nombre: '', telefono: '', parentesco: '', direccion: '' }
|
||||
|
||||
it('rechaza cuando ninguna referencia tiene nombre y teléfono', () => {
|
||||
const r = referenciasSchema.safeParse([vacia, vacia, vacia, vacia])
|
||||
expect(r.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rechaza referencia con nombre pero sin teléfono', () => {
|
||||
const r = referenciasSchema.safeParse([
|
||||
{ ...vacia, nombre: 'JOSE ARNOLDO MENDOZA' },
|
||||
vacia,
|
||||
vacia,
|
||||
vacia,
|
||||
])
|
||||
expect(r.success).toBe(false)
|
||||
})
|
||||
|
||||
it('acepta con al menos 1 referencia válida', () => {
|
||||
const r = referenciasSchema.safeParse([
|
||||
{ nombre: 'JOSE ARNOLDO MENDOZA', telefono: '6641887799', parentesco: 'AMIGO', direccion: 'ALTAMIRA' },
|
||||
vacia,
|
||||
vacia,
|
||||
vacia,
|
||||
])
|
||||
expect(r.success).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user