mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-02-06 22:44:22 +08:00
Improve test architecture so failures don't crash the simulator
This commit is contained in:
@@ -32,10 +32,6 @@
|
||||
NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
|
||||
RCTAssert(version.majorVersion == 8 || version.minorVersion == 3, @"Tests should be run on iOS 8.3, found %zd.%zd.%zd", version.majorVersion, version.minorVersion, version.patchVersion);
|
||||
_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.3 simulator.
|
||||
_runner.recordMode = NO;
|
||||
}
|
||||
|
||||
#pragma mark Logic Tests
|
||||
@@ -53,8 +49,7 @@
|
||||
expectErrorBlock:nil];
|
||||
}
|
||||
|
||||
// TODO: this seems to stall forever - figure out why
|
||||
- (void)DISABLED_testTheTester_ExpectError
|
||||
- (void)testTheTester_ExpectError
|
||||
{
|
||||
[_runner runTest:_cmd
|
||||
module:@"IntegrationTestHarnessTest"
|
||||
@@ -91,12 +86,9 @@
|
||||
|
||||
- (void)testSimpleSnapshot
|
||||
{
|
||||
// If tests have changes, set recordMode = YES below and re-run
|
||||
_runner.recordMode = NO;
|
||||
[_runner runTest:_cmd module:@"SimpleSnapshotTest"];
|
||||
}
|
||||
|
||||
- (void)testZZZ_NotInRecordMode
|
||||
{
|
||||
RCTAssert(_runner.recordMode == NO, @"Don't forget to turn record mode back to NO before commit.");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#import "RCTRedBox.h"
|
||||
#import "RCTRootView.h"
|
||||
|
||||
#define TIMEOUT_SECONDS 240
|
||||
|
||||
@interface UIExplorerTests : XCTestCase
|
||||
{
|
||||
RCTTestRunner *_runner;
|
||||
@@ -40,52 +38,6 @@
|
||||
NSString *version = [[UIDevice currentDevice] systemVersion];
|
||||
RCTAssert([version isEqualToString:@"8.3"], @"Snapshot tests should be run on iOS 8.3, found %@", version);
|
||||
_runner = RCTInitRunnerForApp(@"Examples/UIExplorer/UIExplorerApp.ios");
|
||||
|
||||
// If tests have changes, set recordMode = YES below and run the affected
|
||||
// tests on an iPhone5, iOS 8.3 simulator.
|
||||
_runner.recordMode = NO;
|
||||
}
|
||||
|
||||
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
|
||||
{
|
||||
if (test(view)) {
|
||||
return YES;
|
||||
}
|
||||
for (UIView *subview in [view subviews]) {
|
||||
if ([self findSubviewInView:subview matching:test]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Make sure this test runs first because the other tests will tear out the rootView
|
||||
- (void)testAAA_RootViewLoadsAndRenders
|
||||
{
|
||||
// TODO (t7296305) Fix and Re-Enable this UIExplorer Test
|
||||
return;
|
||||
|
||||
UIViewController *vc = [UIApplication sharedApplication].delegate.window.rootViewController;
|
||||
RCTAssert([vc.view isKindOfClass:[RCTRootView class]], @"This test must run first.");
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
|
||||
BOOL foundElement = NO;
|
||||
NSString *redboxError = nil;
|
||||
|
||||
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
|
||||
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
|
||||
redboxError = [[RCTRedBox sharedInstance] currentErrorMessage];
|
||||
foundElement = [self findSubviewInView:vc.view matching:^(UIView *view) {
|
||||
if ([view.accessibilityLabel isEqualToString:@"<View>"]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}];
|
||||
}
|
||||
|
||||
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
|
||||
XCTAssertTrue(foundElement, @"Couldn't find element with '<View>' text in %d seconds", TIMEOUT_SECONDS);
|
||||
}
|
||||
|
||||
#define RCT_SNAPSHOT_TEST(name, reRecord) \
|
||||
@@ -102,10 +54,4 @@ RCT_SNAPSHOT_TEST(SwitchExample, NO)
|
||||
RCT_SNAPSHOT_TEST(SliderExample, NO)
|
||||
RCT_SNAPSHOT_TEST(TabBarExample, NO)
|
||||
|
||||
// Make sure this test runs last
|
||||
- (void)testZZZ_NotInRecordMode
|
||||
{
|
||||
RCTAssert(_runner.recordMode == NO, @"Don't forget to turn record mode back to NO before commit.");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,7 +22,7 @@ var PromiseTest = React.createClass({
|
||||
Promise.all([
|
||||
this.testShouldResolve(),
|
||||
this.testShouldReject(),
|
||||
]).then(() => RCTTestModule.finish(
|
||||
]).then(() => RCTTestModule.markTestPassed(
|
||||
this.shouldResolve && this.shouldReject
|
||||
));
|
||||
},
|
||||
@@ -42,7 +42,7 @@ var PromiseTest = React.createClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
return <React.View />;
|
||||
return <React.View />;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -24,8 +24,8 @@ var SimpleSnapshotTest = React.createClass({
|
||||
requestAnimationFrame(() => TestModule.verifySnapshot(this.done));
|
||||
},
|
||||
|
||||
done() {
|
||||
TestModule.markTestCompleted();
|
||||
done(success) {
|
||||
TestModule.markTestPassed(success);
|
||||
},
|
||||
|
||||
render() {
|
||||
|
||||
@@ -115,7 +115,7 @@ COMPONENTS.concat(APIS).forEach((Example) => {
|
||||
// View is still blank after first RAF :\
|
||||
global.requestAnimationFrame(() =>
|
||||
global.requestAnimationFrame(() => TestModule.verifySnapshot(
|
||||
TestModule.markTestCompleted
|
||||
TestModule.markTestPassed
|
||||
)
|
||||
));
|
||||
},
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
#import "RCTBridgeModule.h"
|
||||
#import "RCTDefines.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, RCTTestStatus) {
|
||||
RCTTestStatusPending = 0,
|
||||
RCTTestStatusPassed,
|
||||
RCTTestStatusFailed
|
||||
};
|
||||
|
||||
@class FBSnapshotTestController;
|
||||
|
||||
@interface RCTTestModule : NSObject <RCTBridgeModule>
|
||||
@@ -32,8 +38,8 @@
|
||||
@property (nonatomic, assign) SEL testSelector;
|
||||
|
||||
/**
|
||||
* This is typically polled while running the runloop until true.
|
||||
* This is polled while running the runloop until true.
|
||||
*/
|
||||
@property (nonatomic, readonly, getter=isDone) BOOL done;
|
||||
@property (nonatomic, readonly) RCTTestStatus status;
|
||||
|
||||
@end
|
||||
|
||||
@@ -51,16 +51,7 @@ RCT_EXPORT_METHOD(verifySnapshot:(RCTResponseSenderBlock)callback)
|
||||
selector:_testSelector
|
||||
identifier:_snapshotCounter[testName]
|
||||
error:&error];
|
||||
|
||||
RCTAssert(success, @"Snapshot comparison failed: %@", error);
|
||||
callback(@[]);
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(markTestCompleted)
|
||||
{
|
||||
[_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
||||
_done = YES;
|
||||
callback(@[@(success)]);
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -79,11 +70,16 @@ RCT_REMAP_METHOD(shouldReject, shouldReject_resolve:(RCTPromiseResolveBlock)reso
|
||||
reject(nil);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(finish:(BOOL)success)
|
||||
RCT_EXPORT_METHOD(markTestCompleted)
|
||||
{
|
||||
RCTAssert(success, @"RCTTestModule finished without success");
|
||||
[self markTestCompleted];
|
||||
[self markTestPassed:YES];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(markTestPassed:(BOOL)success)
|
||||
{
|
||||
[_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
||||
_status = success ? RCTTestStatusPassed : RCTTestStatusFailed;
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#import "RCTTestModule.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
#define TIMEOUT_SECONDS 240
|
||||
#define TIMEOUT_SECONDS 60
|
||||
|
||||
@interface RCTBridge (RCTTestRunner)
|
||||
|
||||
@@ -93,7 +93,7 @@ RCT_NOT_IMPLEMENTED(-init)
|
||||
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
|
||||
NSString *error = [[RCTRedBox sharedInstance] currentErrorMessage];
|
||||
while ([date timeIntervalSinceNow] > 0 && ![testModule isDone] && error == nil) {
|
||||
while ([date timeIntervalSinceNow] > 0 && testModule.status == RCTTestStatusPending && error == nil) {
|
||||
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
error = [[RCTRedBox sharedInstance] currentErrorMessage];
|
||||
@@ -104,11 +104,12 @@ RCT_NOT_IMPLEMENTED(-init)
|
||||
[[RCTRedBox sharedInstance] dismiss];
|
||||
if (expectErrorBlock) {
|
||||
RCTAssert(expectErrorBlock(error), @"Expected an error but nothing matched.");
|
||||
} else if (error) {
|
||||
RCTAssert(error == nil, @"RedBox error: %@", error);
|
||||
} else {
|
||||
RCTAssert([testModule isDone], @"Test didn't finish within %d seconds", TIMEOUT_SECONDS);
|
||||
RCTAssert(error == nil, @"RedBox error: %@", error);
|
||||
RCTAssert(testModule.status != RCTTestStatusPending, @"Test didn't finish within %d seconds", TIMEOUT_SECONDS);
|
||||
RCTAssert(testModule.status == RCTTestStatusPassed, @"Test failed");
|
||||
}
|
||||
RCTAssert(self.recordMode == NO, @"Don't forget to turn record mode back to NO before commit.");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user