diff options
author | Casper Beyer <caspervonb@pm.me> | 2021-09-05 02:19:26 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-04 20:19:26 +0200 |
commit | f9d29115a0164a861c99b36a0919324920225e42 (patch) | |
tree | 3a763cec7d343f0ce11e7ce2fa75b67fcc913fd0 /core/runtime.rs | |
parent | ce79cb579784e8417596fed03f3d2a5bbbad487d (diff) |
feat(cli): close test worker once all tests complete (#11727)
Diffstat (limited to 'core/runtime.rs')
-rw-r--r-- | core/runtime.rs | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/core/runtime.rs b/core/runtime.rs index 8edd0466c..d5089569d 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -647,6 +647,48 @@ impl JsRuntime { scope.perform_microtask_checkpoint(); } + /// Waits for the given value to resolve while polling the event loop. + /// + /// This future resolves when either the value is resolved or the event loop runs to + /// completion. + pub async fn resolve_value( + &mut self, + global: v8::Global<v8::Value>, + ) -> Result<v8::Global<v8::Value>, AnyError> { + poll_fn(|cx| { + let state = self.poll_event_loop(cx, false); + + let mut scope = self.handle_scope(); + let local = v8::Local::<v8::Value>::new(&mut scope, &global); + + if let Ok(promise) = v8::Local::<v8::Promise>::try_from(local) { + match promise.state() { + v8::PromiseState::Pending => match state { + Poll::Ready(Ok(_)) => { + let msg = "Promise resolution is still pending but the event loop has already resolved."; + Poll::Ready(Err(generic_error(msg))) + }, + Poll::Ready(Err(e)) => Poll::Ready(Err(e)), + Poll::Pending => Poll::Pending, + }, + v8::PromiseState::Fulfilled => { + let value = promise.result(&mut scope); + let value_handle = v8::Global::new(&mut scope, value); + Poll::Ready(Ok(value_handle)) + } + v8::PromiseState::Rejected => { + let exception = promise.result(&mut scope); + Poll::Ready(exception_to_err_result(&mut scope, exception, false)) + } + } + } else { + let value_handle = v8::Global::new(&mut scope, local); + Poll::Ready(Ok(value_handle)) + } + }) + .await + } + /// Runs event loop to completion /// /// This future resolves when: @@ -1628,6 +1670,55 @@ pub mod tests { } } + #[tokio::test] + async fn test_resolve_value() { + let mut runtime = JsRuntime::new(Default::default()); + let value_global = runtime + .execute_script("a.js", "Promise.resolve(1 + 2)") + .unwrap(); + let result_global = runtime.resolve_value(value_global).await.unwrap(); + { + let scope = &mut runtime.handle_scope(); + let value = result_global.get(scope); + assert_eq!(value.integer_value(scope).unwrap(), 3); + } + + let value_global = runtime + .execute_script( + "a.js", + "Promise.resolve(new Promise(resolve => resolve(2 + 2)))", + ) + .unwrap(); + let result_global = runtime.resolve_value(value_global).await.unwrap(); + { + let scope = &mut runtime.handle_scope(); + let value = result_global.get(scope); + assert_eq!(value.integer_value(scope).unwrap(), 4); + } + + let value_global = runtime + .execute_script("a.js", "Promise.reject(new Error('fail'))") + .unwrap(); + let err = runtime.resolve_value(value_global).await.unwrap_err(); + assert_eq!( + "Uncaught Error: fail", + err.downcast::<JsError>().unwrap().message + ); + + let value_global = runtime + .execute_script("a.js", "new Promise(resolve => {})") + .unwrap(); + let error_string = runtime + .resolve_value(value_global) + .await + .unwrap_err() + .to_string(); + assert_eq!( + "Promise resolution is still pending but the event loop has already resolved.", + error_string, + ); + } + #[test] fn terminate_execution() { let (mut isolate, _dispatch_count) = setup(Mode::Async); |