diff --git a/ReactWindows/ReactNative.Shared/Bridge/Promise.cs b/ReactWindows/ReactNative.Shared/Bridge/Promise.cs new file mode 100644 index 00000000000..b10eecf98cb --- /dev/null +++ b/ReactWindows/ReactNative.Shared/Bridge/Promise.cs @@ -0,0 +1,69 @@ +using Newtonsoft.Json.Linq; +using System; + +namespace ReactNative.Bridge +{ + class Promise : IPromise + { + private const string DefaultError = "EUNSPECIFIED"; + + private readonly ICallback _resolve; + private readonly ICallback _reject; + + public Promise(ICallback resolve, ICallback reject) + { + _resolve = resolve; + _reject = reject; + } + + public void Resolve(object value) + { + if (_resolve != null) + { + _resolve.Invoke(value); + } + } + + public void Reject(string code, string message) + { + Reject(code, message, default(Exception)); + } + + public void Reject(string message) + { + Reject(DefaultError, message, default(Exception)); + } + + public void Reject(string code, Exception e) + { + Reject(code, e.Message, e); + } + + public void Reject(Exception e) + { + if (e == null) + throw new ArgumentNullException(nameof(e)); + + Reject(DefaultError, e.Message, e); + } + + public void Reject(string code, string message, Exception e) + { + if (_reject != null) + { + var errorData = e?.Data; + var userInfo = errorData != null + ? JToken.FromObject(errorData) + : null; + _reject.Invoke(new JObject + { + { "code", code ?? DefaultError }, + { "message", message }, + { "stack", e?.StackTrace }, + { "userInfo", userInfo }, + }); + } + } + } + +} diff --git a/ReactWindows/ReactNative.Shared/Bridge/ReactDelegateFactoryBase.cs b/ReactWindows/ReactNative.Shared/Bridge/ReactDelegateFactoryBase.cs index 99fa33ee5c6..4db8ca63c21 100644 --- a/ReactWindows/ReactNative.Shared/Bridge/ReactDelegateFactoryBase.cs +++ b/ReactWindows/ReactNative.Shared/Bridge/ReactDelegateFactoryBase.cs @@ -1,6 +1,7 @@ using Newtonsoft.Json.Linq; using ReactNative.Bridge; using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -141,63 +142,5 @@ public void Invoke(params object[] arguments) _instance.InvokeCallback(_id, JArray.FromObject(arguments ?? s_empty)); } } - - class Promise : IPromise - { - private const string DefaultError = "EUNSPECIFIED"; - - private readonly ICallback _resolve; - private readonly ICallback _reject; - - public Promise(ICallback resolve, ICallback reject) - { - _resolve = resolve; - _reject = reject; - } - - public void Resolve(object value) - { - if (_resolve != null) - { - _resolve.Invoke(value); - } - } - - public void Reject(string code, string message) - { - Reject(code, message, default(Exception)); - } - - public void Reject(string message) - { - Reject(DefaultError, message, default(Exception)); - } - - public void Reject(string code, Exception e) - { - Reject(code, e.Message, e); - } - - public void Reject(Exception e) - { - if (e == null) - throw new ArgumentNullException(nameof(e)); - - Reject(DefaultError, e.Message, e); - } - - public void Reject(string code, string message, Exception e) - { - if (_reject != null) - { - _reject.Invoke(new JObject - { - { "code", code ?? DefaultError }, - { "message", message }, - { "stack", e?.StackTrace }, - }); - } - } - } } } diff --git a/ReactWindows/ReactNative.Shared/ReactNative.Shared.projitems b/ReactWindows/ReactNative.Shared/ReactNative.Shared.projitems index 1875c871059..cad6e5edb8a 100644 --- a/ReactWindows/ReactNative.Shared/ReactNative.Shared.projitems +++ b/ReactWindows/ReactNative.Shared/ReactNative.Shared.projitems @@ -30,6 +30,7 @@ + diff --git a/ReactWindows/ReactNative.Tests/Bridge/PromiseTests.cs b/ReactWindows/ReactNative.Tests/Bridge/PromiseTests.cs new file mode 100644 index 00000000000..fecc493869b --- /dev/null +++ b/ReactWindows/ReactNative.Tests/Bridge/PromiseTests.cs @@ -0,0 +1,89 @@ +using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; +using Newtonsoft.Json.Linq; +using ReactNative.Bridge; +using System; +using System.Threading; + +namespace ReactNative.Tests.Bridge +{ + [TestClass] + public class PromiseTests + { + [TestMethod] + public void Promise_Resolve() + { + var args = default(object[]); + var are = new AutoResetEvent(false); + var resolve = new MockCallback(a => + { + args = a; + are.Set(); + }); + var reject = new MockCallback(_ => { }); + var promise = new Promise(resolve, reject); + + var o = new object(); + promise.Resolve(o); + are.WaitOne(); + + Assert.IsNotNull(args); + Assert.AreEqual(1, args.Length); + Assert.AreSame(o, args[0]); + } + + [TestMethod] + public void Promise_Reject() + { + var args = default(object[]); + var are = new AutoResetEvent(false); + var resolve = new MockCallback(_ => { }); + var reject = new MockCallback(a => + { + args = a; + are.Set(); + }); + var promise = new Promise(resolve, reject); + + var code = "42"; + var message = "foo"; + promise.Reject(code, message); + are.WaitOne(); + Assert.IsNotNull(args); + Assert.AreEqual(1, args.Length); + + var json = args[0] as JObject; + Assert.IsNotNull(json); + Assert.AreEqual(code, json["code"]); + Assert.AreEqual(message, json["message"]); + } + + [TestMethod] + public void Promise_Reject_UserInfo() + { + var args = default(object[]); + var are = new AutoResetEvent(false); + var resolve = new MockCallback(_ => { }); + var reject = new MockCallback(a => + { + args = a; + are.Set(); + }); + var promise = new Promise(resolve, reject); + + var code = "42"; + var message = "foo"; + var e = new Exception(); + e.Data.Add("qux", "baz"); + promise.Reject(code, message, e); + are.WaitOne(); + + Assert.IsNotNull(args); + Assert.AreEqual(1, args.Length); + var json = args[0] as JObject; + Assert.IsNotNull(json); + var userInfo = json["userInfo"] as JObject; + Assert.IsNotNull(userInfo); + Assert.AreEqual("baz", userInfo["qux"]); + } + } +} diff --git a/ReactWindows/ReactNative.Tests/ReactNative.Tests.csproj b/ReactWindows/ReactNative.Tests/ReactNative.Tests.csproj index 380019b4579..af1105eda22 100644 --- a/ReactWindows/ReactNative.Tests/ReactNative.Tests.csproj +++ b/ReactWindows/ReactNative.Tests/ReactNative.Tests.csproj @@ -95,6 +95,7 @@ +