Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 28 additions & 12 deletions core/wintertc/src/microtask/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,35 @@
//! # TC55 Status
//!
//! `queueMicrotask` is required in the `WinterTC` TC55 Minimum Common Web API.
//!
//! # TODO
//!
//! - Migrate `queueMicrotask` from `boa_runtime::microtask`.
use boa_engine::realm::Realm;
use boa_engine::{Context, JsResult, boa_module};

#[cfg(test)]
mod tests;

/// JavaScript module containing the `queueMicrotask` function.
#[boa_module]
pub mod js_module {
use boa_engine::job::{Job, PromiseJob};
use boa_engine::object::builtins::JsFunction;
use boa_engine::{Context, JsValue};

/// Register `queueMicrotask` into the given context.
/// The [`queueMicrotask()`][mdn] method of the `Window` interface queues a
/// microtask to be executed at a safe time prior to control returning to
/// the browser's event loop.
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window/queueMicrotask
pub fn queue_microtask(callback: JsFunction, context: &mut Context) {
context.enqueue_job(Job::from(PromiseJob::new(move |context| {
callback.call(&JsValue::undefined(), &[], context)
})));
}
}

/// Register the `queueMicrotask` function to the realm or context.
///
/// # Errors
///
/// Returns a [`boa_engine::JsError`] if registration fails.
pub fn register(
_realm: Option<boa_engine::realm::Realm>,
_ctx: &mut boa_engine::Context,
) -> boa_engine::JsResult<()> {
Ok(())
/// Returns an error if the microtask extension cannot be registered.
pub fn register(realm: Option<Realm>, context: &mut Context) -> JsResult<()> {
js_module::boa_register(realm, context)
}
52 changes: 52 additions & 0 deletions core/wintertc/src/microtask/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use crate::test::{TestAction, run_test_actions_with};
use boa_engine::Context;
use indoc::indoc;

#[test]
fn queue_microtask() {
let context = &mut Context::default();
crate::microtask::register(None, context).unwrap();

run_test_actions_with(
[
// Queue a nested set of microtasks, recording execution order into
// a global array. Microtasks run in FIFO order after the current
// synchronous task completes, and microtasks queued from within a
// microtask are appended to the same queue.
TestAction::run(indoc! {r#"
globalThis.order = [];
order.push(1);
queueMicrotask(() => order.push(2));
order.push(3);
queueMicrotask(() => {
order.push(4);
queueMicrotask(() => {
order.push(5);
queueMicrotask(() => order.push(6));
order.push(7);
});
order.push(8);
});
order.push(9);
"#}),
// Drain the microtask (job) queue.
TestAction::inspect_context(|context| {
context.run_jobs().unwrap();
}),
// The synchronous pushes (1, 3, 9) run first, then the microtasks
// in the order they were queued and re-queued.
TestAction::run(indoc! {r#"
var expected = [1, 3, 9, 2, 4, 8, 5, 7, 6];
if (order.length !== expected.length) {
throw new Error("wrong length: [" + order + "]");
}
for (var i = 0; i < expected.length; i++) {
if (order[i] !== expected[i]) {
throw new Error("wrong order at " + i + ": [" + order + "]");
}
}
"#}),
],
context,
);
}
Loading