Reputation: 473873
The Story:
We've been using a custom jasmine matcher to expect an element to have a hand/pointer cursor:
beforeEach(function() {
jasmine.addMatchers({
toHaveHandCursor: function() {
return {
compare: function(actual) {
return {
pass: actual.getCssValue("cursor").then(function(cursor) {
return cursor === "pointer";
})
};
}
};
},
});
});
It works great and makes the tests readable:
expect(queuePage.sortByButton).toHaveHandCursor();
The problem:
When the expectation fails, currently we get a completely unreadable huge chunk of red text on the console in a form:
- Expected ElementFinder({ ptor_: Protractor({ getProcessedConfig: Function, forkNewDriverInstance: Function, restart: Function, controlFlow: Function, schedule: Function, setFileDetector: Function, getSession: Function, getCapabilities: Function, quit: Function, actions: Function, touchActions: Function, executeScript: Function, executeAsyncScript: Function, call: Function, wait: Function, sleep: Function, getWindowHandle: Function, getAllWindowHandles: Function, getPageSource: Function, close: Function, getCurrentUrl: Function, getTitle: Function, findElementInternal_: Function, findElementsInternal_ ... 10 minutes of scrolling ... , click: Function, sendKeys: Function, getTagName: Function, getCssValue: Function, getAttribute: Function, getText: Function, getSize: Function, getLocation: Function, isEnabled: Function, isSelected: Function, submit: Function, clear: Function, isDisplayed: Function, getOuterHtml: Function, getInnerHtml: Function, getId: Function, getRawId: Function, serialize: Function, takeScreenshot: Function }) to have hand cursor.
The Question:
Why is it happening? How can we improve the matcher and output a user-friendly error instead? Something like:
Expected 'auto' to be equal to 'pointer' cursor value.
From what I understand, we would need to provide a message
value for a custom matcher, but I'm not completely sure how to pass an actual element's cursor
CSS value into the message. Here is what I have so far:
toHaveHandCursor: function() {
return {
compare: function(actual) {
return actual.getCssValue("cursor").then(function(cursor) {
return {
pass: cursor === "pointer",
message: "Expected '" + cursor + "' to be equal to 'pointer' cursor value."
};
});
}
};
},
I expect this to work, but, for some reason, I see the same error message on the console after a test run.
Upvotes: 1
Views: 765
Reputation: 473873
What we were getting on the console was the auto-generated jasmine matcher fail message which consisted of the ElementFinder
instance string representation - which is, it appears, quite huge for some reason.
Now, to improve the failing message, we would need to use the message
key alongside with pass
. We should though take into account that getCssValue()
returns a promise and it needs to be resolved for an actual cursor
value to be used in a custom error message:
toHaveHandCursor: function() {
return {
compare: function(actual) {
var result = {};
result.pass = actual.getCssValue("cursor").then(function(cursor) {
result.message = "Expected '" + cursor + "' to be equal to 'pointer' cursor value.";
return cursor === "pointer";
});
return result;
}
};
},
Now, if the expectation fails, we get a nice error message:
- Expected 'auto' to be equal to 'pointer' cursor value.
Upvotes: 5
Reputation: 42460
You are correct, to set a custom message, you should set the message
attribute of the returned object.
The message is just a regular string. You can use the value of your cursor
variable if you put together the result object after your promise has been fulfilled.
See the following example how it could be done:
beforeEach(function(){
jasmine.addMatchers({
toBeDeactivated: function() {
return {
compare: function(account){
var accountStatusCode = account.get('status').statusCode;
var result = { pass: accountStatusCode === 5 };
if(result.pass) {
result.message = "Expected account with status code '" + accountStatusCode + " NOT to be deactivated.";
} else {
result.message = "Expected account with status code '" + accountStatusCode + "' to be deactivated.";
}
return result;
}
}
}
}
});
Replacing the account.get()
with a Promise should be simple.
Upvotes: 3