Stabilize permissions popup selection tests (#14966)

## What is flaky
The permissions popup tests in the TUI are flaky, especially on Windows.
They assume the popup opens on a specific row and that a fixed number of
`Up` or `Down` keypresses will land on a specific preset. They also
match popup text too loosely, so a non-selected row can satisfy the
assertion.

## Why it was flaky
These tests were asserting incidental rendering details rather than the
actual selected permission preset. On Windows, the initial selection can
differ from non-Windows runs. Some tests also searched the entire popup
for text like `Guardian Approvals` or `(current)`, which can match a row
that is visible but not selected. Once the popup order or current preset
shifted slightly, a test could fail even though the UI behavior was
still correct.

## How this PR fixes it
This PR adds helpers that identify the selected popup row and selected
preset name directly. The tests now assert the current selection by
name, navigate to concrete target presets instead of assuming a fixed
number of keypresses, and explicitly set the reviewer state in the cases
that require `Guardian Approvals` to be current.

## Why this fix fixes the flakiness
The assertions now track semantic state, not fragile text placement.
Navigation is target-based instead of order-based, so
Windows/non-Windows row differences and harmless popup layout changes no
longer break the tests. That removes the scheduler- and
platform-sensitive assumptions that made the popup suite intermittent.

Co-authored-by: Ahmed Ibrahim <219906144+aibrahim-oai@users.noreply.github.com>
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Ahmed Ibrahim
2026-03-17 13:45:44 -07:00
committed by GitHub
parent b02388672f
commit 23a44ddbe8

View File

@@ -6604,6 +6604,50 @@ fn render_bottom_popup(chat: &ChatWidget, width: u16) -> String {
lines.join("\n")
}
fn selected_permissions_popup_line(popup: &str) -> &str {
popup
.lines()
.find(|line| {
line.contains('')
&& (line.contains("Default")
|| line.contains("Read Only")
|| line.contains("Guardian Approvals")
|| line.contains("Full Access"))
})
.unwrap_or_else(|| {
panic!("expected permissions popup to have a selected preset row: {popup}")
})
}
fn selected_permissions_popup_name(popup: &str) -> &'static str {
selected_permissions_popup_line(popup)
.trim_start()
.strip_prefix('')
.map(str::trim_start)
.and_then(|line| line.split_once(". ").map(|(_, rest)| rest))
.and_then(|line| {
["Read Only", "Default", "Guardian Approvals", "Full Access"]
.into_iter()
.find(|label| line.starts_with(label))
})
.unwrap_or_else(|| {
panic!("expected permissions popup row to start with a preset label: {popup}")
})
}
fn move_permissions_popup_selection_to(chat: &mut ChatWidget, label: &str, direction: KeyCode) {
for _ in 0..4 {
let popup = render_bottom_popup(chat, 120);
if selected_permissions_popup_name(&popup) == label {
return;
}
chat.handle_key_event(KeyEvent::from(direction));
}
let popup = render_bottom_popup(chat, 120);
panic!("expected permissions popup to select {label}: {popup}");
}
#[tokio::test]
async fn apps_popup_stays_loading_until_final_snapshot_updates() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(None).await;
@@ -8333,7 +8377,25 @@ async fn permissions_selection_emits_history_cell_when_selection_changes() {
chat.config.notices.hide_full_access_warning = Some(true);
chat.open_permissions_popup();
let popup = render_bottom_popup(&chat, 120);
#[cfg(target_os = "windows")]
let expected_initial = "Read Only";
#[cfg(not(target_os = "windows"))]
let expected_initial = "Default";
assert!(
selected_permissions_popup_name(&popup) == expected_initial,
"expected permissions popup to open with {expected_initial} selected: {popup}"
);
chat.handle_key_event(KeyEvent::from(KeyCode::Down));
let popup = render_bottom_popup(&chat, 120);
#[cfg(target_os = "windows")]
let expected_after_one_down = "Default";
#[cfg(not(target_os = "windows"))]
let expected_after_one_down = "Full Access";
assert!(
selected_permissions_popup_name(&popup) == expected_after_one_down,
"expected moving down to select {expected_after_one_down} before confirmation: {popup}"
);
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
let cells = drain_insert_history(&mut rx);
@@ -8360,9 +8422,21 @@ async fn permissions_selection_history_snapshot_after_mode_switch() {
chat.config.notices.hide_full_access_warning = Some(true);
chat.open_permissions_popup();
chat.handle_key_event(KeyEvent::from(KeyCode::Down));
let popup = render_bottom_popup(&chat, 120);
#[cfg(target_os = "windows")]
chat.handle_key_event(KeyEvent::from(KeyCode::Down));
let expected_initial = "Read Only";
#[cfg(not(target_os = "windows"))]
let expected_initial = "Default";
assert!(
selected_permissions_popup_name(&popup) == expected_initial,
"expected permissions popup to open with {expected_initial} selected: {popup}"
);
move_permissions_popup_selection_to(&mut chat, "Full Access", KeyCode::Down);
let popup = render_bottom_popup(&chat, 120);
assert!(
selected_permissions_popup_name(&popup) == "Full Access",
"expected navigation to land on Full Access before confirmation: {popup}"
);
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
let cells = drain_insert_history(&mut rx);
@@ -8395,10 +8469,16 @@ async fn permissions_selection_history_snapshot_full_access_to_default() {
chat.open_permissions_popup();
let popup = render_bottom_popup(&chat, 120);
chat.handle_key_event(KeyEvent::from(KeyCode::Up));
if popup.contains("Guardian Approvals") {
chat.handle_key_event(KeyEvent::from(KeyCode::Up));
}
assert!(
selected_permissions_popup_name(&popup) == "Full Access",
"expected permissions popup to open with Full Access selected: {popup}"
);
move_permissions_popup_selection_to(&mut chat, "Default", KeyCode::Up);
let popup = render_bottom_popup(&chat, 120);
assert!(
selected_permissions_popup_name(&popup) == "Default",
"expected navigation to land on Default before confirmation: {popup}"
);
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
let cells = drain_insert_history(&mut rx);
@@ -8437,6 +8517,11 @@ async fn permissions_selection_emits_history_cell_when_current_is_selected() {
.expect("set sandbox policy");
chat.open_permissions_popup();
let popup = render_bottom_popup(&chat, 120);
assert!(
selected_permissions_popup_name(&popup) == "Default",
"expected permissions popup to open with Default selected: {popup}"
);
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
let cells = drain_insert_history(&mut rx);
@@ -8542,7 +8627,8 @@ async fn permissions_selection_marks_guardian_approvals_current_after_session_co
let popup = render_bottom_popup(&chat, 120);
assert!(
popup.contains("Guardian Approvals (current)"),
selected_permissions_popup_name(&popup) == "Guardian Approvals"
&& selected_permissions_popup_line(&popup).contains("(current)"),
"expected Guardian Approvals to be current after SessionConfigured sync: {popup}"
);
}
@@ -8597,7 +8683,8 @@ async fn permissions_selection_marks_guardian_approvals_current_with_custom_work
let popup = render_bottom_popup(&chat, 120);
assert!(
popup.contains("Guardian Approvals (current)"),
selected_permissions_popup_name(&popup) == "Guardian Approvals"
&& selected_permissions_popup_line(&popup).contains("(current)"),
"expected Guardian Approvals to be current even with custom workspace-write details: {popup}"
);
}
@@ -8622,9 +8709,22 @@ async fn permissions_selection_can_disable_guardian_approvals() {
.sandbox_policy
.set(SandboxPolicy::new_workspace_write_policy())
.expect("set sandbox policy");
chat.set_approvals_reviewer(ApprovalsReviewer::GuardianSubagent);
chat.open_permissions_popup();
chat.handle_key_event(KeyEvent::from(KeyCode::Up));
let popup = render_bottom_popup(&chat, 120);
assert!(
selected_permissions_popup_name(&popup) == "Guardian Approvals"
&& selected_permissions_popup_line(&popup).contains("(current)"),
"expected permissions popup to open with Guardian Approvals selected: {popup}"
);
move_permissions_popup_selection_to(&mut chat, "Default", KeyCode::Up);
let popup = render_bottom_popup(&chat, 120);
assert!(
selected_permissions_popup_name(&popup) == "Default",
"expected one Up from Guardian Approvals to select Default: {popup}"
);
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
let events = std::iter::from_fn(|| rx.try_recv().ok()).collect::<Vec<_>>();
@@ -8668,18 +8768,14 @@ async fn permissions_selection_sends_approvals_reviewer_in_override_turn_context
chat.open_permissions_popup();
let popup = render_bottom_popup(&chat, 120);
assert!(
popup
.lines()
.any(|line| line.contains("(current)") && line.contains('')),
selected_permissions_popup_line(&popup).contains("(current)"),
"expected permissions popup to open with the current preset selected: {popup}"
);
chat.handle_key_event(KeyEvent::from(KeyCode::Down));
move_permissions_popup_selection_to(&mut chat, "Guardian Approvals", KeyCode::Down);
let popup = render_bottom_popup(&chat, 120);
assert!(
popup
.lines()
.any(|line| line.contains("Guardian Approvals") && line.contains('')),
selected_permissions_popup_name(&popup) == "Guardian Approvals",
"expected one Down from Default to select Guardian Approvals: {popup}"
);
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
@@ -8720,9 +8816,7 @@ async fn permissions_full_access_history_cell_emitted_only_after_confirmation()
chat.config.notices.hide_full_access_warning = None;
chat.open_permissions_popup();
chat.handle_key_event(KeyEvent::from(KeyCode::Down));
#[cfg(target_os = "windows")]
chat.handle_key_event(KeyEvent::from(KeyCode::Down));
move_permissions_popup_selection_to(&mut chat, "Full Access", KeyCode::Down);
chat.handle_key_event(KeyEvent::from(KeyCode::Enter));
let mut open_confirmation_event = None;