Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if a function is called when a specific parameter is passed

I have 2 simple functions. First function X either receives a number or string. If it receives a number, I return its double and if it receives a string I call another function Y. How do I test if my function X calls function Y when it receives a string as parameter?

function X(arg) {
  if (typeof (arg) === 'String') Y(arg)
  else return arg * 2
}

function Y(arg) {
  return 'Got empty string'
}

What I want to do in my test..

describe('A function X that checks data type', function() {
  it('should call function Y is argument is a string', function() {
    let arg = arguments[0]
    expect(Y is called if typeof(arg)).toEqual('string')
  })
})

A more general answer for these type of problems where 'do X if Y' would be awesome. Thanks :)

like image 634
Jamie Avatar asked Apr 09 '17 10:04

Jamie


2 Answers

You have to create a spy. You can even check the argument with which Y was called. Assuming you defined those functions globally, they belong to the window object:

function X(arg) {
  if (typeof (arg) === 'String') Y(arg)
  else return arg * 2
}

function Y(arg) {
  return 'Got empty string'
}

Your tests:

describe('A function X that checks data type', () => {
  beforeEach(() => {
    spyOn(window, 'Y')
  })
  it('should call function Y is argument is a string', () => {
    // Call X with a string
    window.X('hello')
    // If you don't want to check the argument:
    expect(window.Y).toHaveBeenCalled()
    // If you want to check the argument:
    expect(window.Y).toHaveBeenCalledWitH('hello')
  })
})

It is worth noticing that using the window object for this kind of things is not the best way to go. If you want to use spies like this you should create an object where you hold your methods.

Documentation on jasmine spies: https://jasmine.github.io/2.0/introduction.html#section-Spies

like image 96
fnune Avatar answered Oct 18 '22 21:10

fnune


If you're using Jasmine, you can use Spies: https://jasmine.github.io/2.0/introduction.html#section-Spies

function X(arg) {
  if (typeof (arg) === 'string') Y(arg);
  else return arg * 2;
}

function Y(arg) {
  return 'Got empty string'
}

describe('A function X that checks data type', function() {
  it('should call function Y is argument is a string', function() {
    spyOn(window, 'Y').and.callThrough();
    X('Hello');
    expect(window.Y).toHaveBeenCalledWith('Hello');
  })
})

Check the working demo here: jsFiddle

And here is how you can handle async Y function: jsFiddle - asnyc

function X(arg) {
  let deferred = {};
  let promise = new Promise(function(res, rej) {
    deferred.res = res;
    deferred.rej = rej;
  });
  if (typeof(arg) === 'string') {
    setTimeout(function() {
      deferred.res(Y(arg));
    }, 1000);
    return promise;
  } else {
    return arg * 2;
  }
}

function Y(arg) {
  console.log('Y with timeout');
  return 'Got empty string';
}

describe('A function X that checks data type', function() {
  it('should call function Y is argument is a string', function(done) {
    spyOn(window, 'Y').and.callThrough();
    let promise = X('Hello');
    if (promise instanceof Promise) {
      promise.then(function() {
        expect(window.Y).toHaveBeenCalledWith('Hello');
        done();
      });
    } else {
      done();
    }

  })
})

However I recommend to attach your functions to some objects (modules), to easier track what was called when and where.

like image 21
Oskar Avatar answered Oct 18 '22 20:10

Oskar