Repository: wix/Detox
Pull request #2151 (2020-06-25 11:17:34)

fix(js): less intrusive error stack trace filtering
- [x] This is a small change 

---

**Description:**

Before:

![image](https://user-images.githubusercontent.com/1962469/85710029-8353cb80-b6ee-11ea-8da5-654779b1c940.png)

After:

![image](https://user-images.githubusercontent.com/1962469/85710074-8ea6f700-b6ee-11ea-9f36-d624ddc21ad1.png)



Patch:
diff --git a/detox/package.json b/detox/package.json
index c68126c32..c61bf548d 100644
--- a/detox/package.json
+++ b/detox/package.json
@@ -1,7 +1,7 @@
 {
   "name": "detox",
   "description": "E2E tests and automation for mobile",
-  "version": "16.9.1",
+  "version": "16.9.2",
   "bin": {
     "detox": "local-cli/cli.js"
   },
diff --git a/detox/src/client/Client.js b/detox/src/client/Client.js
index 47e2d25ad..eba03e272 100644
--- a/detox/src/client/Client.js
+++ b/detox/src/client/Client.js
@@ -3,6 +3,7 @@ const AsyncWebSocket = require('./AsyncWebSocket');
 const actions = require('./actions/actions');
 const argparse = require('../utils/argparse');
 const log = require('../utils/logger').child({ __filename });
+const { asError, removeInternalStackEntries } = require('../utils/errorUtils');
 
 class Client {
   constructor(config) {
@@ -95,30 +96,11 @@ class Client {
       this.slowInvocationStatusHandler = this.slowInvocationStatus();
     }
 
-    // when this test run fails, we want a stack trace from up here where the
-    // $callee is still available, and not inside the catch block where it isn't
-    const potentialError = new Error();
-
-    let stackArray = potentialError.stack.split('\n');
-    let newStack = 'Error:\n';
-    let i = 1; //First line is "Error:\n"
-    for(; i < stackArray.length; i++) {
-      if(!stackArray[i].includes('detox/src')) {
-        break;
-      }
-    }
-    for(; i < stackArray.length; i++) {
-      newStack += stackArray[i] + "\n";
-    }
-    potentialError.stack = newStack;
-
     try {
       return await this.sendAction(new actions.Invoke(invocation));
     } catch (err) {
       this.successfulTestRun = false;
-
-      potentialError.message = _.isError(err) ? err.message : String(err);
-      throw potentialError;
+      throw removeInternalStackEntries(asError(err));
     } finally {
       clearTimeout(this.slowInvocationStatusHandler);
     }
diff --git a/detox/src/utils/errorUtils.js b/detox/src/utils/errorUtils.js
new file mode 100644
index 000000000..fb3bd70d2
--- /dev/null
+++ b/detox/src/utils/errorUtils.js
@@ -0,0 +1,30 @@
+const S = require('path').sep;
+const { isError } = require('lodash');
+
+const DETOX_SRC_PATH =  `${S}detox${S}src`;
+
+function removeInternalStackEntries(error) {
+  const lines = error.stack.split('\n');
+
+  const filtered = lines.filter(rawLine => {
+    const line = rawLine.trim();
+
+    if (line.startsWith('at ') && line.includes(DETOX_SRC_PATH)) {
+      return false;
+    }
+
+    return true;
+  });
+
+  error.stack = filtered.join('\n');
+  return error;
+}
+
+function asError(error) {
+  return isError(error) ? error : new Error(error);
+}
+
+module.exports = {
+  removeInternalStackEntries,
+  asError,
+};


Test patch:
diff --git a/detox/src/utils/errorUtils.test.js b/detox/src/utils/errorUtils.test.js
new file mode 100644
index 000000000..305d37aad
--- /dev/null
+++ b/detox/src/utils/errorUtils.test.js
@@ -0,0 +1,40 @@
+const { asError, removeInternalStackEntries } = require('./errorUtils');
+
+describe('removeInternalStackEntries', () => {
+  let error;
+
+  beforeEach(() => {
+    error = new Error('This is a test error\non multiple lines.');
+    error.stack = `Error: This is a test error
+on multiple lines.
+    at Object.<anonymous> (/home/noomorph/Projects/wix/Detox/detox/src/utils/errorUtils.test.js:19:12)
+    at Object.asyncJestTest (/home/noomorph/Projects/wix/Detox/detox/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:100:37)
+    at /home/noomorph/Projects/wix/Detox/detox/node_modules/jest-jasmine2/build/queueRunner.js:47:12
+    at new Promise (<anonymous>)
+    at mapper (/home/noomorph/Projects/wix/Detox/detox/node_modules/jest-jasmine2/build/queueRunner.js:30:19)
+    at /home/noomorph/Projects/wix/Detox/detox/node_modules/jest-jasmine2/build/queueRunner.js:77:41
+    at processTicksAndRejections (internal/process/task_queues.js:97:5)`;
+  });
+
+  it('should include regular stack lines and omit detox/src stack lines', () => {
+    expect(removeInternalStackEntries(error).stack).toBe(`Error: This is a test error
+on multiple lines.
+    at Object.asyncJestTest (/home/noomorph/Projects/wix/Detox/detox/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:100:37)
+    at /home/noomorph/Projects/wix/Detox/detox/node_modules/jest-jasmine2/build/queueRunner.js:47:12
+    at new Promise (<anonymous>)
+    at mapper (/home/noomorph/Projects/wix/Detox/detox/node_modules/jest-jasmine2/build/queueRunner.js:30:19)
+    at /home/noomorph/Projects/wix/Detox/detox/node_modules/jest-jasmine2/build/queueRunner.js:77:41
+    at processTicksAndRejections (internal/process/task_queues.js:97:5)`);
+  });
+});
+
+describe('asError', () => {
+  it('should pass through errors', () => {
+    const e = new Error();
+    expect(asError(e)).toBe(e);
+  });
+
+  it('should wrap non-errors with new Error()', () => {
+    expect(asError(42)).toEqual(new Error('42'));
+  });
+});