【问题标题】:Angular/Karma - "Unexpected Request" error when expected and observed request are the sameAngular/Karma - 预期和观察到的请求相同时出现“意外请求”错误
【发布时间】:2014-11-26 17:12:10
【问题描述】:

我正在对控制器的方法进行单元测试。我的应用程序在应用程序启动时触发了一些 GET 请求,并且在我运行测试时遇到了意外的请求错误。

这是我的控制器的登录方法。注意:我使用的是 angular classy(因此是非标准语法):

login: function() {
    var self = this,
        params,
        loginSuccess,
        user;

    if (self.$.user.email === '' || self.$.user.password === '') {

      self.$notification.alert({
        title: "Error",
        message: "Email and password can't be blank!"
      });

    } else {

      params = {
         user: self.$.user,
         position: self.Geolocation.currentPosition
      };

      self.$session.login(params).then(loginSuccess);

    }
};

这是测试:

describe("LoginController", function() {
  var scope, $rootScope, createController, $controller,
      $httpBackend, $session, session, $notification;

  var emptyCredentials = {
    email: "bleh",
    password: ""
  };

  beforeEach(angular.mock.module('myapp'));

  beforeEach(inject(function($injector){

    jasmine.getJSONFixtures().fixturesPath='base/unit/fixtures';

    $httpBackend = $injector.get("$httpBackend");

    $httpBackend
      .when('GET', 'http://myapp.com:3000/api/v2/apps/3?app_id=3')
      .respond(200, getJSONFixture('apps.json'));
    $httpBackend
      .when('GET', 'http://myapp.com:3000/api/v2.2/locations?app_id=3')
      .respond(200, getJSONFixture('locations.json'));
    $httpBackend
      .when('GET', 'http://myapp.com:3000/api/v2/users/me?app_id=3')
      .respond(200, getJSONFixture('me.json'));

    $session = $injector.get("$session");

    // mock session so that session.loggedIn doesn't return true
    // on subsequent tests
    session = {
      setUser: function() {
      },
      loggedIn: function() {
        return false;
      },
      authPath: function() {
        return false;
      },
      login: $session.login
    };

    $rootScope = $injector.get("$rootScope");
    $controller = $injector.get("$controller");
    $notification = $injector.get("$notification");
    scope = $rootScope.$new();

    createController = function () {
      return $controller('LoginController', {
        $scope: scope,
        $session: session,
        $notification: $notification
      });
    };

    // spies on $notification.alerts
    spyOn($notification, 'alert');

  }));

  afterEach (function () {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();

    $httpBackend.resetExpectations();

  });

  it('should show alert on empty login credentials', function() {

    $httpBackend.expectGET('http://myapp.com:3000/api/v2/apps/3?app_id=3');
    $httpBackend.expectGET('http://myapp.com:3000/api/v2.2/locations?app_id=3');
    $httpBackend.expectGET('http://myapp.com:3000/api/v2/users/me?app_id=3');

    var controller = createController();
    scope.user = emptyCredentials;
    scope.login();

    $httpBackend.flush();

    expect($notification.alert).toHaveBeenCalledWith({
      title: "Error",
      message: "Email and password can't be blank!"
    });

  });

当我运行 karma 时,出现以下错误:

Error: Unexpected request: GET http://myapp.com:3000/api/v2/apps/3?app_id=3
Expected GET http://myapp.com:3000/api/v2/apps/3?app_id=3
    at $httpBackend (/Users/myapp/vendor/angular-mocks/angular-mocks.js:1178:9)
    at sendReq (/Users/myapp/vendor/angular/angular.js:8315:9)
    at serverRequest (/Users/myapp/vendor/angular/angular.js:8049:16)
    at wrappedCallback (/Users/myapp/vendor/angular/angular.js:11520:81)
    at wrappedCallback (/Users/myapp/vendor/angular/angular.js:11520:81)
    at /Users/myapp/vendor/angular/angular.js:11606:26
    at Scope.$eval (/Users/myapp/vendor/angular/angular.js:12632:28)
    at Scope.$digest (/Users/myapp/vendor/angular/angular.js:12444:31)
    at Function.$httpBackend.flush (/Users/myapp/vendor/angular-mocks/angular-mocks.js:1438:16)
    at null.<anonymous> (/Users/myapp/test/unit/controllers/login_controller.test.js:104:18)
Error: Unexpected request: GET http://myapp.com:3000/api/v2.2/locations?app_id=3
Expected GET http://myapp.com:3000/api/v2/apps/3?app_id=3
    at $httpBackend (/Users/myapp/vendor/angular-mocks/angular-mocks.js:1178:9)
    at sendReq (/Users/myapp/vendor/angular/angular.js:8315:9)
    at serverRequest (/Users/myapp/vendor/angular/angular.js:8049:16)
    at wrappedCallback (/Users/myapp/vendor/angular/angular.js:11520:81)
    at wrappedCallback (/Users/myapp/vendor/angular/angular.js:11520:81)
    at /Users/myapp/vendor/angular/angular.js:11606:26
    at Scope.$eval (/Users/myapp/vendor/angular/angular.js:12632:28)
    at Scope.$digest (/Users/myapp/vendor/angular/angular.js:12444:31)
    at Function.$httpBackend.verifyNoOutstandingExpectation (/Users/myapp/vendor/angular-mocks/angular-mocks.js:1470:16)
    at null.<anonymous> (/Users/myapp/test/unit/controllers/login_controller.test.js:75:18)

login_controller.test.js 的第 104 行仅供参考是$httpBackend.flush()。 login_controller.test.js 的第 75 行是$httpBackend.verifyNoOutstandingExpectation()

我相信 $httpBackend.when() 在应用程序启动之前被调用(因此在应用程序启动的请求被触发之前),但也许这不是真的。奇怪的是,错误报告它发现了一个意外的 XXX 请求,并且下一行说它期望一个相同路径的请求!所以不知道为什么会这样。

运行 Angular 1.2.21,Angular Mocks 1.2.21

谁能向我解释为什么我会看到这个错误,以及我可以做些什么来正确刷新和处理这些请求?

谢谢。

【问题讨论】:

    标签: javascript angularjs unit-testing karma-runner


    【解决方案1】:

    我知道发生了什么:

    事实证明,供应商插件正在扩展本机 String 对象,重新定义了 match() 方法。这与 angular-mocks 将期望值与请求进行比较的方式相冲突,因此错误地抛出了错误。

    如果您碰巧遇到此问题(预期请求和观察到的请求相同),请查找扩展本机 String 对象的插件或库。

    例如,Mootools 会执行此操作并会导致此问题。

    【讨论】:

      【解决方案2】:

      问题在于,现在 $http 甚至对请求拦截器也使用了 Promise,因此验证是在 $httpBackend 获取请求之前发生的。尝试添加 $rootScope.$digest();你会得到“没有更多的请求”。

      参考:https://github.com/angular/angular.js/issues/5453

      【讨论】:

      • 我在 it() 回调的开头添加了 $rootScope.$digest:it('should show alert on empty login credentials', function() { $rootScope.$digest(); ...——我仍然收到一个意外请求错误:Error: Unexpected request: GET http://myapp.com:3000/api/v2/apps/3?app_id=3 No more request expected,这无助于我处理这些要求。关于如何让测试正确预期和处理请求的想法?
      • Digest 将尝试执行队列中的所有回调。所以在$httpBackend.flush() 之后你必须在期望之前执行$rootScope.$digest()
      • @VamshiSuram 你确定 $httpBackend.flush();需要跟一个 $rootScope.$digest() 吗?没有我的测试就可以正常工作。
      • 已经有一段时间了。我想我指的是这样的测试过程:. $httpBackend.flush() - 后端会响应。 $rootScope.$digest() - 承诺已解决。 expect(a).toEqual('something') - 期望已经过测试。
      猜你喜欢
      • 2015-07-08
      • 2014-06-19
      • 1970-01-01
      • 1970-01-01
      • 2016-01-17
      • 1970-01-01
      • 2020-01-13
      • 1970-01-01
      • 2019-07-17
      相关资源
      最近更新 更多