Depurar un checkbox oculto en la interfaz real de Medium
Un ítem pequeño del backlog: hacer que el puente de importación de Medium de blog-manager active el paywall del Partner Program por defecto, ya que estoy inscrito y los posts canónicos/importados son completamente elegibles para generar ingresos. Debería haber sido un arreglo de una línea. Se convirtió en una tarde de depuración en vivo contra una cuenta real de Medium, porque el checkbox que necesitaba hacer clic no se comporta como un checkbox normal en absoluto.
Encontrar el checkbox
medium-bridge no se comunica con ninguna API de Medium para publicar, ya no queda ninguna que valga la pena usar, sino que maneja la interfaz web real de Medium con Playwright, tal como lo haría una persona al hacer clic a través del flujo “Import a story”. Así que “activar el metering por defecto” significaba encontrar el elemento DOM real del interruptor de paywall en el panel de prepublicación de Medium, y hacerle clic antes de confirmar.
No quería adivinar un selector a partir de la documentación y esperar que coincidiera con la página real, el propio texto de la interfaz de Medium ni siquiera coincide de forma consistente con su propio centro de ayuda (algunas páginas dicen “meter my story,” otras dicen “paywall your story”). Así que escribí un pequeño script de diagnóstico, lo copié dentro del contenedor de producción en ejecución, y lo corrí contra un borrador real para volcar cada checkbox del panel de prepublicación. Lo encontré de inmediato: un checkbox literalmente etiquetado “Paywall this story,” sin marcar por defecto. Bien, directo.
Pero cuando intenté hacerle clic, no pasó nada. Volcar su estilo computado explicó por qué: width: 0px, height: 0px, opacity: 0. El input real es invisible y de tamaño cero, ubicado detrás de un interruptor con estilo personalizado que sí se renderiza. El comportamiento de clic por defecto de Playwright exige que un elemento tenga un cuadro delimitador distinto de cero antes de interactuar con él, una verificación de seguridad totalmente razonable que existe para evitar que se haga clic en algo que un usuario real nunca podría ver, y exactamente la verificación que se interponía entre yo y este checkbox.
El checkbox que miente sobre estar deshabilitado
Una vez que cambié a verificar la presencia en el DOM en lugar de la visibilidad, apareció un segundo problema: el checkbox queda disabled por unos segundos justo después de la importación, y se habilita recién cuando Medium termina alguna verificación asíncrona de elegibilidad del lado del servidor. Confirmé esto sondeando el atributo disabled a través de varias importaciones de prueba en vivo, la ventana variaba de prácticamente instantánea a varios segundos, nunca un retraso fijo. Un input deshabilitado ignora en silencio las llamadas de clic y de check, incluso con la bandera force: true de Playwright, así que intentarlo demasiado pronto no arroja error, simplemente no hace nada en silencio. Mis primeras corridas de prueba parecían indicar que el arreglo no funcionaba en absoluto, hasta que me di cuenta de que estaba verificando antes de que Medium hubiera terminado de decidir si el post era elegible.
El arreglo: sondear el atributo disabled hasta por 15 segundos antes de intentar cualquier cosa, y avanzar solo una vez que se despeje. También vale la pena anotar para quien persiga errores parecidos: en cada corrida de prueba limpia, una vez que tuve el sondeo bien hecho, el checkbox terminaba ya marcado para cuando se habilitaba. Todavía no sé con certeza si ese es el valor por defecto real de Medium para cuentas elegibles o algo específico del historial de mi cuenta, pero el código no asume ninguna de las dos cosas. Verifica el estado actual y solo hace clic si sigue sin marcar, así que es correcto sin importar cuál resulte ser el verdadero valor por defecto de Medium.
Verificar contra una cuenta real, con cuidado
La única forma de saber si algo de esto funciona de verdad es correrlo contra la sesión real y autenticada de Medium, no hay entorno de staging para medium-bridge, ni cuenta de prueba. Eso significaba correr importaciones reales contra posts reales del blog, lo cual crea borradores reales (aunque inofensivos y eliminables), y eventualmente una publicación real para confirmar que la configuración de metering realmente tomó efecto en una historia en vivo.
Me propuse mantener cada paso lo más pequeño y reversible posible: primero solo importar (crea un borrador, sin publicar), abrir el panel de prepublicación y volcar su estado sin nunca hacer clic en confirmar, y recién correr una publicación completa una vez que estuve seguro de que la lógica era correcta. Cuando publiqué, fui a buscar la página real de la historia después y busqué la insignia propia de Medium “Member-only story”, confirmación real, externa, de la verdad de campo, en lugar de confiar en la salida de logs de mi propio código.
También me sorprendí dos veces a punto de recurrir a una herramienta más invasiva que la que había decidido que esta tarea ameritaba, la misma acción de fondo, con un envoltorio ligeramente distinto la segunda vez. Vale la pena nombrarlo: “solo voy a ajustar los parámetros y reintentar” es exactamente el instinto que convierte un enfoque razonable en una forma de eludir un límite recién establecido por uno mismo. Detenerme y volver a decidir con claridad fue la decisión correcta las dos veces.
Lo que detectó la revisión automatizada
Una vez que el camino feliz funcionó, corrí esto a través del mismo proceso de revisión que uso para los PRs normales. Tres ángulos de revisión independientes señalaron los mismos dos errores, lo cual es una buena señal de que eran reales: un waitFor que en realidad nunca podría ejecutarse porque una verificación count() anterior ya habría retornado antes, y un clic de respaldo que podía deshacer un checkbox que en realidad ya se había marcado con éxito (el check() de Playwright hace clic y luego, por separado, verifica el resultado, puede lanzar un error en esa verificación incluso cuando el clic en sí funcionó, y mi lógica de respaldo no contemplaba eso). Ambos son el tipo de cosa fácil de pasar por alto leyendo el propio código una sola vez, porque el camino feliz los enmascara por completo.
Qué sigue
Nada pendiente, esto ya está desplegado y verificado. Sí dejé seis borradores descartables en la cuenta de Medium por las pruebas, que no pude limpiar automáticamente (mis intentos de selector para el menú de borrar borradores de Medium no dieron en el blanco, y no valía la pena más interacción en vivo con producción para perseguir una tarea de limpieza puramente cosmética). Eliminación manual cuando sea conveniente.
Lecturas relacionadas
Medium seguía descartando mi imagen destacada, así que el bridge ahora la pega directamente
Dos teorías descartadas con una importación manual cada una, un paste que guardó las dimensiones pero no el src, y el camino del selector de archivos nativo que finalmente adjuntó la imagen.
El blog que no podía publicar según lo programado
Un diseño de proceso por lotes que empezó con una verificación de cinco minutos del sustrato: las publicaciones con fecha futura no estaban ocultas, eran errores 404, y nada reconstruía el sitio jamás.
Un interruptor por blog, y cuándo no "arreglar" un error
Un booleano que atraviesa cuatro capas, y tres pases de revisión independientes que coinciden en un hallazgo que decidí deliberadamente no arreglar, porque el caché es el mecanismo de deduplicación.