6

Here is the failing test:

describe("Checking errors", function () {
    var scope = {};

    beforeEach(function () {
        browser.get("/#endpoint");
        browser.waitForAngular();

        scope.page = new MyPage();
    });

    it("should not show any errors", function () {
        expect(scope.page.errors).toBeEmptyArray();
    });
});

where MyPage is a Page Object:

var MyPage = function () {
    this.errors = element.all(by.css("div.error-block b.error"))
        .filter(function (elm) {
            return elm.isDisplayed().then(function (value) {
                return value;
            });
        })
        .map(function (elm) {
            return elm.getText();
        });
};

module.exports = MyPage;

where errors supposed to be an array of visible error texts found on a page.

Here is the error we are getting:

Failures:

  1) Checking errors should not show any errors
   Message:
     Expected [  ] to be empty array.
   Stacktrace:
     Error: Failed expectation

FYI, toBeEmptyArray() matcher is coming from jasmine-matchers third-party.


I've tried to print out the value of scope.page.errors this way:

scope.page.errors.then(function (errors) {
    console.log(errors);
});

And it is printed out as []. Array.isArray(errors) returns true.

From what I see, scope.page.errors is an empty array, but the expectation fails. What I a missing?

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • What do you get if you log Array.isArray(errors)? – Ryan Mar 18 '15 at 23:12
  • @Ryan was not expecting this, but it prints `true`..weird. Thanks. – alecxe Mar 18 '15 at 23:15
  • Does `expect(scope.page.errors.length).toBe(0);` work? You might be running into a problem from the scopes webdriver creates (like iframes in a page) that have their own "Array" definition. See http://stackoverflow.com/a/2265999/960524 (so this might be a bug in the `toBeEmptyArray()` method -- its probably failing the "array"-ness part of the check.) – P.T. Mar 18 '15 at 23:36
  • @P.T. thank you for the point, the expectation you've posted fails with `Expected undefined to be 0`. I actually suspect this has smth to do with `ElementArrayFinder`..[this particular comment](https://github.com/angular/protractor/blob/34f0eebd7e73b10e9b990caa06b63b6fd22b2589/lib/element.js#L26) could be related to what we are experiencing: `You can treat an ElementArrayFinder as an array of WebElements for most purposes...` – alecxe Mar 18 '15 at 23:45
  • Does `expect(scope.page.errors).toBeArray();` pass? – phts Apr 04 '15 at 21:38
  • `ElementArrayFinder` extends promise so you need to use `then` in your tests (see also in the [docs](https://github.com/angular/protractor/blob/34f0eebd7e73b10e9b990caa06b63b6fd22b2589/lib/element.js#L47-L50): `it("should not show any errors", function () { scope.page.errors.then(function(items) { expect(items).toBeEmptyArray(); }); });` – nemesv Apr 05 '15 at 16:53
  • @nemesv yes, but `expect()` is patched by `jasminewd` to resolve promises implicitly. – alecxe Apr 05 '15 at 22:38

2 Answers2

3

the answer is four lines down in the protractor src.

ElementArrayFinder extends Promise, while jasmine-matchers checks first checks that errors is an actual array exactly how Array.isArray is done , which will return false;

This is also consistent with expect(scope.page.errors.length).toBe(0) being undefined because promises do not have lengths.

Just run errors.then on your promise, and test that the argument is [] You've also shown that can be done when you ran scope.page.errors.then

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
michael truong
  • 321
  • 1
  • 4
  • Thank you, this is what I've suspected (see comments). Though, resolving `scope.page.errors` with `then()` didn't help: `Expected [ ] to be empty array.` when using the following code: `scope.page.errors.then(function (errors) { expect(errors).toBeEmptyArray(); });`. – alecxe Apr 08 '15 at 16:21
  • In other words, even the resolved value is not an array, it looks like an array but it's not (forget about the "duck" principle :)). But, now I have a workaround - I'm making an array out of "almost an array": `expect([].concat(errors)).toBeEmptyArray();`. Worth +1 anyway. – alecxe Apr 08 '15 at 19:25
  • unfortunately, their implementation does not follow the 'duck' principle by testing the toString of the object – michael truong Apr 16 '15 at 00:43
0
Inside test script your code line "scope.page = new MyPage();" is creating new empty MyPage object.Code which you have written in application script is creating page object locally and its not bounded with any angular scope.When there is requirement of testing such objects you need to replicate code for page object creation in beforeEach(); block of test script.And test it.
 describe("Checking errors", function () {
    var scope = {};
     var MyPage ;
    beforeEach(function () {
        browser.get("/#endpoint");
        browser.waitForAngular();

       MyPage = function () {
    this.errors = element.all(by.css("div.error-block b.error"))
        .filter(function (elm) {
            return elm.isDisplayed().then(function (value) {
                return value;
            });
        })
        .map(function (elm) {
            return elm.getText();
        });
};
    });

    it("should not show any errors", function () {
        expect(MyPage.errors).toBeEmptyArray();
    });
});
samyak bhalerao
  • 307
  • 2
  • 10