summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/error.rs46
-rw-r--r--core/examples/http_bench_bin_ops.rs3
-rw-r--r--core/examples/http_bench_json_ops.rs3
-rw-r--r--core/modules.rs9
-rw-r--r--core/runtime.rs322
5 files changed, 257 insertions, 126 deletions
diff --git a/core/error.rs b/core/error.rs
index 25a7ec12b..1aa67e26c 100644
--- a/core/error.rs
+++ b/core/error.rs
@@ -97,6 +97,7 @@ pub struct JsError {
pub start_column: Option<i64>, // 0-based
pub end_column: Option<i64>, // 0-based
pub frames: Vec<JsStackFrame>,
+ pub stack: Option<String>,
}
#[derive(Debug, PartialEq, Clone)]
@@ -166,7 +167,7 @@ impl JsError {
let msg = v8::Exception::create_message(scope, exception);
- let (message, frames) = if exception.is_native_error() {
+ let (message, frames, stack) = if exception.is_native_error() {
// The exception is a JS Error object.
let exception: v8::Local<v8::Object> =
exception.clone().try_into().unwrap();
@@ -184,7 +185,14 @@ impl JsError {
// Access error.stack to ensure that prepareStackTrace() has been called.
// This should populate error.__callSiteEvals.
- let _ = get_property(scope, exception, "stack");
+ let stack: Option<v8::Local<v8::String>> =
+ get_property(scope, exception, "stack")
+ .unwrap()
+ .try_into()
+ .ok();
+ let stack = stack.map(|s| s.to_rust_string_lossy(scope));
+
+ // FIXME(bartlmieju): the rest of this function is CLI only
// Read an array of structured frames from error.__callSiteEvals.
let frames_v8 = get_property(scope, exception, "__callSiteEvals");
@@ -300,12 +308,12 @@ impl JsError {
});
}
}
- (message, frames)
+ (message, frames, stack)
} else {
// The exception is not a JS Error object.
// Get the message given by V8::Exception::create_message(), and provide
// empty frames.
- (msg.get(scope).to_rust_string_lossy(scope), vec![])
+ (msg.get(scope).to_rust_string_lossy(scope), vec![], None)
};
Self {
@@ -321,6 +329,7 @@ impl JsError {
start_column: msg.get_start_column().try_into().ok(),
end_column: msg.get_end_column().try_into().ok(),
frames,
+ stack,
}
}
}
@@ -339,35 +348,24 @@ fn format_source_loc(
impl Display for JsError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ if let Some(stack) = &self.stack {
+ let stack_lines = stack.lines();
+ if stack_lines.count() > 1 {
+ return writeln!(f, "{}", stack);
+ }
+ }
+
+ writeln!(f, "{}", self.message)?;
if let Some(script_resource_name) = &self.script_resource_name {
if self.line_number.is_some() && self.start_column.is_some() {
- assert!(self.line_number.is_some());
- assert!(self.start_column.is_some());
let source_loc = format_source_loc(
script_resource_name,
self.line_number.unwrap(),
self.start_column.unwrap(),
);
- write!(f, "{}", source_loc)?;
- }
- if self.source_line.is_some() {
- let source_line = self.source_line.as_ref().unwrap();
- write!(f, "\n{}\n", source_line)?;
- let mut s = String::new();
- for i in 0..self.end_column.unwrap() {
- if i >= self.start_column.unwrap() {
- s.push('^');
- } else if source_line.chars().nth(i as usize).unwrap() == '\t' {
- s.push('\t');
- } else {
- s.push(' ');
- }
- }
- writeln!(f, "{}", s)?;
+ writeln!(f, " at {}", source_loc)?;
}
}
-
- write!(f, "{}", self.message)?;
Ok(())
}
}
diff --git a/core/examples/http_bench_bin_ops.rs b/core/examples/http_bench_bin_ops.rs
index 513ac5b3a..bc92007b0 100644
--- a/core/examples/http_bench_bin_ops.rs
+++ b/core/examples/http_bench_bin_ops.rs
@@ -3,7 +3,6 @@
#[macro_use]
extern crate log;
-use deno_core::js_check;
use deno_core::BufVec;
use deno_core::JsRuntime;
use deno_core::Op;
@@ -263,7 +262,7 @@ fn main() {
.unwrap();
isolate.await
};
- js_check(runtime.block_on(future));
+ runtime.block_on(future).unwrap();
}
#[test]
diff --git a/core/examples/http_bench_json_ops.rs b/core/examples/http_bench_json_ops.rs
index fab222f4c..a260159e5 100644
--- a/core/examples/http_bench_json_ops.rs
+++ b/core/examples/http_bench_json_ops.rs
@@ -5,7 +5,6 @@ extern crate log;
use deno_core::error::bad_resource_id;
use deno_core::error::AnyError;
-use deno_core::js_check;
use deno_core::BufVec;
use deno_core::JsRuntime;
use deno_core::OpState;
@@ -196,5 +195,5 @@ fn main() {
.unwrap();
isolate.await
};
- js_check(runtime.block_on(future));
+ runtime.block_on(future).unwrap();
}
diff --git a/core/modules.rs b/core/modules.rs
index 414423be2..294bcfb05 100644
--- a/core/modules.rs
+++ b/core/modules.rs
@@ -466,7 +466,6 @@ impl Modules {
#[cfg(test)]
mod tests {
use super::*;
- use crate::js_check;
use crate::JsRuntime;
use crate::RuntimeOptions;
use futures::future::FutureExt;
@@ -654,7 +653,7 @@ mod tests {
let a_id_fut = runtime.load_module(&spec, None);
let a_id = futures::executor::block_on(a_id_fut).expect("Failed to load");
- js_check(runtime.mod_evaluate(a_id));
+ runtime.mod_evaluate(a_id).unwrap();
let l = loads.lock().unwrap();
assert_eq!(
l.to_vec(),
@@ -721,7 +720,7 @@ mod tests {
let result = runtime.load_module(&spec, None).await;
assert!(result.is_ok());
let circular1_id = result.unwrap();
- js_check(runtime.mod_evaluate(circular1_id));
+ runtime.mod_evaluate(circular1_id).unwrap();
let l = loads.lock().unwrap();
assert_eq!(
@@ -798,7 +797,7 @@ mod tests {
println!(">> result {:?}", result);
assert!(result.is_ok());
let redirect1_id = result.unwrap();
- js_check(runtime.mod_evaluate(redirect1_id));
+ runtime.mod_evaluate(redirect1_id).unwrap();
let l = loads.lock().unwrap();
assert_eq!(
l.to_vec(),
@@ -948,7 +947,7 @@ mod tests {
let main_id =
futures::executor::block_on(main_id_fut).expect("Failed to load");
- js_check(runtime.mod_evaluate(main_id));
+ runtime.mod_evaluate(main_id).unwrap();
let l = loads.lock().unwrap();
assert_eq!(
diff --git a/core/runtime.rs b/core/runtime.rs
index 9c076efd1..2a6d9f3ee 100644
--- a/core/runtime.rs
+++ b/core/runtime.rs
@@ -332,7 +332,7 @@ impl JsRuntime {
pub(crate) fn shared_init(&mut self) {
if self.needs_init {
self.needs_init = false;
- js_check(self.execute("core.js", include_str!("core.js")));
+ self.execute("core.js", include_str!("core.js")).unwrap();
}
}
@@ -1359,16 +1359,18 @@ pub mod tests {
runtime.register_op("test", dispatch);
- js_check(runtime.execute(
- "setup.js",
- r#"
+ runtime
+ .execute(
+ "setup.js",
+ r#"
function assert(cond) {
if (!cond) {
throw Error("assert");
}
}
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
(runtime, dispatch_count)
}
@@ -1376,9 +1378,10 @@ pub mod tests {
#[test]
fn test_dispatch() {
let (mut runtime, dispatch_count) = setup(Mode::Async);
- js_check(runtime.execute(
- "filename.js",
- r#"
+ runtime
+ .execute(
+ "filename.js",
+ r#"
let control = new Uint8Array([42]);
Deno.core.send(1, control);
async function main() {
@@ -1386,40 +1389,45 @@ pub mod tests {
}
main();
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
}
#[test]
fn test_dispatch_no_zero_copy_buf() {
let (mut runtime, dispatch_count) = setup(Mode::AsyncZeroCopy(0));
- js_check(runtime.execute(
- "filename.js",
- r#"
+ runtime
+ .execute(
+ "filename.js",
+ r#"
Deno.core.send(1);
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
}
#[test]
fn test_dispatch_stack_zero_copy_bufs() {
let (mut runtime, dispatch_count) = setup(Mode::AsyncZeroCopy(2));
- js_check(runtime.execute(
- "filename.js",
- r#"
+ runtime
+ .execute(
+ "filename.js",
+ r#"
let zero_copy_a = new Uint8Array([0]);
let zero_copy_b = new Uint8Array([1]);
Deno.core.send(1, zero_copy_a, zero_copy_b);
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
}
#[test]
fn test_dispatch_heap_zero_copy_bufs() {
let (mut runtime, dispatch_count) = setup(Mode::AsyncZeroCopy(5));
- js_check(runtime.execute(
+ runtime.execute(
"filename.js",
r#"
let zero_copy_a = new Uint8Array([0]);
@@ -1429,7 +1437,7 @@ pub mod tests {
let zero_copy_e = new Uint8Array([4]);
Deno.core.send(1, zero_copy_a, zero_copy_b, zero_copy_c, zero_copy_d, zero_copy_e);
"#,
- ));
+ ).unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
}
@@ -1438,39 +1446,45 @@ pub mod tests {
run_in_task(|cx| {
let (mut runtime, dispatch_count) = setup(Mode::Async);
- js_check(runtime.execute(
- "setup2.js",
- r#"
+ runtime
+ .execute(
+ "setup2.js",
+ r#"
let nrecv = 0;
Deno.core.setAsyncHandler(1, (buf) => {
nrecv++;
});
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
- js_check(runtime.execute(
- "check1.js",
- r#"
+ runtime
+ .execute(
+ "check1.js",
+ r#"
assert(nrecv == 0);
let control = new Uint8Array([42]);
Deno.core.send(1, control);
assert(nrecv == 0);
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
assert!(matches!(runtime.poll_unpin(cx), Poll::Ready(Ok(_))));
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
- js_check(runtime.execute(
- "check2.js",
- r#"
+ runtime
+ .execute(
+ "check2.js",
+ r#"
assert(nrecv == 1);
Deno.core.send(1, control);
assert(nrecv == 1);
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
assert!(matches!(runtime.poll_unpin(cx), Poll::Ready(Ok(_))));
- js_check(runtime.execute("check3.js", "assert(nrecv == 2)"));
+ runtime.execute("check3.js", "assert(nrecv == 2)").unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
// We are idle, so the next poll should be the last.
assert!(matches!(runtime.poll_unpin(cx), Poll::Ready(Ok(_))));
@@ -1481,9 +1495,10 @@ pub mod tests {
fn test_poll_async_optional_ops() {
run_in_task(|cx| {
let (mut runtime, dispatch_count) = setup(Mode::AsyncUnref);
- js_check(runtime.execute(
- "check1.js",
- r#"
+ runtime
+ .execute(
+ "check1.js",
+ r#"
Deno.core.setAsyncHandler(1, (buf) => {
// This handler will never be called
assert(false);
@@ -1491,7 +1506,8 @@ pub mod tests {
let control = new Uint8Array([42]);
Deno.core.send(1, control);
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
// The above op never finish, but runtime can finish
// because the op is an unreffed async op.
@@ -1520,7 +1536,7 @@ pub mod tests {
match isolate.execute("infinite_loop.js", "for(;;) {}") {
Ok(_) => panic!("execution should be terminated"),
Err(e) => {
- assert_eq!(e.to_string(), "Uncaught Error: execution terminated")
+ assert_eq!(e.to_string(), "Uncaught Error: execution terminated\n")
}
};
@@ -1561,9 +1577,10 @@ pub mod tests {
#[test]
fn overflow_req_sync() {
let (mut runtime, dispatch_count) = setup(Mode::OverflowReqSync);
- js_check(runtime.execute(
- "overflow_req_sync.js",
- r#"
+ runtime
+ .execute(
+ "overflow_req_sync.js",
+ r#"
let asyncRecv = 0;
Deno.core.setAsyncHandler(1, (buf) => { asyncRecv++ });
// Large message that will overflow the shared space.
@@ -1574,7 +1591,8 @@ pub mod tests {
assert(response[0] == 43);
assert(asyncRecv == 0);
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
}
@@ -1583,9 +1601,10 @@ pub mod tests {
// TODO(ry) This test is quite slow due to memcpy-ing 100MB into JS. We
// should optimize this.
let (mut runtime, dispatch_count) = setup(Mode::OverflowResSync);
- js_check(runtime.execute(
- "overflow_res_sync.js",
- r#"
+ runtime
+ .execute(
+ "overflow_res_sync.js",
+ r#"
let asyncRecv = 0;
Deno.core.setAsyncHandler(1, (buf) => { asyncRecv++ });
// Large message that will overflow the shared space.
@@ -1596,7 +1615,8 @@ pub mod tests {
assert(response[0] == 99);
assert(asyncRecv == 0);
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
}
@@ -1604,9 +1624,10 @@ pub mod tests {
fn overflow_req_async() {
run_in_task(|cx| {
let (mut runtime, dispatch_count) = setup(Mode::OverflowReqAsync);
- js_check(runtime.execute(
- "overflow_req_async.js",
- r#"
+ runtime
+ .execute(
+ "overflow_req_async.js",
+ r#"
let asyncRecv = 0;
Deno.core.setAsyncHandler(1, (buf) => {
assert(buf.byteLength === 1);
@@ -1620,10 +1641,13 @@ pub mod tests {
assert(response == null);
assert(asyncRecv == 0);
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
assert!(matches!(runtime.poll_unpin(cx), Poll::Ready(Ok(_))));
- js_check(runtime.execute("check.js", "assert(asyncRecv == 1);"));
+ runtime
+ .execute("check.js", "assert(asyncRecv == 1);")
+ .unwrap();
});
}
@@ -1633,9 +1657,10 @@ pub mod tests {
// TODO(ry) This test is quite slow due to memcpy-ing 100MB into JS. We
// should optimize this.
let (mut runtime, dispatch_count) = setup(Mode::OverflowResAsync);
- js_check(runtime.execute(
- "overflow_res_async.js",
- r#"
+ runtime
+ .execute(
+ "overflow_res_async.js",
+ r#"
let asyncRecv = 0;
Deno.core.setAsyncHandler(1, (buf) => {
assert(buf.byteLength === 100 * 1024 * 1024);
@@ -1648,10 +1673,13 @@ pub mod tests {
assert(response == null);
assert(asyncRecv == 0);
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
poll_until_ready(&mut runtime, 3).unwrap();
- js_check(runtime.execute("check.js", "assert(asyncRecv == 1);"));
+ runtime
+ .execute("check.js", "assert(asyncRecv == 1);")
+ .unwrap();
});
}
@@ -1661,9 +1689,10 @@ pub mod tests {
// should optimize this.
run_in_task(|_cx| {
let (mut runtime, dispatch_count) = setup(Mode::OverflowResAsync);
- js_check(runtime.execute(
- "overflow_res_multiple_dispatch_async.js",
- r#"
+ runtime
+ .execute(
+ "overflow_res_multiple_dispatch_async.js",
+ r#"
let asyncRecv = 0;
Deno.core.setAsyncHandler(1, (buf) => {
assert(buf.byteLength === 100 * 1024 * 1024);
@@ -1679,10 +1708,13 @@ pub mod tests {
// are done even if shared space overflows
Deno.core.dispatch(1, control);
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
poll_until_ready(&mut runtime, 3).unwrap();
- js_check(runtime.execute("check.js", "assert(asyncRecv == 2);"));
+ runtime
+ .execute("check.js", "assert(asyncRecv == 2);")
+ .unwrap();
});
}
@@ -1690,9 +1722,10 @@ pub mod tests {
fn test_pre_dispatch() {
run_in_task(|mut cx| {
let (mut runtime, _dispatch_count) = setup(Mode::OverflowResAsync);
- js_check(runtime.execute(
- "bad_op_id.js",
- r#"
+ runtime
+ .execute(
+ "bad_op_id.js",
+ r#"
let thrown;
try {
Deno.core.dispatch(100);
@@ -1701,7 +1734,8 @@ pub mod tests {
}
assert(String(thrown) === "TypeError: Unknown op id: 100");
"#,
- ));
+ )
+ .unwrap();
if let Poll::Ready(Err(_)) = runtime.poll_unpin(&mut cx) {
unreachable!();
}
@@ -1712,7 +1746,9 @@ pub mod tests {
fn core_test_js() {
run_in_task(|mut cx| {
let (mut runtime, _dispatch_count) = setup(Mode::Async);
- js_check(runtime.execute("core_test.js", include_str!("core_test.js")));
+ runtime
+ .execute("core_test.js", include_str!("core_test.js"))
+ .unwrap();
if let Poll::Ready(Err(_)) = runtime.poll_unpin(&mut cx) {
unreachable!();
}
@@ -1733,10 +1769,12 @@ pub mod tests {
fn test_encode_decode() {
run_in_task(|mut cx| {
let (mut runtime, _dispatch_count) = setup(Mode::Async);
- js_check(runtime.execute(
- "encode_decode_test.js",
- include_str!("encode_decode_test.js"),
- ));
+ runtime
+ .execute(
+ "encode_decode_test.js",
+ include_str!("encode_decode_test.js"),
+ )
+ .unwrap();
if let Poll::Ready(Err(_)) = runtime.poll_unpin(&mut cx) {
unreachable!();
}
@@ -1750,7 +1788,7 @@ pub mod tests {
will_snapshot: true,
..Default::default()
});
- js_check(runtime.execute("a.js", "a = 1 + 2"));
+ runtime.execute("a.js", "a = 1 + 2").unwrap();
runtime.snapshot()
};
@@ -1759,7 +1797,9 @@ pub mod tests {
startup_snapshot: Some(snapshot),
..Default::default()
});
- js_check(runtime2.execute("check.js", "if (a != 3) throw Error('x')"));
+ runtime2
+ .execute("check.js", "if (a != 3) throw Error('x')")
+ .unwrap();
}
#[test]
@@ -1769,7 +1809,7 @@ pub mod tests {
will_snapshot: true,
..Default::default()
});
- js_check(runtime.execute("a.js", "a = 1 + 2"));
+ runtime.execute("a.js", "a = 1 + 2").unwrap();
let snap: &[u8] = &*runtime.snapshot();
Vec::from(snap).into_boxed_slice()
};
@@ -1779,7 +1819,9 @@ pub mod tests {
startup_snapshot: Some(snapshot),
..Default::default()
});
- js_check(runtime2.execute("check.js", "if (a != 3) throw Error('x')"));
+ runtime2
+ .execute("check.js", "if (a != 3) throw Error('x')")
+ .unwrap();
}
#[test]
@@ -1926,16 +1968,18 @@ pub mod tests {
});
runtime.register_op("test", dispatcher);
- js_check(runtime.execute(
- "setup.js",
- r#"
+ runtime
+ .execute(
+ "setup.js",
+ r#"
function assert(cond) {
if (!cond) {
throw Error("assert");
}
}
"#,
- ));
+ )
+ .unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
@@ -1972,14 +2016,14 @@ pub mod tests {
assert_eq!(imports.len(), 0);
}
- js_check(runtime.mod_instantiate(mod_b));
+ runtime.mod_instantiate(mod_b).unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
assert_eq!(resolve_count.load(Ordering::SeqCst), 1);
- js_check(runtime.mod_instantiate(mod_a));
+ runtime.mod_instantiate(mod_a).unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
- js_check(runtime.mod_evaluate(mod_a));
+ runtime.mod_evaluate(mod_a).unwrap();
assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
}
@@ -2024,14 +2068,16 @@ pub mod tests {
..Default::default()
});
- js_check(runtime.execute(
- "file:///dyn_import2.js",
- r#"
+ runtime
+ .execute(
+ "file:///dyn_import2.js",
+ r#"
(async () => {
await import("/foo.js");
})();
"#,
- ));
+ )
+ .unwrap();
assert_eq!(count.load(Ordering::Relaxed), 0);
// We should get an error here.
@@ -2107,9 +2153,10 @@ pub mod tests {
});
// Dynamically import mod_b
- js_check(runtime.execute(
- "file:///dyn_import3.js",
- r#"
+ runtime
+ .execute(
+ "file:///dyn_import3.js",
+ r#"
(async () => {
let mod = await import("./b.js");
if (mod.b() !== 'b') {
@@ -2122,7 +2169,8 @@ pub mod tests {
}
})();
"#,
- ));
+ )
+ .unwrap();
// First poll runs `prepare_load` hook.
assert!(matches!(runtime.poll_unpin(cx), Poll::Pending));
@@ -2148,9 +2196,10 @@ pub mod tests {
module_loader: Some(loader),
..Default::default()
});
- js_check(runtime.execute(
- "file:///dyn_import3.js",
- r#"
+ runtime
+ .execute(
+ "file:///dyn_import3.js",
+ r#"
(async () => {
let mod = await import("./b.js");
if (mod.b() !== 'b') {
@@ -2160,7 +2209,8 @@ pub mod tests {
Deno.core.ops();
})();
"#,
- ));
+ )
+ .unwrap();
// First poll runs `prepare_load` hook.
let _ = runtime.poll_unpin(cx);
assert_eq!(prepare_load_count.load(Ordering::Relaxed), 1);
@@ -2213,8 +2263,94 @@ pub mod tests {
)
.unwrap();
- js_check(runtime.mod_evaluate(module_id));
+ runtime.mod_evaluate(module_id).unwrap();
let _snapshot = runtime.snapshot();
}
+
+ #[test]
+ fn test_error_without_stack() {
+ let mut runtime = JsRuntime::new(RuntimeOptions::default());
+ // SyntaxError
+ let result = runtime.execute(
+ "error_without_stack.js",
+ r#"
+function main() {
+ console.log("asdf);
+}
+
+main();
+"#,
+ );
+ let expected_error = r#"Uncaught SyntaxError: Invalid or unexpected token
+ at error_without_stack.js:3:14
+"#;
+ assert_eq!(result.unwrap_err().to_string(), expected_error);
+ }
+
+ #[test]
+ fn test_error_stack() {
+ let mut runtime = JsRuntime::new(RuntimeOptions::default());
+ let result = runtime.execute(
+ "error_stack.js",
+ r#"
+function assert(cond) {
+ if (!cond) {
+ throw Error("assert");
+ }
+}
+
+function main() {
+ assert(false);
+}
+
+main();
+ "#,
+ );
+ let expected_error = r#"Error: assert
+ at assert (error_stack.js:4:11)
+ at main (error_stack.js:9:3)
+ at error_stack.js:12:1
+"#;
+ assert_eq!(result.unwrap_err().to_string(), expected_error);
+ }
+
+ #[test]
+ fn test_error_async_stack() {
+ run_in_task(|cx| {
+ let mut runtime = JsRuntime::new(RuntimeOptions::default());
+ runtime
+ .execute(
+ "error_async_stack.js",
+ r#"
+(async () => {
+ const p = (async () => {
+ await Promise.resolve().then(() => {
+ throw new Error("async");
+ });
+ })();
+
+ try {
+ await p;
+ } catch (error) {
+ console.log(error.stack);
+ throw error;
+ }
+})();"#,
+ )
+ .unwrap();
+ let expected_error = r#"Error: async
+ at error_async_stack.js:5:13
+ at async error_async_stack.js:4:5
+ at async error_async_stack.js:10:5
+"#;
+
+ match runtime.poll_unpin(cx) {
+ Poll::Ready(Err(e)) => {
+ assert_eq!(e.to_string(), expected_error);
+ }
+ _ => panic!(),
+ };
+ })
+ }
}