3

I am trying to implement a custom matcher for Jasmine where I would like to check if the given object property values lie within the range of the other two object property values.

Here is what I got so far:

let matcher = {
            toLieWithin: function (util: jasmine.MatchersUtil, customEqualityTesters: Array<jasmine.CustomEqualityTester>): jasmine.CustomMatcher {
                return {
                    compare: function (actual: any, expected: any): jasmine.CustomMatcherResult {
                        let result: jasmine.CustomMatcherResult = {
                            pass: false,
                            message: ''
                        };

                        result.pass = liesWithin(actual, expected);

                        return result;
                    }
                }
            }
        }; 

function liesWithin<T>(objActual: T, objExpected: T[]): boolean {
        let output: boolean;
        if(objExpected) {
          output = objActual.x > objExpected[0].x && objActual.x < objExpected[1].x && objActual.y > objExpected[0].y && objExpected[1].y;
        }
return output;    
}

Here, I am assuming, the actual has two properties x and y. And the expected is an array of two objects which also has two properties each x and y.

actual = {x: -5, y: -10}; expected = [{x: -10, y: -17},{x: 0, y: 0}];

Now, this scenario works I believe for the above given simple example. But when I am trying to implement it as a generic, how do I find what properties does the object have? And is my approach correct? Could anyone give me some ideas how can I implement such a method.

Thank you.

zelda
  • 753
  • 2
  • 8
  • 19

1 Answers1

4

It looks like you're on the right track with your liesWithin function, you just need to account for the situation where the expected object may not come back ordered how you expect. This code should cover those situations as well:

// Helper to reduce repeated code
function isWithinRange(val, a, b) {
    return (val > a && val < b) || (val > b && val < a);
}

function liesWithin<T>(objActual: T, objExpected: T[]): boolean {
    if (objExpected) {
        let props = Object.keys(objActual);
        // Splitting X and Y checks into two for readability
        let isInYRange = isWithinRange( objActual[ props[0] ], objExpected[0][ props[0] ], objExpected[1][ props[0] ] );
        let isInXRange = isWithinRange( objActual[ props[1] ], objExpected[0][ props[1] ], objExpected[1][ props[1] ] );
        return isInXRange && isInYRange;
    }
    return;
}
Murad Khan
  • 401
  • 2
  • 8
  • Sweet. But What if the `x` and `y` are not the properties of the object and they are `a` and `b`. How can I implement it generically which wouldn't rely on the hardcoded properties as implemented in this case? – zelda Apr 11 '18 at 21:15
  • I just edited my answer to account for that situation. You can use Object.keys to get an array of the property names in the object, but this assumes there will be only two keys in objExpected. – Murad Khan Apr 11 '18 at 21:18
  • Thanks a lot for the awesome answer :) – zelda Apr 11 '18 at 22:15