From 217ea590c523b7b85cbbede628bb410af089d69f Mon Sep 17 00:00:00 2001 From: PJ Date: Sun, 16 Aug 2026 01:46:11 +0530 Subject: [PATCH] test(runner): cover the silently dropped log fetch Claude-Session: https://claude.ai/code/session_01ShuAy8q8ZfPi8KHxwc8JpQ --- internal/runner/web_last_action_test.go | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/internal/runner/web_last_action_test.go b/internal/runner/web_last_action_test.go index 34a247c..6f66304 100644 --- a/internal/runner/web_last_action_test.go +++ b/internal/runner/web_last_action_test.go @@ -1,9 +1,12 @@ package runner import ( + "bytes" "context" "encoding/json" "errors" + "log/slog" + "strings" "testing" "time" @@ -121,6 +124,37 @@ func TestRunner_WebInstallsTheStepsLogsInThePage(t *testing.T) { } } +// A log fetch that fails decides the verdict of every log property: they all +// evaluate against an empty slice and hold. That is not a fact about the app, +// so the step it happened on has to be visible in the run's output. It used to +// be dropped in silence, under a comment claiming it was warned about. +func TestRunner_ReportsALogFetchItCouldNotMake(t *testing.T) { + state := newHarnessWithSpec(t, lastActionSpec) + state.mock.Failures[mockdriver.ActionRecentLogs] = errors.New("adb: device offline") + + var buffer bytes.Buffer + logger := slog.New(slog.NewTextHandler(&buffer, &slog.HandlerOptions{Level: slog.LevelWarn})) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if _, err := Run(ctx, Options{ + Duration: time.Hour, + IdleTimeout: 20 * time.Millisecond, + MaxSteps: 2, + Driver: state.mock, + Verifier: state.verifier, + TraceWriter: state.writer, + Logger: logger, + }); err != nil { + t.Fatalf("Run: %v", err) + } + + if !strings.Contains(buffer.String(), "adb: device offline") { + t.Errorf("the run never reported the failed log fetch, so noLogcatErrors "+ + "held on evidence nobody collected; log was %q", buffer.String()) + } +} + // failingTapWebDriver dispatches the tap and then fails the call, the shape an // RPC deadline takes: the page has the click, the runner has an error. type failingTapWebDriver struct {