Expect item in array

One of my test expects an error message text to be one of multiple values. Since getText() returns a promise I cannot use toContain() jasmine matcher. The following would not work since protractor (jasminewd under-the-hood) would not resolve a promise in the second part of the matcher, toContain() in this case:

expect(["Unknown Error", "Connection Error"]).toContain(page.errorMessage.getText());

Question: Is there a way to check if an element is in an array with jasmine+protractor where an element is a promise?

In other words, I'm looking for inverse of toContain() so that the expect() would implicitly resolve the promise passed in.


As a workaround, I can explicitly resolve the promise with then():

page.errorMessage.getText().then(function (text) {
    expect(["Unknown Error", "Connection Error"]).toContain(text);
});

I'm not sure if this is the best option. I would also be okay with a solution based on third-parties like jasmine-matchers.


As an example, this kind of assertion exists in Python:

self.assertIn(1, [1, 2, 3, 4]) 

Answers:

Answer

Looks like you need a custom matcher. Depending on the version of Jasmine you are using:

With Jasmine 1:

this.addMatchers({
    toBeIn: function(expected) {
        var possibilities = Array.isArray(expected) ? expected : [expected];
        return possibilities.indexOf(this.actual) > -1;
    }
});


With Jasmine 2:

this.addMatchers({
    toBeIn: function(util, customEqualityTesters) {
        return {
            compare: function(actual, expected) {
                var possibilities = Array.isArray(expected) ? expected : [expected];
                var passed = possibilities.indexOf(actual) > -1;

                return {
                    pass: passed,
                    message: 'Expected [' + possibilities.join(', ') + ']' + (passed ? ' not' : '') + ' to contain ' + actual
                };
            }
        };
    }
});


You'll have to execute this in the beforeEach section on each of your describe blocks it's going to be used in.

Your expect would look like:

expect(page.errorMessage.getText()).toBeIn(["Unknown Error", "Connection Error"]);
Answer

The alternative solution is to use .toMatch() matcher with Regular Expressions and specifically a special character | (called "or"), which allows to match only one entry to succeed:

expect(page.errorMessage.getText()).toMatch(/Unknown Error|Connection Error/);
Answer

To me, the work-around that you identified is the best solution. However, we should not forget that this is an asynchronous execution and you might want to consider Jasmine's asynchronous support.

Then, your test will look like the following one:

it('should check item is in array', function(done){ //Note the argument for callback

    // do your stuff/prerequisites for the spec here

    page.errorMessage.getText().then(function (text) {
        expect(["Unknown Error", "Connection Error"]).toContain(text);
        done(); // Spec is done! 
    });
});

Note: If you don't pass this done argument to the spec callback, it is going to run to completion without failures, but no assertions are going to be reported in the execution results for that spec (in other words, that spec will have 0 assertions) and it might lead to confusions.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.