Saltar al contenido
Development

El error de escape que solo aparece con un segundo parámetro de consulta

Por Victor Da Luz
astrotestingdev-logastro-tools

Mi paquete de enlaces de afiliados tiene una función que redirige HTML ya renderizado para reposteos: cambia la etiqueta de Amazon del sitio canónico por una específica de Medium, por ejemplo, sin recompilar la página. Construye un mapa de URL por defecto a URL de canal y hace sustitución exacta de cadenas contra la salida renderizada.

Tenía exactamente un error latente, y ese error solo existe en URLs que todavía no existen.

Un error sin víctima actual

buildChannelRewriteMap indexa su mapa de sustitución con la URL resuelta cruda. rewriteAffiliateLinksForChannel hace coincidencia exacta de cadenas contra el HTML renderizado buscando esa clave.

El problema: el HTML renderizado escapa & como & dentro de los atributos href. Una URL con dos parámetros de consulta, ?tag=example-20&ref=homepage, se renderiza como ?tag=example-20&ref=homepage en la página real. La clave cruda del mapa nunca coincide. El reposteo mantiene la etiqueta por defecto en silencio, y nada indica que falló. Ni un error de build, ni una advertencia, solo datos de atribución equivocados fluyendo calladamente hacia algún dashboard.

Hoy, cada URL que toca esta función tiene exactamente un parámetro de consulta. Ningún & en ninguna parte. El error nunca se ha disparado en producción. Está a un solo parámetro de consulta agregado de convertirse en un problema real y silencioso de calidad de datos, del tipo que se descubre semanas después mirando números de reportes de Associates que no cuadran.

Escribir una prueba para un error que todavía no existe

Los fixtures existentes eran todos URLs de un solo parámetro, lo que significaba que pasarían sin importar si el arreglo funcionaba o no. Una suite de pruebas en verde hoy no es prueba de nada si ninguno de los fixtures puede ejercitar el modo de falla. Agregué un segundo programa con una URL de dos parámetros específicamente para tener un ampersand real que escapar, y después una prueba que verifica la reescritura contra HTML con la forma real que renderiza un navegador, la forma escapada, no la cruda:

const html = '<a href="https://example.com/deal?ref=site&amp;utm_source=site">Deal</a>';
const rewritten = rewriteAffiliateLinksForChannel(html, config, 'medium');
assert.equal(rewritten, '<a href="https://example.com/deal?ref=site-medium&amp;utm_source=site">Deal</a>');

El arreglo en sí es pequeño: agregar al mapa la variante escapada de cada URL por defecto que contenga un ampersand, apuntando a la URL de canal escapada, con una guarda para que las URLs de un solo parámetro no reciban una entrada duplicada sin sentido.

map[defaultResolved.url] = channelResolved.url;
const escapedDefault = defaultResolved.url.replace(/&/g, '&amp;');
if (escapedDefault !== defaultResolved.url) {
  map[escapedDefault] = channelResolved.url.replace(/&/g, '&amp;');
}

También en este lote

Tres cosas más pequeñas llegaron en el mismo release, ya que tocaban el mismo paquete. El constructor de URLs tenía www.amazon.com fijo en el código; un post planeado para el mercado brasileño necesita amazon.com.br con su propia etiqueta de Associates, así que ahora eso es un campo domain en la configuración del programa, con el dominio de EE. UU. por defecto para que nada existente cambie. AffiliateDisclosure acepta una prop locale y una forma de texto de divulgación localizado desde hace tiempo, y el README nunca mencionó ninguna de las dos cosas, una función real y funcional invisible para cualquiera que no hubiera leído el código fuente. Y tres de los cuatro paquetes hermanos de esta familia tienen un archivo de convenciones para futuras sesiones de agente; a este le faltaba, así que recibió la plantilla con un ajuste para lo que este paquete hace distinto.

Qué revisaría la próxima vez

“Esto nunca se ha roto en producción” no es la misma afirmación que “esto no se puede romper.” Las URLs de Amazon tienen un solo parámetro por casualidad de lo que el esquema de Amazon necesita hoy, no por ninguna garantía de que eso siga siendo así. Los fixtures de prueba que solo pueden ejercitar el camino que funciona dan una falsa sensación de confianza. Cuando un reporte describe una clase de entrada que los fixtures no cubren, hay que agregar un fixture que la cubra antes de tocar el arreglo, para que la prueba realmente pueda fallar con el código viejo.

Lecturas relacionadas