From 1f8fb50c1c9821d0de7669fe772d380423d64ce8 Mon Sep 17 00:00:00 2001 From: hadasz <42683604+hadasz@users.noreply.github.com> Date: Fri, 26 Oct 2018 15:03:49 -0400 Subject: [PATCH] Detox (#26) * this is a mock for doc purposes * implemented aes function * iOS unit tests * detox setup * test app for detox * m * reset index.js in cleanup of detox tests * including e2e test notes in readme * make iv proper length, delete unused files * this is a mock for doc purposes * implemented aes function * iOS unit tests * detox setup * test app for detox * reset index.js in cleanup of detox tests * including e2e test notes in readme * make iv proper length, delete unused files * this is a mock for doc purposes * implemented aes function * iOS unit tests * detox setup * make iv proper length, delete unused files * package.json * detox detox detox * detox * made test directory for unit tests * testing detox with travis * travis <3 detox * travis attempt 3 * travis * travis * travis <3 brew * travis still <3 brew * travis <3 xcode tools * downgraded iphone to match xcode 9, which is used to match travis xcode cli tools * updated index files * package json alteration to get detox to work in travis * ensure there is a polyfill * fixed package.json * travis <3 react-native * typo * install react-native-cli * travis <3 detox-cli * took detox out of travis * changed some filenames for more clarity * updated readme * code review changes * reverted travis * made readme more readable * post install react-native link" * corrected file name * Remove Polyfill from index * Update index.ios.js * Update meat-grinder.js * Update init.js * Delete index.js --- .eslintrc.js | 3 ++- .gitignore | 2 ++ .travis.yml | 4 +-- README.md | 10 ++++++++ e2e/E2ETests.js | 35 +++++++++++++++++++++++++++ e2e/config.json | 4 +++ e2e/firstTest.spec.js | 20 +++++++++++++++ e2e/init.js | 22 +++++++++++++++++ index.e2e.js | 4 +++ index.ios.js | 4 +++ index.js | 9 ------- jest.config.js | 2 +- package.json | 19 ++++++++++++++- src/utils/meat-grinder.js | 51 +++++++++++++++++++++++++++++++++++++++ 14 files changed, 175 insertions(+), 14 deletions(-) create mode 100644 e2e/E2ETests.js create mode 100644 e2e/config.json create mode 100644 e2e/firstTest.spec.js create mode 100644 e2e/init.js create mode 100644 index.e2e.js create mode 100644 index.ios.js delete mode 100644 index.js create mode 100644 src/utils/meat-grinder.js diff --git a/.eslintrc.js b/.eslintrc.js index 2a1c3a4..a9f07cb 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,6 +5,7 @@ module.exports = { node: true, browser: true, jest: true, + jasmine: true, mocha: true }, globals: { @@ -18,7 +19,7 @@ module.exports = { 'plugin:react/recommended', 'plugin:prettier/recommended' ], - plugins: ['react', 'react-native'], + plugins: ['react', 'react-native', 'jasmine', 'detox'], settings: { react: { pragma: 'React', diff --git a/.gitignore b/.gitignore index e4a416e..b851f5a 100644 --- a/.gitignore +++ b/.gitignore @@ -60,5 +60,7 @@ buck-out/ # Bundle artifact *.jsbundle +#index file that gets replaced by e2e test scripts +./index.js # env .env.* diff --git a/.travis.yml b/.travis.yml index d832e33..bb061ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: -- "8" + - '8' branches: only: - - master + - master diff --git a/README.md b/README.md index 74ce49c..37a6b36 100644 --- a/README.md +++ b/README.md @@ -12,3 +12,13 @@ UPORT_APP_NAME=Sojourn UPORT_APP_ADDRESS=2onKAS55Vs9hGwDPsBT6DYHwAP1HJ3FsBXh UPORT_PRIVATE_KEY= ``` + +# Testing + +### End to End Tests + +Run `yarn e2e` to run end to end tests. Because schemes other than debug and release are not trivial in react-native, +and because javascript environment variables are not trivial to pass in react-native, +there are two index files, index.ios.js which is the entry point for the regular app as it should be used in production, +and index.e2e.js, an entry point which is used for e2e tests. This is a temporary measure, as a way to test native modules +on the javascript side that are not yet integrated into the app (mainly for cryptography functions); diff --git a/e2e/E2ETests.js b/e2e/E2ETests.js new file mode 100644 index 0000000..6efbcae --- /dev/null +++ b/e2e/E2ETests.js @@ -0,0 +1,35 @@ +import React, { Component } from 'react'; +import { encryptWithAes } from '../src/utils/meat-grinder.js'; +import { View, Text } from 'react-native'; +var inputSizes = [16, 20, 48]; +const testPrivateKey = + '8238BAE35C77FE4AEBB2DEB1B83A6F0027A01D0E4D93BF5B81F7117796955A17'; +export default class E2ETests extends Component { + constructor(props) { + super(props); + this.state = { input16: 0, input20: 0, input48: 0 }; + inputSizes.map(inputSize => { + this.encryptForSize(inputSize); + }); + } + async encryptForSize(sizeInBytes) { + let aesOutput = await encryptWithAes( + testPrivateKey, + new Array(sizeInBytes).join('x') + ); + if (!aesOutput) { + throw Error('output is not good'); + } + this.setState({ ['input'.concat(sizeInBytes)]: aesOutput.ciphertext }); + return 'success'; + } + render() { + return ( + + {this.state.input16.length} + {this.state.input20.length} + {this.state.input48.length} + + ); + } +} diff --git a/e2e/config.json b/e2e/config.json new file mode 100644 index 0000000..cb0de04 --- /dev/null +++ b/e2e/config.json @@ -0,0 +1,4 @@ +{ + "setupTestFrameworkScriptFile": "./init.js", + "testEnvironment": "node" +} diff --git a/e2e/firstTest.spec.js b/e2e/firstTest.spec.js new file mode 100644 index 0000000..144eee4 --- /dev/null +++ b/e2e/firstTest.spec.js @@ -0,0 +1,20 @@ +/* eslint-env detox/detox, jest*/ +describe('Example', () => { + beforeEach(async () => { + await device.reloadReactNative(); + }); + + it('should have welcome screen', async () => { + await expect(element(by.id('16ByteInput'))).toHaveText('24'); + }); + /* it('should show hello screen after tap', async () => { + await element(by.id('hello_button')).tap(); + await expect(element(by.text('Hello!!!'))).toBeVisible(); + }); + + it('should show world screen after tap', async () => { + await element(by.id('world_button')).tap(); + await expect(element(by.text('World!!!'))).toBeVisible(); + }); +*/ +}); diff --git a/e2e/init.js b/e2e/init.js new file mode 100644 index 0000000..f9215cb --- /dev/null +++ b/e2e/init.js @@ -0,0 +1,22 @@ +const detox = require('detox'); +const config = require('../package.json').detox; +const adapter = require('detox/runners/jest/adapter'); +const { exec } = require('child_process'); + +jest.setTimeout(120000); +jasmine.getEnv().addReporter(adapter); + +beforeAll(async () => { + exec('cp index.e2e.js index.js'); + await detox.init(config); +}); + +beforeEach(async () => { + await adapter.beforeEach(); +}); + +afterAll(async () => { + await adapter.afterAll(); + exec('rm index.js'); + await detox.cleanup(); +}); diff --git a/index.e2e.js b/index.e2e.js new file mode 100644 index 0000000..6a25305 --- /dev/null +++ b/index.e2e.js @@ -0,0 +1,4 @@ +import { AppRegistry } from 'react-native'; +import { name as appName } from './app.json'; +import E2ETests from './e2e/E2ETests'; +AppRegistry.registerComponent(appName, () => E2ETests); diff --git a/index.ios.js b/index.ios.js new file mode 100644 index 0000000..434afd2 --- /dev/null +++ b/index.ios.js @@ -0,0 +1,4 @@ +import { AppRegistry } from 'react-native'; +import App from './src/App'; +import { name as appName } from './app.json'; +AppRegistry.registerComponent(appName, () => App); diff --git a/index.js b/index.js deleted file mode 100644 index c56d632..0000000 --- a/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import { AppRegistry, YellowBox } from 'react-native'; -import App from './src/App'; -import { name as appName } from './app.json'; - -YellowBox.ignoreWarnings([ - 'Remote debugger is in a background tab which may cause apps to perform' -]); - -AppRegistry.registerComponent(appName, () => App); diff --git a/jest.config.js b/jest.config.js index deb7961..d1f0185 100644 --- a/jest.config.js +++ b/jest.config.js @@ -8,5 +8,5 @@ module.exports = { }, transformIgnorePatterns: ['node_modules/(?!react-|drizzle).+\\.js$'], setupFiles: ['./src/setupJest.js'], - testPathIgnorePatterns: ['/node_modules/', '/test/'] + testPathIgnorePatterns: ['/node_modules', '/e2e/', '/test/'] }; diff --git a/package.json b/package.json index 61b18b8..92cef7c 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,13 @@ "ios": "react-native run-ios", "lint": "eslint .", "jest": "yarn build:truffle && jest", + "prettier": "prettier \"**/*.{js,json,css,md}\" --write", "test": "yarn lint && yarn jest --coverage && yarn solidity-coverage", - "prettier": "prettier \"**/*.{js,json,css,md}\" --write" + "post-install": "react-native link", + "e2e": "detox build && detox test" }, "dependencies": { + "react-native-aes-crypto": "^1.2.3", "react": "16.5.0", "react-native": "0.57.2", "react-native-dotenv": "^0.2.0", @@ -35,8 +38,11 @@ "babel-jest": "^23.6.0", "chai": "^4.2.0", "concurrently": "^4.0.1", + "detox": "^9.0.4", "eslint": "^5.6.1", "eslint-config-prettier": "^3.1.0", + "eslint-plugin-detox": "^1.0.0", + "eslint-plugin-jasmine": "^2.10.1", "eslint-plugin-prettier": "^3.0.0", "eslint-plugin-react": "^7.11.1", "eslint-plugin-react-native": "^3.3.0", @@ -58,5 +64,16 @@ "hooks": { "pre-commit": "pretty-quick --staged" } + }, + "detox": { + "configurations": { + "ios.sim.debug": { + "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/sojourn.app", + "build": "xcodebuild -project ios/sojourn.xcodeproj -configuration Debug -scheme sojourn -sdk iphonesimulator -derivedDataPath ios/build -UseModernBuildSystem=NO", + "type": "ios.simulator", + "name": "iPhone 7" + } + }, + "test-runner": "jest" } } diff --git a/src/utils/meat-grinder.js b/src/utils/meat-grinder.js new file mode 100644 index 0000000..10cc3a4 --- /dev/null +++ b/src/utils/meat-grinder.js @@ -0,0 +1,51 @@ +import Aes from 'react-native-aes-crypto'; +//arguments: file - plaintext file +//return value:encrypted file +export async function encryptWithAes(privateKey, plainTextFile) { + const iv = 'sixteen bytes iv'; //To DO: randomly generate + try { + const ciphertext = await Aes.encrypt(plainTextFile, privateKey, iv); + return { ciphertext, iv }; + } catch (error) { + throw error; + } +} + +//arguments: encrypted file +//return value: array of (x,y) coordinates +/* + + + +import Aes from '@trackforce/react-native-aes-crypto'; + +//arguments: file - plaintext file +//return value:encrypted file +export async function encryptWithAes(privateKey, plainTextFile) { + const iv = 'sixteen bytes iv'; //To DO: randomly generate + try { + const ciphertext = await Aes.encrypt(plainTextFile, privateKey, iv); + return { ciphertext, iv }; + } catch (error) { + throw error; + } +} + +//arguments: encrypted file +//return value: array of (x,y) coordinates +function encryptWithShamirs(encryptedFile) {} +//arguments:array points needed to reconstruct encryptedFile +//return value: array of new (x,y) coordinates +function hashPointsWithPrivateKey(arrayOfPoints) {} +//argument: array of (x,y) coordinates +//return value: Promise that resolves to an array of IPFS Hashe's +async function submitPointsToIPFS(points) {} + +async function saveToVault(plainTextFile) { + let points = hashPointsWithPrivateKey( + encryptWithShamirs(encryptWithAes(plainTextFile)) + ); + let ipfsHashes = await submitPointsToIPFS(points); + return ipfsHashes; +} +*/