105 lines
3.0 KiB
Rust
105 lines
3.0 KiB
Rust
use std::{cell::RefCell, rc::Rc, time::Duration};
|
|
|
|
use gpui::prelude::FluentBuilder as _;
|
|
use gpui::{
|
|
Context, IntoElement, ParentElement as _, Render, Styled as _, TestAppContext, Window, div,
|
|
};
|
|
use gpui_native_core::spinner::{Spinner, SpinnerVariant};
|
|
use gpui_native_theme::Theme;
|
|
|
|
struct SpinnerHost {
|
|
variant: SpinnerVariant,
|
|
determinate: bool,
|
|
renders: Rc<RefCell<usize>>,
|
|
}
|
|
|
|
impl Render for SpinnerHost {
|
|
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
|
*self.renders.borrow_mut() += 1;
|
|
let spinner = Spinner::new("test-spinner")
|
|
.variant(self.variant)
|
|
.when(self.determinate, |spinner| spinner.value(0.4));
|
|
div().size_full().child(spinner)
|
|
}
|
|
}
|
|
|
|
fn host_window(
|
|
variant: SpinnerVariant,
|
|
determinate: bool,
|
|
reduce_motion: bool,
|
|
) -> (TestAppContext, Rc<RefCell<usize>>) {
|
|
let mut cx = TestAppContext::single();
|
|
cx.update(|cx| {
|
|
Theme::init(cx);
|
|
if reduce_motion {
|
|
cx.set_reduce_motion(true);
|
|
}
|
|
});
|
|
let renders = Rc::new(RefCell::new(0));
|
|
let host_renders = renders.clone();
|
|
cx.add_window(move |_, _| SpinnerHost {
|
|
variant,
|
|
determinate,
|
|
renders: host_renders,
|
|
});
|
|
cx.run_until_parked();
|
|
(cx, renders)
|
|
}
|
|
|
|
#[test]
|
|
fn spinning_repaints_on_the_animation_clock() {
|
|
let (cx, renders) = host_window(SpinnerVariant::Ring, false, false);
|
|
assert_eq!(*renders.borrow(), 1);
|
|
|
|
// The 60fps cap drives re-renders with timers, not frame callbacks.
|
|
cx.executor().advance_clock(Duration::from_millis(100));
|
|
cx.run_until_parked();
|
|
assert!(
|
|
*renders.borrow() > 1,
|
|
"the spinner must repaint while spinning"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn determinate_paints_one_static_frame() {
|
|
let (cx, renders) = host_window(SpinnerVariant::Ring, true, false);
|
|
assert_eq!(*renders.borrow(), 1);
|
|
|
|
cx.executor().advance_clock(Duration::from_millis(200));
|
|
cx.run_until_parked();
|
|
assert_eq!(*renders.borrow(), 1, "a determinate ring holds still");
|
|
}
|
|
|
|
#[test]
|
|
fn reduce_motion_paints_one_static_frame() {
|
|
let (cx, renders) = host_window(SpinnerVariant::Ring, false, true);
|
|
assert_eq!(*renders.borrow(), 1);
|
|
|
|
cx.executor().advance_clock(Duration::from_millis(200));
|
|
cx.run_until_parked();
|
|
assert_eq!(*renders.borrow(), 1, "reduced motion must freeze the spin");
|
|
}
|
|
|
|
#[test]
|
|
fn the_icon_variant_repaints_while_spinning() {
|
|
let (cx, renders) = host_window(SpinnerVariant::Icon, false, false);
|
|
assert_eq!(*renders.borrow(), 1);
|
|
|
|
cx.executor().advance_clock(Duration::from_millis(100));
|
|
cx.run_until_parked();
|
|
assert!(
|
|
*renders.borrow() > 1,
|
|
"the icon must repaint while spinning"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn the_icon_variant_holds_still_when_determinate() {
|
|
let (cx, renders) = host_window(SpinnerVariant::Icon, true, false);
|
|
assert_eq!(*renders.borrow(), 1);
|
|
|
|
cx.executor().advance_clock(Duration::from_millis(200));
|
|
cx.run_until_parked();
|
|
assert_eq!(*renders.borrow(), 1, "a held icon must not animate");
|
|
}
|