test(html-examples): make lazy load visibly update
Show a server-update count in the lazy panel so manual clicks have an observable change, and strengthen the browser smoke to assert the panel text changes. req: examples/001 req: htmx_equivalents/005 req: test/006
This commit is contained in:
@@ -20,7 +20,7 @@ struct GalleryState {
|
|||||||
rows: Mutex<Vec<RowRecord>>,
|
rows: Mutex<Vec<RowRecord>>,
|
||||||
loaded_count: Mutex<usize>,
|
loaded_count: Mutex<usize>,
|
||||||
infinite_count: Mutex<usize>,
|
infinite_count: Mutex<usize>,
|
||||||
lazy_loaded: Mutex<bool>,
|
lazy_loads: Mutex<usize>,
|
||||||
progress: Mutex<u8>,
|
progress: Mutex<u8>,
|
||||||
email: Mutex<String>,
|
email: Mutex<String>,
|
||||||
email_status: Mutex<String>,
|
email_status: Mutex<String>,
|
||||||
@@ -263,7 +263,7 @@ impl GalleryState {
|
|||||||
]),
|
]),
|
||||||
loaded_count: Mutex::new(2),
|
loaded_count: Mutex::new(2),
|
||||||
infinite_count: Mutex::new(3),
|
infinite_count: Mutex::new(3),
|
||||||
lazy_loaded: Mutex::new(false),
|
lazy_loads: Mutex::new(0),
|
||||||
progress: Mutex::new(0),
|
progress: Mutex::new(0),
|
||||||
email: Mutex::new(String::new()),
|
email: Mutex::new(String::new()),
|
||||||
email_status: Mutex::new("Waiting for an email".into()),
|
email_status: Mutex::new("Waiting for an email".into()),
|
||||||
@@ -331,7 +331,7 @@ fn gallery_view(state: &GalleryState) -> Gallery {
|
|||||||
.collect();
|
.collect();
|
||||||
let loaded_count = *state.loaded_count.lock().unwrap();
|
let loaded_count = *state.loaded_count.lock().unwrap();
|
||||||
let infinite_count = *state.infinite_count.lock().unwrap();
|
let infinite_count = *state.infinite_count.lock().unwrap();
|
||||||
let lazy_loaded = *state.lazy_loaded.lock().unwrap();
|
let lazy_loads = *state.lazy_loads.lock().unwrap();
|
||||||
let progress = *state.progress.lock().unwrap();
|
let progress = *state.progress.lock().unwrap();
|
||||||
let email = state.email.lock().unwrap().clone();
|
let email = state.email.lock().unwrap().clone();
|
||||||
let email_status = state.email_status.lock().unwrap().clone();
|
let email_status = state.email_status.lock().unwrap().clone();
|
||||||
@@ -343,11 +343,7 @@ fn gallery_view(state: &GalleryState) -> Gallery {
|
|||||||
Gallery {
|
Gallery {
|
||||||
contacts,
|
contacts,
|
||||||
rows,
|
rows,
|
||||||
lazy_panel: if lazy_loaded {
|
lazy_panel: lazy_panel_text(lazy_loads),
|
||||||
"Lazy content loaded".into()
|
|
||||||
} else {
|
|
||||||
"Waiting to be revealed".into()
|
|
||||||
},
|
|
||||||
loaded_rows: loaded_rows(loaded_count),
|
loaded_rows: loaded_rows(loaded_count),
|
||||||
load_status: format!("Showing {loaded_count} rows"),
|
load_status: format!("Showing {loaded_count} rows"),
|
||||||
infinite_rows: loaded_rows(infinite_count),
|
infinite_rows: loaded_rows(infinite_count),
|
||||||
@@ -368,6 +364,14 @@ fn gallery_view(state: &GalleryState) -> Gallery {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lazy_panel_text(loads: usize) -> String {
|
||||||
|
if loads == 0 {
|
||||||
|
"Waiting to be revealed".into()
|
||||||
|
} else {
|
||||||
|
format!("Lazy content loaded by server update #{loads}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn contact_card_view(record: ContactRecord) -> ContactCard {
|
fn contact_card_view(record: ContactRecord) -> ContactCard {
|
||||||
ContactCard {
|
ContactCard {
|
||||||
id: Id(record.id),
|
id: Id(record.id),
|
||||||
@@ -434,8 +438,9 @@ mod gallery_handlers {
|
|||||||
Form(input): Form<LazyLoad>,
|
Form(input): Form<LazyLoad>,
|
||||||
) -> impl IntoEffect {
|
) -> impl IntoEffect {
|
||||||
let _ = input.request;
|
let _ = input.request;
|
||||||
*state.lazy_loaded.lock().unwrap() = true;
|
let mut lazy_loads = state.lazy_loads.lock().unwrap();
|
||||||
gallery::lazy_panel.set("Lazy content loaded")
|
*lazy_loads += 1;
|
||||||
|
gallery::lazy_panel.set(lazy_panel_text(*lazy_loads))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hemx::handler]
|
#[hemx::handler]
|
||||||
@@ -805,7 +810,7 @@ mod tests {
|
|||||||
.batch,
|
.batch,
|
||||||
);
|
);
|
||||||
assert!(lazy.updates_text(gallery::lazy_panel));
|
assert!(lazy.updates_text(gallery::lazy_panel));
|
||||||
assert!(lazy.payload_contains("Lazy content loaded"));
|
assert!(lazy.payload_contains("Lazy content loaded by server update #1"));
|
||||||
|
|
||||||
let more = inspect_batch(
|
let more = inspect_batch(
|
||||||
InteractionRequest::from(form(gallery::load_more, &[("request", "more")]))
|
InteractionRequest::from(form(gallery::load_more, &[("request", "more")]))
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ const EDIT_ROW_SMOKE: &str = r#"(async()=>{const text=()=>document.body.textCont
|
|||||||
const INLINE_VALIDATION_SMOKE: &str = r#"(async()=>{const f=Array.from(document.querySelectorAll("form")).find(f=>f.getAttribute("data-hemx-on")==="input"); const input=f.elements.email; input.value="wrong"; input.dispatchEvent(new InputEvent("input",{bubbles:true,inputType:"insertText",data:"g"})); await new Promise(r=>setTimeout(r,700)); const afterBad=document.body.textContent; input.value="xyz@example.com"; input.dispatchEvent(new InputEvent("input",{bubbles:true,inputType:"insertText",data:"m"})); await new Promise(r=>setTimeout(r,700)); const afterGood=document.body.textContent; if(!(afterBad.includes("Email needs an @ sign")&&!afterGood.includes("Email needs an @ sign")&&afterGood.includes("xyz@example.com is valid"))) throw new Error("inline validation did not recover"); return true;})()"#;
|
const INLINE_VALIDATION_SMOKE: &str = r#"(async()=>{const f=Array.from(document.querySelectorAll("form")).find(f=>f.getAttribute("data-hemx-on")==="input"); const input=f.elements.email; input.value="wrong"; input.dispatchEvent(new InputEvent("input",{bubbles:true,inputType:"insertText",data:"g"})); await new Promise(r=>setTimeout(r,700)); const afterBad=document.body.textContent; input.value="xyz@example.com"; input.dispatchEvent(new InputEvent("input",{bubbles:true,inputType:"insertText",data:"m"})); await new Promise(r=>setTimeout(r,700)); const afterGood=document.body.textContent; if(!(afterBad.includes("Email needs an @ sign")&&!afterGood.includes("Email needs an @ sign")&&afterGood.includes("xyz@example.com is valid"))) throw new Error("inline validation did not recover"); return true;})()"#;
|
||||||
const ACTIVE_SEARCH_SMOKE: &str = r#"(async()=>{const f=Array.from(document.querySelectorAll("form")).find(f=>f.elements.query); f.elements.query.value="beta"; f.dispatchEvent(new Event("submit",{bubbles:true,cancelable:true})); await new Promise(r=>setTimeout(r,900)); const results=Array.from(document.querySelectorAll("[data-sid=\"1037530521\"]")).map(e=>e.textContent.trim()); if(!(results.length===2&&results.every(t=>t==="Beta"))) throw new Error("active search did not filter rows"); return true;})()"#;
|
const ACTIVE_SEARCH_SMOKE: &str = r#"(async()=>{const f=Array.from(document.querySelectorAll("form")).find(f=>f.elements.query); f.elements.query.value="beta"; f.dispatchEvent(new Event("submit",{bubbles:true,cancelable:true})); await new Promise(r=>setTimeout(r,900)); const results=Array.from(document.querySelectorAll("[data-sid=\"1037530521\"]")).map(e=>e.textContent.trim()); if(!(results.length===2&&results.every(t=>t==="Beta"))) throw new Error("active search did not filter rows"); return true;})()"#;
|
||||||
const DELETE_ROW_SMOKE: &str = r#"(async()=>{const text=()=>document.body.textContent.replace(/\s+/g," "); const del=Array.from(document.querySelectorAll("form")).find(f=>f.textContent.trim()==="Delete"&&Array.from(f.elements).some(e=>e.name==="id"&&e.value==="1")); del.querySelector("button,input[type=submit]").click(); await new Promise(r=>setTimeout(r,700)); if(text().includes("Review content")) throw new Error("delete row did not remove row"); return true;})()"#;
|
const DELETE_ROW_SMOKE: &str = r#"(async()=>{const text=()=>document.body.textContent.replace(/\s+/g," "); const del=Array.from(document.querySelectorAll("form")).find(f=>f.textContent.trim()==="Delete"&&Array.from(f.elements).some(e=>e.name==="id"&&e.value==="1")); del.querySelector("button,input[type=submit]").click(); await new Promise(r=>setTimeout(r,700)); if(text().includes("Review content")) throw new Error("delete row did not remove row"); return true;})()"#;
|
||||||
const LAZY_LOAD_SMOKE: &str = r#"(async()=>{const text=()=>document.body.textContent.replace(/\s+/g," "); const f=Array.from(document.querySelectorAll("form")).find(f=>f.textContent.includes("Load lazy content")); f.querySelector("button,input[type=submit]").click(); await new Promise(r=>setTimeout(r,700)); if(!text().includes("Lazy content loaded")) throw new Error("lazy load did not update"); return true;})()"#;
|
const LAZY_LOAD_SMOKE: &str = r#"(async()=>{const f=Array.from(document.querySelectorAll("form")).find(f=>f.textContent.includes("Load lazy content")); const panel=()=>f.nextElementSibling; const before=panel().textContent.trim(); f.querySelector("button,input[type=submit]").click(); await new Promise(r=>setTimeout(r,700)); const after=panel().textContent.trim(); if(!(after.includes("Lazy content loaded by server update #")&&after!==before)) throw new Error("lazy load did not visibly update"); return true;})()"#;
|
||||||
const CLICK_TO_LOAD_SMOKE: &str = r#"(async()=>{const text=()=>document.body.textContent.replace(/\s+/g," "); const f=Array.from(document.querySelectorAll("form")).find(f=>f.textContent.includes("Load more")); f.querySelector("button,input[type=submit]").click(); await new Promise(r=>setTimeout(r,700)); if(!(text().includes("Loaded row 3")&&text().includes("Loaded row 4"))) throw new Error("click-to-load did not append rows"); return true;})()"#;
|
const CLICK_TO_LOAD_SMOKE: &str = r#"(async()=>{const text=()=>document.body.textContent.replace(/\s+/g," "); const f=Array.from(document.querySelectorAll("form")).find(f=>f.textContent.includes("Load more")); f.querySelector("button,input[type=submit]").click(); await new Promise(r=>setTimeout(r,700)); if(!(text().includes("Loaded row 3")&&text().includes("Loaded row 4"))) throw new Error("click-to-load did not append rows"); return true;})()"#;
|
||||||
const INFINITE_SCROLL_SMOKE: &str = r#"(async()=>{const text=()=>document.body.textContent.replace(/\s+/g," "); const f=Array.from(document.querySelectorAll("form")).find(f=>f.textContent.includes("Reveal more rows")); f.querySelector("button,input[type=submit]").click(); await new Promise(r=>setTimeout(r,700)); if(!(text().includes("Loaded row 4")&&text().includes("Loaded row 6"))) throw new Error("infinite scroll did not append rows"); return true;})()"#;
|
const INFINITE_SCROLL_SMOKE: &str = r#"(async()=>{const text=()=>document.body.textContent.replace(/\s+/g," "); const f=Array.from(document.querySelectorAll("form")).find(f=>f.textContent.includes("Reveal more rows")); f.querySelector("button,input[type=submit]").click(); await new Promise(r=>setTimeout(r,700)); if(!(text().includes("Loaded row 4")&&text().includes("Loaded row 6"))) throw new Error("infinite scroll did not append rows"); return true;})()"#;
|
||||||
const PROGRESS_SMOKE: &str = r#"(async()=>{await new Promise(r=>setTimeout(r,700)); const progress=document.querySelector("progress"); if(!(progress&&progress.textContent.includes("% complete")&&progress.textContent!=="0% complete")) throw new Error("progress did not tick"); return true;})()"#;
|
const PROGRESS_SMOKE: &str = r#"(async()=>{await new Promise(r=>setTimeout(r,700)); const progress=document.querySelector("progress"); if(!(progress&&progress.textContent.includes("% complete")&&progress.textContent!=="0% complete")) throw new Error("progress did not tick"); return true;})()"#;
|
||||||
|
|||||||
Reference in New Issue
Block a user