mirror of
https://github.com/zhigang1992/react-native-code-push.git
synced 2026-06-10 23:59:42 +08:00
@@ -22,6 +22,11 @@
|
||||
|
||||
+ (NSString *)getApplicationSupportDirectory;
|
||||
|
||||
// The below methods are only used during tests.
|
||||
+ (BOOL)isUsingTestConfiguration;
|
||||
+ (void)setUsingTestConfiguration:(BOOL)shouldUseTestConfiguration;
|
||||
+ (void)clearTestUpdates;
|
||||
|
||||
@end
|
||||
|
||||
@interface CodePushConfig : NSObject
|
||||
@@ -77,6 +82,10 @@ failCallback:(void (^)(NSError *err))failCallback;
|
||||
|
||||
+ (void)rollbackPackage;
|
||||
|
||||
// The below methods are only used during tests.
|
||||
+ (void)downloadAndReplaceCurrentBundle:(NSString *)remoteBundleUrl;
|
||||
+ (void)clearTestUpdates;
|
||||
|
||||
@end
|
||||
|
||||
typedef NS_ENUM(NSInteger, CodePushInstallMode) {
|
||||
|
||||
152
CodePush.js
152
CodePush.js
@@ -20,75 +20,75 @@ function checkForUpdate(deploymentKey = null) {
|
||||
* different from the CodePush update they have already installed.
|
||||
*/
|
||||
return getConfiguration()
|
||||
.then((configResult) => {
|
||||
/*
|
||||
* If a deployment key was explicitly provided,
|
||||
* then let's override the one we retrieved
|
||||
* from the native-side of the app. This allows
|
||||
* dynamically "redirecting" end-users at different
|
||||
* deployments (e.g. an early access deployment for insiders).
|
||||
*/
|
||||
if (deploymentKey) {
|
||||
config = Object.assign({}, configResult, { deploymentKey });
|
||||
} else {
|
||||
config = configResult;
|
||||
}
|
||||
|
||||
sdk = getSDK(config);
|
||||
|
||||
// Allow dynamic overwrite of function. This is only to be used for tests.
|
||||
return module.exports.getCurrentPackage();
|
||||
})
|
||||
.then((localPackage) => {
|
||||
var queryPackage = { appVersion: config.appVersion };
|
||||
|
||||
/*
|
||||
* If the app has a previously installed update, and that update
|
||||
* was targetted at the same app version that is currently running,
|
||||
* then we want to use its package hash to determine whether a new
|
||||
* release has been made on the server. Otherwise, we only need
|
||||
* to send the app version to the server, since we are interested
|
||||
* in any updates for current app store version, regardless of hash.
|
||||
*/
|
||||
if (localPackage && localPackage.appVersion && semver.compare(localPackage.appVersion, config.appVersion) === 0) {
|
||||
queryPackage = localPackage;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
sdk.queryUpdateWithCurrentPackage(queryPackage, (err, update) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
/*
|
||||
* There are three cases where checkForUpdate will resolve to null:
|
||||
* ----------------------------------------------------------------
|
||||
* 1) The server said there isn't an update. This is the most common case.
|
||||
* 2) The server said there is an update but it requires a newer binary version.
|
||||
* This would occur when end-users are running an older app store version than
|
||||
* is available, and CodePush is making sure they don't get an update that
|
||||
* potentially wouldn't be compatible with what they are running.
|
||||
* 3) The server said there is an update, but the update's hash is the same as
|
||||
* the currently running update. This should _never_ happen, unless there is a
|
||||
* bug in the server, but we're adding this check just to double-check that the
|
||||
* client app is resilient to a potential issue with the update check.
|
||||
*/
|
||||
if (!update || update.updateAppVersion || (update.packageHash === localPackage.packageHash)) {
|
||||
return resolve(null);
|
||||
}
|
||||
.then((configResult) => {
|
||||
/*
|
||||
* If a deployment key was explicitly provided,
|
||||
* then let's override the one we retrieved
|
||||
* from the native-side of the app. This allows
|
||||
* dynamically "redirecting" end-users at different
|
||||
* deployments (e.g. an early access deployment for insiders).
|
||||
*/
|
||||
if (deploymentKey) {
|
||||
config = Object.assign({}, configResult, { deploymentKey });
|
||||
} else {
|
||||
config = configResult;
|
||||
}
|
||||
|
||||
sdk = new module.exports.AcquisitionSdk(requestFetchAdapter, config);
|
||||
|
||||
// Allow dynamic overwrite of function. This is only to be used for tests.
|
||||
return module.exports.getCurrentPackage();
|
||||
})
|
||||
.then((localPackage) => {
|
||||
var queryPackage = { appVersion: config.appVersion };
|
||||
|
||||
/*
|
||||
* If the app has a previously installed update, and that update
|
||||
* was targetted at the same app version that is currently running,
|
||||
* then we want to use its package hash to determine whether a new
|
||||
* release has been made on the server. Otherwise, we only need
|
||||
* to send the app version to the server, since we are interested
|
||||
* in any updates for current app store version, regardless of hash.
|
||||
*/
|
||||
if (localPackage && localPackage.appVersion && semver.compare(localPackage.appVersion, config.appVersion) === 0) {
|
||||
queryPackage = localPackage;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
sdk.queryUpdateWithCurrentPackage(queryPackage, (err, update) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
/*
|
||||
* There are three cases where checkForUpdate will resolve to null:
|
||||
* ----------------------------------------------------------------
|
||||
* 1) The server said there isn't an update. This is the most common case.
|
||||
* 2) The server said there is an update but it requires a newer binary version.
|
||||
* This would occur when end-users are running an older app store version than
|
||||
* is available, and CodePush is making sure they don't get an update that
|
||||
* potentially wouldn't be compatible with what they are running.
|
||||
* 3) The server said there is an update, but the update's hash is the same as
|
||||
* the currently running update. This should _never_ happen, unless there is a
|
||||
* bug in the server, but we're adding this check just to double-check that the
|
||||
* client app is resilient to a potential issue with the update check.
|
||||
*/
|
||||
if (!update || update.updateAppVersion || (update.packageHash === localPackage.packageHash)) {
|
||||
return resolve(null);
|
||||
}
|
||||
|
||||
update = Object.assign(update, PackageMixins.remote);
|
||||
|
||||
NativeCodePush.isFailedUpdate(update.packageHash)
|
||||
.then((isFailedHash) => {
|
||||
update.failedInstall = isFailedHash;
|
||||
resolve(update);
|
||||
})
|
||||
.catch(reject)
|
||||
.done();
|
||||
})
|
||||
});
|
||||
});
|
||||
update = Object.assign(update, PackageMixins.remote);
|
||||
|
||||
NativeCodePush.isFailedUpdate(update.packageHash)
|
||||
.then((isFailedHash) => {
|
||||
update.failedInstall = isFailedHash;
|
||||
resolve(update);
|
||||
})
|
||||
.catch(reject)
|
||||
.done();
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var getConfiguration = (() => {
|
||||
@@ -129,30 +129,21 @@ function getCurrentPackage() {
|
||||
});
|
||||
}
|
||||
|
||||
function getSDK(config) {
|
||||
if (testSdk) {
|
||||
return testSdk;
|
||||
} else {
|
||||
return new Sdk(requestFetchAdapter, config);
|
||||
}
|
||||
}
|
||||
|
||||
/* Logs messages to console with the [CodePush] prefix */
|
||||
function log(message) {
|
||||
console.log(`[CodePush] ${message}`)
|
||||
}
|
||||
|
||||
var testConfig;
|
||||
var testSdk;
|
||||
|
||||
// This function is only used for tests. Replaces the default SDK, configuration and native bridge
|
||||
function setUpTestDependencies(providedTestSdk, providedTestConfig, testNativeBridge) {
|
||||
if (providedTestSdk) testSdk = providedTestSdk;
|
||||
function setUpTestDependencies(testSdk, providedTestConfig, testNativeBridge) {
|
||||
if (testSdk) module.exports.AcquisitionSdk = testSdk;
|
||||
if (providedTestConfig) testConfig = providedTestConfig;
|
||||
if (testNativeBridge) NativeCodePush = testNativeBridge;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* The sync method provides a simple, one-line experience for
|
||||
* incorporating the check, download and application of an update.
|
||||
*
|
||||
@@ -303,6 +294,7 @@ function sync(options = {}, syncStatusChangeCallback, downloadProgressCallback)
|
||||
};
|
||||
|
||||
var CodePush = {
|
||||
AcquisitionSdk: Sdk,
|
||||
checkForUpdate: checkForUpdate,
|
||||
getConfiguration: getConfiguration,
|
||||
getCurrentPackage: getCurrentPackage,
|
||||
|
||||
87
CodePush.m
87
CodePush.m
@@ -13,7 +13,7 @@
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
static BOOL usingTestFolder = NO;
|
||||
static BOOL testConfigurationFlag = NO;
|
||||
|
||||
// These keys represent the names we use to store data in NSUserDefaults
|
||||
static NSString *const FailedUpdatesKey = @"CODE_PUSH_FAILED_UPDATES";
|
||||
@@ -50,7 +50,10 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
NSString *packageFile = [CodePushPackage getCurrentPackageBundlePath:&error];
|
||||
NSURL *binaryJsBundleUrl = [[NSBundle mainBundle] URLForResource:resourceName withExtension:resourceExtension];
|
||||
|
||||
NSString *logMessageFormat = @"Loading JS bundle from %@";
|
||||
|
||||
if (error || !packageFile) {
|
||||
NSLog(logMessageFormat, binaryJsBundleUrl);
|
||||
return binaryJsBundleUrl;
|
||||
}
|
||||
|
||||
@@ -61,8 +64,11 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
|
||||
if ([binaryDate compare:packageDate] == NSOrderedAscending) {
|
||||
// Return package file because it is newer than the app store binary's JS bundle
|
||||
return [[NSURL alloc] initFileURLWithPath:packageFile];
|
||||
NSURL *packageUrl = [[NSURL alloc] initFileURLWithPath:packageFile];
|
||||
NSLog(logMessageFormat, packageUrl);
|
||||
return packageUrl;
|
||||
} else {
|
||||
NSLog(logMessageFormat, binaryJsBundleUrl);
|
||||
return binaryJsBundleUrl;
|
||||
}
|
||||
}
|
||||
@@ -73,6 +79,40 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
return applicationSupportDirectory;
|
||||
}
|
||||
|
||||
/*
|
||||
* This returns a boolean value indicating whether CodePush has
|
||||
* been set to run under a test configuration.
|
||||
*/
|
||||
+ (BOOL)isUsingTestConfiguration
|
||||
{
|
||||
return testConfigurationFlag;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used to enable an environment in which tests can be run.
|
||||
* Specifically, it flips a boolean flag that causes bundles to be
|
||||
* saved to a test folder and enables the ability to modify
|
||||
* installed bundles on the fly from JavaScript.
|
||||
*/
|
||||
+ (void)setUsingTestConfiguration:(BOOL)shouldUseTestConfiguration
|
||||
{
|
||||
testConfigurationFlag = shouldUseTestConfiguration;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used to clean up all test updates. It can only be used
|
||||
* when the testConfigurationFlag is set to YES, otherwise it will
|
||||
* simply no-op.
|
||||
*/
|
||||
+ (void)clearTestUpdates
|
||||
{
|
||||
if ([CodePush isUsingTestConfiguration]) {
|
||||
[CodePushPackage clearTestUpdates];
|
||||
[self removePendingUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Private API methods
|
||||
|
||||
/*
|
||||
@@ -125,6 +165,7 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
if (updateIsLoading) {
|
||||
// Pending update was initialized, but notifyApplicationReady was not called.
|
||||
// Therefore, deduce that it is a broken update and rollback.
|
||||
NSLog(@"Update did not finish loading the last time, rolling back to a previous version.");
|
||||
[self rollbackPackage];
|
||||
} else {
|
||||
// Mark that we tried to initialize the new update, so that if it crashes,
|
||||
@@ -179,7 +220,7 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
// is debugging and therefore, shouldn't be redirected to a local
|
||||
// file (since Chrome wouldn't support it). Otherwise, update
|
||||
// the current bundle URL to point at the latest update
|
||||
if (![_bridge.bundleURL.scheme hasPrefix:@"http"]) {
|
||||
if ([CodePush isUsingTestConfiguration] || ![_bridge.bundleURL.scheme hasPrefix:@"http"]) {
|
||||
_bridge.bundleURL = [CodePush bundleURL];
|
||||
}
|
||||
|
||||
@@ -204,7 +245,7 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
|
||||
// Rollback to the previous version and de-register the new update
|
||||
[CodePushPackage rollbackPackage];
|
||||
[self removePendingUpdate];
|
||||
[CodePush removePendingUpdate];
|
||||
[self loadBundle];
|
||||
}
|
||||
|
||||
@@ -231,10 +272,10 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is used to register the fact that a pending
|
||||
* This method is used to register the fact that a pending
|
||||
* update succeeded and therefore can be removed.
|
||||
*/
|
||||
- (void)removePendingUpdate
|
||||
+ (void)removePendingUpdate
|
||||
{
|
||||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
[preferences removeObjectForKey:PendingUpdateKey];
|
||||
@@ -351,19 +392,15 @@ RCT_EXPORT_METHOD(installUpdate:(NSDictionary*)updatePackage
|
||||
[self savePendingUpdate:updatePackage[PackageHashKey]
|
||||
isLoading:NO];
|
||||
|
||||
if (installMode == CodePushInstallModeImmediate) {
|
||||
[self loadBundle];
|
||||
} else if (installMode == CodePushInstallModeOnNextResume) {
|
||||
if (installMode == CodePushInstallModeOnNextResume && !_hasResumeListener) {
|
||||
// Ensure we do not add the listener twice.
|
||||
if (!_hasResumeListener) {
|
||||
// Register for app resume notifications so that we
|
||||
// can check for pending updates which support "restart on resume"
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(loadBundle)
|
||||
name:UIApplicationWillEnterForegroundNotification
|
||||
object:[UIApplication sharedApplication]];
|
||||
_hasResumeListener = YES;
|
||||
}
|
||||
// Register for app resume notifications so that we
|
||||
// can check for pending updates which support "restart on resume"
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(loadBundle)
|
||||
name:UIApplicationWillEnterForegroundNotification
|
||||
object:[UIApplication sharedApplication]];
|
||||
_hasResumeListener = YES;
|
||||
}
|
||||
// Signal to JS that the update has been applied.
|
||||
resolve(nil);
|
||||
@@ -406,7 +443,7 @@ RCT_EXPORT_METHOD(isFirstRun:(NSString *)packageHash
|
||||
RCT_EXPORT_METHOD(notifyApplicationReady:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
[self removePendingUpdate];
|
||||
[CodePush removePendingUpdate];
|
||||
resolve([NSNull null]);
|
||||
}
|
||||
|
||||
@@ -418,9 +455,17 @@ RCT_EXPORT_METHOD(restartApp)
|
||||
[self loadBundle];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(setUsingTestFolder:(BOOL)shouldUseTestFolder)
|
||||
/*
|
||||
* This method is the native side of the CodePush.downloadAndReplaceCurrentBundle()
|
||||
* method, which replaces the current bundle with the one downloaded from
|
||||
* removeBundleUrl. It is only to be used during tests and no-ops if the test
|
||||
* configuration flag is not set.
|
||||
*/
|
||||
RCT_EXPORT_METHOD(downloadAndReplaceCurrentBundle:(NSString *)remoteBundleUrl)
|
||||
{
|
||||
usingTestFolder = shouldUseTestFolder;
|
||||
if ([CodePush isUsingTestConfiguration]) {
|
||||
[CodePushPackage downloadAndReplaceCurrentBundle:remoteBundleUrl];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -14,7 +14,12 @@ NSString * const UnzippedFolderName = @"unzipped";
|
||||
|
||||
+ (NSString *)getCodePushPath
|
||||
{
|
||||
return [[CodePush getApplicationSupportDirectory] stringByAppendingPathComponent:@"CodePush"];
|
||||
NSString* codePushPath = [[CodePush getApplicationSupportDirectory] stringByAppendingPathComponent:@"CodePush"];
|
||||
if ([CodePush isUsingTestConfiguration]) {
|
||||
codePushPath = [codePushPath stringByAppendingPathComponent:@"TestPackages"];
|
||||
}
|
||||
|
||||
return codePushPath;
|
||||
}
|
||||
|
||||
+ (NSString *)getDownloadFilePath
|
||||
@@ -481,4 +486,31 @@ NSString * const UnzippedFolderName = @"unzipped";
|
||||
[self updateCurrentPackageInfo:info error:&error];
|
||||
}
|
||||
|
||||
+ (void)downloadAndReplaceCurrentBundle:(NSString *)remoteBundleUrl
|
||||
{
|
||||
NSURL *urlRequest = [NSURL URLWithString:remoteBundleUrl];
|
||||
NSError *error = nil;
|
||||
NSString *downloadedBundle = [NSString stringWithContentsOfURL:urlRequest
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:&error];
|
||||
|
||||
if (error) {
|
||||
NSLog(@"Error downloading from URL %@", remoteBundleUrl);
|
||||
} else {
|
||||
NSString *currentPackageBundlePath = [self getCurrentPackageBundlePath:&error];
|
||||
[downloadedBundle writeToFile:currentPackageBundlePath
|
||||
atomically:YES
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:&error];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)clearTestUpdates
|
||||
{
|
||||
if ([CodePush isUsingTestConfiguration]) {
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[self getCodePushPath] error:nil];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[self getStatusFilePath] error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,70 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <RCTTest/RCTTestRunner.h>
|
||||
|
||||
#import "RCTAssert.h"
|
||||
#import "CodePush.h"
|
||||
|
||||
#define FB_REFERENCE_IMAGE_DIR "\"$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages\""
|
||||
|
||||
@interface CheckForUpdateTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation CheckForUpdateTests
|
||||
{
|
||||
RCTTestRunner *_runner;
|
||||
}
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
#if __LP64__
|
||||
RCTAssert(false, @"Tests should be run on 32-bit device simulators (e.g. iPhone 5)");
|
||||
#endif
|
||||
|
||||
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);
|
||||
[CodePush setUsingTestConfiguration:YES];
|
||||
[CodePush clearTestUpdates];
|
||||
_runner = RCTInitRunnerForApp(@"CodePushDemoAppTests/CheckForUpdateTests/CheckForUpdateTestApp", nil);
|
||||
}
|
||||
|
||||
#pragma mark Logic Tests
|
||||
|
||||
- (void)testFirstUpdate
|
||||
{
|
||||
[_runner runTest:_cmd
|
||||
module:@"FirstUpdateTest"];
|
||||
}
|
||||
|
||||
- (void)testNewUpdate
|
||||
{
|
||||
[_runner runTest:_cmd
|
||||
module:@"NewUpdateTest"];
|
||||
}
|
||||
|
||||
- (void)testNoRemotePackage
|
||||
{
|
||||
|
||||
[_runner runTest:_cmd module:@"NoRemotePackageTest"];
|
||||
}
|
||||
|
||||
- (void)testRemotePackageAppVersionNewer
|
||||
{
|
||||
[_runner runTest:_cmd
|
||||
module:@"RemotePackageAppVersionNewerTest"];
|
||||
}
|
||||
|
||||
- (void)testSamePackage
|
||||
{
|
||||
[_runner runTest:_cmd
|
||||
module:@"SamePackageTest"];
|
||||
}
|
||||
|
||||
- (void)testSwitchDeploymentKey
|
||||
{
|
||||
[_runner runTest:_cmd
|
||||
module:@"SwitchDeploymentKeyTest"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,8 +1,8 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var React = require('react-native');
|
||||
import React from "react-native";
|
||||
|
||||
var {
|
||||
let {
|
||||
AppRegistry,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
@@ -11,25 +11,26 @@ var {
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var TESTS = [
|
||||
require('./NoRemotePackageTest'),
|
||||
require('./NoRemotePackageWithSameAppVersionTest'),
|
||||
require('./FirstUpdateTest'),
|
||||
require('./NewUpdateTest'),
|
||||
require('./SamePackageTest')
|
||||
let TESTS = [
|
||||
require("./testcases/FirstUpdateTest"),
|
||||
require("./testcases/NewUpdateTest"),
|
||||
require("./testcases/NoRemotePackageTest"),
|
||||
require("./testcases/RemotePackageAppVersionNewerTest"),
|
||||
require("./testcases/SamePackageTest"),
|
||||
require("./testcases/SwitchDeploymentKeyTest")
|
||||
];
|
||||
|
||||
TESTS.forEach(
|
||||
(test) => AppRegistry.registerComponent(test.displayName, () => test)
|
||||
);
|
||||
|
||||
var QueryUpdateTestApp = React.createClass({
|
||||
getInitialState: function() {
|
||||
let CheckForUpdateTestApp = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
test: null,
|
||||
};
|
||||
},
|
||||
render: function() {
|
||||
render() {
|
||||
if (this.state.test) {
|
||||
return (
|
||||
<ScrollView>
|
||||
@@ -40,9 +41,7 @@ var QueryUpdateTestApp = React.createClass({
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.row}>
|
||||
Click on a test to run it in this shell for easier debugging and
|
||||
development. Run all tests in the testing environment with cmd+U in
|
||||
Xcode.
|
||||
CheckForUpdate Tests
|
||||
</Text>
|
||||
<View style={styles.separator} />
|
||||
<ScrollView>
|
||||
@@ -53,6 +52,9 @@ var QueryUpdateTestApp = React.createClass({
|
||||
<Text style={styles.testName}>
|
||||
{test.displayName}
|
||||
</Text>
|
||||
<Text style={styles.testDescription}>
|
||||
{test.description}
|
||||
</Text>
|
||||
</TouchableOpacity>,
|
||||
<View style={styles.separator} />
|
||||
])}
|
||||
@@ -62,9 +64,9 @@ var QueryUpdateTestApp = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
let styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: 'white',
|
||||
backgroundColor: "white",
|
||||
marginTop: 40,
|
||||
margin: 15,
|
||||
},
|
||||
@@ -72,12 +74,15 @@ var styles = StyleSheet.create({
|
||||
padding: 10,
|
||||
},
|
||||
testName: {
|
||||
fontWeight: '500',
|
||||
fontWeight: "500",
|
||||
},
|
||||
testDescription: {
|
||||
fontSize: 10
|
||||
},
|
||||
separator: {
|
||||
height: 1,
|
||||
backgroundColor: '#bbbbbb',
|
||||
backgroundColor: "#bbbbbb",
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent('QueryUpdateTestApp', () => QueryUpdateTestApp);
|
||||
AppRegistry.registerComponent("CheckForUpdateTestApp", () => CheckForUpdateTestApp);
|
||||
@@ -0,0 +1,32 @@
|
||||
export let serverPackage = {
|
||||
appVersion: "1.5.0",
|
||||
description: "Angry flappy birds",
|
||||
downloadUrl: "http://www.windowsazure.com/blobs/awperoiuqpweru",
|
||||
isAvailable: true,
|
||||
isMandatory: false,
|
||||
packageHash: "hash240",
|
||||
packageSize: 1024,
|
||||
updateAppVersion: false
|
||||
};
|
||||
|
||||
export let localPackage = {
|
||||
downloadURL: "http://www.windowsazure.com/blobs/awperoiuqpweru",
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
label: "2.4.0",
|
||||
isMandatory: false,
|
||||
isAvailable: true,
|
||||
updateAppVersion: false,
|
||||
packageHash: "hash123",
|
||||
packageSize: 1024
|
||||
};
|
||||
|
||||
export let updateAppVersionPackage = {
|
||||
appVersion: "1.5.0",
|
||||
description: "",
|
||||
downloadUrl: "",
|
||||
isAvailable: false,
|
||||
isMandatory: false,
|
||||
packageHash: "",
|
||||
updateAppVersion: true
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
import createMockAcquisitionSdk from "../../utils/mockAcquisitionSdk";
|
||||
|
||||
import { serverPackage } from "../resources/testPackages";
|
||||
const localPackage = {};
|
||||
|
||||
let FirstUpdateTest = createTestCaseComponent(
|
||||
"FirstUpdateTest",
|
||||
"should return an update when called from freshly installed binary if the server has one",
|
||||
() => {
|
||||
let mockAcquisitionSdk = createMockAcquisitionSdk(serverPackage, localPackage);
|
||||
let mockConfiguration = { appVersion : "1.5.0" };
|
||||
CodePush.setUpTestDependencies(mockAcquisitionSdk, mockConfiguration, NativeCodePush);
|
||||
CodePush.getCurrentPackage = () => {
|
||||
return Promise.resolve(localPackage);
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
return CodePush.checkForUpdate()
|
||||
.then((update) => {
|
||||
if (update) {
|
||||
assert.deepEqual(update, Object.assign(serverPackage, PackageMixins.remote));
|
||||
} else {
|
||||
throw new Error("checkForUpdate did not return the update from the server");
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = FirstUpdateTest;
|
||||
@@ -0,0 +1,37 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
import createMockAcquisitionSdk from "../../utils/mockAcquisitionSdk";
|
||||
|
||||
import { serverPackage, localPackage } from "../resources/testPackages";
|
||||
|
||||
let NewUpdateTest = createTestCaseComponent(
|
||||
"NewUpdateTest",
|
||||
"should return an update when server has a package that is newer than the current one",
|
||||
() => {
|
||||
let mockAcquisitionSdk = createMockAcquisitionSdk(serverPackage, localPackage);
|
||||
let mockConfiguration = { appVersion : "1.5.0" };
|
||||
CodePush.setUpTestDependencies(mockAcquisitionSdk, mockConfiguration, NativeCodePush);
|
||||
CodePush.getCurrentPackage = () => {
|
||||
return Promise.resolve(localPackage);
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
return CodePush.checkForUpdate()
|
||||
.then((update) => {
|
||||
if (update) {
|
||||
assert.deepEqual(update, Object.assign(serverPackage, PackageMixins.remote));
|
||||
} else {
|
||||
throw new Error("checkForUpdate did not return the update from the server");
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = NewUpdateTest;
|
||||
@@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
import createMockAcquisitionSdk from "../../utils/mockAcquisitionSdk";
|
||||
|
||||
let serverPackage = null;
|
||||
let localPackage = {};
|
||||
|
||||
let NoRemotePackageTest = createTestCaseComponent(
|
||||
"NoRemotePackageTest",
|
||||
"should not return an update when the server has none",
|
||||
() => {
|
||||
let mockAcquisitionSdk = createMockAcquisitionSdk(serverPackage, localPackage);
|
||||
let mockConfiguration = { appVersion : "1.5.0" };
|
||||
CodePush.setUpTestDependencies(mockAcquisitionSdk, mockConfiguration, NativeCodePush);
|
||||
CodePush.getCurrentPackage = () => {
|
||||
return Promise.resolve(localPackage);
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
return CodePush.checkForUpdate()
|
||||
.then((update) => {
|
||||
if (update) {
|
||||
throw new Error("checkForUpdate should not return an update if there is none on the server");
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = NoRemotePackageTest;
|
||||
@@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
import createMockAcquisitionSdk from "../../utils/mockAcquisitionSdk";
|
||||
|
||||
import { updateAppVersionPackage as serverPackage } from "../resources/testPackages";
|
||||
let localPackage = {};
|
||||
|
||||
let RemotePackageAppVersionNewerTest = createTestCaseComponent(
|
||||
"RemotePackageAppVersionNewerTest",
|
||||
"should drop the update when the server reports one with a newer binary version",
|
||||
() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let mockAcquisitionSdk = createMockAcquisitionSdk(serverPackage, localPackage);
|
||||
let mockConfiguration = { appVersion : "1.0.0" };
|
||||
CodePush.setUpTestDependencies(mockAcquisitionSdk, mockConfiguration, NativeCodePush);
|
||||
CodePush.getCurrentPackage = () => {
|
||||
return Promise.resolve(localPackage);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
() => {
|
||||
return CodePush.checkForUpdate()
|
||||
.then((update) => {
|
||||
if (update) {
|
||||
throw new Error("checkForUpdate should not return an update if remote package is of a different binary version");
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = RemotePackageAppVersionNewerTest;
|
||||
@@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
import createMockAcquisitionSdk from "../../utils/mockAcquisitionSdk";
|
||||
|
||||
import { serverPackage } from "../resources/testPackages";
|
||||
const localPackage = serverPackage;
|
||||
|
||||
let SamePackageTest = createTestCaseComponent(
|
||||
"SamePackageTest",
|
||||
"should not return an update when the server's version is the same as the local version",
|
||||
() => {
|
||||
let mockAcquisitionSdk = createMockAcquisitionSdk(serverPackage, localPackage);
|
||||
let mockConfiguration = { appVersion : "1.5.0" };
|
||||
CodePush.setUpTestDependencies(mockAcquisitionSdk, mockConfiguration, NativeCodePush);
|
||||
CodePush.getCurrentPackage = () => {
|
||||
return Promise.resolve(localPackage);
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
return CodePush.checkForUpdate()
|
||||
.then((update) => {
|
||||
if (update) {
|
||||
throw new Error("checkForUpdate should not return a package when local package is identical");
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = SamePackageTest;
|
||||
@@ -0,0 +1,40 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
import createMockAcquisitionSdk from "../../utils/mockAcquisitionSdk";
|
||||
|
||||
import { serverPackage } from "../resources/testPackages";
|
||||
const localPackage = {};
|
||||
|
||||
let deploymentKey = "myKey123";
|
||||
|
||||
let SwitchDeploymentKeyTest = createTestCaseComponent(
|
||||
"SwitchDeploymentKeyTest",
|
||||
"should check for an update under the specified deployment key",
|
||||
() => {
|
||||
let mockAcquisitionSdk = createMockAcquisitionSdk(serverPackage, localPackage, deploymentKey);
|
||||
let mockConfiguration = { appVersion : "1.5.0" };
|
||||
CodePush.setUpTestDependencies(mockAcquisitionSdk, mockConfiguration, NativeCodePush);
|
||||
CodePush.getCurrentPackage = () => {
|
||||
return Promise.resolve(localPackage);
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
return CodePush.checkForUpdate(deploymentKey)
|
||||
.then((update) => {
|
||||
if (update) {
|
||||
assert.deepEqual(update, Object.assign(serverPackage, PackageMixins.remote));
|
||||
} else {
|
||||
throw new Error("checkForUpdate did not return the update from the server");
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = SwitchDeploymentKeyTest;
|
||||
@@ -3,6 +3,7 @@
|
||||
#import <RCTTest/RCTTestRunner.h>
|
||||
|
||||
#import "RCTAssert.h"
|
||||
#import "CodePush.h"
|
||||
|
||||
#define FB_REFERENCE_IMAGE_DIR "\"$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages\""
|
||||
|
||||
@@ -12,25 +13,27 @@
|
||||
|
||||
@implementation DownloadProgressTests
|
||||
{
|
||||
RCTTestRunner *_runner;
|
||||
RCTTestRunner *_runner;
|
||||
}
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
#if __LP64__
|
||||
RCTAssert(false, @"Tests should be run on 32-bit device simulators (e.g. iPhone 5)");
|
||||
RCTAssert(false, @"Tests should be run on 32-bit device simulators (e.g. iPhone 5)");
|
||||
#endif
|
||||
|
||||
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(@"CodePushDemoAppTests/DownloadProgressTests/DownloadProgressTestApp", nil);
|
||||
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);
|
||||
[CodePush setUsingTestConfiguration:YES];
|
||||
[CodePush clearTestUpdates];
|
||||
_runner = RCTInitRunnerForApp(@"CodePushDemoAppTests/DownloadProgressTests/DownloadProgressTestApp", nil);
|
||||
}
|
||||
|
||||
#pragma mark Logic Tests
|
||||
- (void)testDownloadProgress
|
||||
{
|
||||
|
||||
[_runner runTest:_cmd module:@"DownloadProgressTest"];
|
||||
[_runner runTest:_cmd module:@"DownloadProgressTest"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var React = require("react-native");
|
||||
var { Platform, DeviceEventEmitter } = require("react-native");
|
||||
var CodePushSdk = require("react-native-code-push");
|
||||
var NativeCodePush = require("react-native").NativeModules.CodePush;
|
||||
var RCTTestModule = require('NativeModules').TestModule || {};
|
||||
|
||||
var {
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var DownloadProgressTest = React.createClass({
|
||||
propTypes: {
|
||||
shouldThrow: React.PropTypes.bool,
|
||||
waitOneFrame: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
done: false,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.waitOneFrame) {
|
||||
requestAnimationFrame(this.runTest);
|
||||
} else {
|
||||
this.runTest();
|
||||
}
|
||||
},
|
||||
|
||||
checkReceivedAndExpectedBytesEqual() {
|
||||
if (this.state.progress.receivedBytes !== this.state.progress.totalBytes) {
|
||||
throw new Error("Bytes do not tally: Received bytes=" + this.state.progress.receivedBytes + " Total bytes=" + this.state.progress.totalBytes);
|
||||
}
|
||||
},
|
||||
|
||||
runTest() {
|
||||
var downloadProgressSubscription = DeviceEventEmitter.addListener(
|
||||
"CodePushDownloadProgress",
|
||||
(progress) => {
|
||||
this.setState({
|
||||
progress:progress,
|
||||
done: false,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
var updates = require("./TestPackages");
|
||||
NativeCodePush.downloadUpdate(updates.smallPackage)
|
||||
.then((smallPackage) => {
|
||||
if (smallPackage) {
|
||||
this.checkReceivedAndExpectedBytesEqual();
|
||||
return NativeCodePush.downloadUpdate(updates.mediumPackage);
|
||||
} else {
|
||||
throw new Error("Small package download failed.");
|
||||
}
|
||||
})
|
||||
.then((mediumPackage) => {
|
||||
if (mediumPackage) {
|
||||
this.checkReceivedAndExpectedBytesEqual();
|
||||
return NativeCodePush.downloadUpdate(updates.largePackage);
|
||||
} else {
|
||||
throw new Error("Medium package download failed.");
|
||||
}
|
||||
})
|
||||
.done((largePackage) => {
|
||||
if (largePackage) {
|
||||
this.checkReceivedAndExpectedBytesEqual();
|
||||
this.setState({done: true}, RCTTestModule.markTestCompleted);
|
||||
} else {
|
||||
throw new Error("Large package download failed.");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
var progressView;
|
||||
if (this.state.progress) {
|
||||
progressView = (
|
||||
<Text>{this.state.progress.receivedBytes} of {this.state.progress.totalBytes} bytes received</Text>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
{this.constructor.displayName + ": "}
|
||||
{this.state.done ? "Done" : "Testing..."}
|
||||
</Text>
|
||||
{progressView}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
DownloadProgressTest.displayName = "DownloadProgressTest";
|
||||
|
||||
module.exports = DownloadProgressTest;
|
||||
@@ -1,8 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
var React = require("react-native");
|
||||
import React from "react-native";
|
||||
|
||||
var {
|
||||
let {
|
||||
AppRegistry,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
@@ -11,21 +11,21 @@ var {
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var TESTS = [
|
||||
require("./DownloadProgressTest")
|
||||
let TESTS = [
|
||||
require("./testcases/DownloadProgressTest")
|
||||
];
|
||||
|
||||
TESTS.forEach(
|
||||
(test) => AppRegistry.registerComponent(test.displayName, () => test)
|
||||
);
|
||||
|
||||
var DownloadProgressTestApp = React.createClass({
|
||||
getInitialState: function() {
|
||||
let DownloadProgressTestApp = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
test: null,
|
||||
};
|
||||
},
|
||||
render: function() {
|
||||
render() {
|
||||
if (this.state.test) {
|
||||
return (
|
||||
<ScrollView>
|
||||
@@ -36,9 +36,7 @@ var DownloadProgressTestApp = React.createClass({
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.row}>
|
||||
Click on a test to run it in this shell for easier debugging and
|
||||
development. Run all tests in the testing environment with cmd+U in
|
||||
Xcode.
|
||||
DownloadProgress Tests
|
||||
</Text>
|
||||
<View style={styles.separator} />
|
||||
<ScrollView>
|
||||
@@ -49,6 +47,9 @@ var DownloadProgressTestApp = React.createClass({
|
||||
<Text style={styles.testName}>
|
||||
{test.displayName}
|
||||
</Text>
|
||||
<Text style={styles.testDescription}>
|
||||
{test.description}
|
||||
</Text>
|
||||
</TouchableOpacity>,
|
||||
<View style={styles.separator} />
|
||||
])}
|
||||
@@ -58,7 +59,7 @@ var DownloadProgressTestApp = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
let styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: "white",
|
||||
marginTop: 40,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
var { Platform } = require("react-native");
|
||||
let { Platform } = require("react-native");
|
||||
|
||||
var packages = {
|
||||
smallPackage: {
|
||||
let packages = [
|
||||
{
|
||||
downloadUrl: "smallFile",
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
@@ -12,7 +12,7 @@ var packages = {
|
||||
packageHash: "hash240",
|
||||
packageSize: 1024
|
||||
},
|
||||
mediumPackage: {
|
||||
{
|
||||
downloadUrl: "mediumFile",
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
@@ -23,7 +23,7 @@ var packages = {
|
||||
packageHash: "hash240",
|
||||
packageSize: 1024
|
||||
},
|
||||
largePackage: {
|
||||
{
|
||||
downloadUrl: "largeFile",
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
@@ -34,15 +34,14 @@ var packages = {
|
||||
packageHash: "hash240",
|
||||
packageSize: 1024
|
||||
}
|
||||
};
|
||||
];
|
||||
|
||||
for (var aPackage in packages) {
|
||||
packages.forEach((aPackage) => {
|
||||
if (Platform.OS === "android") {
|
||||
// Genymotion forwards 10.0.3.2 to host machine's localhost
|
||||
packages[aPackage].downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/DownloadProgressTests/" + packages[aPackage].downloadUrl;
|
||||
aPackage.downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/DownloadProgressTests/resources/" + aPackage.downloadUrl;
|
||||
} else if (Platform.OS === "ios") {
|
||||
packages[aPackage].downloadUrl = "http://localhost:8081/CodePushDemoAppTests/DownloadProgressTests/" + packages[aPackage].downloadUrl;
|
||||
aPackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/DownloadProgressTests/resources/" + aPackage.downloadUrl;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = packages;
|
||||
export default packages;
|
||||
@@ -0,0 +1,52 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
|
||||
import testPackages from "../resources/TestPackages";
|
||||
let localPackage = {};
|
||||
let saveProgress;
|
||||
|
||||
function checkReceivedAndExpectedBytesEqual() {
|
||||
assert(saveProgress, "Download progress was not reported.");
|
||||
assert.equal(
|
||||
saveProgress.receivedBytes,
|
||||
saveProgress.totalBytes,
|
||||
`Bytes do not tally: Received bytes=${saveProgress.receivedBytes} Total bytes=${saveProgress.totalBytes}`
|
||||
);
|
||||
console.log("Downloaded one package.");
|
||||
saveProgress = null;
|
||||
}
|
||||
|
||||
let DownloadProgressTest = createTestCaseComponent(
|
||||
"DownloadProgressTest",
|
||||
"should successfully download all the bytes contained in the test packages",
|
||||
() => {
|
||||
testPackages.forEach((aPackage, index) => {
|
||||
testPackages[index] = Object.assign(aPackage, PackageMixins.remote);
|
||||
});
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
let downloadProgressCallback = (downloadProgress) => {
|
||||
console.log(`Expecting ${downloadProgress.totalBytes} bytes, received ${downloadProgress.receivedBytes} bytes.`);
|
||||
saveProgress = downloadProgress;
|
||||
};
|
||||
|
||||
// Chains promises together.
|
||||
return testPackages.reduce((aPackageDownloaded, nextPackage, index) => {
|
||||
return aPackageDownloaded
|
||||
.then(() => {
|
||||
// Skip the first time.
|
||||
index && checkReceivedAndExpectedBytesEqual();
|
||||
return nextPackage.download(downloadProgressCallback);
|
||||
})
|
||||
}, Promise.resolve());
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = DownloadProgressTest;
|
||||
@@ -3,6 +3,9 @@
|
||||
#import <RCTTest/RCTTestRunner.h>
|
||||
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTRootView.h"
|
||||
#import "RCTText.h"
|
||||
#import "CodePush.h"
|
||||
|
||||
#define FB_REFERENCE_IMAGE_DIR "\"$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages\""
|
||||
|
||||
@@ -12,25 +15,97 @@
|
||||
|
||||
@implementation InstallUpdateTests
|
||||
{
|
||||
RCTTestRunner *_runner;
|
||||
RCTTestRunner *_runner;
|
||||
}
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
#if __LP64__
|
||||
RCTAssert(false, @"Tests should be run on 32-bit device simulators (e.g. iPhone 5)");
|
||||
RCTAssert(false, @"Tests should be run on 32-bit device simulators (e.g. iPhone 5)");
|
||||
#endif
|
||||
|
||||
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(@"CodePushDemoAppTests/InstallUpdateTests/InstallUpdateTestApp", nil);
|
||||
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);
|
||||
[CodePush setUsingTestConfiguration:YES];
|
||||
}
|
||||
|
||||
#pragma mark Logic Tests
|
||||
- (void)testDownloadAndInstallUpdate
|
||||
- (void)testInstallModeImmediate
|
||||
{
|
||||
[self runTest:@"InstallModeImmediateTest"];
|
||||
}
|
||||
|
||||
- (void)testInstallModeOnNextResume
|
||||
{
|
||||
[self runTest:@"InstallModeOnNextResumeTest"];
|
||||
}
|
||||
|
||||
- (void)testInstallModeOnNextRestart
|
||||
{
|
||||
[self runTest:@"InstallModeOnNextRestartTest"];
|
||||
}
|
||||
|
||||
- (void)testIsFirstRun
|
||||
{
|
||||
[self runTest:@"IsFirstRunTest"];
|
||||
}
|
||||
|
||||
- (void)testNotifyApplicationReady
|
||||
{
|
||||
[self runTest:@"NotifyApplicationReadyTest"];
|
||||
}
|
||||
|
||||
- (void)testRollback
|
||||
{
|
||||
[self runTest:@"RollbackTest"];
|
||||
}
|
||||
|
||||
- (void)testIsFailedUpdate
|
||||
{
|
||||
[self runTest:@"IsFailedUpdateTest"];
|
||||
}
|
||||
|
||||
- (void)testIsPending
|
||||
{
|
||||
[self runTest:@"IsPendingTest"];
|
||||
}
|
||||
|
||||
- (void)runTest:(NSString *)testName
|
||||
{
|
||||
[CodePush clearTestUpdates];
|
||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/testcases/%@.bundle?platform=ios&dev=true", testName]]
|
||||
moduleName:testName
|
||||
initialProperties:nil
|
||||
launchOptions:nil];
|
||||
rootView.frame = CGRectMake(0, 0, 320, 2000); // Constant size for testing on multiple devices
|
||||
UIViewController *vc = [UIApplication sharedApplication].delegate.window.rootViewController;
|
||||
vc.view = [UIView new];
|
||||
[vc.view addSubview:rootView];
|
||||
while (![self foundTestPassedText:vc.view]) {
|
||||
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)foundTestPassedText:(UIView *)view {
|
||||
BOOL foundText = NO;
|
||||
NSArray *subviews = [view subviews];
|
||||
if ([subviews count] == 0) {
|
||||
if ([view isKindOfClass:[RCTText class]] && [[((RCTText *)view) textStorage].string isEqualToString:@"Test Passed!"]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
[_runner runTest:_cmd module:@"DownloadAndInstallUpdateTest"];
|
||||
for (UIView *subview in subviews) {
|
||||
foundText = [self foundTestPassedText:subview];
|
||||
if (foundText) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return foundText;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
* Sample React Native App
|
||||
* https://github.com/facebook/react-native
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
AppRegistry,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var RCTTestModule = require('NativeModules').TestModule;
|
||||
var NativeCodePush = require('react-native').NativeModules.CodePush;
|
||||
|
||||
var CodePushDemoApp = React.createClass({
|
||||
componentDidMount: function() {
|
||||
NativeCodePush.setUsingTestFolder(true);
|
||||
NativeCodePush.getCurrentPackage().then(
|
||||
(savedPackage) => {
|
||||
if (savedPackage) {
|
||||
var testPackage = require("./TestPackage");
|
||||
for (var key in testPackage) {
|
||||
if (savedPackage[key] !== testPackage[key]) {
|
||||
throw new Error("The local package is still different from the updated package after installation");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error("The updated package was not saved");
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
throw new Error("The updated package was not saved");
|
||||
}
|
||||
);
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.welcome}>
|
||||
If you see this, you have successfully installed an update!
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#F5FCFF',
|
||||
},
|
||||
welcome: {
|
||||
fontSize: 20,
|
||||
textAlign: 'center',
|
||||
margin: 10,
|
||||
}
|
||||
});
|
||||
|
||||
CodePushDemoApp.displayName = 'CodePushDemoApp';
|
||||
AppRegistry.registerComponent('CodePushDemoApp', () => CodePushDemoApp);
|
||||
@@ -1,72 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var CodePushSdk = require('react-native-code-push');
|
||||
var NativeCodePush = require("react-native").NativeModules.CodePush;
|
||||
var RCTTestModule = require('NativeModules').TestModule || {};
|
||||
|
||||
var {
|
||||
AppRegistry,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var DownloadAndInstallUpdateTest = React.createClass({
|
||||
propTypes: {
|
||||
shouldThrow: React.PropTypes.bool,
|
||||
waitOneFrame: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
done: false,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.waitOneFrame) {
|
||||
requestAnimationFrame(this.runTest);
|
||||
} else {
|
||||
this.setUp();
|
||||
this.runTest();
|
||||
}
|
||||
},
|
||||
|
||||
setUp(callWhenDone) {
|
||||
var mockConfiguration = { appVersion : "1.5.0" };
|
||||
NativeCodePush.setUsingTestFolder(true);
|
||||
CodePushSdk.setUpTestDependencies(null, mockConfiguration, NativeCodePush);
|
||||
},
|
||||
|
||||
runTest() {
|
||||
var update = require("./TestPackage");
|
||||
NativeCodePush.downloadUpdate(update).done((downloadedPackage) => {
|
||||
NativeCodePush.installUpdate(downloadedPackage, /*rollbackTimeout*/ 1000, CodePushSdk.InstallMode.IMMEDIATE)
|
||||
.then(() => {
|
||||
CodePushSdk.getCurrentPackage().then((localPackage) => {
|
||||
if (localPackage.packageHash == update.packageHash) {
|
||||
this.setState({done: true}, RCTTestModule.markTestCompleted);
|
||||
} else {
|
||||
throw new Error("Update was not installed");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: 'white', padding: 40}}>
|
||||
<Text>
|
||||
{this.constructor.displayName + ': '}
|
||||
{this.state.done ? 'Done' : 'Testing...'}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
DownloadAndInstallUpdateTest.displayName = 'DownloadAndInstallUpdateTest';
|
||||
AppRegistry.registerComponent('CodePushDemoApp', () => DownloadAndInstallUpdateTest);
|
||||
|
||||
module.exports = DownloadAndInstallUpdateTest;
|
||||
@@ -1,79 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
|
||||
var {
|
||||
AppRegistry,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var TESTS = [
|
||||
require('./DownloadAndInstallUpdateTest')
|
||||
];
|
||||
|
||||
TESTS.forEach(
|
||||
(test) => AppRegistry.registerComponent(test.displayName, () => test)
|
||||
);
|
||||
|
||||
var InstallUpdateTestApp = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
test: null,
|
||||
};
|
||||
},
|
||||
render: function() {
|
||||
if (this.state.test) {
|
||||
return (
|
||||
<ScrollView>
|
||||
<this.state.test />
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.row}>
|
||||
Click on a test to run it in this shell for easier debugging and
|
||||
development. Run all tests in the testing environment with cmd+U in
|
||||
Xcode.
|
||||
</Text>
|
||||
<View style={styles.separator} />
|
||||
<ScrollView>
|
||||
{TESTS.map((test) => [
|
||||
<TouchableOpacity
|
||||
onPress={() => this.setState({test})}
|
||||
style={styles.row}>
|
||||
<Text style={styles.testName}>
|
||||
{test.displayName}
|
||||
</Text>
|
||||
</TouchableOpacity>,
|
||||
<View style={styles.separator} />
|
||||
])}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: 'white',
|
||||
marginTop: 40,
|
||||
margin: 15,
|
||||
},
|
||||
row: {
|
||||
padding: 10,
|
||||
},
|
||||
testName: {
|
||||
fontWeight: '500',
|
||||
},
|
||||
separator: {
|
||||
height: 1,
|
||||
backgroundColor: '#bbbbbb',
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent('InstallUpdateTestApp', () => InstallUpdateTestApp);
|
||||
@@ -1,21 +0,0 @@
|
||||
var { Platform } = require("react-native");
|
||||
|
||||
var testPackage = {
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
label: "2.4.0",
|
||||
isMandatory: false,
|
||||
isAvailable: true,
|
||||
updateAppVersion: false,
|
||||
packageHash: "hash240",
|
||||
packageSize: 1024
|
||||
};
|
||||
|
||||
if (Platform.OS === "android") {
|
||||
// Genymotion forwards 10.0.3.2 to host machine's localhost
|
||||
testPackage.downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/CodePushDemoApp.includeRequire.runModule.bundle?platform=android&dev=true"
|
||||
} else if (Platform.OS === "ios") {
|
||||
testPackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/CodePushDemoApp.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
module.exports = testPackage;
|
||||
@@ -0,0 +1,42 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
|
||||
let {
|
||||
AppRegistry,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
let IsFirstRunTest = React.createClass({
|
||||
getInitialState() {
|
||||
return {};
|
||||
},
|
||||
componentDidMount() {
|
||||
CodePush.getCurrentPackage()
|
||||
.then((localPackage) => {
|
||||
if (localPackage.isFirstRun) {
|
||||
this.setState({ passed: true });
|
||||
} else {
|
||||
this.setState({ passed: false });
|
||||
}
|
||||
});
|
||||
},
|
||||
render() {
|
||||
let text = "Testing...";
|
||||
if (this.state.passed !== undefined) {
|
||||
text = this.state.passed ? "Test Passed!" : "Test Failed!";
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
{text}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent("IsFirstRunTest", () => IsFirstRunTest);
|
||||
@@ -0,0 +1,73 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import createMockAcquisitionSdk from "../../utils/mockAcquisitionSdk";
|
||||
|
||||
let {
|
||||
AppRegistry,
|
||||
Platform,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
let IsFailedUpdateTest = React.createClass({
|
||||
getInitialState() {
|
||||
return {};
|
||||
},
|
||||
componentDidMount() {
|
||||
let serverPackage = {
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
label: "2.4.0",
|
||||
isMandatory: false,
|
||||
isAvailable: true,
|
||||
updateAppVersion: false,
|
||||
packageHash: "hash241",
|
||||
packageSize: 1024
|
||||
};
|
||||
|
||||
if (Platform.OS === "android") {
|
||||
serverPackage.downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/resources/IsFailedUpdateTestBundleV2.includeRequire.runModule.bundle?platform=android&dev=true"
|
||||
} else if (Platform.OS === "ios") {
|
||||
serverPackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/IsFailedUpdateTestBundleV2.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
let mockAcquisitionSdk = createMockAcquisitionSdk(serverPackage);
|
||||
let mockConfiguration = { appVersion : "1.5.0" };
|
||||
CodePush.setUpTestDependencies(mockAcquisitionSdk, mockConfiguration, NativeCodePush);
|
||||
|
||||
CodePush.notifyApplicationReady()
|
||||
.then(() => {
|
||||
return CodePush.checkForUpdate();
|
||||
})
|
||||
.then((remotePackage) => {
|
||||
if (remotePackage.failedInstall) {
|
||||
this.setState({ passed: true });
|
||||
} else {
|
||||
return remotePackage.download();
|
||||
}
|
||||
})
|
||||
.then((localPackage) => {
|
||||
return localPackage && localPackage.install(NativeCodePush.codePushInstallModeImmediate);
|
||||
});
|
||||
},
|
||||
render() {
|
||||
let text = "Testing...";
|
||||
if (this.state.passed !== undefined) {
|
||||
text = this.state.passed ? "Test Passed!" : "Test Failed!";
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
{text}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent("IsFailedUpdateTest", () => IsFailedUpdateTest);
|
||||
@@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
|
||||
let {
|
||||
AppRegistry,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
let IsFailedUpdateTest = React.createClass({
|
||||
componentDidMount() {
|
||||
CodePush.restartApp();
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
Testing...
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent("IsFailedUpdateTest", () => IsFailedUpdateTest);
|
||||
@@ -0,0 +1,37 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import { Platform, AppRegistry, Text, View } from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
let RCTTestModule = React.NativeModules.TestModule;
|
||||
|
||||
let NotifyApplicationReadyTest = React.createClass({
|
||||
getInitialState() {
|
||||
return {};
|
||||
},
|
||||
componentDidMount() {
|
||||
CodePush.notifyApplicationReady()
|
||||
.then(() => {
|
||||
if (Platform.OS === "android") {
|
||||
return NativeCodePush.downloadAndReplaceCurrentBundle("http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/resources/PassNotifyApplicationReadyTest.includeRequire.runModule.bundle?platform=android&dev=true");
|
||||
} else if (Platform.OS === "ios") {
|
||||
return NativeCodePush.downloadAndReplaceCurrentBundle("http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/PassNotifyApplicationReadyTest.includeRequire.runModule.bundle?platform=ios&dev=true");
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
CodePush.restartApp();
|
||||
});
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
Testing...
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent("NotifyApplicationReadyTest", () => NotifyApplicationReadyTest);
|
||||
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
|
||||
let {
|
||||
AppRegistry,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
let InstallModeImmediateTest = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
Test Passed!
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent("InstallModeImmediateTest", () => InstallModeImmediateTest);
|
||||
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
|
||||
let {
|
||||
AppRegistry,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
let InstallModeOnNextRestartTest = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
Test Passed!
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent("InstallModeOnNextRestartTest", () => InstallModeOnNextRestartTest);
|
||||
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
|
||||
let {
|
||||
AppRegistry,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
let InstallModeOnNextResumeTest = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
Test Passed!
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent("InstallModeOnNextResumeTest", () => InstallModeOnNextResumeTest);
|
||||
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
|
||||
let {
|
||||
AppRegistry,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
let NotifyApplicationReadyTest = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
Test Passed!
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent("NotifyApplicationReadyTest", () => NotifyApplicationReadyTest);
|
||||
@@ -0,0 +1,61 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let RCTTestModule = React.NativeModules.TestModule;
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
|
||||
let {
|
||||
AppRegistry,
|
||||
Platform,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
let RollbackTest = React.createClass({
|
||||
componentDidMount() {
|
||||
let remotePackage = {
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
label: "2.4.0",
|
||||
isMandatory: false,
|
||||
isAvailable: true,
|
||||
updateAppVersion: false,
|
||||
packageHash: "hash241",
|
||||
packageSize: 1024
|
||||
};
|
||||
|
||||
if (Platform.OS === "android") {
|
||||
remotePackage.downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/resources/RollbackTestBundleV2.includeRequire.runModule.bundle?platform=android&dev=true"
|
||||
CodePush.notifyApplicationReady()
|
||||
.then(() => {
|
||||
NativeCodePush.downloadAndReplaceCurrentBundle("http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/resources/RollbackTestBundleV1Pass.includeRequire.runModule.bundle?platform=android&dev=true");
|
||||
});
|
||||
} else if (Platform.OS === "ios") {
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/RollbackTestBundleV2.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
CodePush.notifyApplicationReady()
|
||||
.then(() => {
|
||||
NativeCodePush.downloadAndReplaceCurrentBundle("http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/RollbackTestBundleV1Pass.includeRequire.runModule.bundle?platform=ios&dev=true");
|
||||
});
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
|
||||
remotePackage.download()
|
||||
.then((localPackage) => {
|
||||
return localPackage.install(NativeCodePush.codePushInstallModeImmediate);
|
||||
});
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
Testing...
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent("RollbackTest", () => RollbackTest);
|
||||
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
|
||||
let {
|
||||
AppRegistry,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
let RollbackTest = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
Test Passed!
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent("RollbackTest", () => RollbackTest);
|
||||
@@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
|
||||
let {
|
||||
AppRegistry,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
let RollbackTest = React.createClass({
|
||||
componentDidMount() {
|
||||
CodePush.restartApp();
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
Testing...
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent("RollbackTest", () => RollbackTest);
|
||||
@@ -0,0 +1,10 @@
|
||||
export default {
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
label: "2.4.0",
|
||||
isMandatory: false,
|
||||
isAvailable: true,
|
||||
updateAppVersion: false,
|
||||
packageHash: "hash240",
|
||||
packageSize: 1024
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import { DeviceEventEmitter, Platform, AppRegistry } from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
|
||||
let remotePackage = require("../resources/remotePackage");
|
||||
|
||||
let InstallModeImmediateTest = createTestCaseComponent(
|
||||
"InstallModeImmediateTest",
|
||||
"App should restart immediately to the new version after it is installed",
|
||||
() => {
|
||||
if (Platform.OS === "android") {
|
||||
remotePackage.downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/resources/PassInstallModeImmediateTest.includeRequire.runModule.bundle?platform=android&dev=true"
|
||||
} else if (Platform.OS === "ios") {
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/PassInstallModeImmediateTest.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
remotePackage.download()
|
||||
.then((localPackage) => {
|
||||
return localPackage.install(NativeCodePush.codePushInstallModeImmediate);
|
||||
});
|
||||
},
|
||||
/*passAfterRun*/ false
|
||||
);
|
||||
|
||||
AppRegistry.registerComponent("InstallModeImmediateTest", () => InstallModeImmediateTest);
|
||||
@@ -0,0 +1,39 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import { DeviceEventEmitter, Platform, AppRegistry } from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
|
||||
let remotePackage = require("../resources/remotePackage");
|
||||
|
||||
let InstallModeOnNextRestartTest = createTestCaseComponent(
|
||||
"InstallModeOnNextRestartTest",
|
||||
"App should boot up the new version after it is installed and restarted",
|
||||
() => {
|
||||
if (Platform.OS === "android") {
|
||||
// Genymotion forwards 10.0.3.2 to host machine's localhost
|
||||
remotePackage.downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/resources/PassInstallModeOnNextRestartTest.includeRequire.runModule.bundle?platform=android&dev=true"
|
||||
} else if (Platform.OS === "ios") {
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/PassInstallModeOnNextRestartTest.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
remotePackage.download()
|
||||
.then((localPackage) => {
|
||||
return localPackage.install(NativeCodePush.codePushInstallModeOnNextRestart);
|
||||
})
|
||||
.then(() => {
|
||||
CodePush.restartApp();
|
||||
});
|
||||
},
|
||||
/*passAfterRun*/ false
|
||||
);
|
||||
|
||||
AppRegistry.registerComponent("InstallModeOnNextRestartTest", () => InstallModeOnNextRestartTest);
|
||||
@@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import { DeviceEventEmitter, Platform, AppRegistry } from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
|
||||
let remotePackage = require("../resources/remotePackage");
|
||||
|
||||
let InstallModeOnNextResumeTest = createTestCaseComponent(
|
||||
"InstallModeOnNextResumeTest",
|
||||
"App should boot up the new version after it is installed and resumed",
|
||||
() => {
|
||||
if (Platform.OS === "android") {
|
||||
remotePackage.downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/resources/PassInstallModeOnNextResumeTest.includeRequire.runModule.bundle?platform=android&dev=true"
|
||||
} else if (Platform.OS === "ios") {
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/PassInstallModeOnNextResumeTest.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
remotePackage.download()
|
||||
.then((localPackage) => {
|
||||
return localPackage.install(NativeCodePush.codePushInstallModeOnNextResume);
|
||||
})
|
||||
.then(() => {
|
||||
CodePush.restartApp();
|
||||
});
|
||||
},
|
||||
/*passAfterRun*/ false
|
||||
);
|
||||
|
||||
AppRegistry.registerComponent("InstallModeOnNextResumeTest", () => InstallModeOnNextResumeTest);
|
||||
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import { DeviceEventEmitter, Platform, AppRegistry } from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
|
||||
let remotePackage = require("../resources/remotePackage");
|
||||
|
||||
let IsFailedUpdateTest = createTestCaseComponent(
|
||||
"IsFailedUpdateTest",
|
||||
"After an installed update is rolled back, checkForUpdate should return a package with the failedInstall property set to \"true\"",
|
||||
() => {
|
||||
if (Platform.OS === "android") {
|
||||
remotePackage.downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/resources/IsFailedUpdateTestBundleV1.includeRequire.runModule.bundle?platform=android&dev=true"
|
||||
} else if (Platform.OS === "ios") {
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/IsFailedUpdateTestBundleV1.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
remotePackage.download()
|
||||
.then((localPackage) => {
|
||||
return localPackage.install(NativeCodePush.codePushInstallModeImmediate);
|
||||
});
|
||||
},
|
||||
/*passAfterRun*/ false
|
||||
);
|
||||
|
||||
AppRegistry.registerComponent("IsFailedUpdateTest", () => IsFailedUpdateTest);
|
||||
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import { DeviceEventEmitter, Platform, AppRegistry } from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
|
||||
let remotePackage = require("../resources/remotePackage");
|
||||
|
||||
let IsFirstRunTest = createTestCaseComponent(
|
||||
"IsFirstRunTest",
|
||||
"After the app is installed, the isFirstRun property on the current package should be set to \"true\"",
|
||||
() => {
|
||||
if (Platform.OS === "android") {
|
||||
remotePackage.downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/resources/CheckIsFirstRunAndPassTest.includeRequire.runModule.bundle?platform=android&dev=true"
|
||||
} else if (Platform.OS === "ios") {
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/CheckIsFirstRunAndPassTest.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
remotePackage.download()
|
||||
.then((localPackage) => {
|
||||
return localPackage.install(NativeCodePush.codePushInstallModeImmediate);
|
||||
});
|
||||
},
|
||||
/*passAfterRun*/ false
|
||||
);
|
||||
|
||||
AppRegistry.registerComponent("IsFirstRunTest", () => IsFirstRunTest);
|
||||
@@ -0,0 +1,41 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import { DeviceEventEmitter, Platform, AppRegistry } from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
|
||||
let remotePackage = require("../resources/remotePackage");
|
||||
|
||||
let IsPendingTest = createTestCaseComponent(
|
||||
"IsPendingTest",
|
||||
"After the app is installed, the isPending property on the installed package should be set to \"true\"",
|
||||
() => {
|
||||
if (Platform.OS === "android") {
|
||||
remotePackage.downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/resources/CheckIsFirstRunAndPassTest.includeRequire.runModule.bundle?platform=android&dev=true"
|
||||
} else if (Platform.OS === "ios") {
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/CheckIsFirstRunAndPassTest.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
remotePackage.download()
|
||||
.then((localPackage) => {
|
||||
return localPackage.install(NativeCodePush.codePushInstallModeOnNextRestart);
|
||||
})
|
||||
.then((localPackage) => {
|
||||
assert(localPackage.isPending, "isPending should be set to \"true\" after an install");
|
||||
return CodePush.getCurrentPackage();
|
||||
})
|
||||
.then((localPackage) => {
|
||||
assert(localPackage.isPending, "isPending should be set to \"true\" after an install");
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
AppRegistry.registerComponent("IsPendingTest", () => IsPendingTest);
|
||||
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import { DeviceEventEmitter, Platform, AppRegistry } from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
|
||||
let remotePackage = require("../resources/remotePackage");
|
||||
|
||||
let NotifyApplicationReadyTest = createTestCaseComponent(
|
||||
"NotifyApplicationReadyTest",
|
||||
"After an update, the app should remain using the installed version after multiple restarts if \"notifyApplicationReady\" is called.",
|
||||
() => {
|
||||
if (Platform.OS === "android") {
|
||||
remotePackage.downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/resources/NotifyApplicationReadyAndRestart.includeRequire.runModule.bundle?platform=android&dev=true"
|
||||
} else if (Platform.OS === "ios") {
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/NotifyApplicationReadyAndRestart.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
remotePackage.download()
|
||||
.then((localPackage) => {
|
||||
return localPackage.install(NativeCodePush.codePushInstallModeImmediate);
|
||||
});
|
||||
},
|
||||
/*passAfterRun*/ false
|
||||
);
|
||||
|
||||
AppRegistry.registerComponent("NotifyApplicationReadyTest", () => NotifyApplicationReadyTest);
|
||||
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import { DeviceEventEmitter, Platform, AppRegistry } from "react-native";
|
||||
import CodePush from "react-native-code-push";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
import createTestCaseComponent from "../../utils/createTestCaseComponent";
|
||||
let PackageMixins = require("react-native-code-push/package-mixins.js")(NativeCodePush);
|
||||
import assert from "assert";
|
||||
|
||||
let remotePackage = require("../resources/remotePackage");
|
||||
|
||||
let RollbackTest = createTestCaseComponent(
|
||||
"RollbackTest",
|
||||
"should successfully rollback if \"notifyApplicationReady\" is not called in the installed package.",
|
||||
() => {
|
||||
if (Platform.OS === "android") {
|
||||
remotePackage.downloadUrl = "http://10.0.3.2:8081/CodePushDemoAppTests/InstallUpdateTests/resources/RollbackTestBundleV1.includeRequire.runModule.bundle?platform=android&dev=true"
|
||||
} else if (Platform.OS === "ios") {
|
||||
remotePackage.downloadUrl = "http://localhost:8081/CodePushDemoAppTests/InstallUpdateTests/resources/RollbackTestBundleV1.includeRequire.runModule.bundle?platform=ios&dev=true"
|
||||
}
|
||||
|
||||
remotePackage = Object.assign(remotePackage, PackageMixins.remote);
|
||||
return Promise.resolve();
|
||||
},
|
||||
() => {
|
||||
remotePackage.download()
|
||||
.then((localPackage) => {
|
||||
return localPackage.install(NativeCodePush.codePushInstallModeImmediate);
|
||||
});
|
||||
},
|
||||
/*passAfterRun*/ false
|
||||
);
|
||||
|
||||
AppRegistry.registerComponent("RollbackTest", () => RollbackTest);
|
||||
@@ -1,61 +0,0 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <RCTTest/RCTTestRunner.h>
|
||||
|
||||
#import "RCTAssert.h"
|
||||
|
||||
#define FB_REFERENCE_IMAGE_DIR "\"$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages\""
|
||||
|
||||
@interface QueryUpdateTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation QueryUpdateTests
|
||||
{
|
||||
RCTTestRunner *_runner;
|
||||
}
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
#if __LP64__
|
||||
RCTAssert(false, @"Tests should be run on 32-bit device simulators (e.g. iPhone 5)");
|
||||
#endif
|
||||
|
||||
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(@"CodePushDemoAppTests/QueryUpdateTests/QueryUpdateTestApp", nil);
|
||||
}
|
||||
|
||||
#pragma mark Logic Tests
|
||||
- (void)testNoRemotePackage
|
||||
{
|
||||
|
||||
[_runner runTest:_cmd module:@"NoRemotePackageTest"];
|
||||
}
|
||||
|
||||
- (void)testNoRemotePackageWithSameAppVersion
|
||||
{
|
||||
[_runner runTest:_cmd
|
||||
module:@"NoRemotePackageWithSameAppVersionTest"];
|
||||
}
|
||||
|
||||
- (void)testFirstUpdate
|
||||
{
|
||||
[_runner runTest:_cmd
|
||||
module:@"FirstUpdateTest"];
|
||||
}
|
||||
|
||||
- (void)testNewUpdate
|
||||
{
|
||||
[_runner runTest:_cmd
|
||||
module:@"NewUpdateTest"];
|
||||
}
|
||||
|
||||
- (void)testSamePackage
|
||||
{
|
||||
[_runner runTest:_cmd
|
||||
module:@"SamePackageTest"];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -1,96 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var RCTTestModule = require('NativeModules').TestModule;
|
||||
var React = require('react-native');
|
||||
var CodePushSdk = require('react-native-code-push');
|
||||
var NativeCodePush = require("react-native").NativeModules.CodePush;
|
||||
var RCTTestModule = require('NativeModules').TestModule || {};
|
||||
|
||||
var {
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var FirstUpdateTest = React.createClass({
|
||||
propTypes: {
|
||||
shouldThrow: React.PropTypes.bool,
|
||||
waitOneFrame: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
done: false,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.waitOneFrame) {
|
||||
requestAnimationFrame(this.runTest);
|
||||
} else {
|
||||
this.setUp(this.runTest);
|
||||
}
|
||||
},
|
||||
|
||||
setUp(callWhenDone) {
|
||||
var mockAcquisitionSdk = {
|
||||
latestPackage: {
|
||||
downloadUrl: "http://www.windowsazure.com/blobs/awperoiuqpweru",
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
label: "2.4.0",
|
||||
isMandatory: false,
|
||||
isAvailable: true,
|
||||
updateAppVersion: false,
|
||||
packageHash: "hash240",
|
||||
packageSize: 1024
|
||||
},
|
||||
queryUpdateWithCurrentPackage: function(queryPackage, callback){
|
||||
if (!this.latestPackage || queryPackage.appVersion !== this.latestPackage.appVersion ||
|
||||
queryPackage.packageHash == this.latestPackage.packageHash) {
|
||||
callback(/*err:*/ null, false);
|
||||
} else {
|
||||
callback(/*err:*/ null, this.latestPackage);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var mockConfiguration = { appVersion : "1.5.0" };
|
||||
NativeCodePush.setUsingTestFolder(true);
|
||||
CodePushSdk.setUpTestDependencies(mockAcquisitionSdk, mockConfiguration, NativeCodePush);
|
||||
|
||||
CodePushSdk.getCurrentPackage = function () {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
callWhenDone();
|
||||
},
|
||||
|
||||
runTest() {
|
||||
CodePushSdk.checkForUpdate().then(
|
||||
(update) => {
|
||||
if (update) {
|
||||
this.setState({done: true}, RCTTestModule.markTestCompleted);
|
||||
} else {
|
||||
throw new Error('SDK should return a package when there is an update');
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
throw new Error(err.message);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: 'white', padding: 40}}>
|
||||
<Text>
|
||||
{this.constructor.displayName + ': '}
|
||||
{this.state.done ? 'Done' : 'Testing...'}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
FirstUpdateTest.displayName = 'FirstUpdateTest';
|
||||
|
||||
module.exports = FirstUpdateTest;
|
||||
@@ -1,108 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var RCTTestModule = require('NativeModules').TestModule;
|
||||
var React = require('react-native');
|
||||
var CodePushSdk = require('react-native-code-push');
|
||||
var NativeCodePush = require("react-native").NativeModules.CodePush;
|
||||
var RCTTestModule = require('NativeModules').TestModule || {};
|
||||
|
||||
var {
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var NewUpdateTest = React.createClass({
|
||||
propTypes: {
|
||||
shouldThrow: React.PropTypes.bool,
|
||||
waitOneFrame: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
done: false,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.waitOneFrame) {
|
||||
requestAnimationFrame(this.runTest);
|
||||
} else {
|
||||
this.setUp(this.runTest);
|
||||
}
|
||||
},
|
||||
|
||||
setUp(callWhenDone) {
|
||||
var mockAcquisitionSdk = {
|
||||
latestPackage: {
|
||||
downloadUrl: "http://www.windowsazure.com/blobs/awperoiuqpweru",
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
label: "2.4.0",
|
||||
isMandatory: false,
|
||||
isAvailable: true,
|
||||
updateAppVersion: false,
|
||||
packageHash: "hash240",
|
||||
packageSize: 1024
|
||||
},
|
||||
queryUpdateWithCurrentPackage: function(queryPackage, callback){
|
||||
if (!this.latestPackage || queryPackage.appVersion !== this.latestPackage.appVersion ||
|
||||
queryPackage.packageHash == this.latestPackage.packageHash) {
|
||||
callback(/*err:*/ null, false);
|
||||
} else {
|
||||
callback(/*err:*/ null, this.latestPackage);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var localPackage = {
|
||||
downloadURL: "http://www.windowsazure.com/blobs/awperoiuqpweru",
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
label: "2.4.0",
|
||||
isMandatory: false,
|
||||
isAvailable: true,
|
||||
updateAppVersion: false,
|
||||
packageHash: "hash123",
|
||||
packageSize: 1024
|
||||
};
|
||||
|
||||
var mockConfiguration = { appVersion : "1.5.0" };
|
||||
NativeCodePush.setUsingTestFolder(true);
|
||||
CodePushSdk.setUpTestDependencies(mockAcquisitionSdk, mockConfiguration, NativeCodePush);
|
||||
|
||||
CodePushSdk.getCurrentPackage = function () {
|
||||
return Promise.resolve(localPackage);
|
||||
}
|
||||
callWhenDone();
|
||||
},
|
||||
|
||||
runTest() {
|
||||
CodePushSdk.checkForUpdate().then(
|
||||
(update) => {
|
||||
if (update) {
|
||||
this.setState({done: true}, RCTTestModule.markTestCompleted);
|
||||
} else {
|
||||
throw new Error('SDK should return a package when there is a new update');
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
throw new Error(err.message);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: 'white', padding: 40}}>
|
||||
<Text>
|
||||
{this.constructor.displayName + ': '}
|
||||
{this.state.done ? 'Done' : 'Testing...'}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
NewUpdateTest.displayName = 'NewUpdateTest';
|
||||
|
||||
module.exports = NewUpdateTest;
|
||||
@@ -1,81 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var CodePushSdk = require('react-native-code-push');
|
||||
var NativeCodePush = require("react-native").NativeModules.CodePush;
|
||||
var RCTTestModule = require('NativeModules').TestModule || {};
|
||||
|
||||
var {
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var NoRemotePackageTest = React.createClass({
|
||||
propTypes: {
|
||||
shouldThrow: React.PropTypes.bool,
|
||||
waitOneFrame: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
done: false,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.waitOneFrame) {
|
||||
requestAnimationFrame(this.runTest);
|
||||
} else {
|
||||
this.setUp();
|
||||
this.runTest();
|
||||
}
|
||||
},
|
||||
|
||||
setUp() {
|
||||
var mockAcquisitionSdk = {
|
||||
latestPackage: null,
|
||||
queryUpdateWithCurrentPackage: function(queryPackage, callback){
|
||||
if (!this.latestPackage || queryPackage.appVersion !== this.latestPackage.appVersion ||
|
||||
queryPackage.packageHash == this.latestPackage.packageHash) {
|
||||
callback(/*err:*/ null, false);
|
||||
} else {
|
||||
callback(/*err:*/ null, latestPackage);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var mockConfiguration = { appVersion : "1.5.0" };
|
||||
NativeCodePush.setUsingTestFolder(true);
|
||||
CodePushSdk.setUpTestDependencies(mockAcquisitionSdk, mockConfiguration, NativeCodePush);
|
||||
},
|
||||
|
||||
runTest() {
|
||||
CodePushSdk.checkForUpdate().then(
|
||||
(update) => {
|
||||
if (update) {
|
||||
throw new Error('SDK should not return a package if remote does not contain a package');
|
||||
} else {
|
||||
this.setState({done: true}, RCTTestModule.markTestCompleted);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
throw new Error(err.message);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: 'white', padding: 40}}>
|
||||
<Text>
|
||||
{this.constructor.displayName + ': '}
|
||||
{this.state.done ? 'Done' : 'Testing...'}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
NoRemotePackageTest.displayName = 'NoRemotePackageTest';
|
||||
|
||||
module.exports = NoRemotePackageTest;
|
||||
@@ -1,108 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var RCTTestModule = React.NativeModules.TestModule;
|
||||
var CodePushSdk = require('react-native-code-push');
|
||||
var NativeCodePush = require("react-native").NativeModules.CodePush;
|
||||
var RCTTestModule = require('NativeModules').TestModule || {};
|
||||
|
||||
var {
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var NoRemotePackageWithSameAppVersionTest = React.createClass({
|
||||
propTypes: {
|
||||
shouldThrow: React.PropTypes.bool,
|
||||
waitOneFrame: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
done: false,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.waitOneFrame) {
|
||||
requestAnimationFrame(this.runTest);
|
||||
} else {
|
||||
this.setUp(this.runTest);
|
||||
}
|
||||
},
|
||||
|
||||
setUp(callWhenDone) {
|
||||
var mockAcquisitionSdk = {
|
||||
latestPackage: {
|
||||
downloadUrl: "http://www.windowsazure.com/blobs/awperoiuqpweru",
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
label: "2.4.0",
|
||||
isMandatory: false,
|
||||
isAvailable: true,
|
||||
updateAppVersion: false,
|
||||
packageHash: "hash240",
|
||||
packageSize: 1024
|
||||
},
|
||||
queryUpdateWithCurrentPackage: function(queryPackage, callback){
|
||||
if (!this.latestPackage || queryPackage.appVersion !== this.latestPackage.appVersion ||
|
||||
queryPackage.packageHash == this.latestPackage.packageHash) {
|
||||
callback(/*err:*/ null, false);
|
||||
} else {
|
||||
callback(/*err:*/ null, latestPackage);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
NativeCodePush.setUsingTestFolder(true);
|
||||
var localPackage = {
|
||||
downloadURL: "http://www.windowsazure.com/blobs/awperoiuqpweru",
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.0.0",
|
||||
label: "2.4.0",
|
||||
isMandatory: false,
|
||||
isAvailable: true,
|
||||
updateAppVersion: false,
|
||||
packageHash: "hash123",
|
||||
packageSize: 1024
|
||||
};
|
||||
|
||||
var mockConfiguration = { appVersion : "1.0.0" };
|
||||
CodePushSdk.setUpTestDependencies(mockAcquisitionSdk, mockConfiguration, NativeCodePush);
|
||||
|
||||
CodePushSdk.getCurrentPackage = function () {
|
||||
return Promise.resolve(localPackage);
|
||||
}
|
||||
callWhenDone();
|
||||
},
|
||||
|
||||
runTest() {
|
||||
CodePushSdk.checkForUpdate().then(
|
||||
(update) => {
|
||||
if (update) {
|
||||
throw new Error('SDK should not return a package if remote package is of a different version');
|
||||
} else {
|
||||
this.setState({done: true}, RCTTestModule.markTestCompleted);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
throw new Error(err.message);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: 'white', padding: 40}}>
|
||||
<Text>
|
||||
{this.constructor.displayName + ': '}
|
||||
{this.state.done ? 'Done' : 'Testing...'}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
NoRemotePackageWithSameAppVersionTest.displayName = 'NoRemotePackageWithSameAppVersionTest';
|
||||
|
||||
module.exports = NoRemotePackageWithSameAppVersionTest;
|
||||
@@ -1,108 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var RCTTestModule = require('NativeModules').TestModule;
|
||||
var React = require('react-native');
|
||||
var CodePushSdk = require('react-native-code-push');
|
||||
var NativeCodePush = require("react-native").NativeModules.CodePush;
|
||||
var RCTTestModule = require('NativeModules').TestModule || {};
|
||||
|
||||
var {
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var SamePackageTest = React.createClass({
|
||||
propTypes: {
|
||||
shouldThrow: React.PropTypes.bool,
|
||||
waitOneFrame: React.PropTypes.bool,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
done: false,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.waitOneFrame) {
|
||||
requestAnimationFrame(this.runTest);
|
||||
} else {
|
||||
this.setUp(this.runTest);
|
||||
}
|
||||
},
|
||||
|
||||
setUp(callWhenDone) {
|
||||
var mockAcquisitionSdk = {
|
||||
latestPackage: {
|
||||
downloadUrl: "http://www.windowsazure.com/blobs/awperoiuqpweru",
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
label: "2.4.0",
|
||||
isMandatory: false,
|
||||
isAvailable: true,
|
||||
updateAppVersion: false,
|
||||
packageHash: "hash240",
|
||||
packageSize: 1024
|
||||
},
|
||||
queryUpdateWithCurrentPackage: function(queryPackage, callback){
|
||||
if (!this.latestPackage || queryPackage.appVersion !== this.latestPackage.appVersion ||
|
||||
queryPackage.packageHash == this.latestPackage.packageHash) {
|
||||
callback(/*err:*/ null, false);
|
||||
} else {
|
||||
callback(/*err:*/ null, this.latestPackage);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var localPackage = {
|
||||
downloadURL: "http://www.windowsazure.com/blobs/awperoiuqpweru",
|
||||
description: "Angry flappy birds",
|
||||
appVersion: "1.5.0",
|
||||
label: "2.4.0",
|
||||
isMandatory: false,
|
||||
isAvailable: true,
|
||||
updateAppVersion: false,
|
||||
packageHash: "hash240",
|
||||
packageSize: 1024
|
||||
};
|
||||
|
||||
var mockConfiguration = { appVersion : "1.5.0" };
|
||||
NativeCodePush.setUsingTestFolder(true);
|
||||
CodePushSdk.setUpTestDependencies(mockAcquisitionSdk, mockConfiguration, NativeCodePush);
|
||||
|
||||
CodePushSdk.getCurrentPackage = function () {
|
||||
return Promise.resolve(localPackage);
|
||||
}
|
||||
callWhenDone();
|
||||
},
|
||||
|
||||
runTest() {
|
||||
CodePushSdk.checkForUpdate().then(
|
||||
(update) => {
|
||||
if (update) {
|
||||
throw new Error('SDK should not return a package when local package is identical');
|
||||
} else {
|
||||
this.setState({done: true}, RCTTestModule.markTestCompleted);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
throw new Error(err.message);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: 'white', padding: 40}}>
|
||||
<Text>
|
||||
{this.constructor.displayName + ': '}
|
||||
{this.state.done ? 'Done' : 'Testing...'}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
SamePackageTest.displayName = 'SamePackageTest';
|
||||
|
||||
module.exports = SamePackageTest;
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
Test Cases
|
||||
---
|
||||
* QueryUpdateTests - Tests the functionality of querying for new app updates via the SDK
|
||||
* testNoRemotePackage - Checks that when the remote server has no update packages available, CodePushSdk.queryUpdate does not return a new package nor throw an error.
|
||||
* testNoRemotePackageWithSameAppVersion - Checks that when the remote server has an update with a different appVersion, the CodePushSdk.queryUpdate does not return a new package nor throw an error.
|
||||
* testFirstUpdate - Checks that when there is no current package (for example, the current build is a fresh install from the app store) and the remote server has a new package, CodePushSdk.queryUpdate returns that new package without throwing an error.
|
||||
* testNewUpdate - Checks that when the remote server has a new package with a different package hash and same version as the current package, CodePushSdk.queryUpdate returns that new package without throwing an error.
|
||||
* testSamePackage - Checks that when the remote server has a package that is identical to the current package, CodePushSdk.queryUpdate does not return a new package nor throw an error.
|
||||
|
||||
* InstallUpdateTests - Tests the functionality of installing new app updates downloaded from the server via the SDK
|
||||
* testDownloadAndInstallUpdate - Queries for a new update, downloads it and then verifies that from the UI that the new update has been installed.
|
||||
|
||||
* DownloadProgressTests - Tests the functionality of downloading app updates and tracking the download progress via the SDK
|
||||
* testDownloadProgress - Downloads three files of different sizes and verifies that the reported number of bytes tally.
|
||||
@@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
|
||||
import React from "react-native";
|
||||
import { DeviceEventEmitter, Text, View } from "react-native";
|
||||
let NativeCodePush = React.NativeModules.CodePush;
|
||||
|
||||
// RCTTestModule is not implemented yet for RN Android.
|
||||
let RCTTestModule = React.NativeModules.TestModule || {};
|
||||
|
||||
function createTestCaseComponent(displayName, description, setUp, runTest, passAfterRun = true) {
|
||||
let TestCaseComponent = React.createClass({
|
||||
propTypes: {
|
||||
shouldThrow: React.PropTypes.bool,
|
||||
waitOneFrame: React.PropTypes.bool,
|
||||
},
|
||||
getInitialState() {
|
||||
return {
|
||||
done: false,
|
||||
};
|
||||
},
|
||||
componentDidMount() {
|
||||
setUp()
|
||||
.then(runTest)
|
||||
.then(() => {
|
||||
if (passAfterRun) {
|
||||
this.setState({done: true}, RCTTestModule.markTestCompleted);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<View style={{backgroundColor: "white", padding: 40}}>
|
||||
<Text>
|
||||
{this.state.done ? "Test Passed!" : "Testing..."}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
TestCaseComponent.displayName = displayName;
|
||||
TestCaseComponent.description = description;
|
||||
|
||||
return TestCaseComponent;
|
||||
}
|
||||
|
||||
export default createTestCaseComponent;
|
||||
@@ -0,0 +1,19 @@
|
||||
import assert from "assert";
|
||||
|
||||
function createMockAcquisitionSdk(serverPackage, localPackage, expectedDeploymentKey) {
|
||||
let AcquisitionManager = (httpRequester, configuration) => {
|
||||
expectedDeploymentKey && assert.equal(expectedDeploymentKey, configuration.deploymentKey, "checkForUpdate did not initialize Acquisition SDK with the expected deployment key");
|
||||
};
|
||||
|
||||
AcquisitionManager.prototype.queryUpdateWithCurrentPackage = (queryPackage, callback) => {
|
||||
if (localPackage) {
|
||||
localPackage.appVersion = queryPackage.appVersion;
|
||||
assert.deepEqual(queryPackage, localPackage, "checkForUpdate did not attach current package info to the acquisition request");
|
||||
}
|
||||
callback(/*err:*/ null, serverPackage);
|
||||
};
|
||||
|
||||
return AcquisitionManager;
|
||||
}
|
||||
|
||||
export default createMockAcquisitionSdk;
|
||||
@@ -17,9 +17,6 @@ android {
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
buildConfigField "String", "RUN_TEST", "\"\""
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
|
||||
@@ -29,29 +29,10 @@ public class MainActivity extends FragmentActivity implements DefaultHardwareBac
|
||||
|
||||
ReactInstanceManager.Builder builder = ReactInstanceManager.builder()
|
||||
.setApplication(getApplication())
|
||||
.setJSBundleFile(codePush.getBundleUrl("index.android.bundle"));
|
||||
.setJSBundleFile(codePush.getBundleUrl("index.android.bundle"))
|
||||
.setJSMainModuleName("index.android");
|
||||
|
||||
String mainComponentName = null;
|
||||
|
||||
switch (BuildConfig.RUN_TEST) {
|
||||
case "DOWNLOAD_PROGRESS":
|
||||
builder = builder.setJSMainModuleName(TEST_FOLDER_PREFIX + "DownloadProgressTests/DownloadProgressTestApp");
|
||||
mainComponentName = "DownloadProgressTestApp";
|
||||
break;
|
||||
case "INSTALL_UPDATE":
|
||||
builder = builder.setJSMainModuleName(TEST_FOLDER_PREFIX + "InstallUpdateTests/InstallUpdateTestApp");
|
||||
mainComponentName = "InstallUpdateTestApp";
|
||||
break;
|
||||
case "QUERY_UPDATE":
|
||||
builder = builder.setJSMainModuleName(TEST_FOLDER_PREFIX + "QueryUpdateTests/QueryUpdateTestApp");
|
||||
mainComponentName = "QueryUpdateTestApp";
|
||||
break;
|
||||
default:
|
||||
// Run the standard demo app.
|
||||
builder = builder.setJSMainModuleName("index.android");
|
||||
mainComponentName = "CodePushDemoApp";
|
||||
break;
|
||||
}
|
||||
String mainComponentName = "CodePushDemoApp";
|
||||
|
||||
mReactInstanceManager = builder.addPackage(new MainReactPackage())
|
||||
.addPackage(codePush.getReactPackage())
|
||||
|
||||
@@ -16,10 +16,7 @@ var Button = require("react-native-button");
|
||||
var CodePush = require('react-native-code-push');
|
||||
|
||||
var CodePushDemoApp = React.createClass({
|
||||
|
||||
componentDidMount: function() {
|
||||
},
|
||||
sync: function() {
|
||||
sync() {
|
||||
var self = this;
|
||||
CodePush.sync(
|
||||
{
|
||||
@@ -83,10 +80,10 @@ var CodePushDemoApp = React.createClass({
|
||||
CodePush.log(error);
|
||||
});
|
||||
},
|
||||
getInitialState: function() {
|
||||
getInitialState() {
|
||||
return { };
|
||||
},
|
||||
render: function() {
|
||||
render() {
|
||||
var syncView;
|
||||
var syncButton;
|
||||
var progressView;
|
||||
|
||||
@@ -21,8 +21,9 @@
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
|
||||
542D39D41C22CED700D4B648 /* libCodePush.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 81551E0F1B3B427200F5B9F1 /* libCodePush.a */; };
|
||||
544161591B8BCA81000D9E25 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
|
||||
5451ACBA1B86A5B600E2A7DF /* QueryUpdateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5451ACB81B86A5B600E2A7DF /* QueryUpdateTests.m */; };
|
||||
5451ACBA1B86A5B600E2A7DF /* CheckForUpdateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5451ACB81B86A5B600E2A7DF /* CheckForUpdateTests.m */; };
|
||||
5451ACEC1B86E40A00E2A7DF /* libRCTTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5451ACEB1B86E34300E2A7DF /* libRCTTest.a */; };
|
||||
54D774BA1B87DAF800F2ABF8 /* InstallUpdateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 54D774B91B87DAF800F2ABF8 /* InstallUpdateTests.m */; };
|
||||
54F5F2B41BF6B45D007C3CEA /* DownloadProgressTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 54F5F2B31BF6B45D007C3CEA /* DownloadProgressTests.m */; };
|
||||
@@ -149,7 +150,7 @@
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = CodePushDemoApp/Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = CodePushDemoApp/main.m; sourceTree = "<group>"; };
|
||||
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
|
||||
5451ACB81B86A5B600E2A7DF /* QueryUpdateTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QueryUpdateTests.m; sourceTree = "<group>"; };
|
||||
5451ACB81B86A5B600E2A7DF /* CheckForUpdateTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CheckForUpdateTests.m; sourceTree = "<group>"; };
|
||||
5451ACE61B86E34300E2A7DF /* RCTTest.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTTest.xcodeproj; path = "../node_modules/react-native/Libraries/RCTTest/RCTTest.xcodeproj"; sourceTree = "<group>"; };
|
||||
54D774B91B87DAF800F2ABF8 /* InstallUpdateTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InstallUpdateTests.m; sourceTree = "<group>"; };
|
||||
54F5F2B31BF6B45D007C3CEA /* DownloadProgressTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DownloadProgressTests.m; sourceTree = "<group>"; };
|
||||
@@ -163,6 +164,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
542D39D41C22CED700D4B648 /* libCodePush.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -241,7 +243,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
54F5F2B31BF6B45D007C3CEA /* DownloadProgressTests.m */,
|
||||
5451ACB81B86A5B600E2A7DF /* QueryUpdateTests.m */,
|
||||
5451ACB81B86A5B600E2A7DF /* CheckForUpdateTests.m */,
|
||||
54D774B91B87DAF800F2ABF8 /* InstallUpdateTests.m */,
|
||||
00E356F01AD99517003FC87E /* Supporting Files */,
|
||||
);
|
||||
@@ -628,7 +630,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5451ACBA1B86A5B600E2A7DF /* QueryUpdateTests.m in Sources */,
|
||||
5451ACBA1B86A5B600E2A7DF /* CheckForUpdateTests.m in Sources */,
|
||||
54F5F2B41BF6B45D007C3CEA /* DownloadProgressTests.m in Sources */,
|
||||
54D774BA1B87DAF800F2ABF8 /* InstallUpdateTests.m in Sources */,
|
||||
);
|
||||
@@ -678,6 +680,13 @@
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../node_modules/react-native/React/**",
|
||||
"$(SRCROOT)/../../..",
|
||||
"$(SRCROOT)/../node_modules/react-native/Libraries/Text/",
|
||||
);
|
||||
INFOPLIST_FILE = ../CodePushDemoAppTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
@@ -695,6 +704,13 @@
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../node_modules/react-native/React/**",
|
||||
"$(SRCROOT)/../../..",
|
||||
"$(SRCROOT)/../node_modules/react-native/Libraries/Text/",
|
||||
);
|
||||
INFOPLIST_FILE = ../CodePushDemoAppTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
|
||||
@@ -9,5 +9,8 @@
|
||||
"react-native": "0.15.0",
|
||||
"react-native-button": "^1.2.0",
|
||||
"react-native-code-push": "file:../../"
|
||||
},
|
||||
"devDependencies": {
|
||||
"assert": "^1.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@@ -38,8 +37,9 @@ import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class CodePush {
|
||||
|
||||
private static boolean testConfigurationFlag = false;
|
||||
private boolean didUpdate = false;
|
||||
private boolean usingTestFolder = false;
|
||||
|
||||
private String assetsBundleFileName;
|
||||
|
||||
@@ -290,6 +290,22 @@ public class CodePush {
|
||||
}
|
||||
}
|
||||
|
||||
/* The below 3 methods are used for running tests.*/
|
||||
public static boolean isUsingTestConfiguration() {
|
||||
return testConfigurationFlag;
|
||||
}
|
||||
|
||||
public static void setUsingTestConfiguration(boolean shouldUseTestConfiguration) {
|
||||
testConfigurationFlag = shouldUseTestConfiguration;
|
||||
}
|
||||
|
||||
public void clearTestUpdates() {
|
||||
if (isUsingTestConfiguration()) {
|
||||
codePushPackage.clearTestUpdates();
|
||||
removePendingUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private class CodePushNativeModule extends ReactContextBaseJavaModule {
|
||||
|
||||
private LifecycleEventListener lifecycleEventListener = null;
|
||||
@@ -385,27 +401,24 @@ public class CodePush {
|
||||
savePendingUpdate(pendingHash, /* isLoading */false);
|
||||
}
|
||||
|
||||
if (installMode == CodePushInstallMode.IMMEDIATE.getValue()) {
|
||||
loadBundle();
|
||||
} else if (installMode == CodePushInstallMode.ON_NEXT_RESUME.getValue()) {
|
||||
if (installMode == CodePushInstallMode.ON_NEXT_RESUME.getValue() &&
|
||||
lifecycleEventListener == null) {
|
||||
// Ensure we do not add the listener twice.
|
||||
if (lifecycleEventListener == null) {
|
||||
lifecycleEventListener = new LifecycleEventListener() {
|
||||
@Override
|
||||
public void onHostResume() {
|
||||
loadBundle();
|
||||
}
|
||||
lifecycleEventListener = new LifecycleEventListener() {
|
||||
@Override
|
||||
public void onHostResume() {
|
||||
loadBundle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostPause() {
|
||||
}
|
||||
@Override
|
||||
public void onHostPause() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostDestroy() {
|
||||
}
|
||||
};
|
||||
getReactApplicationContext().addLifecycleEventListener(lifecycleEventListener);
|
||||
}
|
||||
@Override
|
||||
public void onHostDestroy() {
|
||||
}
|
||||
};
|
||||
getReactApplicationContext().addLifecycleEventListener(lifecycleEventListener);
|
||||
}
|
||||
|
||||
promise.resolve("");
|
||||
@@ -452,8 +465,16 @@ public class CodePush {
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setUsingTestFolder(boolean shouldUseTestFolder) {
|
||||
usingTestFolder = shouldUseTestFolder;
|
||||
// Replaces the current bundle with the one downloaded from removeBundleUrl.
|
||||
// It is only to be used during tests. No-ops if the test configuration flag is not set.
|
||||
public void downloadAndReplaceCurrentBundle(String remoteBundleUrl) {
|
||||
if (isUsingTestConfiguration()) {
|
||||
try {
|
||||
codePushPackage.downloadAndReplaceCurrentBundle(remoteBundleUrl);
|
||||
} catch (IOException e) {
|
||||
throw new CodePushUnknownException("Unable to replace current bundle", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,7 +38,12 @@ public class CodePushPackage {
|
||||
}
|
||||
|
||||
public String getCodePushPath() {
|
||||
return CodePushUtils.appendPathComponent(getDocumentsDirectory(), CODE_PUSH_FOLDER_PREFIX);
|
||||
String codePushPath = CodePushUtils.appendPathComponent(getDocumentsDirectory(), CODE_PUSH_FOLDER_PREFIX);
|
||||
if (CodePush.isUsingTestConfiguration()) {
|
||||
codePushPath = CodePushUtils.appendPathComponent(codePushPath, "TestPackages");
|
||||
}
|
||||
|
||||
return codePushPath;
|
||||
}
|
||||
|
||||
public String getStatusFilePath() {
|
||||
@@ -186,4 +191,45 @@ public class CodePushPackage {
|
||||
info.putNull(PREVIOUS_PACKAGE_KEY);
|
||||
updateCurrentPackageInfo(info);
|
||||
}
|
||||
|
||||
public void downloadAndReplaceCurrentBundle(String remoteBundleUrl) throws IOException {
|
||||
URL downloadUrl;
|
||||
HttpURLConnection connection = null;
|
||||
BufferedInputStream bin = null;
|
||||
FileOutputStream fos = null;
|
||||
BufferedOutputStream bout = null;
|
||||
try {
|
||||
downloadUrl = new URL(remoteBundleUrl);
|
||||
connection = (HttpURLConnection) (downloadUrl.openConnection());
|
||||
bin = new BufferedInputStream(connection.getInputStream());
|
||||
File downloadFile = new File(getCurrentPackageBundlePath());
|
||||
downloadFile.delete();
|
||||
fos = new FileOutputStream(downloadFile);
|
||||
bout = new BufferedOutputStream(fos, DOWNLOAD_BUFFER_SIZE);
|
||||
byte[] data = new byte[DOWNLOAD_BUFFER_SIZE];
|
||||
int numBytesRead = 0;
|
||||
while ((numBytesRead = bin.read(data, 0, DOWNLOAD_BUFFER_SIZE)) >= 0) {
|
||||
bout.write(data, 0, numBytesRead);
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
throw new CodePushMalformedDataException(remoteBundleUrl, e);
|
||||
} finally {
|
||||
try {
|
||||
if (bout != null) bout.close();
|
||||
if (fos != null) fos.close();
|
||||
if (bin != null) bin.close();
|
||||
if (connection != null) connection.disconnect();
|
||||
} catch (IOException e) {
|
||||
throw new CodePushUnknownException("Error closing IO resources.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clearTestUpdates() {
|
||||
if (CodePush.isUsingTestConfiguration()) {
|
||||
File statusFile = new File(getStatusFilePath());
|
||||
statusFile.delete();
|
||||
CodePushUtils.deleteDirectoryAtPath(getCodePushPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user