From c5ae9d9d19595aea520bb1cbd1bb30fce9aadc16 Mon Sep 17 00:00:00 2001 From: borjaperfra Date: Mon, 21 Sep 2026 19:22:18 +0200 Subject: [PATCH] fix(auth): decir como salir del prompt al que mandamos a la gente Dos cosas que salieron revisando la #25 despues de mergearla. El mensaje del login dice que si el enlace no ha llegado vuelvas a lanzar el comando, y lo dice desde dentro de `Paste the link:`, que es un prompt que bloquea. La linea vacia que uno prueba para salir es la unica salida que no lo es: vuelve como `nothing pasted` y exit 1, que se lee como que el login ha fallado y no como que te has ido. Ahora dice ctrl-c, que es lo que hay. Y el test del panel afirmaba sobre "15 minutes" llamando a View sin fijar m.lay, asi que dependia del 80x24 por defecto y de donde m.wrapped partiera la linea: a 60 columnas sale "expires 15 / minutes" y el test falla con la pantalla correcta. Fija el tamano como hacen los demas tests del fichero y compara contra la pantalla con los saltos colapsados - que "15 minutes" sobreviva junto en una linea es cosa del renderer. Comprobado a 60, 80 y 120 columnas, y sigue fallando si LinkValidity cambia a 20 minutos. Co-Authored-By: Claude Opus 5 (1M context) --- cmd/auth.go | 8 +++++++- internal/tui/config_test.go | 13 ++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/cmd/auth.go b/cmd/auth.go index 613a74a..80b639c 100644 --- a/cmd/auth.go +++ b/cmd/auth.go @@ -116,7 +116,13 @@ func runLogin(cmd *cobra.Command, args []string) error { fmt.Println("Copy the link out of the email. Don't open it in your browser first:") fmt.Println("the link works once, and the browser would spend it.") fmt.Printf("It also expires %s after it is sent — an email that turns up late\n", auth.LinkValidity) - fmt.Println("turns up dead, so if it has not arrived, run this command again.") + // Saying "run this command again" and stopping there sent people at a + // blocking prompt looking for a way out of it. The empty line they reach + // for is the one exit that is not one: it comes back as `nothing pasted` + // and exit 1, which reads like the login failed rather than like they + // left it. + fmt.Println("turns up dead. If it has not arrived, leave with ctrl-c and run") + fmt.Println("this command again.") fmt.Println() fmt.Print("Paste the link: ") diff --git a/internal/tui/config_test.go b/internal/tui/config_test.go index 1133727..1879c7a 100644 --- a/internal/tui/config_test.go +++ b/internal/tui/config_test.go @@ -1765,6 +1765,12 @@ func TestHomeDropsTheGuideWhenSetupIsDone(t *testing.T) { // green and wrong at the same time. func TestSigningInHappensInsideThePanel(t *testing.T) { m := setupModel(t, &session.Session{}) + // Said out loud, because View wraps to it and truncates to it. Left to + // the zero value this asserted against whatever the default happened to + // be: at 60 columns the renderer breaks the sentence as "expires 15 / + // minutes" and at 80x20 the truncation eats it, so the test failed for a + // screen that was right. + m.lay = newLayout(90, 30) if m.loginStage != loginOff { t.Fatal("the panel opens mid-login") @@ -1790,8 +1796,13 @@ func TestSigningInHappensInsideThePanel(t *testing.T) { t.Fatal("an accepted request does not move on to the link") } out = m.View() + // Against the screen with its line breaks collapsed: whether "15 minutes" + // survives as two words on one line is the renderer's business and + // changes with one more word in the message. What this is here to catch + // is the sentence going missing. + flat := strings.Join(strings.Fields(out), " ") for _, want := range []string{"Let's confirm it with the magic link", "Paste the link", "15 minutes"} { - if !strings.Contains(out, want) { + if !strings.Contains(flat, want) { t.Errorf("the second step does not ask for the link:\n%s", out) } }