From 971b083c6abe2158c6015cf658b8090b8f29d4f1 Mon Sep 17 00:00:00 2001 From: Alex Dvornikov Date: Thu, 27 Apr 2017 11:49:50 -0700 Subject: [PATCH] Added tests for synchronous methods in native modules on iOS Reviewed By: javache Differential Revision: D4947631 fbshipit-source-id: d7e497c44602eb6e38896a00edb61639ab2b8cd4 --- .../UIExplorerIntegrationTests.m | 1 + .../UIExplorerTestModule.m | 32 ++++++++ .../RCTModuleMethodTests.m | 79 +++++++++++++++++++ IntegrationTests/IntegrationTestsApp.js | 1 + IntegrationTests/SyncMethodTest.js | 42 ++++++++++ 5 files changed, 155 insertions(+) create mode 100644 Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerTestModule.m create mode 100644 IntegrationTests/SyncMethodTest.js diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m b/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m index f52f9912e34..57b769e3ae4 100644 --- a/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m +++ b/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m @@ -71,6 +71,7 @@ RCT_TEST(ImageCachePolicyTest) RCT_TEST(ImageSnapshotTest) //RCT_TEST(LayoutEventsTest) // Disabled due to flakiness: #8686784 RCT_TEST(SimpleSnapshotTest) +RCT_TEST(SyncMethodTest) RCT_TEST(PromiseTest) RCT_TEST_ONLY_WITH_PACKAGER(WebSocketTest) diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerTestModule.m b/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerTestModule.m new file mode 100644 index 00000000000..e7772ade835 --- /dev/null +++ b/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerTestModule.m @@ -0,0 +1,32 @@ +/** + * 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. + */ + +#import + +#import + +@interface UIExplorerTestModule : NSObject + +@end + +@implementation UIExplorerTestModule + +RCT_EXPORT_MODULE(UIExplorerTestModule) + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(echoString:(NSString *)input) +{ + return input; +} + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(methodThatReturnsNil) +{ + return nil; +} + +@end diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleMethodTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleMethodTests.m index 18ee3f38dc5..ddc8f97cbc7 100644 --- a/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleMethodTests.m +++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleMethodTests.m @@ -48,10 +48,22 @@ static RCTModuleMethod *buildDefaultMethodWithMethodSignature(NSString *methodSi moduleClass:[RCTModuleMethodTests class]]; } +static RCTModuleMethod *buildSyncMethodWithMethodSignature(NSString *methodSignature) { + return [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature + JSMethodName:nil + isSync:YES + moduleClass:[RCTModuleMethodTests class]]; +} + + (NSString *)moduleName { return nil; } +- (void)doFoo { } + - (void)doFooWithBar:(__unused NSString *)bar { } +- (id)echoString:(NSString *)input { return input; } +- (id)methodThatReturnsNil { return nil; } + - (void)testNonnull { NSString *methodSignature = @"doFooWithBar:(nonnull NSString *)bar"; @@ -135,4 +147,71 @@ static RCTModuleMethod *buildDefaultMethodWithMethodSignature(NSString *methodSi })); } +- (void)testFunctionType +{ + { + NSString *methodSignature = @"doFoo"; + RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); + XCTAssertTrue(method.functionType == RCTFunctionTypeNormal); + } + + { + NSString *methodSignature = @"openURL:(NSURL *)URL resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject"; + RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); + XCTAssertTrue(method.functionType == RCTFunctionTypePromise); + } + + { + NSString *methodSignature = @"echoString:(NSString *)input"; + RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature); + XCTAssertTrue(method.functionType == RCTFunctionTypeSync); + } +} + +- (void)testReturnsValueForSyncFunction +{ + { + NSString *methodSignature = @"echoString:(NSString *)input"; + RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature); + id result = [method invokeWithBridge:nil module:self arguments:@[@"Test String Value"]]; + XCTAssertEqualObjects(result, @"Test String Value"); + } + + { + NSString *methodSignature = @"methodThatReturnsNil"; + RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature); + id result = [method invokeWithBridge:nil module:self arguments:@[]]; + XCTAssertNil(result); + } +} + +- (void)testReturnsNilForDefaultFunction +{ + NSString *methodSignature = @"doFoo"; + RCTModuleMethod *method = buildDefaultMethodWithMethodSignature(methodSignature); + id result = [method invokeWithBridge:nil module:self arguments:@[]]; + XCTAssertNil(result); +} + +- (void)testReturnTypeForSyncFunction +{ + { + NSString *methodSignature = @"methodThatReturnsNil"; + RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature); + XCTAssertFalse(RCTLogsError(^{ + // Invoke method to trigger parsing + __unused SEL selector = method.selector; + }), @"Unexpected error when parsing sync function with (id) return type"); + } + + { + NSString *methodSignature = @"doFoo"; + RCTModuleMethod *method = buildSyncMethodWithMethodSignature(methodSignature); + XCTAssertTrue(RCTLogsError(^{ + // Invoke method to trigger parsing + __unused SEL selector = method.selector; + }), @"Failed to trigger an error when parsing sync function with non-(id) return type"); + } +} + @end diff --git a/IntegrationTests/IntegrationTestsApp.js b/IntegrationTests/IntegrationTestsApp.js index 88d4fa7c569..33ddaec45b7 100644 --- a/IntegrationTests/IntegrationTestsApp.js +++ b/IntegrationTests/IntegrationTestsApp.js @@ -33,6 +33,7 @@ var TESTS = [ require('./ImageCachePolicyTest'), require('./ImageSnapshotTest'), require('./PromiseTest'), + require('./SyncMethodTest'), require('./WebSocketTest'), ]; diff --git a/IntegrationTests/SyncMethodTest.js b/IntegrationTests/SyncMethodTest.js new file mode 100644 index 00000000000..1a45072646a --- /dev/null +++ b/IntegrationTests/SyncMethodTest.js @@ -0,0 +1,42 @@ +/** + * 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. + * + * @flow + * @providesModule SyncMethodTest + */ +'use strict'; + +var React = require('react'); +var ReactNative = require('react-native'); +var { View } = ReactNative; + +const { + TestModule, + UIExplorerTestModule, +} = ReactNative.NativeModules; + + +class SyncMethodTest extends React.Component { + componentDidMount() { + if (UIExplorerTestModule.echoString('test string value') !== 'test string value') { + throw new Error('Something wrong with sync method export'); + } + if (UIExplorerTestModule.methodThatReturnsNil() != null) { + throw new Error('Something wrong with sync method export'); + } + TestModule.markTestCompleted(); + } + + render(): React.Element { + return ; + } +} + +SyncMethodTest.displayName = 'SyncMethodTest'; + +module.exports = SyncMethodTest;