Angularjs 异步ng模型和宽度don';t返回初始值(Karma Jasmine)

Angularjs 异步ng模型和宽度don';t返回初始值(Karma Jasmine),angularjs,unit-testing,asynchronous,karma-jasmine,angularjs-ng-model,Angularjs,Unit Testing,Asynchronous,Karma Jasmine,Angularjs Ng Model,我正在从事AngularJS 1.7项目,该项目需要karma jasmine测试 到目前为止,我没有遇到任何问题,直到我使用控制器指定的ng模型测试了一个组件。我读到ng模型变得异步,但我尝试了从done()到setTimeout、$digest等所有解决方案,但似乎仍然无法获得初始值集。。。我也有同样的问题,得到一个组件渲染后的宽度,因为动画的时间 这是我的代码: component.html <div class="test-component"> <ul>

我正在从事AngularJS 1.7项目,该项目需要karma jasmine测试

到目前为止,我没有遇到任何问题,直到我使用控制器指定的ng模型测试了一个组件。我读到ng模型变得异步,但我尝试了从done()到setTimeout、$digest等所有解决方案,但似乎仍然无法获得初始值集。。。我也有同样的问题,得到一个组件渲染后的宽度,因为动画的时间

这是我的代码:

component.html

<div class="test-component">
  <ul>
    <li
      style="display: inline-block; margin-bottom: 12px;"
      ng-repeat="device in $ctrl.devices | orderBy:'-numbersCount'"
    >
      <div class="test-component__container">
        <div class="test-component__progress"></div>
      </div>
      <div class="test-component__info">
        <div class="test-component__label">{{ device.label }}</div>
        <div class="test-component__numbers">
          <ng-pluralize
            class="test-component__numbers-count"
            count="device.numbersCount"
            when="{'1': '1 Number','other': '{} numbers'}"
          ></ng-pluralize>
        </div>
      </div>
      <md-switch ng-model="$ctrl.toggleObj.isActive" ng- 
      disabled="$ctrl.toggleObj.isDisabled" ng-class="[' 
      toggle__'+$ctrl.toggleObj.type]"
      aria-label="$ctrl.toggleObj.label" md-no-ink>
      </md-switch>
    </li>
  </ul>
</div>
组件.scss

import anime from '../../../node_modules/animejs/lib/anime.es';

// CONSTANTS
const ANIMATION_DURATION = 600;
const ANIMATION_OFFSET = 500;

export class TestComponentController {
  constructor($element) {
    'ngInject';
    this.$element = $element[0];
  }

  $onInit() {
    this.devices = this.content;
    this.toggleObj = this.configuration;
    this.biggestNumber = Math.max.apply(
      Math,
      this.devices.map(function(el) {
        return el.numbersCount;
      })
    );

    this.startAnimations(this.$element, this.biggestNumber, this);
  }

  startAnimations(currentElement, highest, ctrl) {
    angular.element(() => {
      const progressBars = currentElement.querySelectorAll(
        '.test-component__progress'
      );

      // ANIMATIONS TIMELINE
      const timeline = anime.timeline({
        autoplay: true,
        easing: 'cubicBezier(0.4, 0.0, 0.2, 1)'
      });

      progressBars.forEach((element, index) => {
        if (index !== 0) {
          timeline.add(progressAnimation(element), `-=${ANIMATION_OFFSET}`);
        } else {
          timeline.add(progressAnimation(element));
        }
      });

      // Fill animation
      function progressAnimation(target) {
        return {
          targets: target,
          width: ['0%', `${(ctrl.getNumbers(target) / highest) * 100}%`],
          duration: ANIMATION_DURATION
        };
      }
    });
  }

  // Function to retrieve hostsCount for each progress bar
  getNumbers(target) {
    return Number(
      target.parentNode.nextElementSibling.children[1].innerText[0]
    );
  }
}
@import "variables";

.test-component {
  font-weight: 600;
  font-size: 12px;
  display: table-caption;

  ul {
    padding: 0;
    margin: 0;
    list-style-type: none;
  }

  .test-component__container {
    width: 280px;
    height: 6px;
    border-radius: 2px;
    box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.08);
    background-color: red;

    .test-component__progress {
      height: 6px;
      width: 0%;
      border-radius: 2px;
      background-image: linear-gradient(
        to right,
        rgba(123, 190, 51, 0.6),
        green
      );
    }
  }

  .test-component__info {
    display: flex;
    justify-content: space-between;
  }

  .test-component__label,
  .test-component__info-difference {
    line-height: 1.67;
  }

  .test-component__label {
    color: grey;
  }

  .test-component__numbers {
    display: flex;
    align-items: center;
    justify-content: flex-end;

    .test-component__numbers-count {
      text-align: right;
      color: grey;
    }

    .test-component__info-difference {
      align-items: center;
      display: flex;
      margin-left: 4px;
      color: grey;
    }

    .test-component__info-difference-icon {
      width: 16px;
      height: 16px;
      min-width: 16px;
      min-height: 16px;
      margin: 0;
    }
  }
}
import angular from 'angular';
import { findAllIn } from '../../../public/test-helpers/globals';

import { TestComponentModule } from './test-compnent.module';

describe('TestComponentModule', () => {
  beforeEach(angular.mock.module(TestComponentModule.name));

  it('should exist', () => {
    expect(TestComponentModule).toBeDefined();
  });

  describe('TestComponent component', () => {
    let parentScope, element, originalTimeout;

    beforeEach(inject(($compile, $rootScope, $componentController) => {
      parentScope = $rootScope.$new();
parentScope.configuration = {
        isActive: true,
        isDisabled: false,
        type: 'active'
      };
      parentScope.content = [
        {
          label: 'first label',
          numbersCount: 4
        },
        {
          label: 'second label',
          numbersCount: 2,
        }
      ];

      element = angular.element(
        '<test-component content="content"></test-component>'
      );
      $compile(element)(parentScope);
      $componentController('TestComponent', { $element: element });

      originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
      jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;

      parentScope.$digest();
    }));

    afterEach(function() {
      jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
    });

it('is active and not disabled according to the configuration', () => {
      const expectedActiveState = parentScope.configuration.isActive;
      const expectedDisabledState = parentScope.configuration.isDisabled;

      const activeValue = findIn(element, 'md-switch')[0].getAttribute(
        'ng-model'
      );
      const disabledValue = findIn(element, 'md-switch')[0].getAttribute(
        'ng-disabled'
      );

      setTimeout(function() {
        expect(activeValue).toEqual(expectedActiveState);
        expect(disabledValue).toEqual(expectedDisabledState);
      }, 400);
    });

    it('sets with of progress bar according to highest host', done => {
      const expectedFirstWidth = '100%'; // for the highest host;
      const expectedSecondWidth = '50%'; // for half the hosts

      setTimeout(function() {
        const progressBars = findAllIn(element, '.test-component__progress');
        const firstWidthValue = progressBars[0].style.width;
        const secondWidthValue = progressBars[1].style.width;

        expect(firstWidthValue).toEqual(expectedFirstWidth);
        expect(secondWidthValue).toEqual(expectedSecondWidth);
        done();
      }, 2500);
    });
  });
});
组件规范js

import anime from '../../../node_modules/animejs/lib/anime.es';

// CONSTANTS
const ANIMATION_DURATION = 600;
const ANIMATION_OFFSET = 500;

export class TestComponentController {
  constructor($element) {
    'ngInject';
    this.$element = $element[0];
  }

  $onInit() {
    this.devices = this.content;
    this.toggleObj = this.configuration;
    this.biggestNumber = Math.max.apply(
      Math,
      this.devices.map(function(el) {
        return el.numbersCount;
      })
    );

    this.startAnimations(this.$element, this.biggestNumber, this);
  }

  startAnimations(currentElement, highest, ctrl) {
    angular.element(() => {
      const progressBars = currentElement.querySelectorAll(
        '.test-component__progress'
      );

      // ANIMATIONS TIMELINE
      const timeline = anime.timeline({
        autoplay: true,
        easing: 'cubicBezier(0.4, 0.0, 0.2, 1)'
      });

      progressBars.forEach((element, index) => {
        if (index !== 0) {
          timeline.add(progressAnimation(element), `-=${ANIMATION_OFFSET}`);
        } else {
          timeline.add(progressAnimation(element));
        }
      });

      // Fill animation
      function progressAnimation(target) {
        return {
          targets: target,
          width: ['0%', `${(ctrl.getNumbers(target) / highest) * 100}%`],
          duration: ANIMATION_DURATION
        };
      }
    });
  }

  // Function to retrieve hostsCount for each progress bar
  getNumbers(target) {
    return Number(
      target.parentNode.nextElementSibling.children[1].innerText[0]
    );
  }
}
@import "variables";

.test-component {
  font-weight: 600;
  font-size: 12px;
  display: table-caption;

  ul {
    padding: 0;
    margin: 0;
    list-style-type: none;
  }

  .test-component__container {
    width: 280px;
    height: 6px;
    border-radius: 2px;
    box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.08);
    background-color: red;

    .test-component__progress {
      height: 6px;
      width: 0%;
      border-radius: 2px;
      background-image: linear-gradient(
        to right,
        rgba(123, 190, 51, 0.6),
        green
      );
    }
  }

  .test-component__info {
    display: flex;
    justify-content: space-between;
  }

  .test-component__label,
  .test-component__info-difference {
    line-height: 1.67;
  }

  .test-component__label {
    color: grey;
  }

  .test-component__numbers {
    display: flex;
    align-items: center;
    justify-content: flex-end;

    .test-component__numbers-count {
      text-align: right;
      color: grey;
    }

    .test-component__info-difference {
      align-items: center;
      display: flex;
      margin-left: 4px;
      color: grey;
    }

    .test-component__info-difference-icon {
      width: 16px;
      height: 16px;
      min-width: 16px;
      min-height: 16px;
      margin: 0;
    }
  }
}
import angular from 'angular';
import { findAllIn } from '../../../public/test-helpers/globals';

import { TestComponentModule } from './test-compnent.module';

describe('TestComponentModule', () => {
  beforeEach(angular.mock.module(TestComponentModule.name));

  it('should exist', () => {
    expect(TestComponentModule).toBeDefined();
  });

  describe('TestComponent component', () => {
    let parentScope, element, originalTimeout;

    beforeEach(inject(($compile, $rootScope, $componentController) => {
      parentScope = $rootScope.$new();
parentScope.configuration = {
        isActive: true,
        isDisabled: false,
        type: 'active'
      };
      parentScope.content = [
        {
          label: 'first label',
          numbersCount: 4
        },
        {
          label: 'second label',
          numbersCount: 2,
        }
      ];

      element = angular.element(
        '<test-component content="content"></test-component>'
      );
      $compile(element)(parentScope);
      $componentController('TestComponent', { $element: element });

      originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
      jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;

      parentScope.$digest();
    }));

    afterEach(function() {
      jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
    });

it('is active and not disabled according to the configuration', () => {
      const expectedActiveState = parentScope.configuration.isActive;
      const expectedDisabledState = parentScope.configuration.isDisabled;

      const activeValue = findIn(element, 'md-switch')[0].getAttribute(
        'ng-model'
      );
      const disabledValue = findIn(element, 'md-switch')[0].getAttribute(
        'ng-disabled'
      );

      setTimeout(function() {
        expect(activeValue).toEqual(expectedActiveState);
        expect(disabledValue).toEqual(expectedDisabledState);
      }, 400);
    });

    it('sets with of progress bar according to highest host', done => {
      const expectedFirstWidth = '100%'; // for the highest host;
      const expectedSecondWidth = '50%'; // for half the hosts

      setTimeout(function() {
        const progressBars = findAllIn(element, '.test-component__progress');
        const firstWidthValue = progressBars[0].style.width;
        const secondWidthValue = progressBars[1].style.width;

        expect(firstWidthValue).toEqual(expectedFirstWidth);
        expect(secondWidthValue).toEqual(expectedSecondWidth);
        done();
      }, 2500);
    });
  });
});
从“角度”导入角度;
从“../../../public/test helpers/globals”导入{findAllIn};
从“./test component.module”导入{TestComponentModule};
描述('TestComponentModule',()=>{
beforeach(angular.mock.module(TestComponentModule.name));
它('应该存在',()=>{
expect(TestComponentModule).tobededefined();
});
描述('TestComponent',()=>{
让parentScope、element、originalTimeout;
beforeach(注入($compile,$rootScope,$componentController)=>{
parentScope=$rootScope.$new();
parentScope.configuration={
是的,
isDisabled:错误,
类型:“活动”
};
parentScope.content=[
{
标签:“第一个标签”,
人数:4
},
{
标签:“第二个标签”,
人数:2,
}
];
元素=角元素(
''
);
$compile(元素)(父范围);
$componentController('TestComponent',{$element:element});
originalTimeout=jasmine.DEFAULT\u TIMEOUT\u INTERVAL;
jasmine.DEFAULT\u TIMEOUT\u INTERVAL=10000;
parentScope.$digest();
}));
之后(函数(){
jasmine.DEFAULT\u TIMEOUT\u INTERVAL=originalTimeout;
});
它('根据配置处于活动状态且未禁用',()=>{
const expectedActiveState=parentScope.configuration.isActive;
const expectedDisabledState=parentScope.configuration.isDisabled;
常量activeValue=findIn(元素“md开关”)[0]。getAttribute(
“ng模型”
);
const disabledValue=findIn(元素'md switch')[0]。getAttribute(
“ng残疾人”
);
setTimeout(函数(){
expect(activeValue).toEqual(expectedActiveState);
expect(disabledValue),toEqual(expecteddisablestate);
}, 400);
});
它('根据最高主机设置进度条的长度',完成=>{
const expectedFirstWidth='100%;//用于最高主机;
const expectedSecondWidth='50%;//对于一半的主机
setTimeout(函数(){
const progressbar=findAllIn(元素,'.test-component_uuuprogress');
const firstWidthValue=progressBars[0]。style.width;
const secondWidthValue=progressBars[1]。style.width;
expected(firstWidthValue).toEqual(expectedFirstWidth);
expected(secondWidthValue).toEqual(expectedSecondWidth);
完成();
}, 2500);
});
});
});
在浏览器上进行全面测试,包括元素的路径和属性; ng模型给出了一个没有做()的假阳性; 宽度返回
预期的“0%”等于“100%”

在这种情况下,是否有人在AngularJs上测试了ng模型,或者需要有一个等待值更改的超时时间?Karma jasmine认为setTimeout预期会通过,但它们是误报。谢谢