Skip to content

Instantly share code, notes, and snippets.

@Gerg
Last active August 29, 2015 13:56
Show Gist options
  • Save Gerg/8925213 to your computer and use it in GitHub Desktop.
Save Gerg/8925213 to your computer and use it in GitHub Desktop.
Example Custom Jasmine Matchers

Example Custom Jasmine Matchers

Note: Some matchers require underscore.js and/or jQuery.

General Purpose Matchers

  • toHaveElement
  • toContainText
  • toContainTranslation
  • toHaveLength
  • toBeA
  • toHaveHref

Matchers for Q Promises

  • toResolveAs
  • toHaveBeenRejectedWith
Acknowledgments

Built at Pivotal Labs

beforeEach(function() {
function getTranslation(args) {
var translationKey = args[0];
var translatedText = t.apply(this, args);
var missingParams = translatedText.match(/missing (\{\{\w+\}\}) value/);
if(!I18n.lookup(translationKey)) {
throw new Error("Test error - Missing translation key '" + translationKey + "'");
}
if(missingParams) {
throw new Error("Test error - Missing parameter for translation key '" + translationKey + "': " + missingParams[1]);
}
return translatedText;
}
jasmine.addMatchers({
toHaveElement: function(selector) {
return {
compare: function(view, selector) {
var result = {pass: false, message: ""};
result.pass = !!view.$(selector).length;
if(result.pass) {
var foundEls = _.map(view.$(selector), function(el) {
return el.outerHTML;
});
result.message = "Expected: " + selector + " not to exist, but found " + foundEls;
} else {
result.message = "Expected: " + selector + " to exist, but found no matching elements.";
}
return result;
}
};
},
toContainText: function(expectedText) {
return {
compare: function(elementOrString, expectedText) {
try {
var actual = _.isString(elementOrString) ? elementOrString : elementOrString.text();
var result = {pass: false, message: ""};
result.pass = actual.indexOf(expectedText) > -1;
if(result.pass) {
result.message = "Text '" + actual + "' contains '" + expectedText + "'";
} else {
result.message = "Expected text '" + actual + "' to contain '" + expectedText + "'";
}
return result;
} catch(e) {
return {
pass: false,
message: e.toString()
};
}
}
};
},
toContainTranslation: function(translationKey) {
return {
compare: function(elementOrString, translationKey) {
var actual = _.isString(elementOrString) ? elementOrString : elementOrString.text();
var translatedText = getTranslation(_.rest(arguments));
var result = { pass: actual.indexOf(translatedText) > -1 };
if(result.pass) {
result.message = "Expected text '" + actual + "' not to contain the translation for '" + translationKey + "' (" + translatedText + ")";
} else {
result.message = "Expected text '" + actual + "' to contain the translation for '" + translationKey + "' (" + translatedText + ")";
}
return result;
}
};
},
toHaveLength: function(expectedLength) {
return {
compare: function(actual, expectedLength) {
var actualLength = _.result(actual, 'length');
var result = {
pass: actualLength === expectedLength
};
if(result.pass) {
result.message = "Expected length not to be " + expectedLength;
} else {
result.message = "Expected length to be " + expectedLength + ", but got " + actualLength;
}
return result;
}
};
},
toBeA: function(expectedClass) {
return {
compare: function(actual, expectedClass) {
var pass;
pass = actual instanceof expectedClass || actual.constructor === expectedClass;
var result = { pass: pass };
if(result.pass) {
result.message = "Expected " + jasmine.pp(actual) + " not to be a " + expectedClass;
} else {
result.message = "Expected " + jasmine.pp(actual) + " to be a " + jasmine.pp(expectedClass);
}
return result;
}
};
},
toHaveHref: function(expectedHref) {
return {
compare: function(actual, expectedHref) {
var actualHref = actual.attr("href");
var result = { pass: actualHref === expectedHref };
if(!actual[0]) {
throw new Error("Actual element does not exist in toHaveHref");
}
var actualHtml = actual[0].outerHTML;
if(result.pass) {
result.message = "Expected " + jasmine.pp(actualHtml) + " not to have href " + expectedHref;
} else {
result.message = "Expected " + jasmine.pp(actualHtml) + " to have href " + expectedHref;
}
return result;
}
};
},
toResolveAs: function(expectedValue) {
return {
compare: function(actual, expectedValue) {
if(!actual.inspect) { throw new Error("Matcher only works with Q Promises"); }
var actualValue = actual.inspect().value;
var result = { pass: actualValue === expectedValue };
if(result.pass) {
result.message = "Expected promise not to resolve as " + expectedValue;
} else {
result.message = "Expected promise to resolve as " + expectedValue;
}
return result;
}
};
},
toHaveBeenRejectedWith: function(expectedReason) {
return {
compare: function(actual, expectedReason) {
if(!actual.inspect) { throw new Error("Matcher only works with Q Promises"); }
var actualState = actual.inspect().state;
var actualReason = actual.inspect().reason;
var result = { pass: (actualState === 'rejected' && actualReason === expectedReason) };
if(result.pass) {
result.message = "Expected promise not to be rejected with '" + expectedReason + "'";
} else {
result.message = "Expected promise to be rejected with with '" + expectedReason + "', but was " + actualState + " with '" + actualReason + "'";
}
return result;
}
};
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment