Jasmine Custom Matchers Do Not Work - jasmine

I made a couple matchers, one designed to always pass, and the other designed to always fail.
Here is my spec file:
/* my-spec.js */
beforeEach(function() {
var matchers = {
toPass: function() {
return {
compare: function(actual) {
return {
pass: true
};
}
};
},
toFail: function() {
return {
compare: function(actual) {
return {
pass: false
};
}
};
}
};
this.addMatchers(matchers);
});
describe("A suite", function() {
it("contains spec with an expectation", function() {
expect('this test').toPass();
expect('this test').toFail();
});
});
When I run jasmine-node tests (my file is in the tests folder), I see:
.
Finished in 0.018 seconds
1 test, 2 assertions, 0 failures, 0 skipped
What am I doing wrong?

I was using an old version of Jasmine, but following the new documentation.

Related

Can't write out protractor network/performance log in a custom jasmine reporter

I'm trying to write to console the network log after a test failure as part of my protractor suite. The code works fine when in an afterEach() block but fails to execute the promise when inside of a custom jasmine reporter. As far as I can tell the promise never executes, but there are no known/shown errors.
protractor config (simplified):
exports.config = {
specs: ['./e2e/**/*.spec.ts'],
capabilities: {
browserName: 'chrome',
chromeOptions: {
perfLoggingPrefs: {
enableNetwork: true,
enablePage: false,
}
},
loggingPrefs: {
performance: 'ALL',
browser: 'ALL'
},
},
onPrepare() {
jasmine.getEnv().addReporter({
specDone: result => {
new ErrorReporter(browser).logNetworkError(result);
}
});
},
};
ErrorReporter:
class ErrorReporter {
constructor(browser) {
this.browser = browser;
}
logNetworkError(result) {
if(result.status === 'failed') {
// execution makes it in here
this.browser.manage().logs().get('performance').then(function(browserLogs) {
// execution DOES NOT make it here
browserLogs.forEach(function(log) {
const message = JSON.parse(log.message).message;
if(message.method === 'Network.responseReceived') {
const status = message.params.response.status;
const url = message.params.response.url;
if(status !== 200 && status !== 304) {
console.log(`----E2E NETWORK ERROR----`);
console.log(`STATUS: [${status}]`);
console.log(`URL: [${url}]`);
console.log(`RESPONSE: [${log.message}]`);
}
}
});
});
}
}
}
module.exports = ErrorReporter;
The code inside the logNetworkError() method works completely fine when executed in an afterEach() block but never writes out any logs when executed as a custom reporter. I would expect that this would work as a jasmine reporter as well.
If it's not possible to execute this as a jasmine reporter is there some way to access the executed test's results in the afterEach() block? I do not want to log on successful test execution.
I figured out the solution. There was 2 main problems. The first was that I needed to use async and await inside of the function that was creating the log:
async logNetworkError(result) {
if(result.status === 'failed') {
const logs = await this.browser.manage().logs().get('performance');
logs.forEach((log) => {
const message = JSON.parse(log.message).message;
if(message.method === 'Network.responseReceived') {
const status = message.params.response.status;
const url = message.params.response.url;
if(status !== 200 && status !== 304) {
console.log(`-----E2E NETWORK ERROR-----`);
console.log(`TEST NAME: ${result.fullName}`);
console.log(`STATUS: [${status}]`);
console.log(`URL: [${url}]`);
console.log(`RESPONSE: [${log.message}]`);
}
}
});
}
}
the second part of the problem was that another reporter which was saving screenshots did not have async and await which was stopping other reporters from completing. Adding async/await to both reporters solved this issue.

jasmine unit test for modalInstance result

i am new to jasmine tests i could not able to find solution for this after trying in all ways i am posting it here can any body suggest to write test case for this code which is in angular js
modalInstance.result.then(function (modalOutput) {
if (modalOutput) {
if ('okToUndoEdits' === modalOutput[1]) {
$scope.chargebackDetail.cbDetails = angular.copy($scope.chargebackDetailBackup.cbDetails);
} else if ('okToSaveUnmatched' === modalOutput[1]) {
$('#noMatchWarning').show();
$scope.isMatchedDoc = false;
}
}
}, function () {
});

Jasmine 2 custom matcher for hasClass in Protactor

I upgrade my Jasmine 1.3 to 2.0 so I added a custom matcher to check css is present.Below is the code to check the matcher
hasClass = function(actual,expected){
return actual.getAttribute('class').then(function (classes) {
return classes.split(' ').indexOf(expected) !== -1;
});
}
But when I upgrade to Jasmine 2 then promise throws error by protactor as it expect return but below is async process
hasClass = function(){
return compare: function(actual,expected){
return actual.getAttribute('class').then(function (classes) {
return {pass: classes.split(' ').indexOf(expected) !== -1};
});
}
}
How can I test class is present in element I don't want to use jasmine-jquery??
The pass should be a promise, not resolved in one. Try to place this in your beforeEach:
this.addMatchers({
hasClass: function() {
return {
compare: function(actual, expected) {
return {
pass: actual.getAttribute('class').then(function(classes) {
return classes.split(' ').indexOf(expected) !== -1;
})
};
}
};
}
});

Jasmine toEqual for complex objects (mixed with functions)

Currently, I have a function that sometimes return an object with some functions inside. When using expect(...).toEqual({...}) it doesn't seem to match those complex objects. Objects having functions or the File class (from input type file), it just can't. How to overcome this?
Try the Underscore _.isEqual() function:
expect(_.isEqual(obj1, obj2)).toEqual(true);
If that works, you could create a custom matcher:
this.addMatchers({
toDeepEqual: function(expected) {
return _.isEqual(this.actual, expected);
};
});
You can then write specs like the following:
expect(some_obj).toDeepEqual(expected_obj);
As Vlad Magdalin pointed out in the comments, making the object to a JSON string, it can be as deep as it is, and functions and File/FileList class. Of course, instead of toString() on the function, it could just be called 'Function'
function replacer(k, v) {
if (typeof v === 'function') {
v = v.toString();
} else if (window['File'] && v instanceof File) {
v = '[File]';
} else if (window['FileList'] && v instanceof FileList) {
v = '[FileList]';
}
return v;
}
beforeEach(function(){
this.addMatchers({
toBeJsonEqual: function(expected){
var one = JSON.stringify(this.actual, replacer).replace(/(\\t|\\n)/g,''),
two = JSON.stringify(expected, replacer).replace(/(\\t|\\n)/g,'');
return one === two;
}
});
});
expect(obj).toBeJsonEqual(obj2);
If anyone is using node.js like myself, the following method is what I use in my Jasmine tests when I am only concerned with comparing the simple properties while ignoring all functions. This method requires json-stable-stringify which is used to sort the object properties prior to serializing.
Usage:
var stringify = require('json-stable-stringify');
var obj1 = {
func: function() {
},
str1: 'str1 value',
str2: 'str2 value',
nest1: {
nest2: {
val1:'value 1',
val2:'value 2',
someOtherFunc: function() {
}
}
}
};
var obj2 = {
str2: 'str2 value',
str1: 'str1 value',
func: function() {
},
nest1: {
nest2: {
otherFunc: function() {
},
val2:'value 2',
val1:'value 1'
}
}
};
it('should compare object properties', function () {
expect(stringify(obj1)).toEqual(stringify(obj2));
});
Extending #Vlad Magdalin's answer, this worked in Jasmine 2:
http://jasmine.github.io/2.0/custom_matcher.html
beforeEach(function() {
jasmine.addMatchers({
toDeepEqual: function(util, customEqualityTesters) {
return {
compare: function(actual, expected) {
var result = {};
result.pass = _.isEqual(actual, expected);
return result;
}
}
}
});
});
If you're using Karma, put that in the startup callback:
callback: function() {
// Add custom Jasmine matchers.
beforeEach(function() {
jasmine.addMatchers({
toDeepEqual: function(util, customEqualityTesters) {
return {
compare: function(actual, expected) {
var result = {};
result.pass = _.isEqual(actual, expected);
return result;
}
}
}
});
});
window.__karma__.start();
});
here's how I did it using the Jasmine 2 syntax.
I created a customMatchers module in ../support/customMatchers.js (I like making modules).
"use strict";
/**
* Custom Jasmine matchers to make unit testing easier.
*/
module.exports = {
// compare two functions.
toBeTheSameFunctionAs: function(util, customEqualityTesters) {
let preProcess = function(func) {
return JSON.stringify(func.toString()).replace(/(\\t|\\n)/g,'');
};
return {
compare: function(actual, expected) {
return {
pass: (preProcess(actual) === preProcess(expected)),
message: 'The functions were not the same'
};
}
};
}
}
Which is then used in my test as follows:
"use strict";
let someExternalFunction = require('../../lib/someExternalFunction');
let thingBeingTested = require('../../lib/thingBeingTested');
let customMatchers = require('../support/customMatchers');
describe('myTests', function() {
beforeEach(function() {
jasmine.addMatchers(customMatchers);
let app = {
use: function() {}
};
spyOn(app, 'use');
thingBeingTested(app);
});
it('calls app.use with the correct function', function() {
expect(app.use.calls.count()).toBe(1);
expect(app.use.calls.argsFor(0)).toBeTheSameFunctionAs(someExternalFunction);
});
});
If you want to compare two objects but ignore their functions, you can use the methods _.isEqualWith together with _.isFunction from lodash as follows.
function ignoreFunctions(objValue, otherValue) {
if (_.isFunction(objValue) && _.isFunction(otherValue)) {
return true;
}
}
it('check object equality but ignore their functions', () => {
...
expect(_.isEqualWith(actualObject, expectedObject, ignoreFunctions)).toBeTrue();
});

how to add mocha jstestdriver to webstorm

I'd like to use the built-in JsTestDriver functionality and code coverage support of the WebStorm IDE. However, I use mocha instead of Jasmine.
How can I configure webstorm to recognize mocha, or use a mocha plugin?
I did find this piece of code to create a mocha jstestdriver adapater on the web, but not sure how and where to add it to webstorm...
/**
* Mocha JsTestDriver Adapter.
* #author jan#prachar.eu (Jan Prachar)
*/
(function(){
/**
* Our mocha setup
*/
var setup = mocha.setup;
var mochaOptions = {};
mocha.setup = function (opts) {
if ('string' === typeof opts) {
mochaOptions.ui = opts;
} else {
mochaOptions = opts;
}
setup.call(mocha, mochaOptions);
};
var getReporter = function (onTestDone, onComplete) {
var Base = mocha.reporters.Base;
var Reporter = function (runner) {
var self = this;
Base.call(this, runner);
this.onTestDone = onTestDone;
this.onComplete = onComplete;
this.reset = function () {
jstestdriver.console.log_ = [];
};
this.reset();
runner.on('start', function () {
});
runner.on('suite', function (suite) {
});
runner.on('suite end', function (suite) {
});
runner.on('test', function (test) {
self.reset();
});
runner.on('pending', function () {
});
runner.on('pass', function (test) {
self.onTestDone(new jstestdriver.TestResult(
test.parent.fullTitle(),
test.title,
'passed',
'',
'',
test.duration
));
});
runner.on('fail', function (test, err) {
var message = {
message: err.message,
name: '',
stack: err.stack
};
self.onTestDone(new jstestdriver.TestResult(
test.parent.fullTitle(),
test.title,
'failed',
jstestdriver.angular.toJson([message]),
'',
test.duration
));
});
runner.on('end', function () {
self.onComplete();
});
};
// Inherit from Base.prototype
Reporter.prototype.__proto__ = Base.prototype;
return Reporter;
};
var MOCHA_TYPE = 'mocha test case';
TestCase('Mocha Adapter Tests', null, MOCHA_TYPE);
jstestdriver.pluginRegistrar.register({
name: 'mocha',
getTestRunsConfigurationFor: function (testCaseInfos, expressions, testRunsConfiguration) {
for (var i = 0; i < testCaseInfos.length; i++) {
if (testCaseInfos[i].getType() === MOCHA_TYPE) {
testRunsConfiguration.push(new jstestdriver.TestRunConfiguration(testCaseInfos[i], []));
}
}
},
runTestConfiguration: function (config, onTestDone, onComplete) {
if (config.getTestCaseInfo().getType() !== MOCHA_TYPE) return false;
mochaOptions.reporter = getReporter(onTestDone, onComplete);
mocha.setup(mochaOptions);
mocha.run();
return true;
},
onTestsFinish: function () {
}
});
})();
Does this Mocha Adapter really work?
Were you able to test it from the command?
I would imagine that it would be configured similar to how the jasmineAdapter.js is configured below.
server: http://<localhost>:4224
load:
- tools/Jasmine/jasmine.js
- tools/Jasmine/jasmineAdapter.js
- lib/require.js
- src/*.js
test:
- specs/*.js

Resources