Remove dependency on JavaScriptCore for RealmReactTests

The test structure is now provided by a JS API, that is used by all things that run tests. Also, the tests can be run manually by tapping a button in the ReactTests app.
This commit is contained in:
Scott Kyle 2015-10-15 11:34:24 -07:00
parent 7a79ac8803
commit 7f5902b021
10 changed files with 223 additions and 224 deletions

View File

@ -144,7 +144,6 @@
/* Begin PBXFileReference section */
02258FB11BC6E2D00075F13A /* RealmRPC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmRPC.h; path = src/RealmRPC.h; sourceTree = "<group>"; };
02258FB21BC6E2D00075F13A /* RealmRPC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmRPC.mm; path = src/RealmRPC.mm; sourceTree = "<group>"; };
02409DC01BCF11D6005F3B3E /* RealmJSCoreTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmJSCoreTests.h; path = src/RealmJSCoreTests.h; sourceTree = SOURCE_ROOT; };
02409DC11BCF11D6005F3B3E /* RealmJSCoreTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RealmJSCoreTests.m; path = src/RealmJSCoreTests.m; sourceTree = SOURCE_ROOT; };
02601F011BA0F0C4007C91FF /* external_commit_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = external_commit_helper.cpp; path = "src/object-store/apple/external_commit_helper.cpp"; sourceTree = "<group>"; };
02601F021BA0F0C4007C91FF /* external_commit_helper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = external_commit_helper.hpp; path = "src/object-store/apple/external_commit_helper.hpp"; sourceTree = "<group>"; };
@ -339,7 +338,6 @@
0270BC7D1B7D020100010E03 /* ResultsTests.js */,
0270BC7A1B7D020100010E03 /* RealmJSTests.h */,
0270BC7B1B7D020100010E03 /* RealmJSTests.mm */,
02409DC01BCF11D6005F3B3E /* RealmJSCoreTests.h */,
02409DC11BCF11D6005F3B3E /* RealmJSCoreTests.m */,
F68A278A1BC2722A0063D40A /* RJSModuleLoader.h */,
F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */,

View File

@ -1,23 +0,0 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2015 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#import "RealmJSTests.h"
@interface RealmJSCoreTests : RealmJSTests
@end

View File

@ -17,12 +17,82 @@
////////////////////////////////////////////////////////////////////////////
#import "RealmJSCoreTests.h"
#import "RealmJSTests.h"
#import "RJSModuleLoader.h"
@interface RealmJSCoreTests : RealmJSTests
@property (nonatomic, strong) JSValue *testObject;
@end
@implementation RealmJSCoreTests
+ (NSURL *)scriptURL {
return [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js"];
+ (XCTestSuite *)defaultTestSuite {
XCTestSuite *suite = [super defaultTestSuite];
JSContext *context = [[JSContext alloc] init];
RJSModuleLoader *moduleLoader = [[RJSModuleLoader alloc] initWithContext:context];
NSURL *scriptURL = [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js"];
[RealmJS initializeContext:context.JSGlobalContextRef];
// Expose the global Realm object as a global 'realm' CommonJS module.
[moduleLoader addGlobalModuleObject:context[@"Realm"] forName:@"realm"];
NSError *error;
JSValue *testObjects = [moduleLoader loadModuleFromURL:scriptURL error:&error];
if (!testObjects) {
NSLog(@"%@", error);
exit(1);
}
NSDictionary *testCaseNames = [[testObjects invokeMethod:@"getTestNames" withArguments:nil] toDictionary];
if (!testCaseNames.count) {
NSLog(@"No test case names from getTestNames() JS method!");
exit(1);
}
for (XCTestSuite *testSuite in [self testSuitesFromDictionary:testCaseNames]) {
for (RealmJSCoreTests *test in testSuite.tests) {
test.testObject = testObjects[testSuite.name];
}
[suite addTest:testSuite];
}
return suite;
}
- (JSContext *)context {
return self.testObject.context;
}
- (void)invokeMethod:(NSString *)method {
JSValue *testObject = self.testObject;
if (![testObject hasProperty:method]) {
return;
}
JSContext *context = testObject.context;
context.exception = nil;
[testObject invokeMethod:method withArguments:nil];
JSValue *exception = context.exception;
if (exception) {
JSValue *message = [exception hasProperty:@"message"] ? exception[@"message"] : exception;
NSString *source = [exception hasProperty:@"sourceURL"] ? [exception[@"sourceURL"] toString] : nil;
NSUInteger line = [exception hasProperty:@"line"] ? [exception[@"line"] toUInt32] - 1 : 0;
NSURL *sourceURL = source ? [NSURL URLWithString:source.lastPathComponent relativeToURL:[NSURL URLWithString:@(__FILE__)]] : nil;
[self recordFailureWithDescription:message.description
inFile:sourceURL ? sourceURL.absoluteString : @(__FILE__)
atLine:sourceURL ? line : __LINE__
expected:YES];
}
}
@end

View File

@ -12,22 +12,19 @@ var {
AppRegistry,
StyleSheet,
Text,
TouchableHighlight,
View,
} = React;
function runTests() {
let specialMethodNames = {'beforeEach': true, 'afterEach': true};
let testNames = RealmTests.getTestNames();
for (let suiteName in RealmTests) {
for (let suiteName in testNames) {
let testSuite = RealmTests[suiteName];
console.log('Starting suite:', suiteName);
for (let testName in testSuite) {
if (testName in specialMethodNames || typeof testSuite[testName] != 'function') {
continue;
}
console.log('Starting ' + suiteName);
for (let testName of testNames[suiteName]) {
if (testSuite.beforeEach) {
testSuite.beforeEach();
}
@ -50,18 +47,11 @@ function runTests() {
}
var ReactTests = React.createClass({
componentDidMount() {
runTests();
},
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.ios.js
<Text style={styles.button} onPress={runTests}>
Tap to Run Tests
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
@ -79,10 +69,14 @@ var styles = StyleSheet.create({
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
button: {
borderColor: '#cccccc',
borderRadius: 4,
borderWidth: 1,
fontSize: 20,
textAlign: 'center',
margin: 10,
margin: 20,
padding: 10,
},
instructions: {
textAlign: 'center',

View File

@ -15,16 +15,6 @@
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
00E356F31AD99517003FC87E /* RealmReactTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* RealmReactTests.m */; };
02409E1E1BCF1F2E005F3B3E /* RealmJSTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 02409E1B1BCF1F2E005F3B3E /* RealmJSTests.mm */; settings = {ASSET_TAGS = (); }; };
02409E1F1BCF1F2E005F3B3E /* RJSModuleLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 02409E1D1BCF1F2E005F3B3E /* RJSModuleLoader.m */; settings = {ASSET_TAGS = (); }; };
02409E291BCF1F45005F3B3E /* ArrayTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E201BCF1F45005F3B3E /* ArrayTests.js */; };
02409E2A1BCF1F45005F3B3E /* asserts.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E211BCF1F45005F3B3E /* asserts.js */; };
02409E2B1BCF1F45005F3B3E /* base-test.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E221BCF1F45005F3B3E /* base-test.js */; };
02409E2C1BCF1F45005F3B3E /* index.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E231BCF1F45005F3B3E /* index.js */; };
02409E2D1BCF1F45005F3B3E /* ObjectTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E241BCF1F45005F3B3E /* ObjectTests.js */; };
02409E2E1BCF1F45005F3B3E /* RealmTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E251BCF1F45005F3B3E /* RealmTests.js */; };
02409E2F1BCF1F45005F3B3E /* ResultsTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E261BCF1F45005F3B3E /* ResultsTests.js */; };
02409E301BCF1F45005F3B3E /* schemas.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E271BCF1F45005F3B3E /* schemas.js */; };
02409E311BCF1F45005F3B3E /* util.js in Resources */ = {isa = PBXBuildFile; fileRef = 02409E281BCF1F45005F3B3E /* util.js */; };
0277991C1BBF3BC600C96559 /* RealmReact.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0277991B1BBF3BB700C96559 /* RealmReact.framework */; };
133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
@ -169,20 +159,9 @@
00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = "<group>"; };
00E356EE1AD99517003FC87E /* RealmReactTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RealmReactTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* RealmReactTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RealmReactTests.m; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* RealmReactTests.m */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = RealmReactTests.m; sourceTree = "<group>"; tabWidth = 4; };
02409E1A1BCF1F2E005F3B3E /* RealmJSTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmJSTests.h; path = ../../../RealmJSTests.h; sourceTree = "<group>"; };
02409E1B1BCF1F2E005F3B3E /* RealmJSTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmJSTests.mm; path = ../../../RealmJSTests.mm; sourceTree = "<group>"; };
02409E1C1BCF1F2E005F3B3E /* RJSModuleLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RJSModuleLoader.h; path = ../../../RJSModuleLoader.h; sourceTree = "<group>"; };
02409E1D1BCF1F2E005F3B3E /* RJSModuleLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RJSModuleLoader.m; path = ../../../RJSModuleLoader.m; sourceTree = "<group>"; };
02409E201BCF1F45005F3B3E /* ArrayTests.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ArrayTests.js; path = ../../ArrayTests.js; sourceTree = "<group>"; };
02409E211BCF1F45005F3B3E /* asserts.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = asserts.js; path = ../../asserts.js; sourceTree = "<group>"; };
02409E221BCF1F45005F3B3E /* base-test.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = "base-test.js"; path = "../../base-test.js"; sourceTree = "<group>"; };
02409E231BCF1F45005F3B3E /* index.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = index.js; path = ../../index.js; sourceTree = "<group>"; };
02409E241BCF1F45005F3B3E /* ObjectTests.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ObjectTests.js; path = ../../ObjectTests.js; sourceTree = "<group>"; };
02409E251BCF1F45005F3B3E /* RealmTests.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = RealmTests.js; path = ../../RealmTests.js; sourceTree = "<group>"; };
02409E261BCF1F45005F3B3E /* ResultsTests.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ResultsTests.js; path = ../../ResultsTests.js; sourceTree = "<group>"; };
02409E271BCF1F45005F3B3E /* schemas.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = schemas.js; path = ../../schemas.js; sourceTree = "<group>"; };
02409E281BCF1F45005F3B3E /* util.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = util.js; path = ../../util.js; sourceTree = "<group>"; };
027799061BBF3BB700C96559 /* RealmJS.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RealmJS.xcodeproj; path = ../../../RealmJS.xcodeproj; sourceTree = "<group>"; };
139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = "<group>"; };
139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = "<group>"; };
@ -273,8 +252,6 @@
00E356F21AD99517003FC87E /* RealmReactTests.m */,
02409E1A1BCF1F2E005F3B3E /* RealmJSTests.h */,
02409E1B1BCF1F2E005F3B3E /* RealmJSTests.mm */,
02409E1C1BCF1F2E005F3B3E /* RJSModuleLoader.h */,
02409E1D1BCF1F2E005F3B3E /* RJSModuleLoader.m */,
00E356F01AD99517003FC87E /* Supporting Files */,
);
name = RealmReactTests;
@ -374,15 +351,6 @@
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
02409E201BCF1F45005F3B3E /* ArrayTests.js */,
02409E211BCF1F45005F3B3E /* asserts.js */,
02409E221BCF1F45005F3B3E /* base-test.js */,
02409E231BCF1F45005F3B3E /* index.js */,
02409E241BCF1F45005F3B3E /* ObjectTests.js */,
02409E251BCF1F45005F3B3E /* RealmTests.js */,
02409E261BCF1F45005F3B3E /* ResultsTests.js */,
02409E271BCF1F45005F3B3E /* schemas.js */,
02409E281BCF1F45005F3B3E /* util.js */,
13B07FAE1A68108700A75B9A /* ReactTests */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
00E356EF1AD99517003FC87E /* RealmReactTests */,
@ -621,15 +589,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
02409E291BCF1F45005F3B3E /* ArrayTests.js in Resources */,
02409E2A1BCF1F45005F3B3E /* asserts.js in Resources */,
02409E2B1BCF1F45005F3B3E /* base-test.js in Resources */,
02409E2C1BCF1F45005F3B3E /* index.js in Resources */,
02409E2D1BCF1F45005F3B3E /* ObjectTests.js in Resources */,
02409E2E1BCF1F45005F3B3E /* RealmTests.js in Resources */,
02409E2F1BCF1F45005F3B3E /* ResultsTests.js in Resources */,
02409E301BCF1F45005F3B3E /* schemas.js in Resources */,
02409E311BCF1F45005F3B3E /* util.js in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -666,7 +625,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
02409E1F1BCF1F2E005F3B3E /* RJSModuleLoader.m in Sources */,
02409E1E1BCF1F2E005F3B3E /* RealmJSTests.mm in Sources */,
00E356F31AD99517003FC87E /* RealmReactTests.m in Sources */,
);

View File

@ -1,11 +1,20 @@
/**
* 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.
*/
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2015 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#import "RealmJSTests.h"
#import "Base/RCTJavaScriptExecutor.h"
@ -16,34 +25,78 @@
@interface RealmReactTests : RealmJSTests
@end
@implementation RealmReactTests
+ (NSURL *)scriptURL {
return [[NSBundle bundleForClass:self] URLForResource:@"index" withExtension:@"js"];
+ (XCTestSuite *)defaultTestSuite {
[self waitForNotification:RCTJavaScriptDidLoadNotification];
NSError *error;
NSDictionary *testCaseNames = [self invokeMethod:@"getTestNames" inModule:@"index" error:&error];
if (error || !testCaseNames.count) {
NSLog(@"Error from calling getTestNames() - %@", error ?: @"None returned");
exit(1);
}
- (void)invokeMethod:(NSString *)method {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self expectationForNotification:RCTJavaScriptDidLoadNotification object:nil handler:^(NSNotification *notification) {
return YES;
}];
[self waitForExpectationsWithTimeout:10000000 handler:NULL];
});
XCTestSuite *suite = [super defaultTestSuite];
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
for (XCTestSuite *testSuite in [self testSuitesFromDictionary:testCaseNames]) {
[suite addTest:testSuite];
}
return suite;
}
+ (void)waitForNotification:(NSString *)notificationName {
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
__block BOOL received = NO;
id token = [nc addObserverForName:notificationName object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
received = YES;
}];
while (!received) {
@autoreleasepool {
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
[nc removeObserver:token];
}
+ (id)invokeMethod:(NSString *)method inModule:(NSString *)module error:(NSError * __strong *)outError {
module = [NSString stringWithFormat:@"realm-tests/%@.js", module];
id<RCTJavaScriptExecutor> executor = [RealmReact executor];
NSString *module = [NSString stringWithFormat:@"realm-tests/%@.js", NSStringFromClass(self.class)];
dispatch_group_t group = dispatch_group_create();
__block id result;
dispatch_group_enter(group);
[executor executeJSCall:module method:method arguments:@[] callback:^(id json, NSError *error) {
XCTAssertNil(error, @"%@", [error description]);
result = json;
if (error && outError) {
*outError = error;
}
dispatch_group_leave(group);
}];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
return result;
}
- (void)invokeMethod:(NSString *)method {
NSError *error;
[self.class invokeMethod:method inModule:NSStringFromClass(self.class) error:&error];
if (error) {
// TODO: Parse and use localizedFailureReason info once we can source map the failure location in JS.
[self recordFailureWithDescription:error.localizedDescription inFile:@(__FILE__) atLine:__LINE__ expected:YES];
}
}
@end

View File

@ -21,4 +21,8 @@
@interface RealmJSTests : XCTestCase
+ (NSArray *)testSuitesFromDictionary:(NSDictionary *)testCaseNames;
- (instancetype)initWithTestName:(NSString *)name;
@end

View File

@ -19,29 +19,29 @@
#import <objc/runtime.h>
#import "RealmJSTests.h"
#import "RJSModuleLoader.h"
@interface RealmJSTests ()
@property (nonatomic, strong) JSValue *testObject;
@end
@implementation RealmJSTests
- (instancetype)initWithJSTestObject:(JSValue *)testObject methodName:(NSString *)methodName {
self = [super initWithSelector:NSSelectorFromString(methodName)];
if (!self) {
return nil;
+ (NSArray *)testSuitesFromDictionary:(NSDictionary *)testCaseNames {
NSMutableArray *testSuites = [[NSMutableArray alloc] init];
for (NSString *suiteName in testCaseNames) {
XCTestSuite *testSuite = [[XCTestSuite alloc] initWithName:suiteName];
Class testClass = objc_allocateClassPair(self, suiteName.UTF8String, 0);
for (NSString *testName in testCaseNames[suiteName]) {
XCTestCase *testCase = [[testClass alloc] initWithTestName:testName];
[testSuite addTest:testCase];
}
_testObject = testObject;
return self;
[testSuites addObject:testSuite];
}
- (JSContext *)context {
return self.testObject.context;
return [testSuites copy];
}
- (instancetype)initWithTestName:(NSString *)name {
return [super initWithSelector:NSSelectorFromString(name)];
}
- (void)setUp {
@ -62,59 +62,6 @@
}
}
+ (NSURL *)scriptURL {
return nil;
}
+ (XCTestSuite *)defaultTestSuite {
XCTestSuite *suite = [super defaultTestSuite];
JSContext *context = [[JSContext alloc] init];
RJSModuleLoader *moduleLoader = [[RJSModuleLoader alloc] initWithContext:context];
[RealmJS initializeContext:context.JSGlobalContextRef];
// Expose the global Realm object as a global 'realm' CommonJS module.
[moduleLoader addGlobalModuleObject:context[@"Realm"] forName:@"realm"];
NSError *error;
NSURL *scriptURL = [self scriptURL];
if (!scriptURL) {
return suite;
}
JSValue *testObjects = [moduleLoader loadModuleFromURL:scriptURL error:&error];
if (!testObjects) {
NSLog(@"index.js - %@", error);
exit(1);
}
NSSet *specialMethodNames = [NSSet setWithObjects:@"beforeEach", @"afterEach", nil];
for (NSString *testName in [testObjects toDictionary]) {
JSValue *testObject = testObjects[testName];
XCTestSuite *testSuite = [[XCTestSuite alloc] initWithName:testName];
Class testClass = objc_allocateClassPair(self, testName.UTF8String, 0);
for (NSString *methodName in [testObject toDictionary]) {
if ([specialMethodNames containsObject:methodName]) {
continue;
}
JSObjectRef jsMethod = JSValueToObject(context.JSGlobalContextRef, [testObject[methodName] JSValueRef], NULL);
if (jsMethod && JSObjectIsFunction(context.JSGlobalContextRef, jsMethod)) {
XCTestCase *testCase = [[testClass alloc] initWithJSTestObject:testObject methodName:methodName];
[testSuite addTest:testCase];
}
}
[suite addTest:testSuite];
}
return suite;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *sig = [super methodSignatureForSelector:aSelector];
return sig ?: [NSMethodSignature signatureWithObjCTypes:"v@:"];
@ -125,29 +72,7 @@
}
- (void)invokeMethod:(NSString *)method {
JSValue *testObject = self.testObject;
if (![testObject hasProperty:method]) {
return;
}
JSContext *context = testObject.context;
context.exception = nil;
[testObject invokeMethod:method withArguments:nil];
JSValue *exception = context.exception;
if (exception) {
JSValue *message = [exception hasProperty:@"message"] ? exception[@"message"] : exception;
NSString *source = [exception hasProperty:@"sourceURL"] ? [exception[@"sourceURL"] toString] : nil;
NSUInteger line = [exception hasProperty:@"line"] ? [exception[@"line"] toUInt32] - 1 : 0;
NSURL *sourceURL = source ? [NSURL URLWithString:source.lastPathComponent relativeToURL:[NSURL URLWithString:@(__FILE__)]] : nil;
[self recordFailureWithDescription:message.description
inFile:sourceURL ? sourceURL.absoluteString : @(__FILE__)
atLine:sourceURL ? line : __LINE__
expected:YES];
}
[self doesNotRecognizeSelector:_cmd];
}
@end

View File

@ -80,7 +80,7 @@ function TestFailureError(message) {
// This regular expression will match stack trace lines provided by JavaScriptCore.
// Example: someMethod@file:///path/to/file.js:10:24
var regex = /^(?:.*?@)?([^\[\(].+?):(\d+)(?::(\d+))?/;
var regex = /^(?:.*?@)?([^\[\(].+?):(\d+)(?::(\d+))?\s*$/;
// Remove the top two stack frames and use information from the third, if possible.
var stack = error.stack && error.stack.split('\n');

View File

@ -23,3 +23,23 @@ exports.ObjectTests = require('./ObjectTests');
exports.RealmTests = require('./RealmTests');
exports.ResultsTests = require('./ResultsTests');
var SPECIAL_METHODS = {
beforeEach: true,
afterEach: true,
};
Object.defineProperty(exports, 'getTestNames', {
value: function() {
var testNames = {};
for (var suiteName in exports) {
var testSuite = exports[suiteName];
testNames[suiteName] = Object.keys(testSuite).filter(function(testName) {
return !(testName in SPECIAL_METHODS) && typeof testSuite[testName] == 'function';
});
}
return testNames;
}
});