6

The Question:

Is it possible to clean up the stack trace and leave only relevant frames eliminating everything Protractor, WebDriverJS and Jasmine specific?

The Story:

Let's execute this example test:

describe("SO test", function () {
    beforeEach(function () {
        browser.get("https://angularjs.org");
    });

    it("should throw a meaningful error", function () {
        element(by.id("not_found")).click();
    });
});

It would fail with a following stacktrace:

SO test should throw a meaningful error
  - Failed: No element found using locator: By.id("not_found")
      at new bot.Error (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/atoms/error.js:108:18)
      at /usr/local/lib/node_modules/protractor/lib/element.js:676:15
      at [object Object].promise.Promise.goog.defineClass.invokeCallback_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/goog/../webdriver/promise.js:1337:14)
      at [object Object].promise.ControlFlow.goog.defineClass.goog.defineClass.abort_.error.executeNext_.execute_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/goog/../webdriver/promise.js:2776:14)
      at [object Object].promise.ControlFlow.goog.defineClass.goog.defineClass.abort_.error.executeNext_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/goog/../webdriver/promise.js:2758:21)
      at goog.async.run.processWorkQueue (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/goog/async/run.js:124:15)
      at process._tickCallback (node.js:377:9)
  Error
      at [object Object].ElementArrayFinder.applyAction_ (/usr/local/lib/node_modules/protractor/lib/element.js:382:21)
      at [object Object].ElementArrayFinder.(anonymous function) [as click] (/usr/local/lib/node_modules/protractor/lib/element.js:78:17)
      at [object Object].ElementFinder.(anonymous function) [as click] (/usr/local/lib/node_modules/protractor/lib/element.js:711:7)
      at Object.<anonymous> (/Users/user/job/project/test/e2e/specs/test.spec.js:9:37)
      at /usr/local/lib/node_modules/protractor/node_modules/jasminewd2/index.js:96:23
      at [object Object].promise.Promise.goog.defineClass.constructor (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/goog/../webdriver/promise.js:1056:7)
      at new wrappedCtr (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/goog/base.js:2468:26)
      at controlFlowExecute (/usr/local/lib/node_modules/protractor/node_modules/jasminewd2/index.js:82:18)
      at [object Object].promise.ControlFlow.goog.defineClass.goog.defineClass.abort_.error.executeNext_.execute_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/goog/../webdriver/promise.js:2776:14)
      at [object Object].promise.ControlFlow.goog.defineClass.goog.defineClass.abort_.error.executeNext_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/goog/../webdriver/promise.js:2758:21)
  From: Task: Run it("should throw a meaningful error") in control flow
      at Object.<anonymous> (/usr/local/lib/node_modules/protractor/node_modules/jasminewd2/index.js:81:14)
      at /usr/local/lib/node_modules/protractor/node_modules/jasminewd2/index.js:18:5
      at [object Object].promise.Promise.goog.defineClass.invokeCallback_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/goog/../webdriver/promise.js:1337:14)
      at [object Object].promise.ControlFlow.goog.defineClass.goog.defineClass.abort_.error.executeNext_.execute_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/goog/../webdriver/promise.js:2776:14)
      at [object Object].promise.ControlFlow.goog.defineClass.goog.defineClass.abort_.error.executeNext_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/goog/../webdriver/promise.js:2758:21)
      at goog.async.run.processWorkQueue (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/goog/async/run.js:124:15)
  From asynchronous test: 
  Error
      at Suite.<anonymous> (/Users/user/job/project/test/e2e/specs/test.spec.js:8:5)
      at Object.<anonymous> (/Users/user/job/project/test/e2e/specs/test.spec.js:3:1)
      at Module._compile (module.js:425:26)
      at Object.Module._extensions..js (module.js:432:10)
      at Module.load (module.js:356:32)

As you can see, it's not easy to find on which line in the test the error actually happened. It's hidden somewhere inside the stack trace covered by Protractor, WebDriverJS and Jasmine stack frames. This makes it difficult to debug and develop end-to-end tests.

Desired output:

SO test should throw a meaningful error
  - Failed: No element found using locator: By.id("not_found")
      at Object.<anonymous> (/Users/user/job/project/test/e2e/specs/test.spec.js:9:37)
  From asynchronous test: 
  Error
      at Suite.<anonymous> (/Users/user/job/project/test/e2e/specs/test.spec.js:8:5)
      at Object.<anonymous> (/Users/user/job/project/test/e2e/specs/test.spec.js:3:1)
      at Module._compile (module.js:425:26)
      at Object.Module._extensions..js (module.js:432:10)
      at Module.load (module.js:356:32)
      at Function.Module._load (module.js:311:12)

Using protractor 3.0.0 and jasmine2.


In mocha world, there is a relevant mocha-clean package that filters out everything coming from inside node_modules and mocha itself leaving a clean stack trace that is easy to read.

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • 1
    Do you use any custom reporters? I have a much cleaner result for the same test. – Michael Radionov Dec 02 '15 at 21:46
  • @MichaelRadionov just tried separately with a default config with no reporters - yeah, the result is different and more clean (though it still contain `selenium` and `jasmine` specific frames). You were right, looks like [`jasmine-spec-reporter`](https://github.com/bcaudan/jasmine-spec-reporter/blob/master/docs/protractor-configuration.md) made the stacktrace worse. Please post an answer and I'll accept that. Thanks! – alecxe Dec 03 '15 at 19:33
  • @MichaelRadionov btw, taking aside `jasmine-spec-reporter` related issue, do you think we can clean up the stack trace even more eliminating everything node_modules and jasmine-core specific? So it would look close to what is under the Desired Output? Thanks. – alecxe Dec 03 '15 at 19:34
  • I see in docs for [`jasmine-spec-reporter`](https://github.com/bcaudan/jasmine-spec-reporter), that it has an option `displayStacktrace: 'none'`. Maybe it will hide everything? – Michael Radionov Dec 03 '15 at 20:23
  • @MichaelRadionov interesting, we've been using `all` and that's really too much of unnecessary information as we've seen in the stacktrace provided in the answer. I've tried `none` - this just outputs an error itself and nothing more. `summary` behaves the same as `all` in this case. In other words, `summary` and `all` throw the stack traces starting with `node_modules/selenium-webdriver/lib/atoms/error.js` and not the line in the actual test itself. Thanks! – alecxe Dec 03 '15 at 21:44
  • @MichaelRadionov also, `displayStacktrace: 'specs'` behaves similar to `summary` and `all`. – alecxe Dec 03 '15 at 21:47

4 Answers4

5

As it turns out, if you use any custom reporters, they may introduce new behavior in controlling output of a stack trace. Protractor itself hides pretty much everything, so you won't see any log entries from node_modules or Jasmine.

As you use jasmine-spec-reporter, which provides an option to control a stack trace, it might be the case, that you have set some verbose mode in the options. In the docs for Protractor for some reason it is suggested to use all mode, which basically displays the enitre stack trace.

    onPrepare: function () {
    jasmine.getEnv().addReporter(new SpecReporter({
      spec: {
        displayStacktrace: true
      }
    }));

If you simply change the option displayStacktrace from all to none, you should get clean results without any stack traces. There are also options summary and specs. You might not notice the difference between them in your example, but if you add a few more specs in your suite, then you'll be able to see the difference:

  1. specs - if spec fails in the process of running tests, you'll see a stack trace for it immediately after a spec failure message
  2. summary - if spec fails in the process of running tests, you'll not see a stack trace for it immediately after a spec failure message, but you'll get a list of all stack traces for failed specs in the end of all tests
  3. all - combines specs and summary - if spec fails in the process of running tests, you'll see a stack trace for it immediately after a spec failure message and you'll get a list of all stack traces for failed specs in the end of all tests
  4. none - stack traces won't be shown anywhere
Lee Goddard
  • 10,680
  • 4
  • 46
  • 63
Michael Radionov
  • 12,859
  • 1
  • 55
  • 72
1

jasmine-spec-reporter's API has changed.

The new example illustrates a simple option to turn off stack traces:

let SpecReporter = require('jasmine-spec-reporter').SpecReporter;

exports.config = {
    framework: 'jasmine',
    // Your config here...

  jasmineNodeOpts: {
    print: function () {}
  },

    onPrepare: function () {
        jasmine.getEnv().addReporter(
            new SpecReporter({
                spec: {
                     displayStacktrace: true
                }
            })
        );
    }
}
Lee Goddard
  • 10,680
  • 4
  • 46
  • 63
0

For those who are looking for a stable and convenient way to filter out Protractor stacktrace, there is one more option - protractor-beautiful-reporter which would generate a very informative HTML report which also can filter out the stacktrace focusing only on the relevant parts ("smart stack trace" feature).

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
0

you can set webdriver logging level by passing parameter --logging. For example, in package.json make it look like this

"start": "node node_modules/protractor/bin/webdriver-manager start --logging=logging.conf"

create file logging.conf and place it in root folder of your project

and in this file put

level=WARNING

andriyze
  • 464
  • 3
  • 7