angularjs - 异步 ng-model 和宽度不返回初始值 (Karma-Jasmine)
问题描述
我正在开发一个需要 karma-jasmine 测试的 AngularJS 1.7 项目。
到目前为止,在我使用控制器分配的 ng-model 测试组件之前,我没有遇到任何问题。我读到 ng-model 变得异步了,但是我已经尝试了从 done() 到 setTimeout、$digest 等的所有解决方案,但似乎仍然无法设置初始值......我也有由于动画的时间安排,在组件渲染后获取宽度的相同问题
这是我的代码:
组件.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>
组件控制器.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]
);
}
}
组件.scss
@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;
}
}
}
组件.spec.js
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);
});
});
});
在浏览器上经过全面测试,包括元素的路径和属性;ng 模型对没有 done() 给出误报;宽度返回Expected '0%' to equal '100%'
;
在这种情况下,是否有人在 AngularJs 上测试过 ng-model,或者需要超时等待值发生变化?Karma-jasmine 认为 setTimeout 预计会通过,但它们是误报。谢谢
解决方案
推荐阅读
- java - Spring MVC @ModelAttribute 未填充 AJAX Post 请求
- c++ - ASIO io_service 在第二次 run() 调用时不处理后处理程序
- opengl - glsl 顶点着色器导致 INTCONSTANT 错误
- java - 加载数据并推送到 RecyclerView 未显示
- r - 为什么使用 plotstyle="ggplot" 时 qqcomp 函数中没有显示任何点?
- google-apps-script - 将 google App Script 部署为 Sheets Add-On 后菜单项未出现
- jenkins - Jenkins 无法访问 Sonarqube 本地主机
- asynchronous - 此语句在 dart 的 Future 类中意味着什么:FutureOr
函数(动态)onValue - android - 获取“连接在收到完整标题之前关闭从网络加载图像时
- javascript - 如何从实时生成的表单输入数据绑定中提取数据