feat(core): format generated resources for templates
Implement Display for generated slots, keyed slots, atoms, and forms so public examples can pass typed resources directly to hemplate dynamic attributes and tests instead of extracting raw numeric ids. req: public_api/001 req: public_api/002
This commit is contained in:
@@ -73,7 +73,7 @@ mod tests {
|
||||
// req: examples/001 req: form/002 req: codegen/003
|
||||
#[test]
|
||||
fn kanban_template_exports_form_and_card_handles() {
|
||||
assert_ne!(ui::board::handles::create_card.id().id, ui::board::handles::move_right.id().id);
|
||||
assert_ne!(ui::board::handles::create_card.id(), ui::board::handles::move_right.id());
|
||||
assert_eq!(ui::board::forms::create_card.field("title").resource, ui::board::forms::create_card.id());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,10 @@ mod tests {
|
||||
// req: examples/001 req: form/002 req: codegen/003
|
||||
#[test]
|
||||
fn techdemo_exports_form_and_interaction_handles() {
|
||||
assert_ne!(ui::control_center::handles::launch_work.id().id, ui::control_center::handles::advance_work.id().id);
|
||||
assert_ne!(
|
||||
ui::control_center::handles::launch_work.id(),
|
||||
ui::control_center::handles::advance_work.id()
|
||||
);
|
||||
assert_eq!(
|
||||
ui::control_center::forms::launch_work.field("title").resource,
|
||||
ui::control_center::forms::launch_work.id()
|
||||
|
||||
@@ -53,11 +53,11 @@ async fn browser_drives_typed_product_end_to_end() -> WebDriverResult<()> {
|
||||
wait_for_runtime(&driver).await?;
|
||||
|
||||
driver
|
||||
.find(By::Css(&handle_selector(ui::control_center::handles::simulate_push.id().id)))
|
||||
.find(By::Css(&handle_selector(ui::control_center::handles::simulate_push)))
|
||||
.await?
|
||||
.click()
|
||||
.await?;
|
||||
wait_for_text(&driver, &slot_selector(ui::control_center::slots::notice.id().id), "Push simulated").await?;
|
||||
wait_for_text(&driver, &slot_selector(ui::control_center::slots::notice), "Push simulated").await?;
|
||||
|
||||
driver.find(By::Css("button.primary-action")).await?.click().await?;
|
||||
wait_for_text(&driver, ".work-card[data-key='4']", "Ship typed effects").await?;
|
||||
@@ -65,40 +65,40 @@ async fn browser_drives_typed_product_end_to_end() -> WebDriverResult<()> {
|
||||
|
||||
drag_card_to_lane(&driver, 2, "product").await?;
|
||||
wait_for_text(&driver, ".lane[data-lane='product'] .work-card[data-key='2']", "Shipped").await?;
|
||||
wait_for_text(&driver, &slot_selector(ui::control_center::slots::notice.id().id), "Drag-and-drop move persisted").await?;
|
||||
wait_for_text(&driver, &slot_selector(ui::control_center::slots::notice), "Drag-and-drop move persisted").await?;
|
||||
|
||||
driver
|
||||
.find(By::Css(&card_button_selector(ui::control_center::handles::spotlight_work.id().id, 2)))
|
||||
.find(By::Css(&card_button_selector(ui::control_center::handles::spotlight_work, 2)))
|
||||
.await?
|
||||
.click()
|
||||
.await?;
|
||||
wait_for_text(
|
||||
&driver,
|
||||
&slot_selector(ui::control_center::slots::inspector.id().id),
|
||||
&slot_selector(ui::control_center::slots::inspector),
|
||||
"Stream typed presence · lane=Product · stage=Shipped · impact=7",
|
||||
)
|
||||
.await?;
|
||||
|
||||
driver
|
||||
.find(By::Css(&card_button_selector(ui::control_center::handles::advance_work.id().id, 3)))
|
||||
.find(By::Css(&card_button_selector(ui::control_center::handles::advance_work, 3)))
|
||||
.await?
|
||||
.click()
|
||||
.await?;
|
||||
wait_for_text(&driver, ".lane[data-lane='product'] .work-card[data-key='3']", "Active").await?;
|
||||
|
||||
driver
|
||||
.find(By::Css(&handle_selector(ui::control_center::handles::simulate_push.id().id)))
|
||||
.find(By::Css(&handle_selector(ui::control_center::handles::simulate_push)))
|
||||
.await?
|
||||
.click()
|
||||
.await?;
|
||||
wait_for_text(&driver, &slot_selector(ui::control_center::slots::live_feed.id().id), "SSE tick").await?;
|
||||
wait_for_text(&driver, &slot_selector(ui::control_center::slots::live_feed), "SSE tick").await?;
|
||||
|
||||
driver.find(By::Css("a[href='/architecture']")).await?.click().await?;
|
||||
wait_for_text(&driver, &slot_selector(ui::control_center::slots::inspector.id().id), "Page swap").await?;
|
||||
wait_for_text(&driver, &slot_selector(ui::control_center::slots::inspector), "Page swap").await?;
|
||||
assert!(driver.current_url().await?.as_str().ends_with("/architecture"));
|
||||
|
||||
driver.goto(&format!("http://{APP_ADDR}/")).await?;
|
||||
wait_for_text(&driver, &slot_selector(ui::control_center::slots::live_feed.id().id), "SSE tick").await?;
|
||||
wait_for_text(&driver, &slot_selector(ui::control_center::slots::live_feed), "SSE tick").await?;
|
||||
|
||||
Ok::<(), WebDriverError>(())
|
||||
}
|
||||
@@ -119,15 +119,15 @@ fn wait_for_tcp(addr: &str) {
|
||||
panic!("timed out waiting for {addr}");
|
||||
}
|
||||
|
||||
fn handle_selector(id: u32) -> String {
|
||||
format!(r#"[data-hid="{id}"]"#)
|
||||
fn handle_selector(handle: impl std::fmt::Display) -> String {
|
||||
format!(r#"[data-hid="{handle}"]"#)
|
||||
}
|
||||
|
||||
fn slot_selector(id: u32) -> String {
|
||||
format!(r#"[data-sid="{id}"]"#)
|
||||
fn slot_selector(slot: impl std::fmt::Display) -> String {
|
||||
format!(r#"[data-sid="{slot}"]"#)
|
||||
}
|
||||
|
||||
fn card_button_selector(handle_id: u32, work_id: u64) -> String {
|
||||
fn card_button_selector(handle_id: impl std::fmt::Display, work_id: u64) -> String {
|
||||
format!(r#"[data-hid="{handle_id}"][data-work-id="{work_id}"]"#)
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ fn product_is_e2e_working_over_http() {
|
||||
|
||||
let move_to_lane = post(
|
||||
"/",
|
||||
&format!("__h={}&work_id=4&lane=runtime", ui::control_center::handles::move_to_lane.id().id),
|
||||
&format!("__h={}&work_id=4&lane=runtime", ui::control_center::handles::move_to_lane),
|
||||
);
|
||||
assert_effect_response(&move_to_lane);
|
||||
let move_to_lane_batch = move_to_lane.batch();
|
||||
|
||||
@@ -730,6 +730,12 @@ impl<T> Clone for Slot<T> {
|
||||
|
||||
impl<T> Copy for Slot<T> {}
|
||||
|
||||
impl<T> core::fmt::Display for Slot<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.id.id.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Slot<T> {
|
||||
pub const fn new(id: u32) -> Self {
|
||||
Self {
|
||||
@@ -778,6 +784,12 @@ impl<K, T> Clone for KeyedSlot<K, T> {
|
||||
|
||||
impl<K, T> Copy for KeyedSlot<K, T> {}
|
||||
|
||||
impl<K, T> core::fmt::Display for KeyedSlot<K, T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.id.id.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, T> KeyedSlot<K, T>
|
||||
where
|
||||
K: ToString,
|
||||
@@ -878,6 +890,12 @@ impl<T> Clone for Atom<T> {
|
||||
|
||||
impl<T> Copy for Atom<T> {}
|
||||
|
||||
impl<T> core::fmt::Display for Atom<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.id.id.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Atom<T> {
|
||||
pub const fn new(id: u32) -> Self {
|
||||
Self {
|
||||
@@ -951,6 +969,12 @@ impl<T> Clone for Form<T> {
|
||||
|
||||
impl<T> Copy for Form<T> {}
|
||||
|
||||
impl<T> core::fmt::Display for Form<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.id.id.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Form<T> {
|
||||
pub const fn new(id: u32) -> Self {
|
||||
Self {
|
||||
|
||||
@@ -102,9 +102,13 @@ fn component_refs_format_generated_component_names() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generated_handles_format_for_hemplate_dynamic_handle_attrs() {
|
||||
fn generated_resources_format_for_hemplate_dynamic_attrs() {
|
||||
// req: public_api/001 req: public_api/002
|
||||
assert_eq!(Slot::<String>::new(10).to_string(), "10");
|
||||
assert_eq!(KeyedSlot::<u64, String>::new(11).to_string(), "11");
|
||||
assert_eq!(Atom::<String>::new(12).to_string(), "12");
|
||||
assert_eq!(Handle::<()>::new(42).to_string(), "42");
|
||||
assert_eq!(Form::<()>::new(13).to_string(), "13");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user