Jasmine toEqual for complex objects (mixed with functions)

后端 未结 5 1820
鱼传尺愫
鱼传尺愫 2020-12-16 13:00

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 c

相关标签:
5条回答
  • 2020-12-16 13:14

    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));
      });
    
    0 讨论(0)
  • 2020-12-16 13:18

    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();
    });
    
    0 讨论(0)
  • 2020-12-16 13:21

    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);
    
    0 讨论(0)
  • 2020-12-16 13:32

    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);
    
    0 讨论(0)
  • 2020-12-16 13:37

    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);
      });
    
    });
    
    0 讨论(0)
提交回复
热议问题