gpui-cn 0.2.0

shadcn-style components for GPUI, built on gpui-base.
Documentation
//! UI integration tests for `Switch`: real input through a headless
//! window.

use std::{cell::Cell, rc::Rc};

use gpui_cn::{ReduceMotion, Root, Switch, Theme};
use gpui_kit::{
    AppContext as _, Context, IntoElement, ParentElement as _, Render, Styled as _, TestAppContext,
    Window, base::Disableable as _, div, px, size, test::TestWindowExt as _,
};

struct Harness {
    checked: Rc<Cell<bool>>,
    changes: Rc<Cell<usize>>,
    disabled: bool,
}

impl Render for Harness {
    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
        let checked = self.checked.clone();
        let changes = self.changes.clone();
        div().size_full().p_4().child(
            Switch::new("wifi")
                .checked(self.checked.get())
                .disabled(self.disabled)
                .accessibility_label("Wi-Fi")
                .on_change(move |next, _, _| {
                    checked.set(*next);
                    changes.set(changes.get() + 1);
                }),
        )
    }
}

struct Setup {
    handle: gpui_kit::WindowHandle<Root>,
    checked: Rc<Cell<bool>>,
    changes: Rc<Cell<usize>>,
}

fn setup(cx: &mut TestAppContext, disabled: bool) -> Setup {
    cx.update(|cx| {
        gpui_kit::init(cx);
        gpui_cn::init(cx);
    });
    let checked = Rc::new(Cell::new(false));
    let changes = Rc::new(Cell::new(0));
    let handle = cx.open_window(size(px(400.), px(300.)), |window, cx| {
        let harness = cx.new(|_| Harness {
            checked: checked.clone(),
            changes: changes.clone(),
            disabled,
        });
        Root::new(harness, window, cx)
    });
    cx.update_window(handle.into(), |_, window, cx| {
        window.render_frame(cx);
    })
    .unwrap();
    Setup {
        handle,
        checked,
        changes,
    }
}

fn tap(window: &mut Window, key: &str, cx: &mut gpui_kit::App) {
    let keystroke = gpui_kit::Keystroke::parse(key).unwrap();
    window.press(key, cx);
    window.dispatch_event(
        gpui_kit::PlatformInput::KeyUp(gpui_kit::KeyUpEvent { keystroke }),
        cx,
    );
    window.render_frame(cx);
}

#[gpui_kit::test]
fn the_track_is_the_reference_size_and_carries_the_name(cx: &mut TestAppContext) {
    let setup = setup(cx, false);
    cx.update_window(setup.handle.into(), |_, window, cx| {
        let switch = window.find("wifi");
        assert_eq!(switch.label(), Some("Wi-Fi"));
        assert_eq!(switch.bounds().size, size(px(32.), px(20.)));
        assert_eq!(
            window.simulate_next_frame(cx),
            0,
            "an idle switch asks for no frame"
        );
    })
    .unwrap();
}

#[gpui_kit::test]
fn on_touch_the_track_is_a_uiswitch_inside_a_row_high_target(cx: &mut TestAppContext) {
    let setup = setup(cx, false);
    cx.update(|cx| Theme::update(cx, |theme| theme.touch = true));
    cx.update_window(setup.handle.into(), |_, window, cx| {
        window.render_frame(cx);
        let bounds = window.find("wifi").bounds();
        assert_eq!(bounds.size.width, px(51.));
        assert_eq!(bounds.size.height, px(44.), "the HIG hit target");
    })
    .unwrap();
}

#[gpui_kit::test]
fn a_click_reports_the_next_value_each_time(cx: &mut TestAppContext) {
    let setup = setup(cx, false);
    cx.update_window(setup.handle.into(), |_, window, cx| {
        window.click("wifi", cx);
    })
    .unwrap();
    assert!(setup.checked.get());
    assert_eq!(setup.changes.get(), 1);
    cx.update_window(setup.handle.into(), |_, window, cx| {
        window.render_frame(cx);
        window.click("wifi", cx);
    })
    .unwrap();
    assert!(!setup.checked.get());
    assert_eq!(setup.changes.get(), 2);
}

#[gpui_kit::test]
fn the_thumb_slides_rather_than_jumps(cx: &mut TestAppContext) {
    let setup = setup(cx, false);
    cx.update_window(setup.handle.into(), |_, window, cx| {
        window.click("wifi", cx);
        window.render_frame(cx);
        assert!(
            window.simulate_next_frame(cx) > 0,
            "the slide asks for frames until it lands"
        );
    })
    .unwrap();
}

#[gpui_kit::test]
fn with_reduce_motion_the_thumb_lands_in_one_frame(cx: &mut TestAppContext) {
    let setup = setup(cx, false);
    cx.update(|cx| Theme::update(cx, |theme| theme.reduce_motion = ReduceMotion::On));
    cx.update_window(setup.handle.into(), |_, window, cx| {
        window.render_frame(cx);
        window.click("wifi", cx);
        window.render_frame(cx);
        assert_eq!(
            window.simulate_next_frame(cx),
            0,
            "no slide, so no frame is asked for"
        );
    })
    .unwrap();
    assert!(setup.checked.get());
}

#[gpui_kit::test]
fn tab_reaches_the_switch_and_space_and_enter_flip_it(cx: &mut TestAppContext) {
    let setup = setup(cx, false);
    cx.update_window(setup.handle.into(), |_, window, cx| {
        window.press("tab", cx);
        window.render_frame(cx);
        assert_eq!(window.find("wifi").focused(), Some(true));
        tap(window, "space", cx);
    })
    .unwrap();
    assert!(setup.checked.get());
    cx.update_window(setup.handle.into(), |_, window, cx| {
        tap(window, "enter", cx);
    })
    .unwrap();
    assert!(!setup.checked.get());
    assert_eq!(setup.changes.get(), 2);
}

#[gpui_kit::test]
fn a_disabled_switch_ignores_input(cx: &mut TestAppContext) {
    let setup = setup(cx, true);
    cx.update_window(setup.handle.into(), |_, window, cx| {
        window.click("wifi", cx);
        window.press("tab", cx);
        window.render_frame(cx);
        assert_ne!(window.find("wifi").focused(), Some(true));
        tap(window, "space", cx);
    })
    .unwrap();
    assert!(!setup.checked.get());
    assert_eq!(setup.changes.get(), 0);
}