69

How do you unit test a filter in Angular?

SoEzPz
  • 14,958
  • 8
  • 61
  • 64
eddiec
  • 7,608
  • 5
  • 34
  • 36

5 Answers5

121

Inject $filter and then call it with $filter('filterName')(input, options);

So to test the equivalent of this template {{ foo | testFilter:capitalize }}

describe('The test filter', function () {
  'use strict'; 

  var $filter;

  beforeEach(function () {
    module('myTestFilterModule');

    inject(function (_$filter_) {
      $filter = _$filter_;
    });
  });

  it('should capitalize a string', function () {
    // Arrange.
    var foo = 'hello world', result;

    // Act.
    result = $filter('testFilter')(foo, 'capitalize');

    // Assert.
    expect(result).toEqual('HELLO WORLD');
  });
});
danwellman
  • 9,068
  • 8
  • 60
  • 88
eddiec
  • 7,608
  • 5
  • 34
  • 36
  • If you use mocha/chai you just change the expect to: expect(result).to.equal('HELLO WORLD'); – Simon Dragsbæk Dec 10 '15 at 12:20
  • 1
    I do not know if I follow 'capitalize' after foo. Can someone explain to me the purpose? – Winnemucca Apr 14 '16 at 20:08
  • 1
    I've added the example template syntax so you can see where it comes from. It's ultimately just a filter argument, some filters don't have these arguments but makes the answer more complete IMO – eddiec Apr 17 '16 at 14:43
  • this works for me on chrome but not on firefox or phantomjs. – artdias90 Oct 12 '16 at 16:23
12

You can inject $filter and load the filter that you want to test. Then you pass the parameter to be filtered through the filter you have injected and you 'expect' what you needed. Here is an example:

describe('Filter test', function(){

  var filter;

  beforeEach(function(){
    module.apply(moduleName);

    inject(function($injector){
      filter = $injector.get('$filter')('nameOfTheFilter');
    });
  });

  it('should filter the parameters passed', function(){
    expect(filter(parameterToBeFiltered)).toBe(Result);
  });
});
Ithilon
  • 412
  • 2
  • 6
3

Filter can be injected right into test (have found a snippet here)

  describe('myApp', function () {

    beforeEach(function () {
      module('myApp');
    });

    it('has a bool filter', inject(function($filter) {
      expect($filter('bool')).not.toBeNull();
    }));

    it("should return true empty array ", inject(function (boolFilter) {
      expect(boolFilter(true)).toBeTruthy();
    }));

  });

In this example filter name is 'bool', in order to inject this filter you shall use 'bool' + 'Filter' = 'boolFilter'

Valeriy
  • 126
  • 4
  • You should not rely on actual code, mock it out ````` module('myApp'); ````` You are calling the whole application which means running actual code. – Peter MK Jan 15 '16 at 11:07
3

Here you have a runnable filter test example.

angular.module('myModule', []).filter('multiplier', function() {
  return function(number, multiplier) {
    if (!angular.isNumber(number)) {
      throw new Error(number + " is not a number!");
    }
    if (!multiplier) {
      multiplier = 2;
    }
    return number * multiplier;
  }
});

describe('multiplierFilter', function() {
  var filter;

  beforeEach(function() {
    module('myModule');
    inject(function(multiplierFilter) {
      filter = multiplierFilter;
    });
  });

  it('multiply by 2 by default', function() {
    expect(filter(2)).toBe(4);
    expect(filter(3)).toBe(6);
  });

  it('allow to specify custom multiplier', function() {
    expect(filter(2, 4)).toBe(8);
  });

  it('throws error on invalid input', function() {
    expect(function() {
      filter(null);
    }).toThrow();
  });
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine-html.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/boot.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular-mocks.js"></script>

Note: this answer was created after the SO Documentation Sunset based on the AngularJS unit test filter example and a suggestion on Meta that all valuable documentation content should be converted into answers.

fracz
  • 20,536
  • 18
  • 103
  • 149
2

There are other ways to test a filter besides injecting the actual $filterservice.

Example:

describe('FILTER: myFilterName', function(){ // You can put anything in the string here,
                                             // I like declaring FILTER: myFilterName, but it 
                                             // could be just the filter name.

var myTestTheFilterVariableName;
// This variable does not have to match the describe name, call it what you wish,
// but use this variable in any it blocks below.

beforeEach(module('obsidian')); // Include app - boilerplate.

beforeEach(inject(function(actualFilterNameFilter){
// If your test variable name is the same as 'actualFilterNameFilter' then you would 
// use this name '_actualFilterNameFilter_' with underscores; The Angularjs injector will
// remove the underscores for you.
// IMPORTANT PART: The important part here is the trailing 'Filter' name. This is how Angularjs
// Knows to grab the filter title "actualFilterName" in this case.

  myTestTheFilterVariableName = actualFilterNameFilter;

})); // This is where you actually include the filter for testing.
     // Use the underscores if your variable name is the exact same as the injected parameter.
     // This is where you would use your variable name from above.


  it('should do something here', function(){
    expect(myTestTheFilterVariableName(filterParameter)).toEqual(expectedResultHere);
  });
});
danwellman
  • 9,068
  • 8
  • 60
  • 88
SoEzPz
  • 14,958
  • 8
  • 61
  • 64