Skip to content
This repository was archived by the owner on Jul 29, 2024. It is now read-only.

Cannot use 'should' assertion style with mocha / chai / chai-as-promised #633

Closed
phuvo opened this issue Mar 22, 2014 · 12 comments
Closed

Comments

@phuvo
Copy link

phuvo commented Mar 22, 2014

I tried to use myElement.getText().should.eventually.equal("foo") as in the chai-as-promised manual, but got TypeError: Cannot read property 'eventually' of undefined. This is not a problem with chai-as-promised either, because myElement.getText().should.equal("foo") failed with a similar error. Using expect works as expected, though.

var chai = require('chai');
chai.use(require('chai-as-promised'));
var should = chai.should();

describe('Home', function() {
  it('should say hello', function() {
    browser.get('/');
    $('h1').getText().should.eventually.equal('Hello, world');
  });
});
@pcwinters
Copy link

I've encountered the same.

@juliemr
Copy link
Member

juliemr commented Mar 26, 2014

Mocha support is slightly limited - I'd suggest sticking with expect for now :)

If someone has time to look into how should adds itself as a property to everything and why that doesn't work with webdriver promises, please go ahead!

@gabejohnson
Copy link

@juliemr I came across the same issue as well. Looking at the code, should adds itself to Object.prototype

https://github.com/chaijs/chai/blob/master/lib/chai/interface/should.js#L35

webdriver.promise.Promise doesn't appear to inherit from Object. It's acting like it comes from a different global context.

(new webdriver.promise.Promise) instanceof Object === false

This isn't an answer, but hopefully it will give someone direction.

@cyberwombat
Copy link

Thanks @gabejohnson that got me on the right track. This works:

var chai = require('chai');
var should = chai.should();
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);

Object.defineProperty(protractor.promise.Promise.prototype, 'should', {
  get: Object.prototype.__lookupGetter__('should'),
  set: Object.prototype.__lookupSetter__('should')
});

describe('home page', function() {
  beforeEach(function() {
    browser.ignoreSynchronization = true;
  });

  it('should get home page title', function() {
    browser.get('http://github.com');
    browser.getTitle().should.eventually.equal("GitHub · Build software better, together.");
  });
});

I think a check in Protractor to see if Object has been extended with should would be nice - then Protractor can add that tidibit to extend Promise.

@jlin412
Copy link

jlin412 commented Jul 30, 2014

It breaks the same way in cucumber framework as well using protractor

@jlin412
Copy link

jlin412 commented Aug 19, 2014

Btw, I try codes from @juliemr and it works.

@domenic
Copy link

domenic commented Aug 19, 2014

I'd suggest

Object.defineProperty(
  protractor.promise.Promise.prototype,
  'should',
  Object.getOwnPropertyDescriptor(Object.prototype, 'should')
);

@rolandjitsu
Copy link

@domenic 👍 works like a charm and it's a bit cleaner than the first version posted here

@vladei
Copy link

vladei commented Mar 31, 2015

@domenic I get the following error when i'm trying to use the code. Can you plz help ? : )

TypeError: Property description must be an object: undefined
Stacktrace:
TypeError: Property description must be an object: undefined
at Function.defineProperty (native)
at Object.
main.spec.js:16:8)
at require (module.js:380:17)

@jodytate
Copy link

@vladei I received a similar error until I confirmed the following as the correct order:

var chai = require('chai');
var should = chai.should();
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);

Object.defineProperty(
  protractor.promise.Promise.prototype,
  'should',
  Object.getOwnPropertyDescriptor(Object.prototype, 'should')
);

@scottohara
Copy link

Note that as of protractor 4.0.0, the workaround above no longer seems to be required (partly due to #3214).

Protractor no longer exposes a Promise object of it's own, and instead defers (no pun intended) to the ManagedPromise object provided by selenium-webdriver.

(Note: if you need to work directly with Promises in protractor 4.0.0, such as protractor.promise.all(), you now need to use the WebDriver promise directly), e.g.

var promise = require('selenium-webdriver').promise;
promise.all([promise1, promise2, promise3])

It would seem that the WebDriver promise inherits from Object.prototype, so initializing chai / chai-as-promised is enough to bestow a should property onto the Promise object, e.g.

// protractor.conf.js

onPrepare() {
  // Load chai assertions
  const chai = require("chai");

  // Load chai-as-promised support
  chai.use(require("chai-as-promised"));

  // Initialise should API (attaches as a property on Object)
  chai.should();
}

@juliemr
Copy link
Member

juliemr commented Dec 22, 2016

Sweet, closing as fixed.

@juliemr juliemr closed this as completed Dec 22, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests