Testing AngularJS $resource

How to test a $resource with Jasmine in AngularJS

HTML

<script src="https://raw.github.com/pivotal/jasmine/master/lib/jasmine-core/jasmine.js"></script>
<script src="https://raw.github.com/pivotal/jasmine/master/lib/jasmine-core/jasmine-html.js"></script>
<script ng:autobind src="http://docs-next.angularjs.org/angular-0.10.1.min.js"></script>
<script src="https://raw.github.com/angular/angular-seed/v0.10.x/test/lib/angular/angular-mocks.js"></script>

CSS

body {
  font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
}


.jasmine_reporter a:visited, .jasmine_reporter a {
  color: #303; 
}

.jasmine_reporter a:hover, .jasmine_reporter a:active {
  color: blue; 
}

.run_spec {
  float:right;
  padding-right: 5px;
  font-size: .8em;
  text-decoration: none;
}

.jasmine_reporter {
  margin: 0 5px;
}

.banner {
  color: #303;
  background-color: #fef;
  padding: 5px;
}

.logo {
  float: left;
  font-size: 1.1em;
  padding-left: 5px;
}

.logo .version {
  font-size: .6em;
  padding-left: 1em;
}

.runner.running {
  background-color: yellow;
}


.options {
  text-align: right;
  font-size: .8em;
}




.suite {
  border: 1px outset gray;
  margin: 5px 0;
  padding-left: 1em;
}

.suite .suite {
  margin: 5px; 
}

.suite.passed {
  background-color: #dfd;
}

.suite.failed {
  background-color: #fdd;
}

.spec {
  margin: 5px;
  padding-left: 1em;
  clear: both;
}

.spec.failed, .spec.passed, .spec.skipped {
  padding-bottom: 5px;
  border: 1px solid gray;
}

.spec.failed {
  background-color: #fbb;
  border-color: red;
}

.spec.passed {
  background-color: #bfb;
  border-color: green;
}

.spec.skipped {
  background-color: #bbb;
}

.messages {
  border-left: 1px dashed gray;
  padding-left: 1em;
  padding-right: 1em;
}

.passed {
  background-color: #cfc;
  display: none;
}

.failed {
  background-color: #fbb;
}

.skipped {
  color: #777;
  background-color: #eee;
  display: none;
}


/*.resultMessage {*/
  /*white-space: pre;*/
/*}*/

.resultMessage span.result {
  display: block;
  line-height: 2em;
  color: black;
}

.resultMessage .mismatch {
  color: black;
}

.stackTrace {
  white-space: pre;
  font-size: .8em;
  margin-left: 10px;
  max-height: 5em;
  overflow: auto;
  border: 1px inset red;
  padding: 1em;
  background: #eef;
}

.finished-at {
  padding-left: 1em;
  font-size: .6em;
}

.show-passed .passed,
.show-skipped .skipped {
  display: block;
}


#jasmine_content {
 ...

JavaScript

angular.service('RestCall', function ($resource) {
  // No need for "query: {method:'GET', isArray:true}",
  // it's the default.
  return $resource('/rest/:action/:file');

}, { $inject: ['$resource'] });

function ProjectListCtrl(RestCall) {
  this.projects = RestCall.query({
    action: 'project',
    file: 'project_index'
  });
  this.page = 'bid';

}

beforeEach(function () {
  this.addMatchers({
    toEqualData: function (expected) {
      return angular.equals(this.actual, expected);
    }
  });
});

describe('ProjectListCtrl', function () {
  var scope = null, $browser = null, ctrl = null,
    projects = [{ name: 'p1' }, { name: 'p2' }];

  function newController() {
    $browser.xhr.
      expectGET('/rest/project/project_index').
      respond(JSON.stringify(projects));
    ctrl = scope.$new(ProjectListCtrl);
  }

  beforeEach(function () {
    scope = angular.scope();
    $browser = scope.$service('$browser');
    ctrl = null;
  });

  afterEach(function () {
    expect($browser.xhr.requests.length).
      toBe(0, 'You have not flushed the requests.');
  });

  describe('inizialization', function () {
    it('should fetch project index', function () {
      newController();
      $browser.xhr.flush();
      expect(ctrl.projects).toEqualData(projects);
    });
  });

});

// run the tests
jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
jasmine.getEnv().execute();