Reputation: 6573
Experiencing some peculiar behaviour from karma-jasmine testing an angular app.
Have a test in one suite that reports failure but message comes from a separate test in another test suite file.
Test result:
factory: page should uncheck all items FAILED
Expected undefined to contain '<div class="ui-select-container ui-select-bootstrap dropdown ng-valid" ng-class="{open: $select.open}" ng-model="test.slctbx.selected" theme="bootstrap" ng-disabled="disabled"></div>'
That test is actually:
describe 'factory: page', () ->
...
it 'should check all items', () ->
Page.checkAll null
expect(Page.actions).toEqual {checkAll: false}
The error actually comes from:
describe 'directive: select', () ->
...
it 'should replace select box', () ->
replacementMarkup = '<div class="ui-select-container ui-select-bootstrap dropdown ng-valid" ng-class="{open: $select.open}" ng-model="test.slctbx.selected" theme="bootstrap" ng-disabled="disabled"></div>'
setTimeout () ->
expect($('select').length).toEqual 0
expect($('form').html()).toContain replacementMarkup
return
, 0
If I remove the factory: page suite this behaviour simply exists but another test suite.
The timeout is smelly but this is only because that directive has a timeout within it that waits an arbitrary amount of time so the element it is about to replace has been populated... (which is a bit smelly itself!)
==== EDIT + directive code ====
link: (scope, element, attrs) ->
items = []
name = element.attr('name').replace '[]', ''
placeholder = ''
for index, el of element.find('option') when typeof el is 'object' and index isnt '0'
if index == '1'
placeholder = el.innerHTML
else if typeof el[0] == 'undefined'
items.push {value: el.getAttribute('value'), label: el.innerHTML}
if typeof scope.$parent.test != 'object'
scope.$parent.test = {}
scope.$parent.test[name] = items
select = '<ui-select ng-model="test.' + name + '.selected" theme="bootstrap" ng-disabled="disabled">
<ui-select-match placeholder="' + placeholder + '">{{ $select.selected.label }}</ui-select-match>
<ui-select-choices repeat="item in test[\'' + name + '\'] | filter: $select.search">
<div ng-bind-html="item.label | highlight: $select.search"></div>
</ui-select-choices>
</ui-select>'
newSel = $compile(select)(scope.$parent)
setTimeout () ->
element.replaceWith angular.element(newSel)
, 10
return false
Upvotes: 1
Views: 198
Reputation: 21278
Why dont you use $timeout
instead of setTimeout()
in both your directive and the test? You would be able to use the $timeout.flush()
in the test to verify if the directive have waited an arbitrary amount of time without waiting for it.
Your directive should use $timeout(func, arbitraryAmountOfTime)
instead of setTimeout(func, arbitraryAmountOfTime)
and then the test becomes:
it 'should replace select box', ->
inject ($timeout) ->
$timeout.flush()
expect($('select').length).toEqual 0
expect($('form').html()).toContain replacementMarkup
I suppose that in current code, jasmie moves on to the next test and then your timeouted call appears from nowhere failing the test that is currently being executed. But it's just a hunch.
Upvotes: 1