Skip to content

Commit

Permalink
Swift support (#277)
Browse files Browse the repository at this point in the history
* Swift Support

* Compiling Detox.framework on the user's machine, to better support swift.

* fixed build script

* Update APIRef.DetoxCLI.md
  • Loading branch information
rotemmiz authored Sep 17, 2017
1 parent 95692c8 commit d882d0e
Show file tree
Hide file tree
Showing 21 changed files with 156 additions and 89 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 210,13 @@ ios.tar
demo-native-ios/ModuleCache
detox/ios/DetoxBuild
Detox.framework.tbz
Detox-ios-src.tbz

detox-server/lib
demo-native-ios/Build
detox/DetoxBuild
examples/demo-native-ios/Build
examples/demo-native-ios/ModuleCache

yarn.lock
yarn.lock
detox/ios_src
1 change: 1 addition & 0 deletions detox/.npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 15,7 @@ Detox.framework/


src/**/*.test.js
ios_src

#################
# from .gitignore
Expand Down
28 changes: 28 additions & 0 deletions detox/local-cli/detox-clean-framework-cache.js
Original file line number Diff line number Diff line change
@@ -0,0 1,28 @@
#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const os = require('os');

if (os.platform() === 'darwin') {
const frameworkPath = path.join(os.homedir(), '/Library/Detox');
console.log(`Removing framework binaries from ${frameworkPath}`);
deleteFolderRecursive(frameworkPath);
}

function deleteFolderRecursive(path) {
let files = [];
if (fs.existsSync(path)) {
files = fs.readdirSync(path);
files.forEach(function(file, index) {
let curPath = path "/" file;
if (fs.lstatSync(curPath).isDirectory()) {
deleteFolderRecursive(curPath);
} else {
console.log(`Removing ${curPath}`);
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
}
31 changes: 16 additions & 15 deletions detox/local-cli/detox-init.js
Original file line number Diff line number Diff line change
@@ -1,36 1,37 @@
const fs = require('fs');
const program = require('commander');
const mochaTemplates = require('./templates/mocha.js')
const mochaTemplates = require('./templates/mocha.js');

program
.option('-r, --runner [runner]', 'Test runner (currently supports mocha)', 'mocha')
.parse(process.argv);

function createFile(dir, content) {
try {
try {
fs.writeFileSync(dir, content);
console.log(`A file was created in "${dir}" `);
} catch(err){
return err;
}
} catch (err) {
return err;
}
}

const dir = './e2e';

function createFolder(firstTestContent, runnerConfig, initjsContent) {
if (!fs.existsSync(dir)){
fs.mkdirSync(dir);
createFile("./e2e/mocha.opts", runnerConfig)
createFile("./e2e/init.js", initjsContent)
createFile("./e2e/firstTest.spec.js", firstTestContent)
} else {
return console.log('e2e folder already exists')
}
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
createFile("./e2e/mocha.opts", runnerConfig);
createFile("./e2e/init.js", initjsContent);
createFile("./e2e/firstTest.spec.js", firstTestContent)
} else {
return console.log('e2e folder already exists')
}
}

switch (program.runner) {
case 'mocha':
createFolder(mochaTemplates.firstTest, mochaTemplates.runnerConfig, mochaTemplates.initjs)
createFolder(mochaTemplates.firstTest, mochaTemplates.runnerConfig, mochaTemplates.initjs);
break;
default:
createFolder(mochaTemplates.firstTest, mochaTemplates.runnerConfig, mochaTemplates.initjs)
createFolder(mochaTemplates.firstTest, mochaTemplates.runnerConfig, mochaTemplates.initjs);
}
1 change: 1 addition & 0 deletions detox/local-cli/detox.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 8,5 @@ program
.command('build', `[convince method] Run the command defined in 'configuration.build'`)
.command('run-server', 'Starts a standalone detox server')
.command('init', 'Create initial e2e tests folder')
.command('clean-framework-cache', `Delete all compiled framework binaries from ~/Library/Detox, they will be rebuilt when running 'detox test'`)
.parse(process.argv);
1 change: 0 additions & 1 deletion detox/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 26,6 @@
"unit": "jest --coverage --verbose",
"test": "npm run unit",
"unit:watch": "jest --watch --coverage --verbose",
"postinstall": "scripts/postinstall.sh",
"prepublish": "npm run build"
},
"devDependencies": {
Expand Down
22 changes: 13 additions & 9 deletions detox/scripts/build.sh
Original file line number Diff line number Diff line change
@@ -1,14 1,18 @@
#!/bin/bash
#!/bin/bash -e

echo -e "\nTranspiling JavaScript sources"
BABEL_ENV=test babel src -d lib
if [ "$1" != "noframework" ]; then
echo -e "\nBuilding Detox.framework"
rm -fr Detox.framework
xcodebuild build -project ios/Detox.xcodeproj -scheme DetoxFramework -configuration Release -derivedDataPath DetoxBuild > /dev/null
cp -fr DetoxBuild/Build/Products/Release-universal/Detox.framework .
rm -fr DetoxBuild
tar -cjf Detox.framework.tbz Detox.framework
fi

echo -e "\nPackaging Detox iOS sources"
rm -fr Detox-ios-src.tbz
#Prepare Earl Grey without building
ios/EarlGrey/Scripts/setup-earlgrey.sh > /dev/null
find ./ios -name Build -type d -exec rm -rf {} \; > /dev/null

cd ios
tar -cjf ../Detox-ios-src.tbz .
cd ..


if [ "$1" == "android" -o "$2" == "android" ] ; then
echo -e "\nBuilding Detox aars"
Expand Down
29 changes: 29 additions & 0 deletions detox/scripts/build_framework.ios.sh
Original file line number Diff line number Diff line change
@@ -0,0 1,29 @@
#!/bin/bash -e

if [ $# -ne 2 ]; then
echo "usage: build_framework_ios.sh detoxIosSourceTarballDirPath detoxFrameworkDirPath"
exit 1
fi

detoxIosSourceTarballDirPath="${1}"
detoxFrameworkDirPath="${2}"
detoxSourcePath="${detoxIosSourceTarballDirPath}"/ios_src


echo "###############################"
echo "Extracting Detox sources..."

mkdir -p "${detoxSourcePath}"
tar -xjf "${detoxIosSourceTarballDirPath}"/Detox-ios-src.tbz -C "${detoxSourcePath}"

echo "###############################"


echo "###############################"
echo "Extracting Detox sources..."

xcodebuild build -project "${detoxSourcePath}"/Detox.xcodeproj -scheme DetoxFramework -configuration Release -derivedDataPath "${detoxFrameworkDirPath}"/DetoxBuild > /dev/null
mv "${detoxFrameworkDirPath}"/DetoxBuild/Build/Products/Release-universal/Detox.framework "${detoxFrameworkDirPath}"
rm -fr "${detoxFrameworkDirPath}"/DetoxBuild

echo "###############################"
17 changes: 0 additions & 17 deletions detox/scripts/clean-build.js

This file was deleted.

10 changes: 0 additions & 10 deletions detox/scripts/postinstall.ios.sh

This file was deleted.

5 changes: 0 additions & 5 deletions detox/scripts/postinstall.sh

This file was deleted.

8 changes: 2 additions & 6 deletions detox/src/devices/Device.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 2,6 @@ const fs = require('fs');
const path = require('path');
const _ = require('lodash');
const argparse = require('../utils/argparse');
const configuration = require('../configuration');
const ArtifactsCopier = require('../artifacts/ArtifactsCopier');

class Device {
Expand All @@ -22,6 21,8 @@ class Device {
this._bundleId = await this.deviceDriver.getBundleIdFromBinary(this._binaryPath);
this._artifactsCopier.prepare(this._deviceId);

await this.deviceDriver.prepare();

await this.deviceDriver.boot(this._deviceId);

if (!argparse.getArgValue('reuse')) {
Expand Down Expand Up @@ -190,17 191,12 @@ class Device {
}

_prepareLaunchArgs(additionalLaunchArgs) {
let args = [];
const merged = _.merge(this._defaultLaunchArgs(), additionalLaunchArgs);
const launchArgs = this._addPrefixToDefaultLaunchArgs(merged);
//args = args.concat(_.flatten(Object.entries(launchArgs)));
return launchArgs;
}

_getAbsolutePath(appPath) {
if (!appPath) {
return '';
}
const absPath = path.join(process.cwd(), appPath);
if (fs.existsSync(absPath)) {
return absPath;
Expand Down
4 changes: 3 additions & 1 deletion detox/src/devices/Device.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 34,8 @@ describe('Device', () => {
jest.mock('child-process-promise');
cpp = require('child-process-promise');

jest.mock('../utils/environment');

jest.mock('./Fbsimctl');
jest.mock('./AppleSimUtils');

Expand Down Expand Up @@ -89,7 91,7 @@ describe('Device', () => {
});

it(`valid scheme, no binary, should not throw`, async () => {
device = validIosNone();
device = validDevice()
await device.prepare();
});

Expand Down
4 changes: 4 additions & 0 deletions detox/src/devices/DeviceDriverBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 8,10 @@ class DeviceDriverBase {
}

async acquireFreeDevice(name) {
await Promise.resolve('');
}

async prepare() {
return await Promise.resolve('');
}

Expand Down
27 changes: 9 additions & 18 deletions detox/src/devices/Fbsimctl.js
Original file line number Diff line number Diff line change
@@ -1,9 1,8 @@
const path = require('path');
const fs = require('fs');
const _ = require('lodash');
const log = require('npmlog');
const exec = require('../utils/exec');
const retry = require('../utils/retry');
const environment = require('../utils/environment');

// FBSimulatorControl command line docs
// https://github.com/facebook/FBSimulatorControl/issues/250
Expand Down Expand Up @@ -53,26 52,26 @@ class Fbsimctl {

async boot(udid) {
let initialState;
await retry({retries: 10, interval: 1000}, async() => {
await retry({retries: 10, interval: 1000}, async () => {
const initialStateCmdResult = await this._execFbsimctlCommand({args: `${udid} list`}, undefined, 1);
initialState = _.get(initialStateCmdResult, 'stdout', '') === '' ? undefined :
_.get(JSON.parse(_.get(initialStateCmdResult, 'stdout')), 'subject.state');
if(initialState === undefined) {
_.get(JSON.parse(_.get(initialStateCmdResult, 'stdout')), 'subject.state');
if (initialState === undefined) {
log.info(`Couldn't get the state of ${udid}`);
throw `Couldn't get the state of the device`;
}
if(initialState === 'Shutting Down') {
if (initialState === 'Shutting Down') {
log.info(`Waiting for device ${udid} to shut down`);
throw `The device is in 'Shutting Down' state`;
}
});

if(initialState === 'Booted') {
if (initialState === 'Booted') {
log.info(`Device ${udid} is already booted`);
return;
}
if(initialState === 'Booting') {

if (initialState === 'Booting') {
log.info(`Device ${udid} is already booting`);
} else {
const launchBin = "/bin/bash -c '`xcode-select -p`/Applications/Simulator.app/Contents/MacOS/Simulator "
Expand Down Expand Up @@ -120,7 119,7 @@ class Fbsimctl {

const logsInfo = new LogsInfo(udid);
const launchBin = `/bin/cat /dev/null >${logsInfo.absStdout} 2>${logsInfo.absStderr} && `
`SIMCTL_CHILD_DYLD_INSERT_LIBRARIES="${this._getFrameworkPath()}" `
`SIMCTL_CHILD_DYLD_INSERT_LIBRARIES="${await environment.getFrameworkPath()}/Detox" `
`/usr/bin/xcrun simctl launch --stdout=${logsInfo.simStdout} --stderr=${logsInfo.simStderr} `
`${udid} ${bundleId} --args ${args.join(' ')}`;
const result = await exec.execWithRetriesAndLogs(launchBin, undefined, {
Expand Down Expand Up @@ -186,14 185,6 @@ class Fbsimctl {
return await exec.execWithRetriesAndLogs(bin, options, statusLogs, retries, interval);
}

_getFrameworkPath() {
const frameworkPath = path.join(__dirname, `/../../Detox.framework/Detox`);
if (!fs.existsSync(frameworkPath)) {
throw new Error(`Detox.framework not found at ${frameworkPath}`);
}
return frameworkPath;
}

_getQueryFromDevice(device) {
let res = '';
const deviceParts = device.split(',');
Expand Down
24 changes: 21 additions & 3 deletions detox/src/devices/IosDriver.js
Original file line number Diff line number Diff line change
@@ -1,12 1,12 @@
const log = require('npmlog');
const path = require('path');
const fs = require('fs');
const os = require('os');
const _ = require('lodash');
const DeviceDriverBase = require('./DeviceDriverBase');
const InvocationManager = require('../invoke').InvocationManager;
const invoke = require('../invoke');
const GREYConfiguration = require('./../ios/earlgreyapi/GREYConfiguration');
const argparse = require('../utils/argparse');
const exec = require('child-process-promise').exec;
const environment = require('../utils/environment');

class IosDriver extends DeviceDriverBase {

Expand All @@ -25,6 25,24 @@ class IosDriver extends DeviceDriverBase {
return notificationFilePath;
}

//TODO:In order to support sharding, we need to create a device factory, and move prepare()
// to that factory, to only have a single instance of it.
async prepare() {
const detoxIosSourceTarballDirPath = path.join(__dirname, '../..');
const detoxFrameworkPath = await environment.getFrameworkPath();
const detoxFrameworkDirPath = path.parse(detoxFrameworkPath).dir;


if (fs.existsSync(detoxFrameworkDirPath)) {
if(!fs.existsSync(`${detoxFrameworkPath}`)) {
throw new Error(`is it currently building ?`);
}
} else {
log.info(`Building Detox.framework (${environment.getDetoxVersion()}) into ${detoxFrameworkDirPath}...`);
await exec(path.join(__dirname, `../../scripts/build_framework.ios.sh "${detoxIosSourceTarballDirPath}" "${detoxFrameworkDirPath}"`));
}
}

async sendUserNotification(notification) {
const notificationFilePath = this.createPushNotificationJson(notification);
await super.sendUserNotification({detoxUserNotificationDataURL: notificationFilePath});
Expand Down
Loading

0 comments on commit d882d0e

Please sign in to comment.