Protractor with mocha and chai

3.8k Views Asked by At

I started using Protractor and the first thing I've tried to do is to use Mocha and Chai instead of Jasmine. Although now I'm not sure if that was a good idea.

first I needed to make Chai accessible from all the spec files, without having to import everytime, I found it's possible to do in protractor.conf file:

  onPrepare: ->
      global.chai = require 'chai'
      chai.use require 'chai-string'
      chai.use require 'chai-as-promised'
      global.expect = chai.expect

now in a spec like this:

  it "when clicked should sort ",->
      headerColumns.get(0).click()
      firstCellText = $$(".first-cell").getText()
      secondCellText = $$(".second-cell").getText()

      # this won't work
      expect(firstCellText).eventually.be.above(secondCellText)             

to make it work I could do:

    # now this works
    $$(".second-cell").getText().then (secondCellText)->
        expect(firstCellText).eventually.be.above(secondCellText)             

but that's ugly, and I don't want to wrap stuff inside of .then all the time. I'm thinking there should be a better way(?)

3

There are 3 best solutions below

0
On

I was having the same problem. The issue for me was to add a longer timeout to mocha through the Protractor config.js.

This works because Protractor tests take considerably longer relative to other modules like supertest since an actual browser is being interacted with.

I added

  mochaOpts: {
   timeout: 5000
  }

to my protractor config and the tests passed.

0
On

I found this question while I was trying to do the same thing in TypeScript, but the approach in the protractor.conf.js is identical.

Making chai available globally

It appears to achieve this you're right that it needs to be done in the on prepare. a fairly terse example is below. As I understand it this is needed because chai is of course not apart of mocha but some additional candy that we can use with mocha. Unlike jasmine where everything is bundled into the framework.

protractor.conf.js fragment

onPrepare: function() {
  var chai = require('chai'); // chai
  var chaiAsPromised = require("chai-as-promised"); // deal with promises from protractor
  chai.use(chaiAsPromised); // add promise candy to the candy of chai
  global.chai = chai; // expose chai globally
}

example spec

Once you've got chai and chai-as-promised setup globally you need to add a "little" boiler plate to your spec to expose expect which comes from chai.

example.e2e-spec.ts fragment

const expect = global['chai'].expect; // obviously TypeScript


it('will display its title', () => {
  pageObject.navigateTo();

  const title = element(by.css('app-root h1')).getText();
  expect(title).to.eventually.contain('An awesome title');
});

Avoiding then

I can't tell what your $$ references are, but if you're using the protractor components browser and by etc. then things clean up a little bit.

The call const title = element(by.css('app-root h1')).getText(); seems to return a promise which jasmine seems to deal with out of the box while mocha+chai doesn't. That's where chai-as-promised comes in.

using our additional syntax candy expect(title).to.eventually.contain('An awesome title'); resolves the promise quite neatly and we've avoided all those then calls, but we do need the eventually.

I've provided you a link to a working TypeScript example that might help demonstrate.

0
On

Either you need to mention timeout for the whole test suite using "this.timeout(1000);" just below the describe block, or you can change it for individual test cases by explicitly defining timeout for each "it" block.

example for describe block:

describe("test-suite",function () {
    this.timeout(5000);
    it("test-case",function () {
       //test case code goes here 
    });
});

example for it block:

it("test-case",function () {
        this.timeout("20000");
    });