docs: function(promise, expectedState, opt_expectedData, opt_util, opt_customEqualityTesters) {
      var info = {};
  
      promise.then(
        function(data) {
          info.actualData = data;
          info.actualState = PROMISE_STATE.RESOLVED;
        },
        function(data) {
          info.actualData = data;
          info.actualState = PROMISE_STATE.REJECTED;
        });
  
      $scope.$apply(); // Trigger Promise resolution
  
      if (!info.actualState) {
        // Trigger $httpBackend flush if any requests are pending
        if ($httpBackend) {
          try {
            $httpBackend.flush();
          } catch (err) {
            if (err.message !== 'No pending request to flush !') {
              throw err;
            }
          }
        }
  
        // Trigger $timeout flush if any deferred tasks are pending
        if ($timeout) {
          try {
            $timeout.flush();
          } catch (err) {
            if (err.message !== 'No deferred tasks to be flushed') {
              throw err;
            }
          }
        }
  
        // Trigger $interval flush if any deferred tasks are pending
        if ($interval) {
          try {
            // Flushing $interval requires an amount of time, I believe this number should flush pretty much anything useful...
            $interval.flush(100000);
          } catch (err) {
            if (err.message !== 'No deferred tasks to be flushed') {
              throw err;
            }
          }
        }
      }
  
      info.message = 'Expected ' + info.actualState + ' to be ' + expectedState;
      info.pass = info.actualState === expectedState;
  
      // If resolve/reject expectations have been made, check the data..
      if (opt_expectedData !== undefined && info.pass) {
  
        // Jasmine 2
        if (opt_util) {
          // Detect Jasmine's asymmetric equality matchers and use Jasmine's own equality test for them
          // Otherwise use Angular's equality check since it ignores properties that are functions
          if (opt_expectedData && opt_expectedData.asymmetricMatch) {
            info.pass = opt_util.equals(info.actualData, opt_expectedData, opt_customEqualityTesters);
          } else {
            info.pass = angular.equals(info.actualData, opt_expectedData);
          }
  
        // Jasmine 1.3
        } else {
          if (opt_expectedData instanceof jasmine.Matchers.Any ||
              opt_expectedData instanceof jasmine.Matchers.ObjectContaining) {
            info.pass = opt_expectedData.jasmineMatches(info.actualData);
          } else {
            info.pass = angular.equals(info.actualData, opt_expectedData);
          }
        }
  
        var actual = jasmine.pp(info.actualData);
        var expected = jasmine.pp(opt_expectedData);
  
        info.message = 'Expected ' + actual + ' to be ' + expected;
      }
  
      return info;
    }