mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
libservo: Allow embedders to execute JavaScript scripts via the API (#35720)
This change adds a new `WebView` API `evaluate_javascript()`, which allows embedders to execute JavaScript code and wait for a reply asynchronously. Ongoing script execution is tracked by a libservo `JavaScriptEvaluator` struct, which maps an id to the callback passed to the `evaluate_javascript()` method. The id is used to track the script and its execution through the other parts of Servo. Testing: This changes includes `WebView` unit tests. --------- Signed-off-by: Narfinger <Narfinger@users.noreply.github.com> Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
91c4c7b998
commit
991be359a3
12 changed files with 391 additions and 18 deletions
|
@ -11,12 +11,14 @@
|
|||
|
||||
mod common;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
|
||||
use anyhow::ensure;
|
||||
use common::{ServoTest, run_api_tests};
|
||||
use servo::{WebViewBuilder, WebViewDelegate};
|
||||
use servo::{
|
||||
JSValue, JavaScriptEvaluationError, LoadStatus, WebView, WebViewBuilder, WebViewDelegate,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
struct WebViewDelegateImpl {
|
||||
|
@ -44,6 +46,81 @@ fn test_create_webview(servo_test: &ServoTest) -> Result<(), anyhow::Error> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn evaluate_javascript(
|
||||
servo_test: &ServoTest,
|
||||
webview: WebView,
|
||||
script: impl ToString,
|
||||
) -> Result<JSValue, JavaScriptEvaluationError> {
|
||||
let load_webview = webview.clone();
|
||||
let _ = servo_test.spin(move || Ok(load_webview.load_status() != LoadStatus::Complete));
|
||||
|
||||
let saved_result = Rc::new(RefCell::new(None));
|
||||
let callback_result = saved_result.clone();
|
||||
webview.evaluate_javascript(script, move |result| {
|
||||
*callback_result.borrow_mut() = Some(result)
|
||||
});
|
||||
|
||||
let spin_result = saved_result.clone();
|
||||
let _ = servo_test.spin(move || Ok(spin_result.borrow().is_none()));
|
||||
|
||||
(*saved_result.borrow())
|
||||
.clone()
|
||||
.expect("Should have waited until value available")
|
||||
}
|
||||
|
||||
fn test_evaluate_javascript_basic(servo_test: &ServoTest) -> Result<(), anyhow::Error> {
|
||||
let delegate = Rc::new(WebViewDelegateImpl::default());
|
||||
let webview = WebViewBuilder::new(servo_test.servo())
|
||||
.delegate(delegate.clone())
|
||||
.build();
|
||||
|
||||
let result = evaluate_javascript(servo_test, webview.clone(), "undefined");
|
||||
ensure!(result == Ok(JSValue::Undefined));
|
||||
|
||||
let result = evaluate_javascript(servo_test, webview.clone(), "null");
|
||||
ensure!(result == Ok(JSValue::Null));
|
||||
|
||||
let result = evaluate_javascript(servo_test, webview.clone(), "42");
|
||||
ensure!(result == Ok(JSValue::Number(42.0)));
|
||||
|
||||
let result = evaluate_javascript(servo_test, webview.clone(), "3 + 4");
|
||||
ensure!(result == Ok(JSValue::Number(7.0)));
|
||||
|
||||
let result = evaluate_javascript(servo_test, webview.clone(), "'abc' + 'def'");
|
||||
ensure!(result == Ok(JSValue::String("abcdef".into())));
|
||||
|
||||
let result = evaluate_javascript(servo_test, webview.clone(), "let foo = {blah: 123}; foo");
|
||||
ensure!(matches!(result, Ok(JSValue::Object(_))));
|
||||
if let Ok(JSValue::Object(values)) = result {
|
||||
ensure!(values.len() == 1);
|
||||
ensure!(values.get("blah") == Some(&JSValue::Number(123.0)));
|
||||
}
|
||||
|
||||
let result = evaluate_javascript(servo_test, webview.clone(), "[1, 2, 3, 4]");
|
||||
let expected = JSValue::Array(vec![
|
||||
JSValue::Number(1.0),
|
||||
JSValue::Number(2.0),
|
||||
JSValue::Number(3.0),
|
||||
JSValue::Number(4.0),
|
||||
]);
|
||||
ensure!(result == Ok(expected));
|
||||
|
||||
let result = evaluate_javascript(servo_test, webview.clone(), "window");
|
||||
ensure!(matches!(result, Ok(JSValue::Window(..))));
|
||||
|
||||
let result = evaluate_javascript(servo_test, webview.clone(), "document.body");
|
||||
ensure!(matches!(result, Ok(JSValue::Element(..))));
|
||||
|
||||
let result = evaluate_javascript(
|
||||
servo_test,
|
||||
webview.clone(),
|
||||
"document.body.innerHTML += '<iframe>'; frames[0]",
|
||||
);
|
||||
ensure!(matches!(result, Ok(JSValue::Frame(..))));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn test_create_webview_and_immediately_drop_webview_before_shutdown(
|
||||
servo_test: &ServoTest,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
|
@ -54,6 +131,7 @@ fn test_create_webview_and_immediately_drop_webview_before_shutdown(
|
|||
fn main() {
|
||||
run_api_tests!(
|
||||
test_create_webview,
|
||||
test_evaluate_javascript_basic,
|
||||
// This test needs to be last, as it tests creating and dropping
|
||||
// a WebView right before shutdown.
|
||||
test_create_webview_and_immediately_drop_webview_before_shutdown
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue