Skip to content

ui::testing::HeadlessUI

Header: winui/testing/HeadlessUI.hpp.

The UI host for tests, with no native window. It holds one Window with a HeadlessWindowHost installed, laid out with a HeadlessTextMeasurer, so layout, focus, input and window-state behavior run the same on any OS with deterministic numbers.

Drive it like a real host: set content, layout(), then feed input to window() and advance time with tick(). Nothing is rendered; call Element::render() with a TestRenderer to inspect output.

Unless a test installed its own, the window comes with a TestClipboard, a TestLauncher, a TestMessageBoxHost, a TestNotifier and a TestJumpListHost installed (set_clipboard(), set_launcher(), set_message_box_host(), set_notifier(), set_jump_list_host()) for as long as this HeadlessUI lives, so a copy, a link, a message box, a notification or a jump list never reaches the OS. clipboard(), launcher(), message_boxes(), notifier() and jump_list() return them.

Example:

ui::testing::HeadlessUI ui = ui::testing::create_headless();
ui::Property<int> clicks{0};
ui::Control<ui::Button> save;
ui.window().set_content(ui::VerticalStack{.content = {
    ui::Text{.text = ui::bind(clicks, [](int n) { return std::to_string(n); })},
    ui::Button{.text = "Save", .on_click = [&] { ++clicks; }, .control = save},
}});
ui.layout({400, 300});

const ui::Point center = save->bounds().center();
ui::testing::seams(ui.window()).handle_pointer({center, ui::PointerButton::Left, ui::PointerAction::Down});
ui::testing::seams(ui.window()).handle_pointer({center, ui::PointerButton::Left, ui::PointerAction::Up});
REQUIRE(clicks.get() == 1);

window

Window& window()

The single logical window (created lazily), with a HeadlessWindowHost already installed. The host owns it; the reference is valid for the lifetime of this HeadlessUI.

host

HeadlessWindowHost& host()

The fake window host (see HeadlessWindowHost).

clipboard

TestClipboard* clipboard() const

The TestClipboard this HeadlessUI installed with window(), or nullptr when a test had installed its own clipboard first.

launcher

TestLauncher* launcher() const

The TestLauncher this HeadlessUI installed with window(), or nullptr when a test had installed its own launcher first.

message_boxes

TestMessageBoxHost* message_boxes() const

The TestMessageBoxHost this HeadlessUI installed with window(), or nullptr when a test had installed its own host first.

notifier

TestNotifier* notifier() const

The TestNotifier this HeadlessUI installed with window(), or nullptr when a test had installed its own notifier first.

jump_list

TestJumpListHost* jump_list() const

The TestJumpListHost this HeadlessUI installed with window(), or nullptr when a test had installed its own host first.

show

void show(Size client, WindowState initial = WindowState::Normal)

Shows the window in the initial state, as ui::WindowOptions::initial_state does, and lays it out at client unless that state is Minimized.

simulate_state

void simulate_state(WindowState state, Size client)

The user changing the state from outside the app (see HeadlessWindowHost:: simulate_state()), followed by the layout a real host runs at the window's new size.

button

std::unique_ptr<ButtonControl> button(std::string text)

Convenience factories. New tests should declare their tree instead, so they build through the API real callers use. .control gives them the same typed observers these factories return (see the class example).

Each returns a freshly owned element. Ownership transfers to whatever the caller hands it to (StackControl::add / Window::set_content).

text

std::unique_ptr<TextControl> text(std::string text)

A new TextControl showing text; see button().

check_box

std::unique_ptr<CheckBoxControl> check_box(std::string text, std::optional<bool> checked = false)

A new CheckBox; checked nullopt is the indeterminate state. See button().

radio_button

std::unique_ptr<RadioButtonControl> radio_button(std::string text, bool checked = false)

A new RadioButton; see button().

toggle_switch

std::unique_ptr<ToggleSwitchControl> toggle_switch(bool on = false)

A new ToggleSwitch; see button().

vertical_stack

template <typename... Children>
std::unique_ptr<StackControl> vertical_stack(Children... children)

Builds a vertical stack, seeded with children in order: ui.vertical_stack(ui.text("Hello"), ui.button("Save")). Children are moved in.

layout

void layout(Size client)

Lays out the window at a client size (DIPs) using the headless measurer, as a real host does when the window is resized.

tick

bool tick(Duration delta)

Advances elapsed time by delta through Window::tick(). Time moves deterministically, with no real clock, for things like a ToolTip's hover delay. Returns whether the tree became dirty and needs a repaint, as Window::tick() does.

measurer

const TextMeasurer& measurer() const

The HeadlessTextMeasurer layout() uses, for measuring or laying out elements outside the window the same way.