Repository: wix/Detox (js)

Issue:
detox init removes final newline in package.json
Running `detox init -r mocha` outputs

```
[...]
detox[47771] INFO:  [init.js] detox-init Patched ./package.json with commands:
detox[47771] INFO:  [init.js] detox-init _.set(packageJson, ['detox', 'test-runner'], "mocha")
detox[47771] INFO:  [init.js] detox-init _.set(packageJson, ['detox', 'specs'], "")
```

As a side effect, it also **removes the newline character** from the last line in `package.json`.

This results warnings like `No newline at end of file`, and malfunctioning of certain tools due to the fact that the file is strictly speaking no longer a valid text file according to [POSIX standards](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html) (3.206 / 3.403).

Also see: https://stackoverflow.com/questions/729692/why-should-text-files-end-with-a-newline

Pull request description:
fix: append newline to package.json on detox init
Resolves #1272 

- [x] This is a small change 

Patch:
diff --git a/detox/local-cli/init.js b/detox/local-cli/init.js
index 625bd7e50..39ef91553 100644
--- a/detox/local-cli/init.js
+++ b/detox/local-cli/init.js
@@ -100,7 +100,7 @@ function patchPackageJson(packageJson, runnerName) {
 
 function savePackageJson(filepath, json) {
   try {
-    fs.writeFileSync(filepath, JSON.stringify(json, null, 2));
+    fs.writeFileSync(filepath, JSON.stringify(json, null, 2) + '\n');
   } catch (err) {
     log.error(PREFIX, `Failed to write changes into ./package.json due to the error:\n${err.message}`);
   }
diff --git a/detox/package.json b/detox/package.json
index dd1d2f6f6..63a497373 100644
--- a/detox/package.json
+++ b/detox/package.json
@@ -1,7 +1,7 @@
 {
   "name": "detox",
   "description": "E2E tests and automation for mobile",
-  "version": "12.2.1",
+  "version": "12.3.0",
   "bin": {
     "detox": "local-cli/cli.js"
   },
diff --git a/detox/src/devices/android/AAPT.js b/detox/src/devices/android/AAPT.js
index 86ad4730b..de1817623 100644
--- a/detox/src/devices/android/AAPT.js
+++ b/detox/src/devices/android/AAPT.js
@@ -2,6 +2,7 @@ const _ = require('lodash');
 const Environment = require('../../utils/environment');
 const path = require('path');
 const exec = require('../../utils/exec').execWithRetriesAndLogs;
+const escape = require('../../utils/pipeCommands').escape.inQuotedString;
 const egrep = require('../../utils/pipeCommands').search.fragment;
 const fsext = require('../../utils/fsext');
 
@@ -23,7 +24,7 @@ class AAPT {
   async getPackageName(apkPath) {
     await this._prepare();
     const process = await exec(
-      `${this.aaptBin} dump badging "${apkPath}" | ${egrep("package: name=")}`,
+      `${this.aaptBin} dump badging "${escape(apkPath)}" | ${egrep("package: name=")}`,
       undefined, undefined, 1
     );
 
diff --git a/detox/src/devices/android/ADB.js b/detox/src/devices/android/ADB.js
index 1ee245400..0e9393cf6 100644
--- a/detox/src/devices/android/ADB.js
+++ b/detox/src/devices/android/ADB.js
@@ -102,6 +102,8 @@ class ADB {
   }
 
   async install(deviceId, apkPath) {
+    apkPath = `"${escape.inQuotedString(apkPath)}"`;
+    
     const apiLvl = await this.apiLevel(deviceId);
 
     let childProcess;
diff --git a/examples/demo-native-android/package.json b/examples/demo-native-android/package.json
index cdda96c89..aa5eed2a7 100644
--- a/examples/demo-native-android/package.json
+++ b/examples/demo-native-android/package.json
@@ -1,6 +1,6 @@
 {
   "name": "detox-demo-native-android",
-  "version": "12.2.1",
+  "version": "12.3.0",
   "private": true,
   "scripts": {
     "packager": "react-native start",
@@ -8,7 +8,7 @@
     "e2e": "mocha e2e --opts ./e2e/mocha.opts"
   },
   "devDependencies": {
-    "detox": "^12.2.1",
+    "detox": "^12.3.0",
     "mocha": "^4.0.0"
   },
   "detox": {}
diff --git a/examples/demo-native-ios/package.json b/examples/demo-native-ios/package.json
index cc01fa85b..6a295323e 100644
--- a/examples/demo-native-ios/package.json
+++ b/examples/demo-native-ios/package.json
@@ -1,9 +1,9 @@
 {
 	"name": "detox-demo-native-ios",
-	"version": "12.2.1",
+	"version": "12.3.0",
 	"private": true,
 	"devDependencies": {
-		"detox": "^12.2.1",
+		"detox": "^12.3.0",
 		"mocha": "^4.0.0"
 	},
 	"detox": {
diff --git a/examples/demo-react-native-jest/package.json b/examples/demo-react-native-jest/package.json
index 2bdb82c6b..ab157de81 100644
--- a/examples/demo-react-native-jest/package.json
+++ b/examples/demo-react-native-jest/package.json
@@ -1,6 +1,6 @@
 {
   "name": "demo-react-native-jest",
-  "version": "12.2.1",
+  "version": "12.3.0",
   "private": true,
   "scripts": {
     "start": "node node_modules/react-native/local-cli/cli.js start",
@@ -14,7 +14,7 @@
   "devDependencies": {
     "babel-jest": "21.2.0",
     "babel-preset-react-native": "4.0.0",
-    "detox": "^12.2.1",
+    "detox": "^12.3.0",
     "jest": "21.2.1",
     "react-test-renderer": "16.0.0-beta.5"
   },
diff --git a/examples/demo-react-native/package.json b/examples/demo-react-native/package.json
index 642fc84c1..a8c409c11 100644
--- a/examples/demo-react-native/package.json
+++ b/examples/demo-react-native/package.json
@@ -1,6 +1,6 @@
 {
   "name": "example",
-  "version": "12.2.1",
+  "version": "12.3.0",
   "private": true,
   "scripts": {
     "start": "react-native start"
@@ -10,7 +10,7 @@
     "react-native": "0.56.0"
   },
   "devDependencies": {
-    "detox": "^12.2.1",
+    "detox": "^12.3.0",
     "mocha": "^4.0.1"
   },
   "detox": {
diff --git a/lerna.json b/lerna.json
index ffc3ad464..56c599c11 100644
--- a/lerna.json
+++ b/lerna.json
@@ -10,7 +10,7 @@
     "examples/demo-react-native-jest",
     "generation"
   ],
-  "version": "12.2.1",
+  "version": "12.3.0",
   "npmClient": "npm",
   "command": {
     "publish": {


Test patch:
diff --git a/detox/src/devices/android/ADB.test.js b/detox/src/devices/android/ADB.test.js
index abd7f230d..964244c6f 100644
--- a/detox/src/devices/android/ADB.test.js
+++ b/detox/src/devices/android/ADB.test.js
@@ -31,8 +31,16 @@ describe('ADB', () => {
   });
 
   it(`install`, async () => {
-    await adb.install('path/to/app');
-    expect(exec).toHaveBeenCalledTimes(2);
+    await adb.install('emulator-5556', 'path inside "quotes" to/app');
+
+    expect(exec).toHaveBeenCalledWith(
+      expect.stringContaining('adb -s emulator-5556 shell "getprop ro.build.version.sdk"'),
+      undefined, undefined, 1
+    );
+
+    expect(exec).toHaveBeenCalledWith(
+      expect.stringContaining('adb -s emulator-5556 install -rg "path inside \\"quotes\\" to/app"'),
+      undefined, undefined, 1);
   });
 
   it(`uninstall`, async () => {
diff --git a/detox/test/package.json b/detox/test/package.json
index 7bd3087f2..52c071cb9 100644
--- a/detox/test/package.json
+++ b/detox/test/package.json
@@ -1,6 +1,6 @@
 {
   "name": "detox-test",
-  "version": "12.2.1",
+  "version": "12.3.0",
   "private": true,
   "scripts": {
     "test": ":",
@@ -19,7 +19,7 @@
     "react-native": "0.56.0"
   },
   "devDependencies": {
-    "detox": "^12.2.1",
+    "detox": "^12.3.0",
     "express": "^4.15.3",
     "jest": "^22.3.0",
     "lodash": "^4.14.1",