♻️ (locale): Sustituye Attr<Lc> por Lc::none()

This commit is contained in:
Manuel Cillero 2026-08-17 03:16:49 +02:00
parent c3ff8a6ff8
commit 213aa18b12
17 changed files with 275 additions and 146 deletions

View file

@ -74,9 +74,9 @@ pub struct Button {
/// Devuelve el valor del botón.
value: AttrValue,
/// Devuelve la etiqueta del botón.
label: Attr<Lc>,
label: Lc,
/// Devuelve el texto emergente del botón (atributo `title`).
title: Attr<Lc>,
title: Lc,
/// Devuelve si el botón recibe el foco automáticamente al cargar la página.
autofocus: bool,
/// Devuelve si el botón está deshabilitado.
@ -124,7 +124,7 @@ impl Button {
pub fn submit(label: Lc) -> Self {
Self {
kind: ButtonAction::Submit,
label: Attr::some(label),
label,
..Default::default()
}
}
@ -135,7 +135,7 @@ impl Button {
pub fn reset(label: Lc) -> Self {
Self {
kind: ButtonAction::Reset,
label: Attr::some(label),
label,
..Default::default()
}
}
@ -147,7 +147,7 @@ impl Button {
pub fn plain(label: Lc) -> Self {
Self {
kind: ButtonAction::Plain,
label: Attr::some(label),
label,
..Default::default()
}
}
@ -188,17 +188,17 @@ impl Button {
self
}
/// Establece o elimina la etiqueta visible del botón (basta pasar `None` para quitarla).
/// Establece la etiqueta visible del botón (usa [`Lc::none()`] para quitarla).
#[builder_fn]
pub fn with_label(mut self, label: impl Into<Option<Lc>>) -> Self {
self.label.alter_opt(label.into());
pub fn with_label(mut self, label: Lc) -> Self {
self.label = label;
self
}
/// Establece o elimina el texto emergente del botón (basta pasar `None` para quitarlo).
/// Establece el texto emergente del botón (usa [`Lc::none()`] para quitarlo).
#[builder_fn]
pub fn with_title(mut self, title: impl Into<Option<Lc>>) -> Self {
self.title.alter_opt(title.into());
pub fn with_title(mut self, title: Lc) -> Self {
self.title = title;
self
}

View file

@ -103,9 +103,9 @@ pub struct Field {
/// Devuelve el nombre compartido por todas las casillas del grupo.
name: AttrName,
/// Devuelve la etiqueta del grupo.
label: Attr<Lc>,
label: Lc,
/// Devuelve el texto de ayuda del grupo.
help_text: Attr<Lc>,
help_text: Lc,
/// Devuelve las casillas del grupo.
items: Vec<Item>,
/// Devuelve si todo el grupo está deshabilitado.
@ -207,17 +207,17 @@ impl Field {
self
}
/// Establece o elimina la etiqueta visible del grupo (basta pasar `None` para quitarla).
/// Establece la etiqueta visible del grupo (usa [`Lc::none()`] para quitarla).
#[builder_fn]
pub fn with_label(mut self, label: impl Into<Option<Lc>>) -> Self {
self.label.alter_opt(label.into());
pub fn with_label(mut self, label: Lc) -> Self {
self.label = label;
self
}
/// Establece o elimina el texto de ayuda del grupo (basta pasar `None` para quitarlo).
/// Establece el texto de ayuda del grupo (usa [`Lc::none()`] para quitarlo).
#[builder_fn]
pub fn with_help_text(mut self, help_text: impl Into<Option<Lc>>) -> Self {
self.help_text.alter_opt(help_text.into());
pub fn with_help_text(mut self, help_text: Lc) -> Self {
self.help_text = help_text;
self
}

View file

@ -46,7 +46,7 @@ pub struct Checkbox {
/// Devuelve el nombre del campo.
name: AttrName,
/// Devuelve la etiqueta del control.
label: Attr<Lc>,
label: Lc,
/// Devuelve si el control debe estar marcado/activo por defecto.
checked: bool,
/// Devuelve si el control recibe el foco automáticamente al cargar la página.
@ -182,10 +182,10 @@ impl Checkbox {
self
}
/// Establece o elimina la etiqueta visible del control (basta pasar `None` para quitarla).
/// Establece la etiqueta visible del control (usa [`Lc::none()`] para quitarla).
#[builder_fn]
pub fn with_label(mut self, label: impl Into<Option<Lc>>) -> Self {
self.label.alter_opt(label.into());
pub fn with_label(mut self, label: Lc) -> Self {
self.label = label;
self
}

View file

@ -27,9 +27,9 @@ pub struct Fieldset {
/// Devuelve identificador, clases CSS, atributos HTML y valores extra del componente.
props: Props,
/// Devuelve la leyenda del `fieldset`.
legend: Attr<Lc>,
legend: Lc,
/// Devuelve la descripción del `fieldset`.
description: Attr<Lc>,
description: Lc,
/// Devuelve si el `fieldset` está deshabilitado.
disabled: bool,
/// Devuelve la lista de componentes del `fieldset`.
@ -84,17 +84,17 @@ impl Fieldset {
self
}
/// Establece o elimina la leyenda del `fieldset` (basta pasar `None` para quitarla).
/// Establece la leyenda del `fieldset` (usa [`Lc::none()`] para quitarla).
#[builder_fn]
pub fn with_legend(mut self, legend: impl Into<Option<Lc>>) -> Self {
self.legend.alter_opt(legend.into());
pub fn with_legend(mut self, legend: Lc) -> Self {
self.legend = legend;
self
}
/// Establece o elimina la descripción del `fieldset` (basta pasar `None` para quitarla).
/// Establece la descripción del `fieldset` (usa [`Lc::none()`] para quitarla).
#[builder_fn]
pub fn with_description(mut self, description: impl Into<Option<Lc>>) -> Self {
self.description.alter_opt(description.into());
pub fn with_description(mut self, description: Lc) -> Self {
self.description = description;
self
}

View file

@ -161,15 +161,15 @@ pub struct Field {
/// Devuelve el valor inicial del campo.
value: AttrValue,
/// Devuelve la etiqueta del campo.
label: Attr<Lc>,
label: Lc,
/// Devuelve el texto de ayuda del campo.
help_text: Attr<Lc>,
help_text: Lc,
/// Devuelve la longitud mínima permitida en caracteres.
minlength: Attr<u16>,
/// Devuelve la longitud máxima permitida en caracteres.
maxlength: Attr<u16>,
/// Devuelve el texto indicativo del campo.
placeholder: Attr<Lc>,
placeholder: Lc,
/// Devuelve la configuración de autocompletado del campo.
autocomplete: Attr<form::Autocomplete>,
/// Devuelve si el campo recibe el foco automáticamente al cargar la página.
@ -418,17 +418,17 @@ impl Field {
self
}
/// Establece o elimina la etiqueta visible del campo (basta pasar `None` para quitarla).
/// Establece la etiqueta visible del campo (usa [`Lc::none()`] para quitarla).
#[builder_fn]
pub fn with_label(mut self, label: impl Into<Option<Lc>>) -> Self {
self.label.alter_opt(label.into());
pub fn with_label(mut self, label: Lc) -> Self {
self.label = label;
self
}
/// Establece o elimina el texto de ayuda del campo (basta pasar `None` para quitarlo).
/// Establece el texto de ayuda del campo (usa [`Lc::none()`] para quitarlo).
#[builder_fn]
pub fn with_help_text(mut self, help_text: impl Into<Option<Lc>>) -> Self {
self.help_text.alter_opt(help_text.into());
pub fn with_help_text(mut self, help_text: Lc) -> Self {
self.help_text = help_text;
self
}
@ -446,13 +446,13 @@ impl Field {
self
}
/// Establece o elimina el texto indicativo del campo (`None` para quitarlo).
/// Establece el texto indicativo del campo (usa [`Lc::none()`] para quitarlo).
///
/// Este texto aparece en el mismo campo y desaparece en cuanto el usuario empieza a escribir.
/// Al ser texto visible para el usuario se acepta [`Lc`] para poder localizarlo.
#[builder_fn]
pub fn with_placeholder(mut self, placeholder: impl Into<Option<Lc>>) -> Self {
self.placeholder.alter_opt(placeholder.into());
pub fn with_placeholder(mut self, placeholder: Lc) -> Self {
self.placeholder = placeholder;
self
}

View file

@ -37,9 +37,9 @@ pub struct Number {
/// Devuelve el valor inicial del campo.
value: Attr<u64>,
/// Devuelve la etiqueta del campo.
label: Attr<Lc>,
label: Lc,
/// Devuelve el texto de ayuda del campo.
help_text: Attr<Lc>,
help_text: Lc,
/// Devuelve el valor mínimo permitido.
min: Attr<u64>,
/// Devuelve el valor máximo permitido.
@ -151,17 +151,17 @@ impl Number {
self
}
/// Establece o elimina la etiqueta visible del campo (basta pasar `None` para quitarla).
/// Establece la etiqueta visible del campo (usa [`Lc::none()`] para quitarla).
#[builder_fn]
pub fn with_label(mut self, label: impl Into<Option<Lc>>) -> Self {
self.label.alter_opt(label.into());
pub fn with_label(mut self, label: Lc) -> Self {
self.label = label;
self
}
/// Establece o elimina el texto de ayuda del campo (basta pasar `None` para quitarlo).
/// Establece el texto de ayuda del campo (usa [`Lc::none()`] para quitarlo).
#[builder_fn]
pub fn with_help_text(mut self, help_text: impl Into<Option<Lc>>) -> Self {
self.help_text.alter_opt(help_text.into());
pub fn with_help_text(mut self, help_text: Lc) -> Self {
self.help_text = help_text;
self
}

View file

@ -101,9 +101,9 @@ pub struct Field {
/// Devuelve el nombre compartido por todos los botones de opción del grupo.
name: AttrName,
/// Devuelve la etiqueta del grupo.
label: Attr<Lc>,
label: Lc,
/// Devuelve el texto de ayuda del grupo.
help_text: Attr<Lc>,
help_text: Lc,
/// Devuelve las opciones del grupo.
items: Vec<Item>,
/// Devuelve si la selección de alguna opción del grupo es obligatoria.
@ -227,17 +227,17 @@ impl Field {
self
}
/// Establece o elimina la etiqueta visible del grupo (basta pasar `None` para quitarla).
/// Establece la etiqueta visible del grupo (usa [`Lc::none()`] para quitarla).
#[builder_fn]
pub fn with_label(mut self, label: impl Into<Option<Lc>>) -> Self {
self.label.alter_opt(label.into());
pub fn with_label(mut self, label: Lc) -> Self {
self.label = label;
self
}
/// Establece o elimina el texto de ayuda del grupo (basta pasar `None` para quitarlo).
/// Establece el texto de ayuda del grupo (usa [`Lc::none()`] para quitarlo).
#[builder_fn]
pub fn with_help_text(mut self, help_text: impl Into<Option<Lc>>) -> Self {
self.help_text.alter_opt(help_text.into());
pub fn with_help_text(mut self, help_text: Lc) -> Self {
self.help_text = help_text;
self
}

View file

@ -38,9 +38,9 @@ pub struct Range {
/// Devuelve el valor inicial del campo.
value: Attr<f64>,
/// Devuelve la etiqueta del campo.
label: Attr<Lc>,
label: Lc,
/// Devuelve el texto de ayuda del campo.
help_text: Attr<Lc>,
help_text: Lc,
/// Devuelve el valor mínimo permitido.
min: Attr<f64>,
/// Devuelve el valor máximo permitido.
@ -139,17 +139,17 @@ impl Range {
self
}
/// Establece o elimina la etiqueta visible del campo (basta pasar `None` para quitarla).
/// Establece la etiqueta visible del campo (usa [`Lc::none()`] para quitarla).
#[builder_fn]
pub fn with_label(mut self, label: impl Into<Option<Lc>>) -> Self {
self.label.alter_opt(label.into());
pub fn with_label(mut self, label: Lc) -> Self {
self.label = label;
self
}
/// Establece o elimina el texto de ayuda del campo (basta pasar `None` para quitarlo).
/// Establece el texto de ayuda del campo (usa [`Lc::none()`] para quitarlo).
#[builder_fn]
pub fn with_help_text(mut self, help_text: impl Into<Option<Lc>>) -> Self {
self.help_text.alter_opt(help_text.into());
pub fn with_help_text(mut self, help_text: Lc) -> Self {
self.help_text = help_text;
self
}

View file

@ -197,9 +197,9 @@ pub struct Field {
/// Devuelve el nombre del campo.
name: AttrName,
/// Devuelve la etiqueta del campo.
label: Attr<Lc>,
label: Lc,
/// Devuelve el texto de ayuda del campo.
help_text: Attr<Lc>,
help_text: Lc,
/// Devuelve las entradas de la lista (elementos individuales y grupos de elementos).
entries: Vec<Entry>,
/// Devuelve si la lista permite selección múltiple.
@ -333,17 +333,17 @@ impl Field {
self
}
/// Establece o elimina la etiqueta visible del campo (basta pasar `None` para quitarla).
/// Establece la etiqueta visible del campo (usa [`Lc::none()`] para quitarla).
#[builder_fn]
pub fn with_label(mut self, label: impl Into<Option<Lc>>) -> Self {
self.label.alter_opt(label.into());
pub fn with_label(mut self, label: Lc) -> Self {
self.label = label;
self
}
/// Establece o elimina el texto de ayuda del campo (basta pasar `None` para quitarlo).
/// Establece el texto de ayuda del campo (usa [`Lc::none()`] para quitarlo).
#[builder_fn]
pub fn with_help_text(mut self, help_text: impl Into<Option<Lc>>) -> Self {
self.help_text.alter_opt(help_text.into());
pub fn with_help_text(mut self, help_text: Lc) -> Self {
self.help_text = help_text;
self
}

View file

@ -40,9 +40,9 @@ pub struct Textarea {
/// Devuelve el valor inicial del área de texto.
value: AttrValue,
/// Devuelve la etiqueta del campo.
label: Attr<Lc>,
label: Lc,
/// Devuelve el texto de ayuda del campo.
help_text: Attr<Lc>,
help_text: Lc,
/// Devuelve el número de filas visibles del área de texto.
rows: Attr<u16>,
/// Devuelve la longitud mínima permitida en caracteres.
@ -50,7 +50,7 @@ pub struct Textarea {
/// Devuelve la longitud máxima permitida en caracteres.
maxlength: Attr<u16>,
/// Devuelve el texto indicativo del área de texto.
placeholder: Attr<Lc>,
placeholder: Lc,
/// Devuelve la configuración de autocompletado del campo.
autocomplete: Attr<form::Autocomplete>,
/// Devuelve si el campo recibe el foco automáticamente al cargar la página.
@ -166,17 +166,17 @@ impl Textarea {
self
}
/// Establece o elimina la etiqueta visible del campo (basta pasar `None` para quitarla).
/// Establece la etiqueta visible del campo (usa [`Lc::none()`] para quitarla).
#[builder_fn]
pub fn with_label(mut self, label: impl Into<Option<Lc>>) -> Self {
self.label.alter_opt(label.into());
pub fn with_label(mut self, label: Lc) -> Self {
self.label = label;
self
}
/// Establece o elimina el texto de ayuda del campo (basta pasar `None` para quitarlo).
/// Establece el texto de ayuda del campo (usa [`Lc::none()`] para quitarlo).
#[builder_fn]
pub fn with_help_text(mut self, help_text: impl Into<Option<Lc>>) -> Self {
self.help_text.alter_opt(help_text.into());
pub fn with_help_text(mut self, help_text: Lc) -> Self {
self.help_text = help_text;
self
}
@ -204,13 +204,13 @@ impl Textarea {
self
}
/// Establece o elimina el texto indicativo del área de texto (`None` para quitarlo).
/// Establece el texto indicativo del área de texto (usa [`Lc::none()`] para quitarlo).
///
/// Este texto aparece en el área de texto y desaparece en cuanto el usuario empieza a escribir.
/// Al ser texto visible para el usuario se acepta [`Lc`] para poder localizarlo.
#[builder_fn]
pub fn with_placeholder(mut self, placeholder: impl Into<Option<Lc>>) -> Self {
self.placeholder.alter_opt(placeholder.into());
pub fn with_placeholder(mut self, placeholder: Lc) -> Self {
self.placeholder = placeholder;
self
}

View file

@ -29,7 +29,7 @@ pub struct Image {
/// Devuelve el origen de la imagen.
source: image::Source,
/// Devuelve el texto alternativo localizado.
alternative: Attr<Lc>,
alternative: Lc,
}
#[async_trait]
@ -140,7 +140,7 @@ impl Image {
/// decorativa.
#[builder_fn]
pub fn with_alternative(mut self, alt: Lc) -> Self {
self.alternative.alter_value(alt);
self.alternative = alt;
self
}
}

View file

@ -1,4 +1,3 @@
use crate::locale::{LangId, Lc};
use crate::{AutoDefault, builder_fn, util};
/// Valor opcional para atributos HTML.
@ -7,8 +6,9 @@ use crate::{AutoDefault, builder_fn, util};
/// opcionales, uniformes y tipados.
///
/// Este tipo **no impone ninguna normalización ni semántica concreta**; dichas reglas se definen en
/// implementaciones concretas como `Attr<Lc>` y `Attr<String>`, o en tipos específicos como
/// [`AttrName`].
/// implementaciones concretas como `Attr<String>`, o en tipos específicos como [`AttrName`]. Para
/// texto localizado usa directamente [`Lc`](crate::locale::Lc) que ya representa su propia ausencia
/// con [`Lc::none()`](crate::locale::Lc::none()), sin necesidad de envolverlo en `Attr<Lc>`.
#[derive(AutoDefault, Clone, Debug)]
pub struct Attr<T>(Option<T>);
@ -72,52 +72,6 @@ impl<T> Attr<T> {
}
}
// **< Attr<Lc> >***********************************************************************************
/// Extiende [`Attr`] para [texto localizado](crate::locale) en atributos HTML.
///
/// Encapsula un [`Lc`] para manejar traducciones de forma segura en atributos.
///
/// # Ejemplo
///
/// ```rust
/// # use pagetop::prelude::*;
/// // Traducción por clave en las locales por defecto de PageTop.
/// let hello = Attr::<Lc>::new(Lc::l("test_hello_world"));
///
/// // Español disponible.
/// assert_eq!(
/// hello.lookup(&Locale::resolve("es-ES")),
/// Some("¡Hola mundo!".to_string())
/// );
///
/// // Japonés no disponible, traduce al idioma de respaldo (`"en-US"`).
/// assert_eq!(
/// hello.lookup(&Locale::resolve("ja-JP")),
/// Some("Hello world!".to_string())
/// );
///
/// // Uso típico en un atributo:
/// let title = hello.value(&Locale::resolve("es-ES"));
/// // Ejemplo: html! { a title=(title) { "Link" } }
/// ```
impl Attr<Lc> {
/// Crea una nueva instancia `Attr<Lc>`.
pub fn new(value: Lc) -> Self {
Self::some(value)
}
/// Devuelve la traducción para `language` si puede resolverse.
pub fn lookup(&self, language: &impl LangId) -> Option<String> {
self.0.as_ref()?.lookup(language)
}
/// Devuelve la traducción para `language` o una cadena vacía si no existe.
pub fn value(&self, language: &impl LangId) -> String {
self.lookup(language).unwrap_or_default()
}
}
// **< Attr<String> >*******************************************************************************
/// Extiende [`Attr`] para cadenas de texto.

View file

@ -32,6 +32,7 @@ enum LcKind {
/// - Un texto puro (`n()`) que no requiere traducción.
/// - Una clave para traducir un texto del conjunto de traducciones predefinidas de PageTop (`l()`).
/// - Una clave para traducir de un conjunto concreto de traducciones (`t()`).
/// - Ningún contenido (`none()`), para representar la ausencia en un campo `Lc` opcional.
///
/// # ¿Cuál usar, `get()`, `lookup()` o `using()`?
///
@ -122,6 +123,23 @@ impl Lc {
}
}
/// Crea una instancia **sin contenido**: no traduce nada y no representa ningún texto.
///
/// Equivale a [`Lc::default()`](Default::default), con un nombre más explícito. Útil para
/// representar la ausencia en un campo `Lc` opcional sin requerir `Option<Lc>`:
/// [`get()`](Self::get) y [`lookup()`](Self::lookup) devuelven `None`, y
/// [`using()`](Self::using) devuelve un marcado vacío.
///
/// ```rust
/// # use pagetop::prelude::*;
/// assert_eq!(Lc::none().get(), None);
/// ```
pub fn none() -> Self {
Self::default()
}
// **< Lc BUILDER >*****************************************************************************
/// Añade un argumento `{$arg}` => `value` a la traducción.
pub fn with_arg(mut self, arg: impl Into<CowStr>, value: impl Into<CowStr>) -> Self {
self.args.push((arg.into(), value.into()));
@ -142,6 +160,8 @@ impl Lc {
self
}
// **< Lc GETTERS >*****************************************************************************
/// Resuelve la traducción usando el idioma por defecto o, si no procede, el de respaldo de la
/// aplicación.
///

View file

@ -25,8 +25,8 @@ use crate::core::component::{AssetsOp, ChildOp, ComponentRender};
use crate::core::component::{Context, ContextError, Contextual};
use crate::core::theme::{CoreRegions, RegionName, RegionRef, TemplateRef, ThemeRef};
use crate::html::{Assets, Favicon, JavaScript, StyleSheet};
use crate::html::{Attr, Props, PropsOp};
use crate::html::{DOCTYPE, Markup, html};
use crate::html::{Props, PropsOp};
use crate::locale::{CharacterDirection, LangId, LanguageIdentifier, Lc};
use crate::web::HttpRequest;
use crate::{AutoDefault, builder_fn};
@ -88,11 +88,11 @@ impl RegionName for ReservedRegions {
#[rustfmt::skip]
#[derive(AutoDefault)]
pub struct Page {
title : Attr<Lc>,
description : Attr<Lc>,
metadata : Vec<(&'static str, &'static str)>,
properties : Vec<(&'static str, &'static str)>,
context : Context,
title : Lc,
description: Lc,
metadata : Vec<(&'static str, &'static str)>,
properties : Vec<(&'static str, &'static str)>,
context : Context,
}
impl Page {
@ -128,14 +128,14 @@ impl Page {
/// Establece el título de la página como un valor traducible.
#[builder_fn]
pub fn with_title(mut self, title: Lc) -> Self {
self.title.alter_value(title);
self.title = title;
self
}
/// Establece la descripción de la página como un valor traducible.
#[builder_fn]
pub fn with_description(mut self, description: Lc) -> Self {
self.description.alter_value(description);
self.description = description;
self
}

45
tests/component_button.rs Normal file
View file

@ -0,0 +1,45 @@
use pagetop::prelude::*;
#[pagetop::test]
async fn label_is_rendered_when_set() {
let mut button = Button::submit(Lc::n("Save"));
let html = button.render(&mut Context::default()).await.into_string();
assert!(html.contains("Save"));
}
#[pagetop::test]
async fn label_can_be_cleared_with_lc_none() {
let mut button = Button::submit(Lc::n("Save")).with_label(Lc::none());
let html = button.render(&mut Context::default()).await.into_string();
assert!(!html.contains("Save"));
// The button itself must still render.
assert!(html.contains("<button"));
}
#[pagetop::test]
async fn title_attribute_is_absent_by_default() {
let mut button = Button::submit(Lc::n("Save"));
let html = button.render(&mut Context::default()).await.into_string();
assert!(!html.contains("title="));
}
#[pagetop::test]
async fn title_attribute_is_present_when_set() {
let mut button = Button::submit(Lc::n("Save")).with_title(Lc::n("Save changes"));
let html = button.render(&mut Context::default()).await.into_string();
assert!(html.contains(r#"title="Save changes""#));
}
#[pagetop::test]
async fn title_attribute_can_be_cleared_with_lc_none() {
let mut button = Button::submit(Lc::n("Save"))
.with_title(Lc::n("Save changes"))
.with_title(Lc::none());
let html = button.render(&mut Context::default()).await.into_string();
assert!(!html.contains("title="));
}

View file

@ -0,0 +1,72 @@
use pagetop::prelude::*;
#[pagetop::test]
async fn label_is_absent_by_default() {
let mut field = form::input::Field::text();
let html = field.render(&mut Context::default()).await.into_string();
assert!(!html.contains(r#"class="form-label""#));
}
#[pagetop::test]
async fn label_is_rendered_when_set() {
let mut field = form::input::Field::text().with_label(Lc::n("Full name"));
let html = field.render(&mut Context::default()).await.into_string();
assert!(html.contains(r#"class="form-label""#));
assert!(html.contains("Full name"));
}
#[pagetop::test]
async fn label_can_be_cleared_with_lc_none() {
let mut field = form::input::Field::text()
.with_label(Lc::n("Full name"))
.with_label(Lc::none());
let html = field.render(&mut Context::default()).await.into_string();
assert!(!html.contains(r#"class="form-label""#));
assert!(!html.contains("Full name"));
}
#[pagetop::test]
async fn help_text_is_absent_by_default() {
let mut field = form::input::Field::text();
let html = field.render(&mut Context::default()).await.into_string();
assert!(!html.contains(r#"class="form-text""#));
}
#[pagetop::test]
async fn help_text_is_rendered_when_set() {
let mut field = form::input::Field::text().with_help_text(Lc::n("We never share your data."));
let html = field.render(&mut Context::default()).await.into_string();
assert!(html.contains(r#"class="form-text""#));
assert!(html.contains("We never share your data."));
}
#[pagetop::test]
async fn placeholder_attribute_is_absent_by_default() {
let mut field = form::input::Field::text();
let html = field.render(&mut Context::default()).await.into_string();
assert!(!html.contains("placeholder="));
}
#[pagetop::test]
async fn placeholder_attribute_is_present_when_set() {
let mut field = form::input::Field::text().with_placeholder(Lc::n("Enter your name"));
let html = field.render(&mut Context::default()).await.into_string();
assert!(html.contains(r#"placeholder="Enter your name""#));
}
#[pagetop::test]
async fn placeholder_attribute_can_be_cleared_with_lc_none() {
let mut field = form::input::Field::text()
.with_placeholder(Lc::n("Enter your name"))
.with_placeholder(Lc::none());
let html = field.render(&mut Context::default()).await.into_string();
assert!(!html.contains("placeholder="));
}

38
tests/response_page.rs Normal file
View file

@ -0,0 +1,38 @@
use pagetop::prelude::*;
fn request() -> HttpRequest {
web::test::TestRequest::get().to_http_request()
}
#[pagetop::test]
async fn title_and_description_are_absent_by_default() {
let page = Page::new(request());
assert_eq!(page.title(), None);
assert_eq!(page.description(), None);
}
#[pagetop::test]
async fn title_and_description_reflect_the_values_set() {
let page = Page::new(request())
.with_title(Lc::n("Dashboard"))
.with_description(Lc::n("Overview of recent activity"));
assert_eq!(page.title(), Some("Dashboard".to_string()));
assert_eq!(
page.description(),
Some("Overview of recent activity".to_string())
);
}
#[pagetop::test]
async fn lc_none_clears_a_previously_set_title_and_description() {
let page = Page::new(request())
.with_title(Lc::n("Dashboard"))
.with_description(Lc::n("Overview of recent activity"))
.with_title(Lc::none())
.with_description(Lc::none());
assert_eq!(page.title(), None);
assert_eq!(page.description(), None);
}