// Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later package app import ( "context" "os" "os/exec" "testing" "time" "git.stormux.org/storm/cthulhu/internal/atspi" ) // Standard web progress must reach the shared handler without Steam policy. func TestNativeBrowserProgress(t *testing.T) { if os.Getenv("CTHULHU_NATIVE_BROWSER") != "1" { t.Skip("requires private browser session") } ctx, cancel := context.WithTimeout(context.Background(), 25*time.Second) defer cancel() adapter := atspi.New() if err := adapter.Start(ctx); err != nil { t.Fatal(err) } defer adapter.Stop(context.Background()) if output, err := exec.CommandContext(ctx, "xdotool", "key", "--clearmodifiers", "Tab").CombinedOutput(); err != nil { t.Fatalf("fixture focus: %s, %v", output, err) } for { select { case event := <-adapter.Events(): if event.Type == atspi.FocusedStateEvent && event.Detail1 == 1 && event.Source.Name == "Update progress" { goto focused } case <-ctx.Done(): t.Fatal("update button focus missing") } } focused: speech := &fakeSpeechQueue{spoken: make(chan string, 8), requests: make(chan speechRequest, 8)} handler := &accessibilityEventHandler{state: &eventLoopState{}, speech: speech} if output, err := exec.CommandContext(ctx, "xdotool", "key", "--clearmodifiers", "space").CombinedOutput(); err != nil { t.Fatalf("update progress: %s, %v", output, err) } seen := make(map[string]bool) for len(seen) < 2 { select { case event := <-adapter.Events(): if !isValueChangeEvent(event.Type) || event.Source.Role != "progress bar" { continue } wantTone := "" switch event.Source.Name { case "Native progress": wantTone = "generated-progress-tone:20" case "ARIA progress": wantTone = "generated-progress-tone:30" default: continue } if seen[event.Source.Name] { continue } if !handler.handle_progress_bar(event) || len(speech.requests) != 1 { t.Fatalf("web progress was lost: %+v", event) } request := <-speech.requests if len(request.Sound) != 1 || request.Sound[0].Name != wantTone || !request.Append || request.Text != "" { t.Fatalf("web progress output: %+v", request) } seen[event.Source.Name] = true case <-ctx.Done(): t.Fatalf("web progress events missing; received %v", seen) } } }