Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cleaning up Protractor stack trace

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.

like image 736
alecxe Avatar asked Dec 02 '15 17:12

alecxe


2 Answers

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
like image 179
Michael Radionov Avatar answered Nov 08 '22 19:11

Michael Radionov


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
                }
            })
        );
    }
}
like image 42
Lee Goddard Avatar answered Nov 08 '22 17:11

Lee Goddard