Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions crates/base/src/progress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use gpui::{
};
use smallvec::SmallVec;

use crate::StyledExt as _;
use crate::{StyledExt as _, TestSupportExt as _};

/// An unstyled linear progress root with controlled value accessibility.
#[derive(IntoElement)]
pub struct Progress {
base: gpui::Stateful<Div>,
base: crate::ObservedElement<gpui::Stateful<Div>>,
style: StyleRefinement,
value: f32,
indeterminate: bool,
Expand All @@ -21,7 +21,7 @@ pub struct Progress {
impl Progress {
pub fn new(id: impl Into<ElementId>) -> Self {
Self {
base: div().id(id),
base: div().id(id).test_support(),
style: StyleRefinement::default(),
value: 0.,
indeterminate: false,
Expand Down
9 changes: 7 additions & 2 deletions crates/component/src/title_bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use gpui::{
WindowControlArea, WindowOptions, div, linear_color_stop, linear_gradient,
prelude::FluentBuilder as _, px,
};
use gpui_base::TestSupportExt as _;
use smallvec::SmallVec;

pub const TITLE_BAR_HEIGHT: Pixels = px(34.);
Expand Down Expand Up @@ -207,6 +208,7 @@ impl RenderOnce for ControlIcon {

div()
.id(self.id())
.test_support()
.flex()
.w(TITLE_BAR_HEIGHT)
.h_full()
Expand Down Expand Up @@ -252,7 +254,7 @@ struct WindowControls {
impl RenderOnce for WindowControls {
fn render(self, window: &mut Window, _: &mut App) -> impl IntoElement {
if cfg!(target_os = "macos") || cfg!(target_family = "wasm") {
return div().id("window-controls");
return div().id("window-controls").test_support();
}

// Under server-side decorations the window manager already renders
Expand All @@ -266,7 +268,7 @@ impl RenderOnce for WindowControls {
// title bar's window-menu overlay.
#[cfg(target_os = "linux")]
if !matches!(window.window_decorations(), Decorations::Client { .. }) {
return div().id("window-controls");
return div().id("window-controls").test_support();
}

// The window manager declares which controls it can honor; a tiling
Expand All @@ -276,6 +278,7 @@ impl RenderOnce for WindowControls {

h_flex()
.id("window-controls")
.test_support()
.items_center()
.flex_shrink_0()
.h_full()
Expand Down Expand Up @@ -347,6 +350,8 @@ impl RenderOnce for TitleBar {
.when(is_macos, |this| {
this.on_double_click(|_, window, _| window.titlebar_double_click())
})
// After `on_double_click`, which is implemented for `Stateful` only.
.test_support()
.on_mouse_down_out(window.listener_for(&state, |state, _, _, _| {
state.should_move = false;
}))
Expand Down
80 changes: 79 additions & 1 deletion crates/kit/tests/components.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
mod common;
use gpui_component::{
Disableable,
Disableable, TitleBar,
button::Button,
clipboard::Clipboard,
input::{Input, InputState},
popover::Popover,
progress::{Progress, ProgressCircle},
};
use gpui_kit::test::{TestSupportExt, TestWindowExt};
use gpui_kit::{AppContext, Context, Entity, TestAppContext, Window, div, prelude::*, px, size};
Expand Down Expand Up @@ -175,3 +176,80 @@ fn scrollable_elements_forward_observed_focus_binding(cx: &mut TestAppContext) {
})
.unwrap();
}

struct Progresses;
impl Render for Progresses {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
div()
.w(px(240.))
.flex()
.flex_col()
.gap_4()
.child(
Progress::new("download")
.value(40.)
.accessibility_label("Downloading release"),
)
.child(
ProgressCircle::new("sync")
.loading(true)
.accessibility_label("Syncing library"),
)
}
}

#[gpui_kit::test]
fn progress_and_progress_circle_are_observable(cx: &mut TestAppContext) {
cx.update(gpui_component::init);
let (handle, _) = common::open_window(cx, None, |_, cx| cx.new(|_| Progresses));
cx.update_window(handle.into(), |_, window, cx| {
window.draw(cx).clear(cx);
for (id, label) in [
("download", "Downloading release"),
("sync", "Syncing library"),
] {
let progress = window.find(id);
assert_eq!(progress.role(), Some(gpui_kit::Role::ProgressIndicator));
assert_eq!(progress.label(), Some(label));
assert!(progress.visible(), "{id} should be visible");
}
})
.unwrap();
}

struct WindowWithTitleBar;
impl Render for WindowWithTitleBar {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
div().size_full().child(TitleBar::new().child("Library"))
}
}

#[gpui_kit::test]
fn title_bar_and_window_controls_are_observable(cx: &mut TestAppContext) {
cx.update(gpui_component::init);
let (handle, _) = common::open_window(cx, Some(size(px(600.), px(400.))), |_, cx| {
cx.new(|_| WindowWithTitleBar)
});
cx.update_window(handle.into(), |_, window, cx| {
window.draw(cx).clear(cx);
assert!(window.find("title-bar").visible());
// Windows draws the caption buttons in the title bar. macOS and the web
// leave them to the system, and so does Linux under the server-side
// decorations of the test window.
#[cfg(target_os = "windows")]
{
let controls = window.find("window-controls");
for id in ["minimize", "maximize", "close"] {
let button = window.within("window-controls").find(id);
assert!(button.visible(), "{id} should be visible");
assert!(controls.bounds().contains(&button.bounds().center()));
}
}
#[cfg(not(target_os = "windows"))]
{
assert!(window.try_find("window-controls").is_some());
assert!(window.try_find("close").is_none());
}
})
.unwrap();
}
2 changes: 2 additions & 0 deletions website/docs/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ observation adds no layout container:
| Dialog / Sheet | Host focus scope and surface bounds; child controls retain their own properties |
| Menu | Item label and selection, menu focus scope and submenu bounds |
| Notification | Alert role and bounds; close button uses normal Button observation |
| Progress / ProgressCircle | Progress indicator role and label; numeric accessibility values are not exposed by `ElementSnapshot::value()` |
| TitleBar | `title-bar` and `window-controls` bounds; caption buttons (`minimize`, `maximize` or `restore`, `close`) only where the title bar draws them |
| Dock | Area/group/content bounds and focus scopes; tabs retain native selection |

Use constructor IDs where available. Input and Select accept `.id("name")`;
Expand Down
2 changes: 2 additions & 0 deletions website/zh-CN/docs/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ cargo test -p gpui-kit --features test-support --test ui --locked
| Dialog / Sheet | 宿主焦点作用域与内容表面边界;子控件保留各自属性 |
| Menu | 菜单项名称与选中状态、菜单焦点作用域、子菜单边界 |
| Notification | Alert 角色与边界;关闭按钮沿用 Button 观察 |
| Progress / ProgressCircle | 进度指示器角色与名称;`ElementSnapshot::value()` 不读取数值型无障碍属性 |
| TitleBar | `title-bar` 与 `window-controls` 边界;窗口控制按钮(`minimize`、`maximize` 或 `restore`、`close`)仅在标题栏自行绘制时可读 |
| Dock | 区域、分组与内容边界及焦点作用域;Tab 保留原生选中状态 |

优先使用构造函数 ID。Input 和 Select 支持 `.id("name")`,默认 ID 包含状态 entity ID。
Expand Down
Loading