0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 09:31:22 -05:00

feat(cli): close test worker once all tests complete (#11727)

This commit is contained in:
Casper Beyer 2021-09-05 02:19:26 +08:00 committed by GitHub
parent ce79cb5797
commit f9d29115a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 129 additions and 32 deletions

View file

@ -61,6 +61,12 @@ itest!(load_unload {
output: "test/load_unload.out",
});
itest!(interval {
args: "test test/interval.ts",
exit_code: 0,
output: "test/interval.out",
});
itest!(doc {
args: "test --doc --allow-all test/doc.ts",
exit_code: 1,

5
cli/tests/testdata/test/interval.out vendored Normal file
View file

@ -0,0 +1,5 @@
Check [WILDCARD]/test/interval.ts
running 0 tests from [WILDCARD]/test/interval.ts
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])

1
cli/tests/testdata/test/interval.ts vendored Normal file
View file

@ -0,0 +1 @@
setInterval(function () {}, 0);

View file

@ -1,6 +1,5 @@
Check [WILDCARD]/test/unresolved_promise.ts
running 2 tests from [WILDCARD]/test/unresolved_promise.ts
test unresolved promise ...
test result: FAILED. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])
error: Module evaluation is still pending but there are no pending ops or dynamic imports. This situation is often caused by unresolved promise.

View file

@ -1,11 +1 @@
Deno.test({
name: "unresolved promise",
fn() {
return new Promise((_resolve, _reject) => {});
},
});
Deno.test({
name: "ok",
fn() {},
});
await new Promise((_resolve, _reject) => {});

View file

@ -11,6 +11,7 @@ use crate::flags::Flags;
use crate::fs_util::collect_specifiers;
use crate::fs_util::is_supported_test_ext;
use crate::fs_util::is_supported_test_path;
use crate::located_script_name;
use crate::media_type::MediaType;
use crate::module_graph;
use crate::module_graph::GraphBuilder;
@ -264,21 +265,6 @@ async fn test_specifier(
test_source.push_str(&format!("import \"{}\";\n", specifier));
}
test_source
.push_str("await new Promise(resolve => setTimeout(resolve, 0));\n");
test_source.push_str("window.dispatchEvent(new Event('load'));\n");
test_source.push_str(&format!(
"await Deno[Deno.internal].runTests({});\n",
json!({
"filter": filter,
"shuffle": shuffle,
}),
));
test_source.push_str("window.dispatchEvent(new Event('unload'));\n");
let test_file = File {
local: test_specifier.to_file_path().unwrap(),
maybe_types: None,
@ -323,9 +309,28 @@ async fn test_specifier(
worker.execute_module(&test_specifier).await?;
worker
.run_event_loop(maybe_coverage_collector.is_none())
.await?;
worker.js_runtime.execute_script(
&located_script_name!(),
"window.dispatchEvent(new Event('load'));",
)?;
let test_result = worker.js_runtime.execute_script(
&located_script_name!(),
&format!(
r#"Deno[Deno.internal].runTests({})"#,
json!({
"filter": filter,
"shuffle": shuffle,
}),
),
)?;
worker.js_runtime.resolve_value(test_result).await?;
worker.js_runtime.execute_script(
&located_script_name!(),
"window.dispatchEvent(new Event('unload'));",
)?;
if let Some(coverage_collector) = maybe_coverage_collector.as_mut() {
worker

View file

@ -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);