Playwright calls Page.getLayoutMetrics before every page.screenshot() to size the capture. Without it the call fails with "Unknown Page method: getLayoutMetrics" and screenshot() throws. Obscura has no visual layout engine, so we return a fixed 1280x720 viewport (Chrome's default) and try to derive the content height from document.documentElement.scrollHeight via the JS runtime, falling back to the viewport height when no live page is bound. Generated by Ora Studio Vibe coded by ousamabenyounes Co-authored-by: Ora Studio <noreply@oratelecom.net>
This commit is contained in:
1 parent
90ededfc44
commit
3bb628eaf0
1 file changed
+88
@@ -223,6 +223,43 @@ pub async fn handle(
|
||||
Ok(json!({}))
|
||||
}
|
||||
"setInterceptFileChooserDialog" => Ok(json!({})),
|
||||
"getLayoutMetrics" => {
|
||||
// Obscura has no visual layout engine, so we return a fixed
|
||||
// 1280x720 viewport (Chrome's default) and try to derive the
|
||||
// content height from document.documentElement.scrollHeight.
|
||||
// Playwright calls this before every page.screenshot() and
|
||||
// would otherwise fail with "Unknown Page method".
|
||||
let width = 1280.0_f64;
|
||||
let height = 720.0_f64;
|
||||
let content_height = ctx
|
||||
.get_session_page_mut(session_id)
|
||||
.map(|p| p.evaluate("document.documentElement && document.documentElement.scrollHeight"))
|
||||
.and_then(|v| v.as_f64())
|
||||
.filter(|n| *n > 0.0)
|
||||
.unwrap_or(height);
|
||||
let layout_viewport = json!({
|
||||
"pageX": 0, "pageY": 0,
|
||||
"clientWidth": width, "clientHeight": height,
|
||||
});
|
||||
let visual_viewport = json!({
|
||||
"offsetX": 0.0, "offsetY": 0.0,
|
||||
"pageX": 0.0, "pageY": 0.0,
|
||||
"clientWidth": width, "clientHeight": height,
|
||||
"scale": 1.0, "zoom": 1.0,
|
||||
});
|
||||
let content_size = json!({
|
||||
"x": 0.0, "y": 0.0,
|
||||
"width": width, "height": content_height,
|
||||
});
|
||||
Ok(json!({
|
||||
"layoutViewport": layout_viewport,
|
||||
"visualViewport": visual_viewport,
|
||||
"contentSize": content_size,
|
||||
"cssLayoutViewport": layout_viewport,
|
||||
"cssVisualViewport": visual_viewport,
|
||||
"cssContentSize": content_size,
|
||||
}))
|
||||
}
|
||||
"getNavigationHistory" => {
|
||||
let page = ctx.get_session_page(session_id).ok_or("No page for session")?;
|
||||
Ok(json!({
|
||||
@@ -246,3 +283,54 @@ fn timestamp() -> f64 {
|
||||
.unwrap_or_default()
|
||||
.as_secs_f64()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::dispatch::CdpContext;
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_layout_metrics_returns_chrome_default_viewport() {
|
||||
let mut ctx = CdpContext::new();
|
||||
let result = handle("getLayoutMetrics", &json!({}), &mut ctx, &None)
|
||||
.await
|
||||
.expect("getLayoutMetrics should succeed without a session");
|
||||
|
||||
// CDP spec requires three top-level shapes; Playwright's screenshot
|
||||
// path reads contentSize.width/height to size the capture. Without
|
||||
// them the screenshot call panics with "cannot read property of
|
||||
// undefined".
|
||||
for key in [
|
||||
"layoutViewport",
|
||||
"visualViewport",
|
||||
"contentSize",
|
||||
"cssLayoutViewport",
|
||||
"cssVisualViewport",
|
||||
"cssContentSize",
|
||||
] {
|
||||
assert!(result.get(key).is_some(), "missing key: {key}");
|
||||
}
|
||||
|
||||
let layout = &result["layoutViewport"];
|
||||
assert_eq!(layout["clientWidth"].as_f64(), Some(1280.0));
|
||||
assert_eq!(layout["clientHeight"].as_f64(), Some(720.0));
|
||||
|
||||
let visual = &result["visualViewport"];
|
||||
assert_eq!(visual["scale"].as_f64(), Some(1.0));
|
||||
assert_eq!(visual["clientWidth"].as_f64(), Some(1280.0));
|
||||
|
||||
let content = &result["contentSize"];
|
||||
assert_eq!(content["width"].as_f64(), Some(1280.0));
|
||||
// Without a live page the content height falls back to the viewport.
|
||||
assert_eq!(content["height"].as_f64(), Some(720.0));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn unknown_page_method_still_errors() {
|
||||
let mut ctx = CdpContext::new();
|
||||
let err = handle("notARealMethod", &json!({}), &mut ctx, &None)
|
||||
.await
|
||||
.expect_err("unknown methods must surface as errors");
|
||||
assert!(err.contains("Unknown Page method"));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user