diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/IntegrationTestsTests.m b/Examples/UIExplorer/UIExplorerIntegrationTests/IntegrationTestsTests.m index 75483fa6e..ddd204f99 100644 --- a/Examples/UIExplorer/UIExplorerIntegrationTests/IntegrationTestsTests.m +++ b/Examples/UIExplorer/UIExplorerIntegrationTests/IntegrationTestsTests.m @@ -33,7 +33,7 @@ _runner = RCTInitRunnerForApp(@"Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestsApp"); // If tests have changes, set recordMode = YES below and run the affected - // tests on an iPhone5, iOS 8.1 simulator. + // tests on an iPhone5, iOS 8.3 simulator. _runner.recordMode = NO; } @@ -81,6 +81,11 @@ [_runner runTest:_cmd module:@"AppEventsTest"]; } +- (void)testPromises +{ + [_runner runTest:_cmd module:@"PromiseTest"]; +} + #pragma mark Snapshot Tests - (void)testSimpleSnapshot diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestsApp.js b/Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestsApp.js index d769c0831..21f0f7a2a 100644 --- a/Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestsApp.js +++ b/Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestsApp.js @@ -28,6 +28,7 @@ var TESTS = [ require('./LayoutEventsTest'), require('./AppEventsTest'), require('./SimpleSnapshotTest'), + require('./PromiseTest'), ]; TESTS.forEach( diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/js/PromiseTest.js b/Examples/UIExplorer/UIExplorerIntegrationTests/js/PromiseTest.js new file mode 100644 index 000000000..38660d3d8 --- /dev/null +++ b/Examples/UIExplorer/UIExplorerIntegrationTests/js/PromiseTest.js @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule PromiseTest + */ +'use strict'; + +var RCTTestModule = require('NativeModules').TestModule; +var React = require('react-native'); + +var PromiseTest = React.createClass({ + + shouldResolve: false, + shouldReject: false, + + componentDidMount() { + Promise.all([ + this.testShouldResolve(), + this.testShouldReject(), + ]).then(() => RCTTestModule.finish( + this.shouldResolve && this.shouldReject + )); + }, + + testShouldResolve() { + return RCTTestModule + .shouldResolve() + .then(() => this.shouldResolve = true) + .catch(() => this.shouldResolve = false); + }, + + testShouldReject() { + return RCTTestModule + .shouldReject() + .then(() => this.shouldReject = false) + .catch(() => this.shouldReject = true); + }, + + render() { + return ; + } + +}); + +module.exports = PromiseTest; diff --git a/Libraries/BatchedBridge/BatchingImplementation/BatchedBridgeFactory.js b/Libraries/BatchedBridge/BatchingImplementation/BatchedBridgeFactory.js index 4702e246d..3243fb145 100644 --- a/Libraries/BatchedBridge/BatchingImplementation/BatchedBridgeFactory.js +++ b/Libraries/BatchedBridge/BatchingImplementation/BatchedBridgeFactory.js @@ -45,23 +45,6 @@ var BatchedBridgeFactory = { _createBridgedModule: function(messageQueue, moduleConfig, moduleName) { var remoteModule = mapObject(moduleConfig.methods, function(methodConfig, memberName) { switch (methodConfig.type) { - case MethodTypes.remote: - return function() { - var lastArg = arguments.length > 0 ? arguments[arguments.length - 1] : null; - var secondLastArg = arguments.length > 1 ? arguments[arguments.length - 2] : null; - var hasErrorCB = typeof lastArg === 'function'; - var hasSuccCB = typeof secondLastArg === 'function'; - hasSuccCB && invariant( - hasErrorCB, - 'Cannot have a non-function arg after a function arg.' - ); - var numCBs = (hasSuccCB ? 1 : 0) + (hasErrorCB ? 1 : 0); - var args = slice.call(arguments, 0, arguments.length - numCBs); - var onSucc = hasSuccCB ? secondLastArg : null; - var onFail = hasErrorCB ? lastArg : null; - messageQueue.call(moduleName, memberName, args, onSucc, onFail); - }; - case MethodTypes.remoteAsync: return function(...args) { return new Promise((resolve, reject) => { @@ -76,7 +59,21 @@ var BatchedBridgeFactory = { return null; default: - throw new Error('Unknown bridge method type: ' + methodConfig.type); + return function() { + var lastArg = arguments.length > 0 ? arguments[arguments.length - 1] : null; + var secondLastArg = arguments.length > 1 ? arguments[arguments.length - 2] : null; + var hasSuccCB = typeof lastArg === 'function'; + var hasErrorCB = typeof secondLastArg === 'function'; + hasErrorCB && invariant( + hasSuccCB, + 'Cannot have a non-function arg after a function arg.' + ); + var numCBs = (hasSuccCB ? 1 : 0) + (hasErrorCB ? 1 : 0); + var args = slice.call(arguments, 0, arguments.length - numCBs); + var onSucc = hasSuccCB ? lastArg : null; + var onFail = hasErrorCB ? secondLastArg : null; + return messageQueue.call(moduleName, memberName, args, onFail, onSucc); + }; } }); for (var constName in moduleConfig.constants) { diff --git a/Libraries/RCTTest/RCTTestModule.m b/Libraries/RCTTest/RCTTestModule.m index 2508b88fe..f7d504b06 100644 --- a/Libraries/RCTTest/RCTTestModule.m +++ b/Libraries/RCTTest/RCTTestModule.m @@ -69,4 +69,21 @@ RCT_EXPORT_METHOD(sendAppEvent:(NSString *)name body:(id)body) [_bridge.eventDispatcher sendAppEventWithName:name body:body]; } +RCT_REMAP_METHOD(shouldResolve, shouldResolve_resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +{ + resolve(@1); +} + +RCT_REMAP_METHOD(shouldReject, shouldReject_resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +{ + reject(nil); +} + +RCT_EXPORT_METHOD(finish:(BOOL)success) +{ + RCTAssert(success, @"RCTTestModule finished without success"); + [self markTestCompleted]; +} + + @end diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js index 8a819a939..8a56aa714 100644 --- a/Libraries/Utilities/MessageQueue.js +++ b/Libraries/Utilities/MessageQueue.js @@ -441,14 +441,14 @@ var MessageQueueMixin = { }, /** - * @param {Function} onSucc Function to store in current thread for later - * lookup, when request succeeds. * @param {Function} onFail Function to store in current thread for later * lookup, when request fails. + * @param {Function} onSucc Function to store in current thread for later + * lookup, when request succeeds. * @param {Object?=} scope Scope to invoke `cb` with. * @param {Object?=} res Resulting callback ids. Use `this._POOLED_CBIDS`. */ - _storeCallbacksInCurrentThread: function(onSucc, onFail, scope) { + _storeCallbacksInCurrentThread: function(onFail, onSucc, scope) { invariant(onFail || onSucc, INTERNAL_ERROR); this._bookkeeping.allocateCallbackIDs(this._POOLED_CBIDS); var succCBID = this._POOLED_CBIDS.successCallbackID; @@ -506,7 +506,7 @@ var MessageQueueMixin = { return ret; }, - call: function(moduleName, methodName, params, onSucc, onFail, scope) { + call: function(moduleName, methodName, params, onFail, onSucc, scope) { invariant( (!onFail || typeof onFail === 'function') && (!onSucc || typeof onSucc === 'function'), @@ -514,10 +514,10 @@ var MessageQueueMixin = { ); // Store callback _before_ sending the request, just in case the MailBox // returns the response in a blocking manner. - if (onSucc || onFail) { - this._storeCallbacksInCurrentThread(onSucc, onFail, scope, this._POOLED_CBIDS); - onSucc && params.push(this._POOLED_CBIDS.successCallbackID); + if (onFail || onSucc) { + this._storeCallbacksInCurrentThread(onFail, onSucc, scope, this._POOLED_CBIDS); onFail && params.push(this._POOLED_CBIDS.errorCallbackID); + onSucc && params.push(this._POOLED_CBIDS.successCallbackID); } var moduleID = this._remoteModuleNameToModuleID[moduleName]; if (moduleID === undefined || moduleID === null) { diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m index 8a479eade..f79026fda 100644 --- a/React/Base/RCTBridge.m +++ b/React/Base/RCTBridge.m @@ -473,7 +473,7 @@ case _value: { \ // Unknown argument type RCTLogError(@"Unknown argument type '%@' in method %@. Extend RCTConvert" - " to support this type.", argumentName, [self methodName]); + " to support this type.", argumentName, [self methodName]); } }