diff --git a/boa_tester/src/exec/mod.rs b/boa_tester/src/exec/mod.rs index 69d82715298..38d285b64f9 100644 --- a/boa_tester/src/exec/mod.rs +++ b/boa_tester/src/exec/mod.rs @@ -198,8 +198,15 @@ impl Test { context.run_jobs(); - if let Err(e) = async_result.inner.borrow().as_ref() { - return (false, format!("Uncaught {e}")); + match *async_result.inner.borrow() { + UninitResult::Err(ref e) => return (false, format!("Uncaught {e}")), + UninitResult::Uninit if self.flags.contains(TestFlags::ASYNC) => { + return ( + false, + "async test did not print \"Test262:AsyncTestComplete\"".to_string(), + ) + } + _ => {} } (true, value.display().to_string()) @@ -423,9 +430,19 @@ fn register_print_fn(context: &mut Context<'_>, async_result: AsyncResult) { .get_or_undefined(0) .to_string(context)? .to_std_string_escaped(); - if message != "Test262:AsyncTestComplete" { - *async_result.inner.borrow_mut() = Err(message); + let mut result = async_result.inner.borrow_mut(); + + match *result { + UninitResult::Uninit | UninitResult::Ok(_) => { + if message == "Test262:AsyncTestComplete" { + *result = UninitResult::Ok(()); + } else { + *result = UninitResult::Err(message); + } + } + UninitResult::Err(_) => {} } + Ok(JsValue::undefined()) }) }, @@ -440,17 +457,35 @@ fn register_print_fn(context: &mut Context<'_>, async_result: AsyncResult) { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ); } + +/// A `Result` value that is possibly uninitialized. +/// +/// This is mainly used to check if an async test did call `print` to signal the termination of +/// a test. Otherwise, all async tests that result in `UninitResult::Uninit` are considered +/// as failed. +/// +/// The Test262 [interpreting guide][guide] contains more information about how to run async tests. +/// +/// [guide]: https://github.com/tc39/test262/blob/main/INTERPRETING.md#flags +#[derive(Debug, Clone, Copy, Default)] +enum UninitResult { + #[default] + Uninit, + Ok(T), + Err(E), +} + /// Object which includes the result of the async operation. #[derive(Debug, Clone)] struct AsyncResult { - inner: Rc>>, + inner: Rc>>, } impl Default for AsyncResult { #[inline] fn default() -> Self { Self { - inner: Rc::new(RefCell::new(Ok(()))), + inner: Rc::new(RefCell::new(UninitResult::default())), } } }