Skip to content

Commit

Permalink
test: add RN E2E test based on detox framework (#1383)
Browse files Browse the repository at this point in the history
* test: add RN integ test app

* test: add RN test cases

* chore: add RN test lock file

* test: add RN test cases

* chore: set up detox RN test lauching script

* test: add S3 test cases on RN

* chore: refactor rn test script for first-time runner

* test: add pod install command

* test: update README to RN integ test

* test: update README with guidance to install simulator and clean workspace

* chore: update lock file
  • Loading branch information
AllanZhengYP committed Aug 5, 2020
1 parent 57aedcc commit 8991f25
Show file tree
Hide file tree
Showing 68 changed files with 3,208 additions and 1 deletion.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -54,6 +54,7 @@
"eslint-config-prettier": "6.11.0",
"eslint-plugin-prettier": "3.1.4",
"eslint-plugin-simple-import-sort": "5.0.3",
"figlet": "^1.5.0",
"fs-extra": "^9.0.0",
"generate-changelog": "^1.7.1",
"husky": "^4.2.3",
Expand Down
3 changes: 2 additions & 1 deletion scripts/verdaccio-publish/index.js
Expand Up @@ -8,7 +8,7 @@
const { spawn, execSync } = require("child_process");
const pipeStdIo = { stdio: [process.stdin, process.stdout, process.stderr] };

execSync("rm -rf verdaccio/storage/@aws-sdk");
execSync("rm -rf verdaccio/storage");

// Start verdaccio in the background
const verdaccio = spawn("npx", ["verdaccio", "-c", "verdaccio/config.yaml"], pipeStdIo).on("error", (e) => {
Expand All @@ -21,6 +21,7 @@ const args = [
"lerna",
"publish",
"prerelease",
"--force-publish",
"--preid",
"ci",
"--exact",
Expand Down
6 changes: 6 additions & 0 deletions tests/react-native/End2End/.buckconfig
@@ -0,0 +1,6 @@

[android]
target = Google Inc.:Google APIs:23

[maven_repositories]
central = https://repo1.maven.org/maven2
14 changes: 14 additions & 0 deletions tests/react-native/End2End/.detoxrc.json
@@ -0,0 +1,14 @@
{
"testRunner": "jest",
"runnerConfig": "e2e/config.json",
"configurations": {
"ios": {
"type": "ios.simulator",
"binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/End2End.app",
"build": "xcodebuild -workspace ios/End2End.xcworkspace -scheme End2End -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
"device": {
"type": "iPhone X"
}
}
}
}
5 changes: 5 additions & 0 deletions tests/react-native/End2End/.env.example
@@ -0,0 +1,5 @@
# When building and testing the app, please rename this file to .env and replace the
# keys with proper resources
AWS_SMOKE_TEST_IDENTITY_POOL_ID=[identity-pool-id]
AWS_SMOKE_TEST_BUCKET=[bucket-name]
AWS_SMOKE_TEST_REGION=[region]
4 changes: 4 additions & 0 deletions tests/react-native/End2End/.eslintrc.js
@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: "@react-native-community"
};
1 change: 1 addition & 0 deletions tests/react-native/End2End/.gitattributes
@@ -0,0 +1 @@
*.pbxproj -text
65 changes: 65 additions & 0 deletions tests/react-native/End2End/.gitignore
@@ -0,0 +1,65 @@
# OSX
#
.DS_Store

# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
project.xcworkspace

# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml

# node.js
#
node_modules/
npm-debug.log
yarn-error.log

# BUCK
buck-out/
\.buckd/
*.keystore

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/

*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots

# Bundle artifact
*.jsbundle

# CocoaPods
/ios/Pods/

.env
junit.xml

# No need to track package SHA because of the testing local packages
yarn.lock
1 change: 1 addition & 0 deletions tests/react-native/End2End/.npmrc
@@ -0,0 +1 @@
@aws-sdk:registry=http://localhost:4873/
1 change: 1 addition & 0 deletions tests/react-native/End2End/.watchmanconfig
@@ -0,0 +1 @@
{}
185 changes: 185 additions & 0 deletions tests/react-native/End2End/App.tsx
@@ -0,0 +1,185 @@
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* Generated with the TypeScript template
* https://github.com/emin93/react-native-template-typescript
*
* @format
*/

import React, { Fragment, useState } from "react";
import { SafeAreaView, StyleSheet, ScrollView, StatusBar, Button, Text } from "react-native";
import { S3 } from "@aws-sdk/client-s3";
import { fromCognitoIdentityPool } from "@aws-sdk/credential-provider-cognito-identity";
import { CognitoIdentityClient } from "@aws-sdk/client-cognito-identity";
import {
//@ts-ignore imported ENVs are injected by Babel at compile time
AWS_SMOKE_TEST_IDENTITY_POOL_ID,
//@ts-ignore
AWS_SMOKE_TEST_REGION,
//@ts-ignore
AWS_SMOKE_TEST_BUCKET,
} from "react-native-dotenv";

const App = () => {
const [responseContent, setResponseContent] = useState("");
const [uploadId, setUploadId] = useState("");
const [uploadParts, setUploadParts] = useState<Array<{ ETag: string; PartNumber: number }>>([]);
const s3 = new S3({
credentials: fromCognitoIdentityPool({
identityPoolId: AWS_SMOKE_TEST_IDENTITY_POOL_ID,
client: new CognitoIdentityClient({
region: AWS_SMOKE_TEST_REGION,
}),
}),
region: AWS_SMOKE_TEST_REGION,
});
const Key = `smoke-test-rn`;

return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<ScrollView contentInsetAdjustmentBehavior="automatic" contentContainerStyle={styles.scrollViewContainer}>
<Fragment>
<Button
title="S3.PutObject"
testID="s3PutObject"
onPress={async () => {
const res = await s3.putObject({
Bucket: AWS_SMOKE_TEST_BUCKET,
Key,
Body: "this is a test payload from RN end-to-end test.",
});
setResponseContent(JSON.stringify(res));
}}
/>
<Button
title="S3.getObject"
testID="s3GetObject"
onPress={async () => {
const res = await s3.getObject({
Bucket: AWS_SMOKE_TEST_BUCKET,
Key,
});
if (!(res.Body instanceof Blob))
throw new Error(`Expected Blob payload but got ${res.Body.constructor}`);
const reader = new FileReader();
reader.addEventListener("loadend", (data) => {
setResponseContent(reader.result as string);
});
reader.readAsText(res.Body);
}}
/>
<Button
title="S3.listObjects"
testID="s3ListObjects"
onPress={async () => {
const res = await s3.listObjects({
Bucket: AWS_SMOKE_TEST_BUCKET,
});
setResponseContent(JSON.stringify(res));
}}
/>
<Button
title="S3.createMultipartUpload"
testID="s3CreateMultipartUpload"
onPress={async () => {
const res = await s3.createMultipartUpload({
Bucket: AWS_SMOKE_TEST_BUCKET,
Key: `${Key}-multipart`,
});
setUploadId(res.UploadId);
setResponseContent(JSON.stringify(res));
}}
/>
<Button
title="S3.uploadPart"
testID="s3UploadPart"
onPress={async () => {
console.log("uploadId ", uploadId);
const res = await s3.uploadPart({
Bucket: AWS_SMOKE_TEST_BUCKET,
Key: `${Key}-multipart`,
PartNumber: 1,
UploadId: uploadId,
Body: new Blob(new Array(1024).fill("x")),
});
uploadParts.push({ PartNumber: 1, ETag: res.ETag });
setUploadParts(uploadParts);
setResponseContent(JSON.stringify(res));
}}
/>
<Button
title="S3.listParts"
testID="s3ListParts"
onPress={async () => {
const res = await s3.listParts({
Bucket: AWS_SMOKE_TEST_BUCKET,
Key: `${Key}-multipart`,
UploadId: uploadId,
});
setResponseContent(JSON.stringify(res));
}}
/>
<Button
title="S3.completeMultipartUpload"
testID="s3CompleteMultipartUpload"
onPress={async () => {
const res = await s3.completeMultipartUpload({
Bucket: AWS_SMOKE_TEST_BUCKET,
Key: `${Key}-multipart`,
UploadId: uploadId,
MultipartUpload: { Parts: uploadParts },
});
setResponseContent(JSON.stringify(res));
}}
/>
<Button
title="S3.headObject"
testID="s3HeadObject"
onPress={async () => {
const res = await s3.headObject({
Bucket: AWS_SMOKE_TEST_BUCKET,
Key: `${Key}-multipart`,
});
setResponseContent(JSON.stringify(res));
}}
/>
<Button
title="S3.deleteObject"
testID="s3DeleteObject"
onPress={async () => {
const res0 = await s3.deleteObject({
Bucket: AWS_SMOKE_TEST_BUCKET,
Key,
});
const res1 = await s3.deleteObject({
Bucket: AWS_SMOKE_TEST_BUCKET,
Key: `${Key}-multipart`,
});
setResponseContent(`${JSON.stringify(res0)}\n${JSON.stringify(res1)}`);
}}
/>
<Text testID="responseContent">{responseContent}</Text>
</Fragment>
</ScrollView>
</SafeAreaView>
</>
);
};

const styles = StyleSheet.create({
safeArea: {
flexGrow: 1,
paddingTop: StatusBar.currentHeight,
},
scrollViewContainer: {
flexGrow: 1,
alignItems: "center",
justifyContent: "center",
},
});

export default App;
75 changes: 75 additions & 0 deletions tests/react-native/End2End/README.md
@@ -0,0 +1,75 @@
# End2End

> end-to-end test run on React-Native testing a subset of AWS SDK clients
## Prerequisite

- See [Detox requirement](https://github.com/wix/Detox#environment)
- Launch XCode.app, if it asks you to install the update or extra components, please follow the instructions to install
them.
- Confirm iPhone X simulator is installed locally, by running:
```console
applesimutils --list | grep "name" | grep iPhone
```
If `applesimutils` command is not found, you can install it [following the guidance](https://github.com/wix/AppleSimulatorUtils#installing).
If iPhone X simulator is not available in the runtime, you can install it following the next step.
- Launch XCode.app, click `Open another project`, choose the directory `tests/react-native/End2End/ios`. Open XCode ->
Open Developer Tool -> simulator. In the simulator.app, open Hardware -> Device -> Manage Devices... -> Simulators ->
click "+" at the button of left side bar. In the pop-up, "Device Type" drop-down, choose "iPhone X", click "Create".
Make sure iPhone X is available in the last step.

## Steps to Setup

1. Build the project:

- change directory to project root: `cd ../../..`
- `yarn`
- `yarn build:all`
- If the command above takes too long on local machine, you can build the only packages that used by the RN test. As
of now\*, the RN test only touches `client-cognito-identity`, `client-s3`, `client-cloudformation`,
`credential-provider-cognito-identity`. You can build them by:

```console
yarn build:crypto-dependencies && lerna run pretest --scope '{@aws-sdk/client-cognito-identity,@aws-sdk/client-s3,@aws-sdk/client-cloudformation,@aws-sdk/credential-provider-cognito-identity}' --include-dependencies
```

- `git fetch [remove] --tags`

1. Launch the ReactNative test:

- change directory to RN test root: `cd tests/react-native/End2End`
- make sure you have configured the SDK with the the credentials from the testing account that contains
`SdkReleaseV3IntegTestResourcesStack`
- `node launch-app.js --local-publish`

## Steps to Re-run the Tests

If the scripts above fail and you need to re-run the test script, you need to make sure the workspace is cleaned and
ready to run the test script again. Follow the steps bellow to clean the workspace.

1. Kill the local NPM registry process. You can get the process PID by running:

```console
lsof -i -P -n | grep "TCP 127.0.0.1:4873"
```

The number after `node` is the PID.

Kill the process by running:

```console
kill -9 [PID]
```

1. Reset the temporary changes to the workspace in git from project root:

```console
git reset --hard clients/*/package.json packages/*/package.json protocol_tests/*/package.json
```

1. Follow the `Launch the ReactNative test:` step of [Steps to Setup](#steps-to-setup). If you don't plan to install
the packages to `End2End` test APP again, you can omit the `--local-publish` option the test script:

```console
node launch-app.js
```

0 comments on commit 8991f25

Please sign in to comment.