iced_aw 0.14.1

Additional widgets for the Iced GUI library
Documentation
# Code Integration Testing Guide


Code integration testing is the practice of testing how different modules, components, or services work together. This directory contains integration tests for `iced_aw` widgets using the `iced_test` simulator framework.

## Quick Start


It is suggested that integration test writers try to use the common test helpers to avoid code duplication:

```rust
//! Integration tests for the MyWidget widget

#[macro_use]

mod common;

use iced::Element;
use iced_aw::MyWidget;

#[derive(Clone, Debug)]

enum Message {
    MyAction,
}

// Generate test helpers for your Message type
test_helpers!(Message);

#[test]

fn my_widget_renders() {
    run_test(|| MyWidget::new().into());
}

#[test]

fn my_widget_shows_text() {
    run_test_and_find(|| MyWidget::new().into(), "Expected Text");
}
```

## Available Helpers


The `test_helpers!` macro generates the following for your Message type:

### Types

- **`App`** - Test application wrapper with `new()`, `update()`, and `view()` methods
- **`ViewFn`** - Type alias for view functions: `Box<dyn Fn() -> Element<'static, Message>>`

### Basic Test Functions

- **`simulator(app: &App) -> Simulator<'_, Message>`**
  Creates a simulator with default settings

- **`run_test<F>(view_fn: F)`**
  Verifies a widget renders without panicking
  ```rust
  run_test(|| MyWidget::new().into());
  ```

- **`run_test_and_find<F>(view_fn: F, text: &str)`**
  Verifies a widget renders and contains specific text
  ```rust
  run_test_and_find(|| MyWidget::new().into(), "Button Label");
  ```

### Mouse and Touch Input Helpers

- **`simulate_mouse_click(ui, position, button)`**
  Simulate a mouse click at a specific Point

- **`simulate_mouse_click_at(ui, x, y, button)`**
  Simulate a mouse click at coordinates

- **`simulate_left_click_at(ui, x, y)`**
  Simulate a left mouse click at coordinates
  ```rust
  simulate_left_click_at(&mut ui, 100.0, 100.0);
  ```

- **`simulate_right_click_at(ui, x, y)`**
  Simulate a right mouse click at coordinates
  ```rust
  simulate_right_click_at(&mut ui, 10.0, 10.0);
  ```

- **`simulate_touch(ui, position)`**
  Simulate a touch event at a specific Point

- **`simulate_touch_at(ui, x, y)`**
  Simulate a touch event at coordinates
  ```rust
  simulate_touch_at(&mut ui, 50.0, 50.0);
  ```

- **`outside_position() -> Point`**
  Returns a position far outside typical widget bounds (1000.0, 1000.0)
  ```rust
  simulate_left_click_at(&mut ui, outside_position().x, outside_position().y);
  ```

### Message Verification Helpers

- **`assert_message_received<F>(ui, app, predicate, error_msg)`**
  Process messages and assert a specific message was received
  ```rust
  assert_message_received(ui, &mut app,
      |msg| matches!(msg, Message::Clicked),
      "Should receive Clicked message");
  ```

- **`check_message_received<F>(ui, app, predicate) -> bool`**
  Process messages and return whether a specific message was received
  ```rust
  let got_message = check_message_received(ui, &mut app,
      |msg| matches!(msg, Message::Expected));
  ```

- **`process_messages(ui, app)`**
  Process all messages from simulator without checking
  ```rust
  process_messages(ui, &mut app);
  ```

- **`collect_messages<F>(ui, app, predicate) -> Vec<Message>`**
  Process messages and return collected messages matching predicate
  ```rust
  let clicks = collect_messages(ui, &mut app,
      |msg| matches!(msg, Message::Clicked));
  assert_eq!(clicks.len(), 3);
  ```

### Snapshot Testing Helpers


- **`assert_snapshot_matches(ui, baseline_name) -> Result<(), Error>`**
  Verify a widget's visual rendering matches both hash and image baselines
  ```rust
  let mut ui = simulator(&app);
  assert_snapshot_matches(&mut ui, "tests/snapshots/widget_state")?;
  ```
  On first run, baseline files are auto-generated. Subsequent runs validate against them.

- **`assert_snapshot_hash_matches(ui, baseline_name) -> Result<(), Error>`**
  Verify a widget's rendering matches hash baseline only (faster than full image comparison)
  ```rust
  let mut ui = simulator(&app);
  assert_snapshot_hash_matches(&mut ui, "tests/snapshots/widget_state")?;
  ```

## Advanced Usage


### Stateful Tests


For tests requiring state management, it is recommended to use `App` directly:

```rust
#[test]

fn button_click_produces_message() -> Result<(), Error> {
    let (mut app, _) = App::new(|| MyWidget::new().into());
    let mut ui = simulator(&app);

    ui.click("Button")?;

    for message in ui.into_messages() {
        app.update(message);
    }

    Ok(())
}
```

### Custom Stateful Apps


For complex state tracking, it is recommended to define a custom app alongside the generated helpers:

```rust
#[derive(Clone)]

struct StatefulTestApp {
    counter: std::rc::Rc<std::cell::RefCell<usize>>,
}

impl StatefulTestApp {
    fn new() -> (Self, iced::Task<Message>) {
        (Self { counter: std::rc::Rc::new(std::cell::RefCell::new(0)) }, iced::Task::none())
    }

    fn update(&mut self, message: Message) {
        match message {
            Message::Increment => *self.counter.borrow_mut() += 1,
        }
    }

    fn view(&self) -> Element<'_, Message> {
        MyWidget::new(*self.counter.borrow()).into()
    }
}
```

## Test Organization


For consistency, it is suggested that you structure your tests with clear section comments:

```rust
// ============================================================================
// Basic Rendering Tests
// ============================================================================

#[test]

fn widget_renders_with_defaults() { /* ... */ }

// ============================================================================
// Interaction Tests
// ============================================================================

#[test]

fn button_click_works() { /* ... */ }
```

## Simulator API


Full API documentation: https://github.com/iced-rs/iced/blob/master/test/src/simulator.rs

Key methods:
- `ui.find(text)` - Locate text in the widget tree
- `ui.click(text)` - Click on element containing text
- `ui.tap_key(key)` - Simulate keyboard input
- `ui.into_messages()` - Consume simulator and get produced messages

## Suggested Best Practices


1. **Use `run_test_and_find` when possible** - Tests both rendering and `operate()` implementation
2. **Keep test names descriptive** - Name should explain what's being tested
3. **Test one thing per test** - Avoid complex multi-step tests
4. **Use `Result<(), Error>` for tests with `?` operator** - Makes error handling cleaner
5. **Keep imports minimal** - Only import what you actually use

## Test Naming Convention


It is suggested that integration test function names begin with the widget name as a prefix.

### Naming Pattern


```rust
fn <widget_name>_<test_description>()
```

### Example test names


**Correct:**
```rust
#[test]

fn badge_renders_with_text() { /* ... */ }

#[test]

fn number_input_increment_button_click_produces_message() { /* ... */ }

#[test]

fn time_picker_displays_12h_format_correctly() { /* ... */ }
```

**Incorrect:**
```rust
#[test]

fn renders_with_text() { /* ... */ }  // Missing widget prefix

#[test]

fn can_increment_number() { /* ... */ }  // Missing widget prefix

#[test]

fn displays_time() { /* ... */ }  // Missing widget prefix
```

This convention helps ensure:
- Tests are clearly associated with their widget
- Test output is easier to read and filter
- grep/search operations are more effective

## Example Test File Structure


```rust
//! Integration tests for the Widget
//!
//! Brief description of what these tests cover.

#[macro_use]

mod common;

use iced::{Element, Length};
use iced_aw::Widget;
use iced_test::{Error, Simulator};

#[derive(Clone, Debug)]

enum Message {
    Action,
}

test_helpers!(Message);

// ============================================================================
// Basic Tests
// ============================================================================

#[test]

fn widget_renders() {
    run_test(|| Widget::new().into());
}

#[test]

fn widget_with_text() {
    run_test_and_find(|| Widget::new().with_label("Test").into(), "Test");
}

// ============================================================================
// Configuration Tests
// ============================================================================

#[test]

fn widget_with_custom_width() {
    run_test(|| Widget::new().width(Length::Fill).into());
}

// ============================================================================
// Interaction Tests
// ============================================================================

#[test]

fn widget_click_works() -> Result<(), Error> {
    let (mut app, _) = App::new(|| Widget::new().into());
    let mut ui = simulator(&app);

    ui.click("Target")?;

    let mut got_message = false;
    for message in ui.into_messages() {
        got_message = true;
        app.update(message);
    }

    assert!(got_message);
    Ok(())
}
```
## Button Icons Reference


Common icon characters used in widgets (searchable with `ui.find()`):

- `\u{e800}` - cancel (close/cancel buttons)
- `\u{e801}` - down_open (down arrow, dropdowns)
- `\u{e802}` - left_open (left navigation)
- `\u{e803}` - right_open (right navigation)
- `\u{e804}` - up_open (up arrow, increment)
- `\u{e805}` - ok (checkmark/submit)

Or search for their display forms: `" ▲ "`, `" ▼ "`, `" ✓ "`, etc.

# Code Coverage


It is suggested that integration testing prioritize critical paths and common failure points rather than exhaustive coverage.  Coverage configuration found at `tarpaulin.toml`.

```bash
cargo tarpaulin
```