Print message on expect() assert failure

JavascriptTestingJasmineProtractor

Javascript Problem Overview


Is there a way to print a custom error message when a Jasmine expect() fails?

As an example, for end to end testing I have an array of web pages and I use one test to go to each URL and assert an element exists on each page. I know I can put every expect() into a separate test, but I'd rather iterate through the array and log the page URL on failure.

Javascript Solutions


Solution 1 - Javascript

UPDATE

I see people still are finding this. Later information from the Jasmine team is that there is an undocumented feature on the expect - you can include a custom failure message and it just works:

expect( fields[i].element.exists() ).toEqual(true, field[i].name + ' is expected to exist');

Which is exactly what I was originally looking for.

Original answer follows:

I've been looking for exactly this today, and put a comment here: https://github.com/adobe/brackets/issues/2752

The syntax that has been discussed is an extension to Jasmine to permit a because to be added - so you'd be able to write:

expect( fields[i].element.exists() ).toEqual(true).because( field[i].name + 'is expected to exist');

That is still being discussed after a few years, and may not come to fruition. Another way that I've found to do this is to create a custom matcher. In general I think I'd discourage a custom matcher without being sure you're covering all the bases with it, but in this case we're really checking a true/false value, so the matcher isn't too scary.

We can create the custom matcher with a beforeEach:

beforeEach(function() {
  var matchers = {
    toEqualBecause: function( value, message ) {
      this.message = function() {
        return "Expected '" + this.actual + "' to equal '" + value + "' because " + message;  
      };

      return this.actual == value;  
    }
 };

  this.addMatchers(matchers);
});

We can then use this matcher to put a message with our failures as such:

expect( field[i].element.exists() ).toEqualBecause( true, field[i].name );

Which will give a failure output including the field name as such:

Expected 'false' to equal 'true' because account_name

Solution 2 - Javascript

Yes, we can print a custom error message when an expect() failed in Jasmine.

 Code Snippet:

  it('print a custom error message when an expect failed', function() {

    var elemenToBeDisplayed=element(by.css("userName"));

    /*custom error message will be displayed if expected condition 
    failed*/

    expect(elemenToBeDisplayed.isPresent).toBe(true,'Write your custom       
         error message here');
   });

Solution 3 - Javascript

Jasmine 3.3 includes withContext as the officially supported way to specify additional information about the expectation without worrying about which matcher you are using.

Solution 4 - Javascript

Since Jasmine 3.3, there's a way to do it through withContext

Example:

expect(someValue).withContext('expected someValue to be true...').toBe(true)

See also https://github.com/jasmine/jasmine/issues/641#issuecomment-457037665

Solution 5 - Javascript

You can do it with fail() method.

it('should fail with a message', function() {    
  if (!foo) fail(`your message here`);
});

Solution 6 - Javascript

The other answers explain how to hack 'expect', but there is another approach that may solve your problem, though it requires you to flip your thinking around a little bit. Instead of thinking of the 'expect' as your behavior under test, think of all the expectations under a single 'it' call as your behavior under test.

The case where I've come across this problem the most is when I have a function that is doing some kind of intensive parsing and I want to write 20, nearly identical, tests.

Arrange your inputs and outputs like so:

var testDatas = [
  {
    input: 'stringtoparse1',
    output: 'String To Parse 1'
  },
  {
    input: 'stringtoparse2',
    output: 'String To Parse 2'
  },
  {
    input: 'stringtoparse3',
    output: 'String To Parse 3'
  },
];

Now iterate over the list of your test data, and call 'it' from inside the loop like so:

testDatas.forEach(function(test) {
  it('should parse for input ' + test.input, function() {
    expect(myParser(test.input).toEqual(test.output);
  });
});

You get to reduce the amount of extraneous code flying around your tests and you get to format a message for each expectation, or group of expectations.

Solution 7 - Javascript

I had a requirement to log custom messages for Jasmine and I used the following method.

beforeEach(function(){
    this.addMatchers({
        customError: function(mesg){
                         this.message= function () {
                                           return mesg;
                                       };
                         return this.actual == true;
                         }
                     });
        });
if(<fail condidtion>){
    expect(false).customError(<Fail message>)
}

Please do note, what I have mentioned above is by jasmine 1 format. There will been slight change if you are using jasmine 2. Hope this is helpful for you

Solution 8 - Javascript

Example: I need to validate the color of the page while loading first time.

expect(obj.color).toBe(true, 10000, 'Custom Message');

in toBe:

  • true - Expected to be True,
  • 10000 - waitTime
  • Custom message(Based on our requirement we can write the msg/error in the log report)

Solution 9 - Javascript

This is what I'm using for Jasmine 2.6.4 with TypeScript (Jasmine+Chutzpah in Visual Studio).

The latest Jasmine version via NuGet seems to be 2.6.4 so I don't have the "withContext" thing (it also seems a bit of a clumsy way to do it, I prefer just to tag a message on the end of the matcher like many other frameworks).

Even though the "expectationFailOutput" parameter (the message to display) is present in the jasmine.d.ts typings it seems it it not officially supported by jasmine:

However, unofficially, it seems to work just fine for all except the toEqual matcher.

I use the following to add a new toBeEqualTo matcher globally which I copied from the original toEqual matcher and simply add the expectationFailOutput message to the end. The interface declaration bit lets us use expect(...).toBeEqualTo(...) without TypeScript complaining.

Example usage:

expect(x).toBe(y, "Some Message"); // stock message works with .toBe
expect(x).toEqual(y, "This is ignored"); // stock message ignored with .toEqual
expect(x).toBeEqualTo(y, "My message is displayed"); // new matcher added below

TypeScript implementation:

/// <reference path="../../Scripts/typings/jasmine/jasmine.d.ts"/>

declare namespace jasmine
{
	interface Matchers
	{
		toBeEqualTo(expected: any, expectationFailOutput?: any): boolean;
	}
}

beforeEach(function ()
{
	jasmine.addMatchers(<any>{
		toBeEqualTo: function (util, customEqualityTesters)
		{
			customEqualityTesters = customEqualityTesters || [];

			return {
				compare: function (actual, expected, expectationFailOutput)
				{
					var diffBuilder = (<any>jasmine).DiffBuilder();

					return {
						pass: util.equals(actual, expected, customEqualityTesters, diffBuilder),

						message: diffBuilder.getMessage() + ": " + expectationFailOutput
					};
				}
			};
		}
	});
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser3517049View Question on Stackoverflow
Solution 1 - JavascriptPaulLView Answer on Stackoverflow
Solution 2 - JavascriptOptimworksView Answer on Stackoverflow
Solution 3 - JavascriptHolgerJerominView Answer on Stackoverflow
Solution 4 - JavascriptErnstjan FreriksView Answer on Stackoverflow
Solution 5 - JavascriptmrdedView Answer on Stackoverflow
Solution 6 - JavascriptcodepuzzlerView Answer on Stackoverflow
Solution 7 - JavascriptMurali KrishnaView Answer on Stackoverflow
Solution 8 - Javascriptuser3815064View Answer on Stackoverflow
Solution 9 - JavascriptEthermanView Answer on Stackoverflow