Richlewis
Richlewis

Reputation: 15374

JS Unit test for prototype methods

Because trim() is not supported in IE8 i want to have a fall back option to use a regexp (many examples on here i know), so have this

function trim(value) {
  if (typeof value === 'string') {
    if (String.prototype.trim) {
      value = value.trim();
    } else {
      value = value.replace(/^\s+|\s+$/g, "");
    }
  }

  return value;
}

What i want to be able to do is write unit tests for this, so basically having String.prototype.trim set to true or false so that i can ensure that native and regexp options are used

describe('trim', function() {
  it('should use native trim if available', function(){
    String.prototype.trim = true; // THIS DOES NOT WORK
    var string = 'test string  ';
    expect(string.trim()).toEqual('test string');
  });  
});

How can i go about doing this?

Thanks

Upvotes: 0

Views: 1034

Answers (2)

piotrek
piotrek

Reputation: 14540

you have at least two options:

  1. test whole method (not just String.prototype.trim) in different browsers. that's the recommended way. your code WILL run in different browsers and you should test it there

  2. if for any reason you can't/don't want to test in different browsers, you can use IOC and higher order functions: build function that takes true/false and returns a function that trims a string. and then test if this function works correctly in both cases. and on production as an input param you use String.prototype.trim

you can also change the prototype of built-in function (AFAIK this not always works because of security reasons) but it's dangerous because you don't (or it's easy to miss) know which built-in functions are used by your testing framework and libraries and code you use in your tests. so don't do it

Upvotes: 0

John Whiles
John Whiles

Reputation: 56

In the example, you are reassigning String.prototype.trim to a boolean. This means that you can no longer call string.trim().

You could check if your polyfill works by assigning String.prototype.trim to false, and then calling trim(string).

describe('trim', function() {
  it('should use native trim if available', function(){
    String.prototype.trim = false;
     var string = 'test string  ';
    expect(trim(string)).toEqual('test string');
  });  
});

I'm quite uncomfortable with reassigning properties of String, so alternately you could break the ie8 trim into a separate function, which you can then test more easily.

function ie8Trim(value) {
  if (typeof value === 'string') {
   return value.replace(/^\s+|\s+$/g, "")
  }
  return value
}

function trim(value) {
  if (typeof value === 'string') {
    if (String.prototype.trim) {
      return value.trim();
    } else {
      return ie8Trim(value)
    }
  }
  return value;
}

Upvotes: 1

Related Questions