javascript - 如何在 AngularJS 中使用 $http.jsonp 对函数进行单元测试?

标签 javascript angularjs jasmine karma-runner karma-jasmine

这是我的 Controller 的一部分:

    $scope.isLoggedIn = function () {
        return Boolean($sessionStorage.isLoggedIn);
    };

    $scope.login = function () {
        //If the browser fills in the username and password field then angular's model will not be updated so we need
        //to manually pull them out of the DOM :(. See this issue for details: https://github.com/angular/angular.js/issues/1460
        var username = $('#usernameInput').val();
        var password = $('#passwordInput').val();
        $scope.loginErrMsg = null;

        $http.jsonp("http://ldap-auth.otpp.me" + '/login?callback=JSON_CALLBACK&username=' + encodeURIComponent(username) + '&password=' + encodeURIComponent(password))
            .success(function (data, isLoggedIn) {
                // This app is for internal use only, security is not a major concern.
                // So using sessionStorage to store the login status is OK.
                $sessionStorage.displayName = data.displayName;
                $sessionStorage.isLoggedIn = true;
            })
            .error(function () {
                $scope.loginErrMsg = "Invalid username or password";
            });
    };

这是我的测试:

describe('Controller: MainCtrl', function () {

// load the controller's module
beforeEach(module('uiappApp'));

var MainCtrl,
    $httpBackend,
    scope;

// Initialize the controller and a mock scope
beforeEach(inject(function ($injector, $controller, $rootScope) {
    scope = $rootScope.$new();
    MainCtrl = $controller('MainCtrl', {
        $scope: scope
    });
    $httpBackend = $injector.get('$httpBackend');

}));
it('should login', function () {
    var isLoggedIn = scope.isLoggedIn();
    expect(isLoggedIn).toBe(false);

    var username = $('<input type="text" id="usernameInput"/>');
    var password = $('<input type="text" id="passwordInput"/>');
    $('body').html('<div>')
        .find('div')
        .append(username)
        .append(password);
    username.val('username');
    password.val('password');
    var response =  $httpBackend.expectJSONP('http://ldap-auth.otpp.me/login?callback=JSON_CALLBACK&username=username&password=password');
    response.respond({displayName: 'userX'}, {'A-Token': 'xxx'});
    scope.login();
    expect(scope.isLoggedIn()).toEqual(true);
    $('body').empty();
    });
});

但是测试总是失败(预期为 false to equal true.)。看来我没有让 $httpBackend 工作。但我无法弄清楚哪里错了。基本上我想模拟 $http.jsonp() 响应以在单元测试时提供模拟的 json,然后测试用户登录。

如果您能提供帮助,非常感谢!

@HackedByChinese 按照你的步骤,我有:

it('should login', function () {
    var isLoggedIn = scope.isLoggedIn();
    expect(isLoggedIn).toBe(false);

    var username = $('<input type="text" id="usernameInput"/>');
    var password = $('<input type="text" id="passwordInput"/>');
    $('body').html('<div>')
        .find('div')
        .append(username)
        .append(password);
    username.val('username');
    password.val('password');
    var response =  $httpBackend.expectJSONP('http://ldap-auth.otpp.me/login?callback=JSON_CALLBACK&username=username&password=password');
    response.respond({displayName: 'userX'}, {'A-Token': 'xxx'});
    scope.login();
    $httpBackend.flush();
    expect(scope.isLoggedIn()).toEqual(true);
    $('body').empty();
});

但我收到以下错误信息:

    Error: Unexpected request: GET views/main.html
No more request expected
    at $httpBackend (C:/repo/docserver-ui/UIApp/app/bower_components/angular-mocks/angular-mocks.js:1177:9)
    at sendReq (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:7967:9)
    at $get.serverRequest (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:7708:16)
    at deferred.promise.then.wrappedCallback (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:11100:81)
    at deferred.promise.then.wrappedCallback (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:11100:81)
    at C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:11186:26
    at Scope.$get.Scope.$eval (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:12175:28)
    at Scope.$get.Scope.$digest (C:/repo/docserver-ui/UIApp/app/bower_components/angular/angular.js:12004:31)
    at Function.$httpBackend.flush (C:/repo/docserver-ui/UIApp/app/bower_components/angular-mocks/angular-mocks.js:1435:16)
    at null.<anonymous> (C:/repo/docserver-ui/UIApp/test/spec/controllers/main.js:43:22)
Process finished with exit code 0

这是我的部分 html:

            <form class="navbar-form navbar-right" role="form" ng-show="!isLoggedIn()">
                <p class="navbar-text" id="loginErrMsg">{{loginErrMsg}}</p>
                <div class="form-group">
                    <input type="text" placeholder="User Name" id="usernameInput"
                           class="form-control"
                           ng-class="{'error-fields': loginErrMsg}">
                </div>
                <div class="form-group">
                    <input type="password" placeholder="Password" id="passwordInput" class="form-control" ng-class="{'error-fields': loginErrMsg}">
                </div>
                <button type="submit" class="btn btn-success" ng-click="login()">Sign in</button>
        </form>

最佳答案

在调用 scope.login() 之后和 expect(...) 之前,您需要调用 $httpBackend.flush() 使其响应指定的期望。

这不是特定于 JSONP,而是一般的单元测试 $http 调用。

总而言之,以下是发出 $http 请求的单元测试代码的步骤:

  1. 使用 $httpBackend 设置您的期望。
  2. 调用进行 $http 调用的代码。
  3. 调用 $httpBackend.flush() 使其以您设置的期望响应任何待处理的请求。
  4. 做出测试断言。

参见 docs关于冲洗。

关于javascript - 如何在 AngularJS 中使用 $http.jsonp 对函数进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24293643/

相关文章:

javascript - 为什么我的 angular-bootstrap 选项卡不呈现?

javascript - Jasmine /Angular Testing 语法混淆

angular - 如何修复 beforeEachProviders(在 RC4 上已弃用)

javascript - 我应该如何使用 requireJs 编写规范文件?

javascript - Angular $routeProvider - 以编程方式添加路由解析

javascript - 多个 HTML 文件仅链接到一个 Javascript 文件

html - 如何添加:active to menu element dynamically

javascript - Angular 的替代方案在旧版本中嵌入后备内容

javascript - 一致的逐渐淡化的文字效果

javascript - 为什么无法通过javascript访问css中的z-index