Skip to content

Commit 6573d25

Browse files
committed
Improve test architecture so failures don't crash the simulator
1 parent 1718b17 commit 6573d25

File tree

8 files changed

+31
-90
lines changed

8 files changed

+31
-90
lines changed

Examples/UIExplorer/UIExplorerIntegrationTests/IntegrationTestsTests.m

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ - (void)setUp
3232
NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
3333
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);
3434
_runner = RCTInitRunnerForApp(@"Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestsApp");
35-
36-
// If tests have changes, set recordMode = YES below and run the affected
37-
// tests on an iPhone5, iOS 8.3 simulator.
38-
_runner.recordMode = NO;
3935
}
4036

4137
#pragma mark Logic Tests
@@ -53,8 +49,7 @@ - (void)testTheTester_waitOneFrame
5349
expectErrorBlock:nil];
5450
}
5551

56-
// TODO: this seems to stall forever - figure out why
57-
- (void)DISABLED_testTheTester_ExpectError
52+
- (void)testTheTester_ExpectError
5853
{
5954
[_runner runTest:_cmd
6055
module:@"IntegrationTestHarnessTest"
@@ -91,12 +86,9 @@ - (void)testPromises
9186

9287
- (void)testSimpleSnapshot
9388
{
89+
// If tests have changes, set recordMode = YES below and re-run
90+
_runner.recordMode = NO;
9491
[_runner runTest:_cmd module:@"SimpleSnapshotTest"];
9592
}
9693

97-
- (void)testZZZ_NotInRecordMode
98-
{
99-
RCTAssert(_runner.recordMode == NO, @"Don't forget to turn record mode back to NO before commit.");
100-
}
101-
10294
@end

Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
#import "RCTRedBox.h"
2222
#import "RCTRootView.h"
2323

24-
#define TIMEOUT_SECONDS 240
25-
2624
@interface UIExplorerTests : XCTestCase
2725
{
2826
RCTTestRunner *_runner;
@@ -40,52 +38,6 @@ - (void)setUp
4038
NSString *version = [[UIDevice currentDevice] systemVersion];
4139
RCTAssert([version isEqualToString:@"8.3"], @"Snapshot tests should be run on iOS 8.3, found %@", version);
4240
_runner = RCTInitRunnerForApp(@"Examples/UIExplorer/UIExplorerApp.ios");
43-
44-
// If tests have changes, set recordMode = YES below and run the affected
45-
// tests on an iPhone5, iOS 8.3 simulator.
46-
_runner.recordMode = NO;
47-
}
48-
49-
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
50-
{
51-
if (test(view)) {
52-
return YES;
53-
}
54-
for (UIView *subview in [view subviews]) {
55-
if ([self findSubviewInView:subview matching:test]) {
56-
return YES;
57-
}
58-
}
59-
return NO;
60-
}
61-
62-
// Make sure this test runs first because the other tests will tear out the rootView
63-
- (void)testAAA_RootViewLoadsAndRenders
64-
{
65-
// TODO (t7296305) Fix and Re-Enable this UIExplorer Test
66-
return;
67-
68-
UIViewController *vc = [UIApplication sharedApplication].delegate.window.rootViewController;
69-
RCTAssert([vc.view isKindOfClass:[RCTRootView class]], @"This test must run first.");
70-
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
71-
BOOL foundElement = NO;
72-
NSString *redboxError = nil;
73-
74-
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
75-
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
76-
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
77-
78-
redboxError = [[RCTRedBox sharedInstance] currentErrorMessage];
79-
foundElement = [self findSubviewInView:vc.view matching:^(UIView *view) {
80-
if ([view.accessibilityLabel isEqualToString:@"<View>"]) {
81-
return YES;
82-
}
83-
return NO;
84-
}];
85-
}
86-
87-
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
88-
XCTAssertTrue(foundElement, @"Couldn't find element with '<View>' text in %d seconds", TIMEOUT_SECONDS);
8941
}
9042

9143
#define RCT_SNAPSHOT_TEST(name, reRecord) \
@@ -102,10 +54,4 @@ - (void)test##name##Snapshot \
10254
RCT_SNAPSHOT_TEST(SliderExample, NO)
10355
RCT_SNAPSHOT_TEST(TabBarExample, NO)
10456

105-
// Make sure this test runs last
106-
- (void)testZZZ_NotInRecordMode
107-
{
108-
RCTAssert(_runner.recordMode == NO, @"Don't forget to turn record mode back to NO before commit.");
109-
}
110-
11157
@end

Examples/UIExplorer/UIExplorerIntegrationTests/js/PromiseTest.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ var PromiseTest = React.createClass({
2222
Promise.all([
2323
this.testShouldResolve(),
2424
this.testShouldReject(),
25-
]).then(() => RCTTestModule.finish(
25+
]).then(() => RCTTestModule.markTestPassed(
2626
this.shouldResolve && this.shouldReject
2727
));
2828
},
@@ -42,7 +42,7 @@ var PromiseTest = React.createClass({
4242
},
4343

4444
render() {
45-
return <React.View />;
45+
return <React.View />;
4646
}
4747

4848
});

Examples/UIExplorer/UIExplorerIntegrationTests/js/SimpleSnapshotTest.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ var SimpleSnapshotTest = React.createClass({
2424
requestAnimationFrame(() => TestModule.verifySnapshot(this.done));
2525
},
2626

27-
done() {
28-
TestModule.markTestCompleted();
27+
done(success) {
28+
TestModule.markTestPassed(success);
2929
},
3030

3131
render() {

Examples/UIExplorer/UIExplorerList.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ COMPONENTS.concat(APIS).forEach((Example) => {
115115
// View is still blank after first RAF :\
116116
global.requestAnimationFrame(() =>
117117
global.requestAnimationFrame(() => TestModule.verifySnapshot(
118-
TestModule.markTestCompleted
118+
TestModule.markTestPassed
119119
)
120120
));
121121
},

Libraries/RCTTest/RCTTestModule.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212
#import "RCTBridgeModule.h"
1313
#import "RCTDefines.h"
1414

15+
typedef NS_ENUM(NSInteger, RCTTestStatus) {
16+
RCTTestStatusPending = 0,
17+
RCTTestStatusPassed,
18+
RCTTestStatusFailed
19+
};
20+
1521
@class FBSnapshotTestController;
1622

1723
@interface RCTTestModule : NSObject <RCTBridgeModule>
@@ -32,8 +38,8 @@
3238
@property (nonatomic, assign) SEL testSelector;
3339

3440
/**
35-
* This is typically polled while running the runloop until true.
41+
* This is polled while running the runloop until true.
3642
*/
37-
@property (nonatomic, readonly, getter=isDone) BOOL done;
43+
@property (nonatomic, readonly) RCTTestStatus status;
3844

3945
@end

Libraries/RCTTest/RCTTestModule.m

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,7 @@ - (instancetype)init
5151
selector:_testSelector
5252
identifier:_snapshotCounter[testName]
5353
error:&error];
54-
55-
RCTAssert(success, @"Snapshot comparison failed: %@", error);
56-
callback(@[]);
57-
}];
58-
}
59-
60-
RCT_EXPORT_METHOD(markTestCompleted)
61-
{
62-
[_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
63-
_done = YES;
54+
callback(@[@(success)]);
6455
}];
6556
}
6657

@@ -79,11 +70,16 @@ - (instancetype)init
7970
reject(nil);
8071
}
8172

82-
RCT_EXPORT_METHOD(finish:(BOOL)success)
73+
RCT_EXPORT_METHOD(markTestCompleted)
8374
{
84-
RCTAssert(success, @"RCTTestModule finished without success");
85-
[self markTestCompleted];
75+
[self markTestPassed:YES];
8676
}
8777

78+
RCT_EXPORT_METHOD(markTestPassed:(BOOL)success)
79+
{
80+
[_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
81+
_status = success ? RCTTestStatusPassed : RCTTestStatusFailed;
82+
}];
83+
}
8884

8985
@end

Libraries/RCTTest/RCTTestRunner.m

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#import "RCTTestModule.h"
1717
#import "RCTUtils.h"
1818

19-
#define TIMEOUT_SECONDS 240
19+
#define TIMEOUT_SECONDS 60
2020

2121
@interface RCTBridge (RCTTestRunner)
2222

@@ -93,7 +93,7 @@ - (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictiona
9393

9494
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
9595
NSString *error = [[RCTRedBox sharedInstance] currentErrorMessage];
96-
while ([date timeIntervalSinceNow] > 0 && ![testModule isDone] && error == nil) {
96+
while ([date timeIntervalSinceNow] > 0 && testModule.status == RCTTestStatusPending && error == nil) {
9797
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
9898
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
9999
error = [[RCTRedBox sharedInstance] currentErrorMessage];
@@ -104,11 +104,12 @@ - (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictiona
104104
[[RCTRedBox sharedInstance] dismiss];
105105
if (expectErrorBlock) {
106106
RCTAssert(expectErrorBlock(error), @"Expected an error but nothing matched.");
107-
} else if (error) {
108-
RCTAssert(error == nil, @"RedBox error: %@", error);
109107
} else {
110-
RCTAssert([testModule isDone], @"Test didn't finish within %d seconds", TIMEOUT_SECONDS);
108+
RCTAssert(error == nil, @"RedBox error: %@", error);
109+
RCTAssert(testModule.status != RCTTestStatusPending, @"Test didn't finish within %d seconds", TIMEOUT_SECONDS);
110+
RCTAssert(testModule.status == RCTTestStatusPassed, @"Test failed");
111111
}
112+
RCTAssert(self.recordMode == NO, @"Don't forget to turn record mode back to NO before commit.");
112113
}
113114

114115
@end

0 commit comments

Comments
 (0)