fix(e2e/copilot): detect trust dialog case-insensitively · Entire
fix(e2e/copilot): detect trust dialog case-insensitively
0677238→main·
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
e2e/agents
- Mcopilot-cli.go+12/-2
Acopilot_trust_test.go+66
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")
}
}