test: assert panel rows-ready fixture data
This commit is contained in:
parent
d32fb3bc3c
commit
fffdfd2721
|
|
@ -151,9 +151,13 @@ pub(crate) async fn run(
|
||||||
#[cfg(feature = "e2e-test")]
|
#[cfg(feature = "e2e-test")]
|
||||||
{
|
{
|
||||||
if !emitted_panel_ready {
|
if !emitted_panel_ready {
|
||||||
|
// `panel_ready` is a first-visible-frame signal only. E2E tests that need
|
||||||
|
// list/data readiness must wait for a concrete `rows_rendered` fixture row.
|
||||||
crate::e2e_observer::emit("panel", "panel_ready", serde_json::json!({}));
|
crate::e2e_observer::emit("panel", "panel_ready", serde_json::json!({}));
|
||||||
emitted_panel_ready = true;
|
emitted_panel_ready = true;
|
||||||
}
|
}
|
||||||
|
// Emit every drawn row snapshot separately so tests can assert data-backed row
|
||||||
|
// readiness without conflating it with the first frame.
|
||||||
app.emit_rows_rendered();
|
app.emit_rows_rendered();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -267,12 +267,78 @@ pub struct RenderedPanelRow {
|
||||||
pub rect: PanelRect,
|
pub rect: PanelRect,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct ExpectedPanelTicketRow {
|
||||||
|
pub id: String,
|
||||||
|
pub title: String,
|
||||||
|
pub status: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExpectedPanelTicketRow {
|
||||||
|
pub fn new(id: impl Into<String>, title: impl Into<String>, status: impl Into<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: id.into(),
|
||||||
|
title: title.into(),
|
||||||
|
status: status.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn matches(&self, row: &RenderedPanelRow) -> bool {
|
||||||
|
row.key.kind == "ticket"
|
||||||
|
&& row.key.id == self.id
|
||||||
|
&& row.title == self.title
|
||||||
|
&& row.status.as_deref() == Some(self.status.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description(&self) -> String {
|
||||||
|
format!(
|
||||||
|
"ticket row id={} title={:?} status={}",
|
||||||
|
self.id, self.title, self.status
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct RowsRendered {
|
pub struct RowsRendered {
|
||||||
pub selected: Option<PanelRowKey>,
|
pub selected: Option<PanelRowKey>,
|
||||||
pub rows: Vec<RenderedPanelRow>,
|
pub rows: Vec<RenderedPanelRow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RowsRendered {
|
||||||
|
pub fn fixture_ticket_row(
|
||||||
|
&self,
|
||||||
|
expected: &ExpectedPanelTicketRow,
|
||||||
|
) -> Option<&RenderedPanelRow> {
|
||||||
|
self.rows.iter().find(|row| expected.matches(row))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_fixture_ticket_row(&self, expected: &ExpectedPanelTicketRow) -> bool {
|
||||||
|
self.fixture_ticket_row(expected).is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rows_rendered_event_has_fixture_ticket(
|
||||||
|
event: &HarnessEvent,
|
||||||
|
expected: &ExpectedPanelTicketRow,
|
||||||
|
) -> bool {
|
||||||
|
serde_json::from_value::<RowsRendered>(event.data.clone())
|
||||||
|
.map(|rows| rows.has_fixture_ticket_row(expected))
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn describe_rows(rows: &RowsRendered) -> String {
|
||||||
|
rows.rows
|
||||||
|
.iter()
|
||||||
|
.map(|row| {
|
||||||
|
format!(
|
||||||
|
"{}:{} title={:?} status={:?}",
|
||||||
|
row.key.kind, row.key.id, row.title, row.status
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum KeyPress {
|
pub enum KeyPress {
|
||||||
CtrlC,
|
CtrlC,
|
||||||
|
|
@ -445,6 +511,69 @@ impl PanelHarness {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Waits for the legacy `panel_ready` observer event, which means the first
|
||||||
|
/// panel frame was painted. It intentionally does not mean workspace rows or
|
||||||
|
/// Ticket data are ready.
|
||||||
|
pub fn wait_for_first_visible_frame(&mut self, timeout: Duration) -> Result<HarnessEvent> {
|
||||||
|
self.wait_for(
|
||||||
|
"first visible panel frame (panel_ready, before rows readiness)",
|
||||||
|
timeout,
|
||||||
|
|event| event.event == "panel_ready",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Waits until a concrete fixture Ticket row has rendered. This is the
|
||||||
|
/// startup rows-ready signal; it validates id + title + state rather than
|
||||||
|
/// using only the number of rendered rows.
|
||||||
|
pub fn wait_for_fixture_ticket_rows_ready(
|
||||||
|
&mut self,
|
||||||
|
expected: &ExpectedPanelTicketRow,
|
||||||
|
timeout: Duration,
|
||||||
|
) -> Result<RowsRendered> {
|
||||||
|
let description = expected.description();
|
||||||
|
let event = self.wait_for(
|
||||||
|
format!("fixture Ticket rows ready ({description})"),
|
||||||
|
timeout,
|
||||||
|
|event| {
|
||||||
|
event.event == "rows_rendered"
|
||||||
|
&& rows_rendered_event_has_fixture_ticket(event, expected)
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
serde_json::from_value(event.data).map_err(HarnessError::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assert_fixture_ticket_row_not_rendered(
|
||||||
|
&mut self,
|
||||||
|
expected: &ExpectedPanelTicketRow,
|
||||||
|
duration: Duration,
|
||||||
|
) -> Result<()> {
|
||||||
|
let start = Instant::now();
|
||||||
|
while start.elapsed() < duration {
|
||||||
|
if let Some(rows) = self
|
||||||
|
.events()?
|
||||||
|
.iter()
|
||||||
|
.filter(|event| event.event == "rows_rendered")
|
||||||
|
.filter_map(|event| serde_json::from_value::<RowsRendered>(event.data.clone()).ok())
|
||||||
|
.find(|rows| rows.has_fixture_ticket_row(expected))
|
||||||
|
{
|
||||||
|
self.flush_output_artifact()?;
|
||||||
|
return Err(HarnessError::Protocol(format!(
|
||||||
|
"fixture Ticket row rendered before data-backed rows readiness was expected: {}; rows: {}",
|
||||||
|
expected.description(),
|
||||||
|
describe_rows(&rows)
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
if let Some(status) = self.child.try_wait()? {
|
||||||
|
self.flush_output_artifact()?;
|
||||||
|
return Err(HarnessError::Protocol(format!(
|
||||||
|
"process exited with {status} while asserting fixture Ticket rows stayed delayed"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
thread::sleep(Duration::from_millis(20));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn wait_for_rows(&mut self, min_rows: usize) -> Result<RowsRendered> {
|
pub fn wait_for_rows(&mut self, min_rows: usize) -> Result<RowsRendered> {
|
||||||
let event = self.wait_for("rows_rendered", DEFAULT_WAIT, |event| {
|
let event = self.wait_for("rows_rendered", DEFAULT_WAIT, |event| {
|
||||||
event.event == "rows_rendered"
|
event.event == "rows_rendered"
|
||||||
|
|
@ -781,6 +910,9 @@ pub struct FixtureCleanupReport {
|
||||||
pub report_path: PathBuf,
|
pub report_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const READY_FIXTURE_TICKET_TITLE: &str = "Ready E2E Ticket";
|
||||||
|
pub const PLANNING_FIXTURE_TICKET_TITLE: &str = "Planning E2E Ticket";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FixtureWorkspace {
|
pub struct FixtureWorkspace {
|
||||||
temp_root: Option<TempDir>,
|
temp_root: Option<TempDir>,
|
||||||
|
|
@ -792,6 +924,8 @@ pub struct FixtureWorkspace {
|
||||||
pub xdg_config_home: PathBuf,
|
pub xdg_config_home: PathBuf,
|
||||||
pub xdg_runtime_dir: PathBuf,
|
pub xdg_runtime_dir: PathBuf,
|
||||||
pub artifacts_dir: PathBuf,
|
pub artifacts_dir: PathBuf,
|
||||||
|
pub ready_ticket_id: String,
|
||||||
|
pub planning_ticket_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FixtureWorkspace {
|
impl FixtureWorkspace {
|
||||||
|
|
@ -832,7 +966,7 @@ impl FixtureWorkspace {
|
||||||
fs::create_dir_all(dir)?;
|
fs::create_dir_all(dir)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let fixture = Self {
|
let mut fixture = Self {
|
||||||
temp_root: Some(temp_root),
|
temp_root: Some(temp_root),
|
||||||
root,
|
root,
|
||||||
workspace,
|
workspace,
|
||||||
|
|
@ -842,6 +976,8 @@ impl FixtureWorkspace {
|
||||||
xdg_config_home,
|
xdg_config_home,
|
||||||
xdg_runtime_dir,
|
xdg_runtime_dir,
|
||||||
artifacts_dir,
|
artifacts_dir,
|
||||||
|
ready_ticket_id: String::new(),
|
||||||
|
planning_ticket_id: String::new(),
|
||||||
};
|
};
|
||||||
fixture.write_fixture_metadata("created", None)?;
|
fixture.write_fixture_metadata("created", None)?;
|
||||||
|
|
||||||
|
|
@ -867,7 +1003,7 @@ impl FixtureWorkspace {
|
||||||
&fixture.xdg_config_home,
|
&fixture.xdg_config_home,
|
||||||
&fixture.xdg_runtime_dir,
|
&fixture.xdg_runtime_dir,
|
||||||
&fixture.artifacts_dir,
|
&fixture.artifacts_dir,
|
||||||
"Ready E2E Ticket",
|
READY_FIXTURE_TICKET_TITLE,
|
||||||
)?;
|
)?;
|
||||||
run_yoi(
|
run_yoi(
|
||||||
binary,
|
binary,
|
||||||
|
|
@ -880,7 +1016,7 @@ impl FixtureWorkspace {
|
||||||
&fixture.artifacts_dir,
|
&fixture.artifacts_dir,
|
||||||
&["ticket", "state", &first, "ready"],
|
&["ticket", "state", &first, "ready"],
|
||||||
)?;
|
)?;
|
||||||
let _second = create_ticket(
|
let second = create_ticket(
|
||||||
binary,
|
binary,
|
||||||
&fixture.workspace,
|
&fixture.workspace,
|
||||||
&fixture.home,
|
&fixture.home,
|
||||||
|
|
@ -889,12 +1025,22 @@ impl FixtureWorkspace {
|
||||||
&fixture.xdg_config_home,
|
&fixture.xdg_config_home,
|
||||||
&fixture.xdg_runtime_dir,
|
&fixture.xdg_runtime_dir,
|
||||||
&fixture.artifacts_dir,
|
&fixture.artifacts_dir,
|
||||||
"Planning E2E Ticket",
|
PLANNING_FIXTURE_TICKET_TITLE,
|
||||||
)?;
|
)?;
|
||||||
|
fixture.ready_ticket_id = first;
|
||||||
|
fixture.planning_ticket_id = second;
|
||||||
fixture.write_fixture_metadata("ready", None)?;
|
fixture.write_fixture_metadata("ready", None)?;
|
||||||
Ok(fixture)
|
Ok(fixture)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ready_fixture_ticket_row(&self) -> ExpectedPanelTicketRow {
|
||||||
|
ExpectedPanelTicketRow::new(
|
||||||
|
self.ready_ticket_id.clone(),
|
||||||
|
READY_FIXTURE_TICKET_TITLE,
|
||||||
|
"ready",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn panel_config(&self, binary: PathBuf) -> PanelHarnessConfig {
|
pub fn panel_config(&self, binary: PathBuf) -> PanelHarnessConfig {
|
||||||
PanelHarnessConfig {
|
PanelHarnessConfig {
|
||||||
binary,
|
binary,
|
||||||
|
|
@ -999,6 +1145,18 @@ impl FixtureWorkspace {
|
||||||
"xdg_config_home": &self.xdg_config_home,
|
"xdg_config_home": &self.xdg_config_home,
|
||||||
"xdg_runtime_dir": &self.xdg_runtime_dir,
|
"xdg_runtime_dir": &self.xdg_runtime_dir,
|
||||||
"artifacts_dir": &self.artifacts_dir,
|
"artifacts_dir": &self.artifacts_dir,
|
||||||
|
"tickets": {
|
||||||
|
"ready": {
|
||||||
|
"id": &self.ready_ticket_id,
|
||||||
|
"title": READY_FIXTURE_TICKET_TITLE,
|
||||||
|
"state": "ready"
|
||||||
|
},
|
||||||
|
"planning": {
|
||||||
|
"id": &self.planning_ticket_id,
|
||||||
|
"title": PLANNING_FIXTURE_TICKET_TITLE,
|
||||||
|
"state": "planning"
|
||||||
|
}
|
||||||
|
},
|
||||||
"env_runtime_policy": {
|
"env_runtime_policy": {
|
||||||
"tested_yoi_uses_env_clear": true,
|
"tested_yoi_uses_env_clear": true,
|
||||||
"host_runtime_inherited": false,
|
"host_runtime_inherited": false,
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,62 @@
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
const FIRST_VISIBLE_RENDER_BUDGET: Duration = Duration::from_millis(1500);
|
const FIRST_VISIBLE_RENDER_BUDGET: Duration = Duration::from_millis(1500);
|
||||||
const FULL_READY_BUDGET: Duration = Duration::from_secs(5);
|
const ROWS_READY_BUDGET: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
use yoi_e2e::{
|
use yoi_e2e::{
|
||||||
FixtureCleanupReport, FixtureWorkspace, KeyPress, PanelHarness, RenderedPanelRow, yoi_binary,
|
ExpectedPanelTicketRow, FixtureCleanupReport, FixtureWorkspace, KeyPress, PanelHarness,
|
||||||
|
PanelRect, PanelRowKey, RenderedPanelRow, RowsRendered, yoi_binary,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn panel_fixture_ticket_row_matcher_rejects_absent_fixture_data() {
|
||||||
|
let expected = ExpectedPanelTicketRow::new("0000000000000", "Ready E2E Ticket", "ready");
|
||||||
|
let wrong_title = RenderedPanelRow {
|
||||||
|
key: PanelRowKey {
|
||||||
|
kind: "ticket".to_string(),
|
||||||
|
id: "0000000000000".to_string(),
|
||||||
|
},
|
||||||
|
title: "Different Ticket".to_string(),
|
||||||
|
status: Some("ready".to_string()),
|
||||||
|
action: None,
|
||||||
|
rect: PanelRect {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 10,
|
||||||
|
height: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let wrong_kind = RenderedPanelRow {
|
||||||
|
key: PanelRowKey {
|
||||||
|
kind: "pod".to_string(),
|
||||||
|
id: "0000000000000".to_string(),
|
||||||
|
},
|
||||||
|
title: "Ready E2E Ticket".to_string(),
|
||||||
|
status: Some("ready".to_string()),
|
||||||
|
action: None,
|
||||||
|
rect: PanelRect {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 10,
|
||||||
|
height: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(!expected.matches(&wrong_title));
|
||||||
|
assert!(!expected.matches(&wrong_kind));
|
||||||
|
let rows = RowsRendered {
|
||||||
|
selected: None,
|
||||||
|
rows: vec![wrong_title, wrong_kind],
|
||||||
|
};
|
||||||
|
assert!(!rows.has_fixture_ticket_row(&expected));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn panel_first_visible_render_arrives_before_background_reload() -> yoi_e2e::Result<()> {
|
fn panel_first_visible_render_arrives_before_background_reload() -> yoi_e2e::Result<()> {
|
||||||
let binary = yoi_binary()?;
|
let binary = yoi_binary()?;
|
||||||
let fixture = FixtureWorkspace::new(&binary)?;
|
let fixture = FixtureWorkspace::new(&binary)?;
|
||||||
assert_fixture_paths_are_isolated(&fixture);
|
assert_fixture_paths_are_isolated(&fixture);
|
||||||
|
let ready_ticket = fixture.ready_fixture_ticket_row();
|
||||||
|
|
||||||
let started = Instant::now();
|
let started = Instant::now();
|
||||||
let mut panel =
|
let mut panel =
|
||||||
|
|
@ -19,17 +64,15 @@ fn panel_first_visible_render_arrives_before_background_reload() -> yoi_e2e::Res
|
||||||
let remaining = FIRST_VISIBLE_RENDER_BUDGET
|
let remaining = FIRST_VISIBLE_RENDER_BUDGET
|
||||||
.checked_sub(started.elapsed())
|
.checked_sub(started.elapsed())
|
||||||
.unwrap_or_else(|| Duration::from_millis(0));
|
.unwrap_or_else(|| Duration::from_millis(0));
|
||||||
panel.wait_for("first visible panel render", remaining, |event| {
|
panel.wait_for_first_visible_frame(remaining)?;
|
||||||
event.event == "panel_ready"
|
|
||||||
})?;
|
|
||||||
let first_visible_elapsed = started.elapsed();
|
let first_visible_elapsed = started.elapsed();
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"panel first visible render: {first_visible_elapsed:?} (budget {FIRST_VISIBLE_RENDER_BUDGET:?}); artifacts at {}",
|
"panel first visible frame: {first_visible_elapsed:?} (budget {FIRST_VISIBLE_RENDER_BUDGET:?}); artifacts at {}",
|
||||||
panel.artifacts().dir.display()
|
panel.artifacts().dir.display()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
first_visible_elapsed <= FIRST_VISIBLE_RENDER_BUDGET,
|
first_visible_elapsed <= FIRST_VISIBLE_RENDER_BUDGET,
|
||||||
"first visible render took {first_visible_elapsed:?}, budget {FIRST_VISIBLE_RENDER_BUDGET:?}; artifacts at {}",
|
"first visible frame took {first_visible_elapsed:?}, budget {FIRST_VISIBLE_RENDER_BUDGET:?}; artifacts at {}",
|
||||||
panel.artifacts().dir.display()
|
panel.artifacts().dir.display()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -42,7 +85,7 @@ fn panel_first_visible_render_arrives_before_background_reload() -> yoi_e2e::Res
|
||||||
events[..ready_index]
|
events[..ready_index]
|
||||||
.iter()
|
.iter()
|
||||||
.all(|event| event.event != "background_task_started"),
|
.all(|event| event.event != "background_task_started"),
|
||||||
"initial render must be emitted before reload/background work starts; artifacts at {}",
|
"initial frame must be emitted before reload/background work starts; artifacts at {}",
|
||||||
panel.artifacts().dir.display()
|
panel.artifacts().dir.display()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -54,12 +97,13 @@ fn panel_first_visible_render_arrives_before_background_reload() -> yoi_e2e::Res
|
||||||
event.event == "background_task_started"
|
event.event == "background_task_started"
|
||||||
&& event.data.get("task").and_then(serde_json::Value::as_str) == Some("reload")
|
&& event.data.get("task").and_then(serde_json::Value::as_str) == Some("reload")
|
||||||
})
|
})
|
||||||
.expect("held reload should start after first visible render");
|
.expect("held reload should start after first visible frame");
|
||||||
assert!(
|
assert!(
|
||||||
ready_index < reload_started_index,
|
ready_index < reload_started_index,
|
||||||
"first visible render and reload ordering should remain separate; artifacts at {}",
|
"first visible frame and reload ordering should remain separate; artifacts at {}",
|
||||||
panel.artifacts().dir.display()
|
panel.artifacts().dir.display()
|
||||||
);
|
);
|
||||||
|
panel.assert_fixture_ticket_row_not_rendered(&ready_ticket, Duration::from_millis(150))?;
|
||||||
|
|
||||||
panel.press(KeyPress::CtrlC)?;
|
panel.press(KeyPress::CtrlC)?;
|
||||||
let status = panel.expect_exit_within(PanelHarness::default_exit_wait())?;
|
let status = panel.expect_exit_within(PanelHarness::default_exit_wait())?;
|
||||||
|
|
@ -70,51 +114,46 @@ fn panel_first_visible_render_arrives_before_background_reload() -> yoi_e2e::Res
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn panel_full_ready_has_separate_startup_budget() -> yoi_e2e::Result<()> {
|
fn panel_fixture_ticket_row_ready_has_startup_budget() -> yoi_e2e::Result<()> {
|
||||||
let binary = yoi_binary()?;
|
let binary = yoi_binary()?;
|
||||||
let fixture = FixtureWorkspace::new(&binary)?;
|
let fixture = FixtureWorkspace::new(&binary)?;
|
||||||
assert_fixture_paths_are_isolated(&fixture);
|
assert_fixture_paths_are_isolated(&fixture);
|
||||||
|
let ready_ticket = fixture.ready_fixture_ticket_row();
|
||||||
|
|
||||||
let started = Instant::now();
|
let started = Instant::now();
|
||||||
let mut panel = PanelHarness::spawn(fixture.panel_config(binary))?;
|
let mut panel = PanelHarness::spawn(fixture.panel_config(binary))?;
|
||||||
let first_visible_remaining = FIRST_VISIBLE_RENDER_BUDGET
|
let first_visible_remaining = FIRST_VISIBLE_RENDER_BUDGET
|
||||||
.checked_sub(started.elapsed())
|
.checked_sub(started.elapsed())
|
||||||
.unwrap_or_else(|| Duration::from_millis(0));
|
.unwrap_or_else(|| Duration::from_millis(0));
|
||||||
panel.wait_for(
|
panel.wait_for_first_visible_frame(first_visible_remaining)?;
|
||||||
"first visible panel render",
|
|
||||||
first_visible_remaining,
|
|
||||||
|event| event.event == "panel_ready",
|
|
||||||
)?;
|
|
||||||
let first_visible_elapsed = started.elapsed();
|
let first_visible_elapsed = started.elapsed();
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"panel first visible render: {first_visible_elapsed:?} (budget {FIRST_VISIBLE_RENDER_BUDGET:?}); artifacts at {}",
|
"panel first visible frame: {first_visible_elapsed:?} (budget {FIRST_VISIBLE_RENDER_BUDGET:?}); artifacts at {}",
|
||||||
panel.artifacts().dir.display()
|
panel.artifacts().dir.display()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
first_visible_elapsed <= FIRST_VISIBLE_RENDER_BUDGET,
|
first_visible_elapsed <= FIRST_VISIBLE_RENDER_BUDGET,
|
||||||
"first visible render took {first_visible_elapsed:?}, budget {FIRST_VISIBLE_RENDER_BUDGET:?}; artifacts at {}",
|
"first visible frame took {first_visible_elapsed:?}, budget {FIRST_VISIBLE_RENDER_BUDGET:?}; artifacts at {}",
|
||||||
panel.artifacts().dir.display()
|
panel.artifacts().dir.display()
|
||||||
);
|
);
|
||||||
|
|
||||||
let full_ready_remaining = FULL_READY_BUDGET
|
let rows_ready_remaining = ROWS_READY_BUDGET
|
||||||
.checked_sub(started.elapsed())
|
.checked_sub(started.elapsed())
|
||||||
.unwrap_or_else(|| Duration::from_millis(0));
|
.unwrap_or_else(|| Duration::from_millis(0));
|
||||||
panel.wait_for("full ready fixture rows", full_ready_remaining, |event| {
|
let rows = panel.wait_for_fixture_ticket_rows_ready(&ready_ticket, rows_ready_remaining)?;
|
||||||
event.event == "rows_rendered"
|
assert!(
|
||||||
&& event
|
rows.has_fixture_ticket_row(&ready_ticket),
|
||||||
.data
|
"rows-ready event must contain concrete ready fixture Ticket row; artifacts at {}",
|
||||||
.get("rows")
|
panel.artifacts().dir.display()
|
||||||
.and_then(serde_json::Value::as_array)
|
);
|
||||||
.is_some_and(|rows| rows.len() >= 2)
|
let rows_ready_elapsed = started.elapsed();
|
||||||
})?;
|
|
||||||
let full_ready_elapsed = started.elapsed();
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"panel full ready: {full_ready_elapsed:?} (budget {FULL_READY_BUDGET:?}); artifacts at {}",
|
"panel fixture rows ready: {rows_ready_elapsed:?} (budget {ROWS_READY_BUDGET:?}); artifacts at {}",
|
||||||
panel.artifacts().dir.display()
|
panel.artifacts().dir.display()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
full_ready_elapsed <= FULL_READY_BUDGET,
|
rows_ready_elapsed <= ROWS_READY_BUDGET,
|
||||||
"full ready took {full_ready_elapsed:?}, budget {FULL_READY_BUDGET:?}; artifacts at {}",
|
"fixture rows ready took {rows_ready_elapsed:?}, budget {ROWS_READY_BUDGET:?}; artifacts at {}",
|
||||||
panel.artifacts().dir.display()
|
panel.artifacts().dir.display()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user