From b8c42f7f6f5f092cca0e649fb6fd0c4a8a76649d Mon Sep 17 00:00:00 2001 From: Dave Miller Date: Fri, 2 Oct 2015 12:13:48 -0700 Subject: [PATCH] Introduce SnapshotView which wraps Renderable content and will verify the snapshot Reviewed By: @javache Differential Revision: D2493722 --- Examples/UIExplorer/UIExplorerList.ios.js | 17 +++--- Libraries/RCTTest/RCTSnapshotManager.h | 14 +++++ Libraries/RCTTest/RCTSnapshotManager.m | 47 ++++++++++++++++ .../RCTTest/RCTTest.xcodeproj/project.pbxproj | 6 +++ Libraries/RCTTest/SnapshotView.js | 54 +++++++++++++++++++ Libraries/react-native/react-native.js | 1 + 6 files changed, 128 insertions(+), 11 deletions(-) create mode 100644 Libraries/RCTTest/RCTSnapshotManager.h create mode 100644 Libraries/RCTTest/RCTSnapshotManager.m create mode 100644 Libraries/RCTTest/SnapshotView.js diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js index 436982dfe..adc2540d9 100644 --- a/Examples/UIExplorer/UIExplorerList.ios.js +++ b/Examples/UIExplorer/UIExplorerList.ios.js @@ -19,11 +19,10 @@ var React = require('react-native'); var { AppRegistry, Settings, + SnapshotView, StyleSheet, } = React; -var { TestModule } = React.addons; - import type { NavigationContext } from 'NavigationContext'; var UIExplorerListBase = require('./UIExplorerListBase'); @@ -83,17 +82,13 @@ var APIS = [ COMPONENTS.concat(APIS).forEach((Example) => { if (Example.displayName) { var Snapshotter = React.createClass({ - componentDidMount: function() { - // View is still blank after first RAF :\ - global.requestAnimationFrame(() => - global.requestAnimationFrame(() => TestModule.verifySnapshot( - TestModule.markTestPassed - ) - )); - }, render: function() { var Renderable = UIExplorerListBase.makeRenderable(Example); - return ; + return ( + + + + ); }, }); AppRegistry.registerComponent(Example.displayName, () => Snapshotter); diff --git a/Libraries/RCTTest/RCTSnapshotManager.h b/Libraries/RCTTest/RCTSnapshotManager.h new file mode 100644 index 000000000..6d6517aa5 --- /dev/null +++ b/Libraries/RCTTest/RCTSnapshotManager.h @@ -0,0 +1,14 @@ +/** + * 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 "RCTViewManager.h" + +@interface RCTSnapshotManager : RCTViewManager + +@end diff --git a/Libraries/RCTTest/RCTSnapshotManager.m b/Libraries/RCTTest/RCTSnapshotManager.m new file mode 100644 index 000000000..637e2db05 --- /dev/null +++ b/Libraries/RCTTest/RCTSnapshotManager.m @@ -0,0 +1,47 @@ +/** + * 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 "RCTSnapshotManager.h" + +@interface RCTSnapshotView : UIView + +@property (nonatomic, copy) RCTDirectEventBlock onSnapshotReady; +@property (nonatomic, copy) NSString *testIdentifier; + +@end + +@implementation RCTSnapshotView + +- (void)setTestIdentifier:(NSString *)testIdentifier +{ + if (![_testIdentifier isEqualToString:testIdentifier]) { + _testIdentifier = [testIdentifier copy]; + dispatch_async(dispatch_get_main_queue(), ^{ + if (self.onSnapshotReady) { + self.onSnapshotReady(@{@"testIdentifier" : self.testIdentifier}); + } + }); + } +} + +@end + + +@implementation RCTSnapshotManager + +RCT_EXPORT_MODULE() + +- (UIView *)view { + return [RCTSnapshotView new]; +} + +RCT_EXPORT_VIEW_PROPERTY(testIdentifier, NSString) +RCT_EXPORT_VIEW_PROPERTY(onSnapshotReady, RCTDirectEventBlock) + +@end diff --git a/Libraries/RCTTest/RCTTest.xcodeproj/project.pbxproj b/Libraries/RCTTest/RCTTest.xcodeproj/project.pbxproj index eae9a6e62..d6aa333e5 100644 --- a/Libraries/RCTTest/RCTTest.xcodeproj/project.pbxproj +++ b/Libraries/RCTTest/RCTTest.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 58E64FED1AB964CD007446E2 /* FBSnapshotTestController.m in Sources */ = {isa = PBXBuildFile; fileRef = 58E64FE71AB964CD007446E2 /* FBSnapshotTestController.m */; }; 58E64FEE1AB964CD007446E2 /* UIImage+Compare.m in Sources */ = {isa = PBXBuildFile; fileRef = 58E64FE91AB964CD007446E2 /* UIImage+Compare.m */; }; 58E64FEF1AB964CD007446E2 /* UIImage+Diff.m in Sources */ = {isa = PBXBuildFile; fileRef = 58E64FEB1AB964CD007446E2 /* UIImage+Diff.m */; }; + 9913A84B1BBE833400D70E66 /* RCTSnapshotManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9913A84A1BBE833400D70E66 /* RCTSnapshotManager.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -42,6 +43,8 @@ 58E64FE91AB964CD007446E2 /* UIImage+Compare.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Compare.m"; sourceTree = ""; }; 58E64FEA1AB964CD007446E2 /* UIImage+Diff.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Diff.h"; sourceTree = ""; }; 58E64FEB1AB964CD007446E2 /* UIImage+Diff.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Diff.m"; sourceTree = ""; }; + 9913A8491BBE833400D70E66 /* RCTSnapshotManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSnapshotManager.h; sourceTree = ""; }; + 9913A84A1BBE833400D70E66 /* RCTSnapshotManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSnapshotManager.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -59,6 +62,8 @@ isa = PBXGroup; children = ( 58E64FE31AB964CD007446E2 /* FBSnapshotTestCase */, + 9913A8491BBE833400D70E66 /* RCTSnapshotManager.h */, + 9913A84A1BBE833400D70E66 /* RCTSnapshotManager.m */, 585135331AB3C56F00882537 /* RCTTestModule.h */, 585135341AB3C56F00882537 /* RCTTestModule.m */, 585135351AB3C56F00882537 /* RCTTestRunner.h */, @@ -149,6 +154,7 @@ buildActionMask = 2147483647; files = ( 58E64FEE1AB964CD007446E2 /* UIImage+Compare.m in Sources */, + 9913A84B1BBE833400D70E66 /* RCTSnapshotManager.m in Sources */, 585135371AB3C56F00882537 /* RCTTestModule.m in Sources */, 58E64FEF1AB964CD007446E2 /* UIImage+Diff.m in Sources */, 58E64FED1AB964CD007446E2 /* FBSnapshotTestController.m in Sources */, diff --git a/Libraries/RCTTest/SnapshotView.js b/Libraries/RCTTest/SnapshotView.js new file mode 100644 index 000000000..83bc95296 --- /dev/null +++ b/Libraries/RCTTest/SnapshotView.js @@ -0,0 +1,54 @@ +/** + * 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 SnapshotView + * @flow + */ +'use strict'; + +var React = require('React'); +var StyleSheet = require('StyleSheet'); +var { TestModule } = require('NativeModules'); + +var requireNativeComponent = require('requireNativeComponent'); + +var SnapshotView = React.createClass({ + onDefaultAction: function(event: Object) { + TestModule.verifySnapshot(TestModule.markTestPassed); + }, + + render: function() { + var testIdentifier = this.props.testIdentifier || 'test'; + var onSnapshotReady = this.props.onSnapshotReady || this.onDefaultAction; + return ( + + ); + }, + + propTypes: { + // A callback when the Snapshot view is ready to be compared + onSnapshotReady : React.PropTypes.func, + // A name to identify the individual instance to the SnapshotView + testIdentifier : React.PropTypes.string, + } +}); + +var style = StyleSheet.create({ + snapshot: { + flex: 1, + }, +}); + +var RCTSnapshot = requireNativeComponent('RCTSnapshot', SnapshotView); + +module.exports = SnapshotView; diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js index 5afdc8d9e..fde908361 100644 --- a/Libraries/react-native/react-native.js +++ b/Libraries/react-native/react-native.js @@ -34,6 +34,7 @@ var ReactNative = Object.assign(Object.create(require('React')), { ScrollView: require('ScrollView'), SegmentedControlIOS: require('SegmentedControlIOS'), SliderIOS: require('SliderIOS'), + SnapshotView: require('SnapshotView'), SwitchAndroid: require('SwitchAndroid'), SwitchIOS: require('SwitchIOS'), TabBarIOS: require('TabBarIOS'),