Refactoring For jQuery

bob.ts - Jan 22 '20 - - Dev Community

Set Up

Recently, in some client code, I found a lot of jQuery usage. While working with them to build a better test suite, I started with some simple refactoring to make these functions more testable.

The initial code looked like this ...

const testableCode1 = {
  test: function() {
    return testableCode.runTest();
  },
  runTest: function() {
    var elements = $('.elements');
    return elements.length;
  }
};
Enter fullscreen mode Exit fullscreen mode

Initial Test Coverage

There were no initial tests. Since we wanted to do some refactoring, we wound up with a simple pattern to allow for refactoring ...

describe('pre-refactor', function() {
  it('test before refactor', function() {
    var itemToReturn = $('<div></div>');
    spyOn(window, '$').and.callFake(function(item) {
      if (item === '.elements') {
        return itemToReturn;
      }
    });

    var result = testableCode1.test();

    expect(result).toEqual(1);
  });
});
Enter fullscreen mode Exit fullscreen mode

Refactor

Now, with these tests in place, we can refactor the code with a level of confidence that the functionality will remain the same.

Here's the refactored testableCode code ...

const testableCode2 = {
  test: function() {
    var elements = $('.elements');
    return testableCode2.runTest(elements);
  },
  runTest: function(items) {
    return items.length;
  }
};
Enter fullscreen mode Exit fullscreen mode

Rework Tests

Given this refactor, the old test put into place should still pass and we can now write tests without the spyOn being used ...

describe('post-refactor', function() {
  it('test before refactor', function() {
    var itemToReturn = $('<div></div>');
    spyOn(window, '$').and.callFake(function(item) {
      if (item === '.elements') {
        return itemToReturn;
      }
    });

    var result = testableCode2.test();

    expect(result).toEqual(1);
  });

  it('test after refactor', function() {
    var itemToReturn = $('<div>');
    var result = testableCode2.runTest(itemToReturn);
    expect(result).toEqual(1);    
  });
});
Enter fullscreen mode Exit fullscreen mode

Conclusion

Now that the code has been refactored, the initial test could easily be removed, making the tests much cleaner and simpler to work with.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .