Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document how to do testing for Relm4 apps #482

Open
chriskilding opened this issue Jun 27, 2023 · 2 comments
Open

Document how to do testing for Relm4 apps #482

chriskilding opened this issue Jun 27, 2023 · 2 comments

Comments

@chriskilding
Copy link
Contributor

One hallmark of any major GUI framework is strong support for testing. For example:

As a first-time user of Relm4, it's not immediately obvious which patterns I should use for testing, or which parts I should test. Therefore it would be much appreciated if a guide for how to test Relm4 apps was added to the documentation.

@AaronErhardt
Copy link
Member

It's not just documentation, actually. We first should decide how we properly implement a testing API. Of course, you can do some testing manually, but so far, there's no API for that in Relm4 yet (see #78).

@chriskilding
Copy link
Contributor Author

chriskilding commented Jun 27, 2023

Good to know - sounds like there's quite a hill to climb here.

As a starter for ten, just thinking about how you might unit test at the component level...

If you have a component like this:

use gtk::prelude::*;
use relm4::prelude::*;
use relm4_icons::icon_name;

// represents the data model in the backend
use crate::model;

fn find_icon_name(value: &model::MyModel) -> &'static str {
    match value {
        Foo => icon_name::FOO,
        Bar => icon_name::BAR,
    }
}

#[tracker::track]
pub struct MyComponent {
    value: model::MyModel,
}

#[derive(Debug)]
pub enum Msg {
    More,
    Less,
}

#[relm4::component(pub)]
impl SimpleComponent for MyComponent {
    type Input = Msg;
    type Init = model::MyModel;
    type Output = ();

    view! {
        #[root]
        gtk::MenuButton {
            #[track = "model.changed(MyModel::value())"]
            set_icon_name: find_icon_name(&model.value),

            #[wrap(Some)]
            set_popover = &gtk::Popover {
                gtk::Grid {

                    attach[0, 0, 1, 1] = &gtk::Button {
                        set_icon_name: icon_name::MINUS,
                        connect_clicked => Msg::Less,
                    },

                    attach[0, 1, 1, 1] = &gtk::Button {
                        set_icon_name: icon_name::PLUS,
                        connect_clicked => Msg::More,
                    },

                    // ...
                }
            }
        }
    }

    fn init(_init: Self::Init, root: &Self::Root, _sender: ComponentSender<Self>) -> ComponentParts<Self> {
        let model = Foo::default();

        let widgets = view_output!();

        ComponentParts { model, widgets }
    }

    fn update(&mut self, msg: Msg, _sender: ComponentSender<Self>) {
        self.reset();

        match msg {
            Msg::Less => self.set_value(model::MyModel::Foo),
            Msg::More => self.set_value(model::MyModel::Bar),
        }
    }
}

impl Default for MyComponent {
    fn default() -> Self {
        MyComponent {
            value: model::MyModel::Foo,
            tracker: 0,
        }
    }
}

Then the first thing you might want to test is that:

  • Given an instance of MyComponent
  • When I call update with the message Msg::Less
  • (Then the value attribute should become MyModel::Foo)
  • Then the menu button's icon name should become relm4_icons::icon_name::FOO

So it would seem that if we can get a testing API/pattern for that, then this would be a reasonable starting point?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants