script: Make adjacent errors and console.log messages log in correct order (#44243)

Made adjacent errors and console.log messages log in correct order

Testing: ```./mach test-unit -p servo --
test_console_log_and_error_ordering``` passed.
Fixes: #44204

---------

Signed-off-by: Sabb <sarafaabbas@gmail.com>
This commit is contained in:
Abbas Olanrewaju Sarafa
2026-04-16 21:33:50 +01:00
committed by GitHub
parent 83eacc517a
commit 77e75aaf9e
3 changed files with 67 additions and 9 deletions

View File

@@ -20,7 +20,9 @@ use content_security_policy::CspList;
use crossbeam_channel::Sender;
use devtools_traits::{PageError, ScriptToDevtoolsControlMsg, get_time_stamp};
use dom_struct::dom_struct;
use embedder_traits::{EmbedderMsg, JavaScriptEvaluationError, ScriptToEmbedderChan};
use embedder_traits::{
ConsoleLogLevel, EmbedderMsg, JavaScriptEvaluationError, ScriptToEmbedderChan,
};
use fonts::FontContext;
use indexmap::IndexSet;
use ipc_channel::ipc::{self};
@@ -2719,11 +2721,6 @@ impl GlobalScope {
/// Steps 6-7 of <https://html.spec.whatwg.org/multipage/#report-an-exception>
pub(crate) fn report_an_error(&self, error_info: ErrorInfo, value: HandleValue, can_gc: CanGc) {
error!(
"Error at {}:{}:{} {}",
error_info.filename, error_info.lineno, error_info.column, error_info.message
);
#[cfg(feature = "js_backtrace")]
LAST_EXCEPTION_BACKTRACE.with(|backtrace| {
if let Some((js_backtrace, rust_backtrace)) = backtrace.borrow_mut().take() {
@@ -2790,6 +2787,17 @@ impl GlobalScope {
},
));
}
self.send_to_embedder(EmbedderMsg::ShowConsoleApiMessage(
self.webview_id(),
ConsoleLogLevel::Error,
format!(
"Error at {}:{}:{} {}",
error_info.filename,
error_info.lineno,
error_info.column,
error_info.message
),
));
}
}
}

View File

@@ -12,9 +12,9 @@ use dpi::PhysicalSize;
use embedder_traits::EventLoopWaker;
use paint_api::rendering_context::{RenderingContext, SoftwareRenderingContext};
use servo::{
EmbedderControl, InputEvent, JSValue, JavaScriptEvaluationError, LoadStatus, MouseButton,
MouseButtonAction, MouseButtonEvent, MouseMoveEvent, Preferences, Servo, ServoBuilder,
SimpleDialog, WebView, WebViewDelegate,
ConsoleLogLevel, EmbedderControl, InputEvent, JSValue, JavaScriptEvaluationError, LoadStatus,
MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, Preferences, Servo,
ServoBuilder, SimpleDialog, WebView, WebViewDelegate,
};
use webrender_api::units::DevicePoint;
@@ -96,6 +96,7 @@ pub(crate) struct WebViewDelegateImpl {
pub(crate) number_of_controls_shown: Cell<usize>,
pub(crate) number_of_controls_hidden: Cell<usize>,
pub(crate) last_accesskit_tree_updates: RefCell<Vec<accesskit::TreeUpdate>>,
pub(crate) console_messages: RefCell<Vec<(ConsoleLogLevel, String)>>,
}
#[allow(dead_code)] // Used by some tests and not others
@@ -108,6 +109,7 @@ impl WebViewDelegateImpl {
self.number_of_controls_shown.set(0);
self.number_of_controls_hidden.set(0);
self.last_accesskit_tree_updates.borrow_mut().clear();
self.console_messages.borrow_mut().clear();
}
}
@@ -159,6 +161,10 @@ impl WebViewDelegate for WebViewDelegateImpl {
.borrow_mut()
.push(tree_update);
}
fn show_console_message(&self, _webview: WebView, level: ConsoleLogLevel, message: String) {
self.console_messages.borrow_mut().push((level, message));
}
}
// Used by some unit tests only. Since they compile into different binaries,

View File

@@ -974,3 +974,47 @@ fn test_webview_load_with_headers() {
assert_eq!(request_count.load(std::sync::atomic::Ordering::SeqCst), 2);
server.close();
}
#[test]
fn test_console_log_and_error_ordering() {
let servo_test = ServoTest::new();
let delegate = Rc::new(WebViewDelegateImpl::default());
let _webview = WebViewBuilder::new(servo_test.servo(), servo_test.rendering_context.clone())
.delegate(delegate.clone())
.url(
Url::parse(
"data:text/html,<!doctype html><script>\
console.log('Hello');\
DocumentFragment.prototype.querySelector.call(document, 'body');\
</script>",
)
.unwrap(),
)
.build();
// Wait until both messages have arrived through the embedder channel.
let captured = delegate.clone();
servo_test.spin(move || captured.console_messages.borrow().len() < 2);
let messages = delegate.console_messages.borrow();
assert_eq!(
messages.len(),
2,
"Expected exactly 2 console messages, got: {messages:?}"
);
// The console.log("Hello") must arrive first.
assert!(
messages[0].1.contains("Hello"),
"Expected first message to contain 'Hello', got: {:?}",
messages[0].1
);
// The uncaught TypeError must arrive second.
assert!(
messages[1].1.contains("DocumentFragment") || messages[1].1.contains("querySelector"),
"Expected second message to contain error info, got: {:?}",
messages[1].1
);
}