Selkie--Test--Focus

NAME

Selkie::Test::Focus - Focus simulation for widget tests without a real App

SYNOPSIS

use Test;
use Selkie::Test::Keys;
use Selkie::Test::Focus;
use Selkie::Widget::TextInput;

my $input = Selkie::Widget::TextInput.new;

# Run a block with the input focused — auto-unfocused after:
with-focus $input, {
    type-text($input, 'hello');
    press-key($input, 'enter');
};

is $input.text, 'hello', 'input received keystrokes while focused';
nok $input.is-focused, 'focus released after block';

DESCRIPTION

Most focusable widgets gate handle-event on is-focused:

return False unless $!focused;

Writing that test setup ($w.set-focused(True) + $w.set-focused(False)) for every widget test gets repetitive and hides the real intent. The with-focus block helper manages the focus state for you.

For widgets that don't have a set-focused method (e.g. display-only widgets), with-focus is a no-op — the block still runs.

If you want to test multi-widget focus scenarios (like Tab cycling), the App's focus and focus-next methods are the right API — use those directly with a real Selkie::App. This module is for single-widget unit tests.

EXAMPLES

Assert focus-gated behaviour

my $btn = Selkie::Widget::Button.new(label => 'OK');

# Unfocused: key press ignored
my @unfocused = collect-from $btn.on-press, {
    press-key($btn, 'enter');
};
is @unfocused.elems, 0, 'unfocused button ignores Enter';

# Focused: key press consumed
my @focused = collect-from $btn.on-press, {
    with-focus $btn, {
        press-key($btn, 'enter');
    };
};
is @focused.elems, 1, 'focused button fires on Enter';

Exception-safe

with-focus restores the unfocused state even if the block throws:

with-focus $widget, {
    die 'something broke';   # focus is still released after
};
CATCH { default { } }
nok $widget.is-focused, 'focus released despite exception';

SEE ALSO

  • Selkie::App — focus, focus-next, focus-prev for multi-widget focus

  • Selkie::Test::Keys — synthesise keys to dispatch inside the with-focus block

sub with-focus

sub with-focus(
    Selkie::Widget $widget,
    &block
) returns Mu

Run a block with the widget marked focused. If the widget has a set-focused(Bool) method it's called with True before the block and False after (including on exception). Widgets without that method — e.g. display-only widgets — are passed through unchanged. Closes over the block with LEAVE so focus is released even if the block throws.

Selkie v0.10.0

High-level TUI framework built on Notcurses

Authors

  • Matt Doughty

License

Artistic-2.0

Dependencies

Notcurses::Native:ver<0.4.0+>:auth<zef:apogee>

Test Dependencies

Provides

  • Selkie
  • Selkie::App
  • Selkie::App::Internal::Dispatch
  • Selkie::App::Internal::ErrorLog
  • Selkie::App::Internal::FocusTree
  • Selkie::App::Internal::HitTest
  • Selkie::App::Internal::IdleBudget
  • Selkie::App::Internal::OverlayTree
  • Selkie::App::Internal::RenderLoop
  • Selkie::App::Internal::ScreenModalLifecycle
  • Selkie::App::Internal::Terminal
  • Selkie::App::Internal::TerminalSequences
  • Selkie::Container
  • Selkie::EffectiveBounds
  • Selkie::Event
  • Selkie::Layout::Allocate
  • Selkie::Layout::HBox
  • Selkie::Layout::Split
  • Selkie::Layout::VBox
  • Selkie::Plot::Palette
  • Selkie::Plot::Scaler
  • Selkie::Plot::Ticks
  • Selkie::ScreenManager
  • Selkie::Sizing
  • Selkie::Store
  • Selkie::Style
  • Selkie::Test::Focus
  • Selkie::Test::Keys
  • Selkie::Test::Snapshot
  • Selkie::Test::Snapshot::Harness
  • Selkie::Test::Store
  • Selkie::Test::Supply
  • Selkie::Test::Tree
  • Selkie::Theme
  • Selkie::Trace
  • Selkie::Tree
  • Selkie::Widget
  • Selkie::Widget::Axis
  • Selkie::Widget::BarChart
  • Selkie::Widget::Border
  • Selkie::Widget::Button
  • Selkie::Widget::CardList
  • Selkie::Widget::Checkbox
  • Selkie::Widget::CommandPalette
  • Selkie::Widget::ConfirmModal
  • Selkie::Widget::FileBrowser
  • Selkie::Widget::FocusableByDefault
  • Selkie::Widget::Heatmap
  • Selkie::Widget::HelpOverlay
  • Selkie::Widget::Histogram
  • Selkie::Widget::Image
  • Selkie::Widget::Legend
  • Selkie::Widget::LineChart
  • Selkie::Widget::ListView
  • Selkie::Widget::Modal
  • Selkie::Widget::MultiLineInput
  • Selkie::Widget::PasswordStrength
  • Selkie::Widget::Plot
  • Selkie::Widget::ProgressBar
  • Selkie::Widget::RadioGroup
  • Selkie::Widget::RichText
  • Selkie::Widget::RichText::Span
  • Selkie::Widget::ScatterPlot
  • Selkie::Widget::ScrollView
  • Selkie::Widget::Select
  • Selkie::Widget::Sparkline
  • Selkie::Widget::Spinner
  • Selkie::Widget::TabBar
  • Selkie::Widget::Table
  • Selkie::Widget::Text
  • Selkie::Widget::TextInput
  • Selkie::Widget::TextInput::HighlightSpan
  • Selkie::Widget::TextStream
  • Selkie::Widget::Toast
  • Selkie::Widget::ViewportedCardList

Documentation

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.