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:
parent
ce79cb5797
commit
f9d29115a0
7 changed files with 129 additions and 32 deletions
|
@ -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
5
cli/tests/testdata/test/interval.out
vendored
Normal 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
1
cli/tests/testdata/test/interval.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
setInterval(function () {}, 0);
|
|
@ -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.
|
||||
|
|
12
cli/tests/testdata/test/unresolved_promise.ts
vendored
12
cli/tests/testdata/test/unresolved_promise.ts
vendored
|
@ -1,11 +1 @@
|
|||
Deno.test({
|
||||
name: "unresolved promise",
|
||||
fn() {
|
||||
return new Promise((_resolve, _reject) => {});
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ok",
|
||||
fn() {},
|
||||
});
|
||||
await new Promise((_resolve, _reject) => {});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue