using Jint.Tests.Runtime.TestClasses; namespace Jint.Tests.Runtime; public class AsyncTests { [Fact] public void AwaitPropagationAgainstPrimitiveValue() { var engine = new Engine(); var result = engine.Evaluate("(async ()=>await '1')()"); result = result.UnwrapIfPromise(); Assert.Equal("1", result); } [Fact] public void ShouldTaskConvertedToPromiseInJS() { Engine engine = new(); engine.SetValue("callable", Callable); var result = engine.Evaluate("callable().then(x=>x*2)"); result = result.UnwrapIfPromise(); Assert.Equal(2, result); static async Task Callable() { await Task.Delay(10); Assert.True(true); return 1; } } [Fact] public void ShouldReturnedTaskConvertedToPromiseInJS() { Engine engine = new(); engine.SetValue("asyncTestClass", new AsyncTestClass()); var result = engine.Evaluate("asyncTestClass.ReturnDelayedTaskAsync().then(x=>x)"); result = result.UnwrapIfPromise(); Assert.Equal(AsyncTestClass.TestString, result); } [Fact] public void ShouldReturnedCompletedTaskConvertedToPromiseInJS() { Engine engine = new(); engine.SetValue("asyncTestClass", new AsyncTestClass()); var result = engine.Evaluate("asyncTestClass.ReturnCompletedTask().then(x=>x)"); result = result.UnwrapIfPromise(); Assert.Equal(AsyncTestClass.TestString, result); } [Fact] public void ShouldTaskCatchWhenCancelled() { Engine engine = new(); CancellationTokenSource cancel = new(); cancel.Cancel(); engine.SetValue("token", cancel.Token); engine.SetValue("callable", Callable); engine.SetValue("assert", new Action(Assert.True)); var result = engine.Evaluate("callable(token).then(_ => assert(false)).catch(_ => assert(true))"); result = result.UnwrapIfPromise(); static async Task Callable(CancellationToken token) { await Task.FromCanceled(token); } } [Fact] public void ShouldReturnedTaskCatchWhenCancelled() { Engine engine = new(); CancellationTokenSource cancel = new(); cancel.Cancel(); engine.SetValue("token", cancel.Token); engine.SetValue("asyncTestClass", new AsyncTestClass()); engine.SetValue("assert", new Action(Assert.True)); var result = engine.Evaluate("asyncTestClass.ReturnCancelledTask(token).then(_ => assert(false)).catch(_ => assert(true))"); result = result.UnwrapIfPromise(); } [Fact] public void ShouldTaskCatchWhenThrowError() { Engine engine = new(); engine.SetValue("callable", Callable); engine.SetValue("assert", new Action(Assert.True)); var result = engine.Evaluate("callable().then(_ => assert(false)).catch(_ => assert(true))"); static async Task Callable() { await Task.Delay(10); throw new Exception(); } } [Fact] public void ShouldReturnedTaskCatchWhenThrowError() { Engine engine = new(); engine.SetValue("asyncTestClass", new AsyncTestClass()); engine.SetValue("assert", new Action(Assert.True)); var result = engine.Evaluate("asyncTestClass.ThrowAfterDelayAsync().then(_ => assert(false)).catch(_ => assert(true))"); result = result.UnwrapIfPromise(); } [Fact] public void ShouldTaskAwaitCurrentStack() { //https://github.com/sebastienros/jint/issues/514#issuecomment-1507127509 Engine engine = new(); AsyncTestClass asyncTestClass = new(); engine.SetValue("myAsyncMethod", new Func(async () => { await Task.Delay(1000); asyncTestClass.StringToAppend += "1"; })); engine.SetValue("mySyncMethod2", new Action(() => { asyncTestClass.StringToAppend += "2"; })); engine.SetValue("asyncTestClass", asyncTestClass); engine.Execute("async function hello() {await myAsyncMethod();mySyncMethod2();await asyncTestClass.AddToStringDelayedAsync(\"3\")} hello();"); Assert.Equal("123", asyncTestClass.StringToAppend); } #if NETFRAMEWORK == false [Fact] public void ShouldValueTaskConvertedToPromiseInJS() { Engine engine = new(); engine.SetValue("callable", Callable); var result = engine.Evaluate("callable().then(x=>x*2)"); result = result.UnwrapIfPromise(); Assert.Equal(2, result); static async ValueTask Callable() { await Task.Delay(10); Assert.True(true); return 1; } } [Fact] public void ShouldValueTaskCatchWhenCancelled() { Engine engine = new(); CancellationTokenSource cancel = new(); cancel.Cancel(); engine.SetValue("token", cancel.Token); engine.SetValue("callable", Callable); engine.SetValue("assert", new Action(Assert.True)); var result = engine.Evaluate("callable(token).then(_ => assert(false)).catch(_ => assert(true))"); result = result.UnwrapIfPromise(); static async ValueTask Callable(CancellationToken token) { await ValueTask.FromCanceled(token); } } [Fact] public void ShouldValueTaskCatchWhenThrowError() { Engine engine = new(); engine.SetValue("callable", Callable); engine.SetValue("assert", new Action(Assert.True)); var result = engine.Evaluate("callable().then(_ => assert(false)).catch(_ => assert(true))"); static async ValueTask Callable() { await Task.Delay(10); throw new Exception(); } } [Fact] public void ShouldValueTaskAwaitCurrentStack() { //https://github.com/sebastienros/jint/issues/514#issuecomment-1507127509 Engine engine = new(); string log = ""; engine.SetValue("myAsyncMethod", new Func(async () => { await Task.Delay(1000); log += "1"; })); engine.SetValue("myAsyncMethod2", new Action(() => { log += "2"; })); engine.Execute("async function hello() {await myAsyncMethod();myAsyncMethod2();} hello();"); Assert.Equal("12", log); } #endif [Fact(Skip = "TODO es6-await https://github.com/sebastienros/jint/issues/1385")] public void ShouldHaveCorrectOrder() { var engine = new Engine(); engine.Evaluate("var log = [];"); const string Script = """ async function foo(name) { log.push(name + " start"); await log.push(name + " middle"); log.push(name + " end"); } foo("First"); foo("Second"); """; engine.Execute(Script); var log = engine.GetValue("log").AsArray(); string[] expected = [ "First start", "First middle", "Second start", "Second middle", "First end", "Second end", ]; Assert.Equal(expected, log.Select(x => x.AsString()).ToArray()); } }