Files
soft_usite/pkg/services/soporte_ingesta_test.go
T
Lizandro GuarnizoandClaude Opus 5 d1bbb4a508 feat(soporte): avisar por Telegram cuando entra un correo, con resumen si es largo
Los tickets del portal ya avisaban por Telegram; los que entran por correo solo
mandaban un mail al admin, que es justo el canal que nadie mira a tiempo. Ahora
pasan por el mismo despachador de notificaciones, así que se prenden y apagan
desde /app/notif-config como cualquier otro evento — nuevo ticket y respuesta
del cliente por separado.

El cuerpo del aviso es un resumen cuando el correo pasa los 700 caracteres
(hilos reenviados, texto pegado); abajo de eso va tal cual, porque resumir tres
renglones es gastar una llamada de IA para decir lo mismo. Si la IA falla, se
manda recortado. El ticket guarda siempre el texto completo.

DispatchTicketNuevo ahora acepta portalUser nil: un correo no tiene usuario de
portal detrás y no por eso hay que dejar de avisar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 19:12:36 -05:00

93 lines
2.6 KiB
Go

package services
import (
"testing"
)
func TestExtractEmailSimple(t *testing.T) {
tests := []struct {
input string
want string
}{
{"user@example.com", "user@example.com"},
{"<user@example.com>", "user@example.com"},
{"John Doe <john@example.com>", "john@example.com"},
{"\"John Doe\" <john@example.com>", "john@example.com"},
{" spaced@example.com ", "spaced@example.com"},
{"", ""},
{"<onlybrackets>", "onlybrackets"},
}
for _, tt := range tests {
got := ExtraerEmail(tt.input)
if got != tt.want {
t.Errorf("ExtraerEmail(%q) = %q, want %q", tt.input, got, tt.want)
}
}
}
func TestExtractNameSimple(t *testing.T) {
tests := []struct {
input string
want string
}{
{"John Doe <john@example.com>", "John Doe"},
{"<user@example.com>", ""},
{"user@example.com", ""},
{" Spaces Here <spaces@example.com>", "Spaces Here"},
{"\"Quoted Name\" <q@example.com>", "\"Quoted Name\""},
{"", ""},
}
for _, tt := range tests {
got := ExtraerNombre(tt.input)
if got != tt.want {
t.Errorf("ExtraerNombre(%q) = %q, want %q", tt.input, got, tt.want)
}
}
}
func TestExtractEmailRealWorld(t *testing.T) {
inputs := []struct {
full string
mail string
name string
}{
{"María López <maria@example.com>", "maria@example.com", "María López"},
{"soporte@u-s.app", "soporte@u-s.app", ""},
{"Cliente Final <cliente+tag@dominio.co>", "cliente+tag@dominio.co", "Cliente Final"},
{"", "", ""},
}
for _, tt := range inputs {
gotMail := ExtraerEmail(tt.full)
gotName := ExtraerNombre(tt.full)
if gotMail != tt.mail {
t.Errorf("ExtraerEmail(%q) = %q, want %q", tt.full, gotMail, tt.mail)
}
if gotName != tt.name {
t.Errorf("ExtraerNombre(%q) = %q, want %q", tt.full, gotName, tt.name)
}
}
}
func TestExtractEmailEdgeCases(t *testing.T) {
// Formato RFC 5322 con nombre y ángulos
if got := ExtraerEmail("a<b@c.com>"); got != "b@c.com" {
t.Errorf("ExtraerEmail('a<b@c.com>') = %q, want 'b@c.com'", got)
}
// Múltiples brackets — usa el último par
if got := ExtraerEmail("<a><b@c.com>"); got != "b@c.com" {
t.Errorf("ExtraerEmail('<a><b@c.com>') = %q, want 'b@c.com'", got)
}
}
func TestResumirTextoSoporteCortoNoLlamaALaIA(t *testing.T) {
// Sin base de datos, cualquier llamada a la IA explota: que este caso pase
// es la prueba de que un correo corto no la usa.
corto := "Hola, no me llega la factura de marzo. Gracias."
if got := ResumirTextoSoporte(corto); got != corto {
t.Errorf("ResumirTextoSoporte devolvió %q, esperaba el texto tal cual", got)
}
if got := ResumirTextoSoporte(" " + corto + "\n"); got != corto {
t.Errorf("no recortó los espacios: %q", got)
}
}