AngularJS 测试 - 来自服务的承诺无法解决

Posted

技术标签:

【中文标题】AngularJS 测试 - 来自服务的承诺无法解决【英文标题】:AngularJS testing - promise from service won't resolve 【发布时间】:2019-09-01 05:36:22 【问题描述】:

我有一个返回承诺的服务。我正在尝试为它编写一个单元测试,但有问题。我的第一个实现:

describe('Application Button Status Service', () => 
    let applicationBtnStatusService;

    beforeEach(() => 
      TestHelper().initApplicationModule();

      inject(($injector) => 
        applicationBtnStatusService = $injector.get('MwcApplicationBtnStatusService');
      );
    );

    it('CLDTX-22772: getStatusForAddDiskCloneBtn should return a promise resolving a button status', () => 
      const spy = spyOn(applicationBtnStatusService, 'getStatusForAddDiskCloneBtn').and.callThrough();

      const deferrdPromise = applicationBtnStatusService.getStatusForAddDiskCloneBtn(applicationDataMock);
      deferrdPromise.then((resolvedBtnStatus) => 
        expect(resolvedBtnStatus).toBeTruthy();
        expect(resolvedBtnStatus.btnDisabled).toBeDefined();
        expect(resolvedBtnStatus.disablingMessage).toBeDefined();
        expect(resolvedBtnStatus.btnDisabled).toBe(true);
        expect(resolvedBtnStatus.disablingMessage).toBe('Instance is running and in compatibility mode');
      );
    );
  ,
);

这通过了,但它没有执行承诺的.then。这是我的第二个实现:

describe('Application Button Status Service', () => 
    let applicationBtnStatusService, rootScope, btnStatus;

    beforeEach(async (done) => 
      TestHelper().initApplicationModule();
      inject((
        MwcApplicationBtnStatusService: ApplicationBtnStatusService,
        $rootScope
      ) => 
        applicationBtnStatusService = MwcApplicationBtnStatusService;
        rootScope = $rootScope;
      );

      const resolvedBtnStatus = await applicationBtnStatusService.getStatusForAddDiskCloneBtn(applicationDataMock);
      rootScope.$apply();
      console.log('promise resolved', resolvedBtnStatus, '\n\n\n\n\n\n\n');
      btnStatus = resolvedBtnStatus;
      done();
    );

    it('CLDTX-22772: getStatusForAddDiskCloneBtn should return a promise resolving a button status', (done) => 
      console.log('btnStatus', btnStatus);
      expect(btnStatus).toBeDefined();
      done();
    );
  
);

第二个失败并出现此错误:

HeadlessChrome 0.0.0 (Windows 10 0.0.0) Application Button Status Service CLDTX-22772: getStatusForAddDiskCloneBtn should return a promise resolving a button status FAILED
        Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
        Expected undefined to be defined.
            at UserContext.<anonymous> (app/application/services/application-btn-status-service/application-btn-status-service.spec.js:229:27)
HeadlessChrome 0.0.0 (Windows 10 0.0.0): Executed 269 of 269 (1 FAILED) (7.443 secs / 7.383 secs)
TOTAL: 1 FAILED, 268 SUCCESS
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! cloudistics-mwc@0.0.1 test: `npm run generate-responses && karma start karma.config.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the cloudistics-mwc@0.0.1 test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\Ryan.Waite\AppData\Roaming\npm-cache\_logs\2019-04-10T17_01_55_717Z-debug.log

无论我如何更改默认间隔,操作所需的时间都会比它长。

【问题讨论】:

asyncawait 运算符使用 ES6 承诺。 ES6 Promise 没有与 AngularJS 摘要循环集成。只有在 AngularJS 执行上下文中应用的操作才能受益于 AngularJS 数据绑定、异常处理、属性监视等。避免 ES6 承诺并仅使用 $q 服务承诺。 @georgeawg 嘿,该服务确实返回了 $q 承诺。当我 console.log deferredPromise 时,我可以在终端中看到它;它有价值。只是它没有解决。不知道如何解决。 【参考方案1】:

在您的第一个解决方案中,请注入$rootScope,然后在异步调用后调用$rootScope.$digest

it('CLDTX-22772: getStatusForAddDiskCloneBtn should return a promise resolving a button status', (done) => 
      const spy = spyOn(applicationBtnStatusService, 'getStatusForAddDiskCloneBtn').and.callThrough();

      const deferrdPromise = applicationBtnStatusService.getStatusForAddDiskCloneBtn(applicationDataMock);
      deferrdPromise.then((resolvedBtnStatus) => 
        expect(resolvedBtnStatus).toBeTruthy();
        expect(resolvedBtnStatus.btnDisabled).toBeDefined();
        expect(resolvedBtnStatus.disablingMessage).toBeDefined();
        expect(resolvedBtnStatus.btnDisabled).toBe(true);
        expect(resolvedBtnStatus.disablingMessage).toBe('Instance is running and in compatibility mode');
        done();
      );
      $rootScope.$digest();
    );

【讨论】:

嘿,这对我不起作用。我仍然收到异步错误。 你确定你的函数返回promise吗?您能否进入您的覆盖率报告并检查从服务功能执行的代码?

以上是关于AngularJS 测试 - 来自服务的承诺无法解决的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS 承诺处理 CoffeeScript 类

在处理来自 AngularJS 承诺的错误时,使用 `.catch(function(error)` 和 `function(err Response)` 有啥区别? [重复]

在 AngularJS 单元测试中模拟 $modal

未捕获(承诺):TypeError:无法读取未定义的属性“创建”(离子 3.9,Angularjs 5.0.3)

拒绝承诺时AngularJS服务重试

在 AngularJS 服务中缓存一个承诺对象