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?

7
  • What do you get if you log Array.isArray(errors)? Commented Mar 18, 2015 at 23:12
  • @Ryan was not expecting this, but it prints true..weird. Thanks. Commented Mar 18, 2015 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 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.) Commented Mar 18, 2015 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 could be related to what we are experiencing: You can treat an ElementArrayFinder as an array of WebElements for most purposes... Commented Mar 18, 2015 at 23:45
  • Does expect(scope.page.errors).toBeArray(); pass? Commented Apr 4, 2015 at 21:38

2 Answers 2

3
+100

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

Sign up to request clarification or add additional context in comments.

3 Comments

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(); });.
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.
unfortunately, their implementation does not follow the 'duck' principle by testing the toString of the object
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();
    });
});

1 Comment

Thank you for the participation, though it doesn't answer the question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.