diff --git a/NativeScript/runtime/Runtime.mm b/NativeScript/runtime/Runtime.mm index c943b0b2..f8773f5f 100644 --- a/NativeScript/runtime/Runtime.mm +++ b/NativeScript/runtime/Runtime.mm @@ -193,6 +193,21 @@ void DisposeIsolateWhenPossible(Isolate* isolate) { DefinePerformanceObject(isolate, globalTemplate); DefineTimeMethod(isolate, globalTemplate); DefineDrainMicrotaskMethod(isolate, globalTemplate); + // queueMicrotask(callback) per spec + { + Local qmtTemplate = FunctionTemplate::New( + isolate, [](const FunctionCallbackInfo& info) { + auto* isolate = info.GetIsolate(); + if (info.Length() < 1 || !info[0]->IsFunction()) { + isolate->ThrowException(Exception::TypeError( + tns::ToV8String(isolate, "queueMicrotask: callback must be a function"))); + return; + } + v8::Local cb = info[0].As(); + isolate->EnqueueMicrotask(cb); + }); + globalTemplate->Set(tns::ToV8String(isolate, "queueMicrotask"), qmtTemplate); + } ObjectManager::Init(isolate, globalTemplate); // SetTimeout::Init(isolate, globalTemplate); MetadataBuilder::RegisterConstantsOnGlobalObject(isolate, globalTemplate, isWorker); diff --git a/TestRunner/app/tests/RuntimeImplementedAPIs.js b/TestRunner/app/tests/RuntimeImplementedAPIs.js index fe3bf575..b3d581e2 100644 --- a/TestRunner/app/tests/RuntimeImplementedAPIs.js +++ b/TestRunner/app/tests/RuntimeImplementedAPIs.js @@ -44,3 +44,37 @@ describe("Performance object", () => { expect(Math.abs(dateNow - performanceAccurateNow)).toBeLessThan(10); }); }); + +describe("queueMicrotask", () => { + it("should be defined as a function", () => { + expect(typeof queueMicrotask).toBe("function"); + }); + + it("should throw TypeError when callback is not a function", () => { + expect(() => queueMicrotask(null)).toThrow(); + expect(() => queueMicrotask(42)).toThrow(); + expect(() => queueMicrotask({})).toThrow(); + }); + + it("runs after current stack but before setTimeout(0)", (done) => { + const order = []; + queueMicrotask(() => order.push("microtask")); + setTimeout(() => { + order.push("timeout"); + expect(order).toEqual(["microtask", "timeout"]); + done(); + }, 0); + expect(order.length).toBe(0); + }); + + it("preserves ordering with Promise microtasks", (done) => { + const order = []; + queueMicrotask(() => order.push("qm1")); + Promise.resolve().then(() => order.push("p")); + queueMicrotask(() => order.push("qm2")); + setTimeout(() => { + expect(order).toEqual(["qm1", "p", "qm2"]); + done(); + }, 0); + }); +});