use crate::util::TestAttr;
use leptos::callback::Callback;
use leptos::prelude::Callable;
use leptos::prelude::*;
#[allow(unused_imports)]
use std::cell::Cell;
#[allow(unused_imports)]
use std::rc::Rc;
#[component]
pub fn Checkbox(
#[prop(into)]
name: String,
#[prop(into)]
checked: Signal<bool>,
#[prop(optional)]
update: Option<Callback<bool>>,
#[prop(optional, into)]
classes: Signal<String>,
#[prop(optional, into)]
disabled: Signal<bool>,
#[prop(optional, into)]
test_attr: Option<TestAttr>,
children: Children,
) -> impl IntoView {
let class = move || {
let extra = classes.get();
if extra.trim().is_empty() {
"checkbox".to_string()
} else {
format!("checkbox {}", extra)
}
};
let (data_testid, data_cy) = match &test_attr {
Some(attr) if attr.key == "data-testid" => (Some(attr.value.clone()), None),
Some(attr) if attr.key == "data-cy" => (None, Some(attr.value.clone())),
_ => (None, None),
};
view! {
<label
class=class
attr:data-testid=move || data_testid.clone()
attr:data-cy=move || data_cy.clone()
>
<input
type="checkbox"
name=name.clone()
prop:checked=move || checked.get()
disabled=move || disabled.get()
on:change=move |ev| {
if let Some(cb) = &update {
cb.run(event_target_checked(&ev));
}
}
/>
{children()}
</label>
}
}
#[cfg(test)]
mod tests {
use super::*;
use leptos::prelude::RenderHtml;
#[test]
fn checkbox_renders_base_class_and_label_text() {
let html = view! { <Checkbox name="agree" checked=true>{"Agree"}</Checkbox> }.to_html();
assert!(
html.contains(r#"class="checkbox""#),
"expected 'checkbox' class in: {}",
html
);
assert!(html.contains(">Agree<"), "expected label text in: {}", html);
}
#[test]
fn checkbox_sets_name_attribute() {
let html = view! { <Checkbox name="terms" checked=false>{"X"}</Checkbox> }.to_html();
assert!(
html.contains(r#"name="terms""#),
"expected name attribute in: {}",
html
);
}
#[test]
fn checkbox_allows_extra_classes() {
let html =
view! { <Checkbox name="c" checked=true classes="is-small custom">"X"</Checkbox> }
.to_html();
assert!(
html.contains(r#"class="checkbox is-small custom""#),
"expected merged classes in: {}",
html
);
}
#[test]
fn checkbox_can_be_disabled() {
let html =
view! { <Checkbox name="d" checked=false disabled=true>"X"</Checkbox> }.to_html();
assert!(
html.contains(r#"disabled"#),
"expected disabled attribute on input in: {}",
html
);
}
}
#[cfg(all(test, target_arch = "wasm32"))]
mod wasm_tests {
use super::*;
use crate::util::TestAttr;
use leptos::prelude::*;
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
fn checkbox_renders_test_attr_as_data_testid() {
let html = view! {
<Checkbox name="agree" checked=true test_attr=TestAttr::test_id("checkbox-test")>"Agree"</Checkbox>
}
.to_html();
assert!(
html.contains(r#"data-testid="checkbox-test""#),
"expected data-testid attribute; got: {}",
html
);
}
#[wasm_bindgen_test]
fn checkbox_no_test_attr_when_not_provided() {
let html = view! {
<Checkbox name="agree" checked=true>"Agree"</Checkbox>
}
.to_html();
assert!(
!html.contains("data-testid") && !html.contains("data-cy"),
"expected no data attribute; got: {}",
html
);
}
}