113 lines
3.8 KiB
Rust
113 lines
3.8 KiB
Rust
use std::{cell::RefCell, rc::Rc};
|
|
|
|
use gpui::{
|
|
Context, IntoElement, Modifiers, MouseButton, ParentElement as _, Render, Styled as _,
|
|
TestAppContext, VisualTestContext, Window, div, point, px,
|
|
};
|
|
use gpui_native_data::tabs::{Tab, Tabs};
|
|
use gpui_native_theme::Theme;
|
|
|
|
type Changes = Rc<RefCell<Vec<usize>>>;
|
|
|
|
struct Harness {
|
|
selected: usize,
|
|
changes: Changes,
|
|
}
|
|
|
|
impl Render for Harness {
|
|
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
let changes = self.changes.clone();
|
|
let view = cx.entity();
|
|
div().size_full().child(
|
|
Tabs::new("test-tabs")
|
|
.selected(self.selected)
|
|
.on_change(move |next, _, cx| {
|
|
changes.borrow_mut().push(next);
|
|
view.update(cx, |harness, cx| {
|
|
harness.selected = next;
|
|
cx.notify();
|
|
});
|
|
})
|
|
.tabs(|_, _| {
|
|
vec![
|
|
Tab::new("One"),
|
|
Tab::new("Two"),
|
|
Tab::new("Off").disabled(true),
|
|
Tab::new("End"),
|
|
]
|
|
}),
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Same-length labels keep the strip's geometry predictable: each tab is
|
|
/// roughly 40 px wide with a 4 px gap, so clicks at `(20/62/104/146, 12)`
|
|
/// land on One / Two / the disabled Off / End.
|
|
fn tabs_window() -> (TestAppContext, VisualTestContext, Changes) {
|
|
let mut cx = TestAppContext::single();
|
|
cx.update(Theme::init);
|
|
let changes = Rc::new(RefCell::new(Vec::new()));
|
|
let harness_changes = changes.clone();
|
|
let window = cx.add_window(move |_, _| Harness {
|
|
selected: 0,
|
|
changes: harness_changes,
|
|
});
|
|
let mut visual = VisualTestContext::from_window(window.into(), &cx);
|
|
visual.update(|window, cx| {
|
|
window.draw(cx).clear(cx);
|
|
});
|
|
(cx, visual, changes)
|
|
}
|
|
|
|
fn click(visual: &mut VisualTestContext, position: gpui::Point<gpui::Pixels>) {
|
|
visual.simulate_mouse_down(position, MouseButton::Left, Modifiers::default());
|
|
visual.simulate_mouse_up(position, MouseButton::Left, Modifiers::default());
|
|
}
|
|
|
|
#[test]
|
|
fn clicking_a_tab_selects_it_and_hands_the_strip_the_keyboard() {
|
|
let (_cx, mut visual, changes) = tabs_window();
|
|
|
|
// Tab 0 is already selected; selecting it again reports nothing.
|
|
click(&mut visual, point(px(20.), px(12.)));
|
|
assert!(changes.borrow().is_empty());
|
|
|
|
// The click focused the strip, so the arrows switch from here.
|
|
visual.simulate_keystrokes("right");
|
|
assert_eq!(*changes.borrow(), vec![1]);
|
|
}
|
|
|
|
#[test]
|
|
fn clicking_a_disabled_tab_reports_nothing() {
|
|
let (_cx, mut visual, changes) = tabs_window();
|
|
|
|
click(&mut visual, point(px(104.), px(12.)));
|
|
assert!(changes.borrow().is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn arrow_keys_skip_disabled_tabs_and_never_wrap() {
|
|
let (_cx, mut visual, changes) = tabs_window();
|
|
|
|
click(&mut visual, point(px(20.), px(12.))); // One: already selected, no report
|
|
visual.simulate_keystrokes("right"); // Two
|
|
visual.simulate_keystrokes("right"); // over the disabled tab → End
|
|
visual.simulate_keystrokes("right"); // last; no wrap
|
|
assert_eq!(*changes.borrow(), vec![1, 3]);
|
|
|
|
visual.simulate_keystrokes("left"); // over the disabled tab → Two
|
|
visual.simulate_keystrokes("home"); // One
|
|
visual.simulate_keystrokes("end"); // End
|
|
assert_eq!(*changes.borrow(), vec![1, 3, 1, 0, 3]);
|
|
}
|
|
|
|
#[test]
|
|
fn clicking_a_different_tab_reports_once() {
|
|
let (_cx, mut visual, changes) = tabs_window();
|
|
|
|
click(&mut visual, point(px(20.), px(12.))); // One: no change, just focus
|
|
click(&mut visual, point(px(62.), px(12.))); // Two
|
|
click(&mut visual, point(px(62.), px(12.))); // Two again: no change
|
|
assert_eq!(*changes.borrow(), vec![1]);
|
|
}
|