【问题标题】:Karma + Jasmine testing async methodsKarma + Jasmine 测试异步方法
【发布时间】:2018-08-08 03:58:11
【问题描述】:

我有以下控制器:

export default function($scope, $state, $http) {
    $scope.login = () => {
        $scope.loginFailed = false;

        const postReq: object = {
            method: 'POST',
            url: `/login`,
            data: {},
        }

        try {
            console.log('$scope.login');

            const response = await $http(postReq);

            console.log('login done');

            console.log('$state.go');

            $state.go('dashboard');

            return true;
        } catch(err) {
            console.error(err);
            $scope.loginFailed = true;

            return false;
        }
    };
}

我正在尝试用 Jasmine 测试这个方法

it('change state to dashboard', async (done) => {
    $httpBackend.expectPOST('/login', undefined).respond(201, { rmId: 123123 });

    await $scope.login();
    expect($state.current.name).toBe('dashboard');
});

我的测试结果如下:

LOG: '$scope.login' PhantomJS 2.1.1 (Mac OS X 0.0.0) $scope.login 将状态更改为仪表板失败

现在看来,Jasmine 并没有等待 $http 调用完成。 (当我在浏览器中手动测试时效果很好)

有没有更好的方法来正确测试异步方法?

【问题讨论】:

    标签: javascript jasmine karma-jasmine


    【解决方案1】:

    您不需要等待。您只需要在期望测试之前刷新后端模拟 您的登录功能必须更改如下:

    $scope.login = () => {
           return new Promise((resolve, reject) => {
              $scope.loginFailed = false;
    
            const postReq = {
                method: 'POST',
                url: `/login`,
                data: {},
            }
    
            const response = $http(postReq).then(
              (success) => {
                  $state.go('dashboard');
                  resolve(true);
                },
                (error) => {
                   $scope.loginFailed = true;
    
                reject(false);
                });
           });
        };
    

    你的测试就像:

    it('change state to dashboard', async (done) => {
        const  backendMock = $httpBackend;
        backendMock.expectPOST('/login').respond(201, { rmId: 123123 });
        $scope.login().then((response) => {
          expect($state.current.name).toBe('dashboard');
          done();
        });
        backendMock.flush();
    
    });
    

    【讨论】:

    • 所以我添加了flush,但我的日志是一样的。 $http 调用似乎从未通过。
    • 您是否创建了变量并设置了 $httpBackend 而不仅仅是 $httpBackend.flush();
    • 我也认为您在控制器上放置的 await 不是一个好主意。最好在 then() 回调中捕获承诺,并在有响应时做你想做的事情
    • $scope.login().then(() => console.log('ok')); $httpBackend.flush(); 我以前试过这个,但我觉得我的login() 方法永远不会完全执行。它永远不会过去await $http(postReq);
    • 但你的反应是正确的,似乎 Angular 不能与 async / await 一起正常工作。我已将其还原为一个简单的承诺,并且能够对其进行测试
    【解决方案2】:

    您需要在编写断言之前使用$httpBackend.flush();。在您的 expect 语句之前添加此行。它应该工作..

    【讨论】:

    • 我刚试过,但结果是一样的。我从来没有看到我的 $scope.login 方法的完整记录。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-21
    • 2018-02-15
    • 2015-12-07
    • 1970-01-01
    • 2018-10-04
    • 2014-12-07
    相关资源
    最近更新 更多