fix(e2e/copilot): detect trust dialog case-insensitively · Entire

fix(e2e/copilot): detect trust dialog case-insensitively

0677238main·

Soph·1mo ago·2 files·+78 added/-2 removed

Copilot v1.0.63 lowercased the trust-dialog footer from "Enter to select" to "enter to select". StartSession's dismissal loop matched the footer with an exact-case strings.Contains, so the dialog stopped being recognized: the loop saw the dialog's "❯ 1. Yes" selection cursor, mistook it for the interactive prompt, and broke out without pressing Enter. The still-open dialog then swallowed the first real prompt, and every interactive copilot-cli e2e test timed out on WaitFor("❯").

Make isStartupDialog() lowercase-fold the pane and match on the dialog title ("Confirm folder trust" / "Do you trust") as well as the footer, so a future footer-wording change can't silently re-break it. Also widen the WaitFor trigger regex to match the footer case-insensitively.

Adds copilot_trust_test.go with the real v1.0.63 dialog capture as a regression fixture, plus a negative case for the bare prompt.

Fixes the 5 TestInteractive* copilot-cli failures.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

Sessions

b6e5e8afae06View transcript

Changes

2

290 unmodified lines

// prompt. The dialog renders its selected option with the same "❯" cursor as
// the input prompt, so presence of "❯" alone cannot distinguish them — we must
// key off the dialog chrome.
//
// Matching is case-insensitive and keyed off both the dialog title and its
// footer: Copilot v1.0.63 lowercased the footer to "enter to select", which
// silently broke the previous exact "Enter to select" match and caused the
// harness to mistake the trust dialog's "❯ 1. Yes" cursor for the prompt —
// breaking out of the dismissal loop without dismissing the dialog, so the
// first real prompt was swallowed by the still-open dialog.
func isStartupDialog(content string) bool {
    return strings.Contains(content, "Enter to select")
    lower := strings.ToLower(content)
    return strings.Contains(lower, "confirm folder trust") ||
        strings.Contains(lower, "do you trust") ||
        strings.Contains(lower, "enter to select")
}

func (c *CopilotCLI) StartSession(ctx context.Context, dir string) (Session, error) {

// new directories. "Yes" is pre-selected, so Enter dismisses it.
foundPrompt := false
for range 5 {
    content, err := s.WaitFor(`(❯|Enter to select)`, 30*time.Second)
    content, err := s.WaitFor(`(❯|(?i:enter to select))`, 30*time.Second)
    if err != nil {
        _ = s.Close()
        return nil, fmt.Errorf("waiting for startup prompt: %w", err)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

package agents

import "testing"

// trustDialogPane is a trimmed capture of Copilot v1.0.63's interactive
// startup dialog. Note the footer renders the navigation hint lowercase
// ("enter to select") and the selected option uses the same "❯" cursor as the
// input prompt — the exact shape that broke the old exact-case detection.
const trustDialogPane = `╭───────────────────────────────────────────────────────────╮
│ Confirm folder trust                                        │
│                                                             │
│ /tmp/e2e-repo-457367550                                     │
│                                                             │
│ Copilot can read files in this folder and, with your        │
│ permission, edit them or run code and shell commands.       │
│                                                             │
│ Do you trust the files in this folder?                      │
│                                                             │
│ ❯ 1. Yes                                                    │
│   2. Yes, and remember this folder for future sessions      │
│   3. No (Esc)                                               │
│                                                             │
│ ↑/↓ to navigate · enter to select · esc to cancel           │
╰───────────────────────────────────────────────────────────╯`

// interactivePromptPane is the real idle prompt: a bare "❯" with no dialog
// chrome. This must NOT be classified as a startup dialog.
const interactivePromptPane = ` Tip: /app
 /tmp/e2e-repo-457367550 [master%]

❯

/ commands · ? help                                  Claude Haiku 4.5`

// TestIsStartupDialog_DetectsLowercaseTrustFooter is the regression guard for
// the Copilot v1.0.63 break: the trust dialog must be recognized even though
// its footer is lowercase ("enter to select"), so the StartSession dismissal
// loop keeps sending Enter instead of mistaking the "❯ 1. Yes" cursor for the
// interactive prompt and swallowing the first real prompt.
func TestIsStartupDialog_DetectsLowercaseTrustFooter(t *testing.T) {
    t.Parallel()
    if !isStartupDialog(trustDialogPane) {
        
t.Fatal("trust dialog with lowercase footer should be detected as a startup dialog")
    }
}

// TestIsStartupDialog_DetectsByTitle confirms detection keys off the dialog
// title too, so a footer-text change in a future Copilot release does not
// silently re-break the handshake.
func TestIsStartupDialog_DetectsByTitle(t *testing.T) {
    t.Parallel()
    const titleOnly = "│ Confirm folder trust │\n│ ❯ 1. Yes │"
    if !isStartupDialog(titleOnly) {
        t.Fatal("dialog title alone should be enough to detect a startup dialog")
    }
}

// TestIsStartupDialog_IgnoresInteractivePrompt ensures the real prompt is not
// classified as a dialog — otherwise StartSession would loop dismissing a
// dialog that isn't there and never hand back a usable session.
func TestIsStartupDialog_IgnoresInteractivePrompt(t *testing.T) {
    t.Parallel()
    if isStartupDialog(interactivePromptPane) {
        
t.Fatal("bare interactive prompt should not be classified as a startup dialog")
    }
}