354 lines
10 KiB
CoffeeScript
354 lines
10 KiB
CoffeeScript
describe 'Calculator', ->
|
|
|
|
KEY =
|
|
TAB : 9
|
|
ENTER : 13
|
|
ALT : 18
|
|
ESC : 27
|
|
SPACE : 32
|
|
LEFT : 37
|
|
UP : 38
|
|
RIGHT : 39
|
|
DOWN : 40
|
|
|
|
beforeEach ->
|
|
loadFixtures 'coffee/fixtures/calculator.html'
|
|
@calculator = new Calculator
|
|
|
|
describe 'bind', ->
|
|
it 'bind the calculator button', ->
|
|
expect($('.calc')).toHandleWith 'click', @calculator.toggle
|
|
|
|
it 'bind key up on calculator', ->
|
|
expect($('#calculator_wrapper')).toHandle 'keyup', @calculator.handleKeyUpOnHint
|
|
|
|
it 'bind the help button', ->
|
|
# This events is bind by $.click()
|
|
expect($('#calculator_hint')).toHandle 'click'
|
|
|
|
it 'bind the calculator submit', ->
|
|
expect($('form#calculator')).toHandleWith 'submit', @calculator.calculate
|
|
|
|
xit 'prevent default behavior on form submit', ->
|
|
jasmine.stubRequests()
|
|
$('form#calculator').submit (e) ->
|
|
expect(e.isDefaultPrevented()).toBeTruthy()
|
|
e.preventDefault()
|
|
$('form#calculator').submit()
|
|
|
|
describe 'toggle', ->
|
|
it 'focuses the input when toggled', (done)->
|
|
|
|
self = this
|
|
focus = ()->
|
|
deferred = $.Deferred()
|
|
|
|
# Since the focus is called asynchronously, we need to
|
|
# wait until focus() is called.
|
|
spyOn($.fn, 'focus').and.callFake (elementName) ->
|
|
deferred.resolve()
|
|
|
|
self.calculator.toggle(jQuery.Event("click"))
|
|
|
|
deferred.promise()
|
|
|
|
focus().then(
|
|
->
|
|
expect($('#calculator_wrapper #calculator_input').focus).toHaveBeenCalled()
|
|
).always(done)
|
|
|
|
it 'toggle the close button on the calculator button', ->
|
|
@calculator.toggle(jQuery.Event("click"))
|
|
expect($('.calc')).toHaveClass('closed')
|
|
|
|
@calculator.toggle(jQuery.Event("click"))
|
|
expect($('.calc')).not.toHaveClass('closed')
|
|
|
|
describe 'showHint', ->
|
|
it 'show the help overlay', ->
|
|
@calculator.showHint()
|
|
expect($('.help')).toHaveClass('shown')
|
|
expect($('.help')).toHaveAttr('aria-hidden', 'false')
|
|
|
|
|
|
describe 'hideHint', ->
|
|
it 'show the help overlay', ->
|
|
@calculator.hideHint()
|
|
expect($('.help')).not.toHaveClass('shown')
|
|
expect($('.help')).toHaveAttr('aria-hidden', 'true')
|
|
|
|
describe 'handleClickOnHintButton', ->
|
|
it 'on click hint button hint popup becomes visible ', ->
|
|
e = jQuery.Event('click');
|
|
$('#calculator_hint').trigger(e);
|
|
expect($('.help')).toHaveClass 'shown'
|
|
|
|
describe 'handleClickOnDocument', ->
|
|
it 'on click out of the hint popup it becomes hidden', ->
|
|
@calculator.showHint()
|
|
e = jQuery.Event('click');
|
|
$(document).trigger(e);
|
|
expect($('.help')).not.toHaveClass 'shown'
|
|
|
|
describe 'handleClickOnHintPopup', ->
|
|
it 'on click of hint popup it remains visible', ->
|
|
@calculator.showHint()
|
|
e = jQuery.Event('click');
|
|
$('#calculator_input_help').trigger(e);
|
|
expect($('.help')).toHaveClass 'shown'
|
|
|
|
describe 'selectHint', ->
|
|
it 'select correct hint item', ->
|
|
spyOn($.fn, 'focus')
|
|
element = $('.hint-item').eq(1)
|
|
@calculator.selectHint(element)
|
|
|
|
expect(element.focus).toHaveBeenCalled()
|
|
expect(@calculator.activeHint).toEqual(element)
|
|
expect(@calculator.hintPopup).toHaveAttr('data-calculator-hint', element.attr('id'))
|
|
|
|
it 'select the first hint if argument element is not passed', ->
|
|
@calculator.selectHint()
|
|
expect(@calculator.activeHint.attr('id')).toEqual($('.hint-item').first().attr('id'))
|
|
|
|
it 'select the first hint if argument element is empty', ->
|
|
@calculator.selectHint([])
|
|
expect(@calculator.activeHint.attr('id')).toBe($('.hint-item').first().attr('id'))
|
|
|
|
describe 'prevHint', ->
|
|
|
|
it 'Prev hint item is selected', ->
|
|
@calculator.activeHint = $('.hint-item').eq(1)
|
|
@calculator.prevHint()
|
|
|
|
expect(@calculator.activeHint.attr('id')).toBe($('.hint-item').eq(0).attr('id'))
|
|
|
|
it 'if this was the second item, select the first one', ->
|
|
@calculator.activeHint = $('.hint-item').eq(1)
|
|
@calculator.prevHint()
|
|
|
|
expect(@calculator.activeHint.attr('id')).toBe($('.hint-item').eq(0).attr('id'))
|
|
|
|
it 'if this was the first item, select the last one', ->
|
|
@calculator.activeHint = $('.hint-item').eq(0)
|
|
@calculator.prevHint()
|
|
|
|
expect(@calculator.activeHint.attr('id')).toBe($('.hint-item').eq(2).attr('id'))
|
|
|
|
it 'if this was the last item, select the second last', ->
|
|
@calculator.activeHint = $('.hint-item').eq(2)
|
|
@calculator.prevHint()
|
|
|
|
expect(@calculator.activeHint.attr('id')).toBe($('.hint-item').eq(1).attr('id'))
|
|
|
|
describe 'nextHint', ->
|
|
|
|
it 'if this was the first item, select the second one', ->
|
|
@calculator.activeHint = $('.hint-item').eq(0)
|
|
@calculator.nextHint()
|
|
|
|
expect(@calculator.activeHint.attr('id')).toBe($('.hint-item').eq(1).attr('id'))
|
|
|
|
it 'If this was the second item, select the last one', ->
|
|
@calculator.activeHint = $('.hint-item').eq(1)
|
|
@calculator.nextHint()
|
|
|
|
expect(@calculator.activeHint.attr('id')).toBe($('.hint-item').eq(2).attr('id'))
|
|
|
|
it 'If this was the last item, select the first one', ->
|
|
@calculator.activeHint = $('.hint-item').eq(2)
|
|
@calculator.nextHint()
|
|
|
|
expect(@calculator.activeHint.attr('id')).toBe($('.hint-item').eq(0).attr('id'))
|
|
|
|
describe 'handleKeyDown', ->
|
|
assertHintIsHidden = (calc, key) ->
|
|
spyOn(calc, 'hideHint')
|
|
calc.showHint()
|
|
e = jQuery.Event('keydown', { keyCode: key });
|
|
value = calc.handleKeyDown(e)
|
|
|
|
expect(calc.hideHint).toHaveBeenCalled
|
|
expect(value).toBeFalsy()
|
|
expect(e.isDefaultPrevented()).toBeTruthy()
|
|
|
|
assertHintIsVisible = (calc, key) ->
|
|
spyOn(calc, 'showHint')
|
|
spyOn($.fn, 'focus')
|
|
e = jQuery.Event('keydown', { keyCode: key });
|
|
value = calc.handleKeyDown(e)
|
|
|
|
expect(calc.showHint).toHaveBeenCalled
|
|
expect(value).toBeFalsy()
|
|
expect(e.isDefaultPrevented()).toBeTruthy()
|
|
expect(calc.activeHint.focus).toHaveBeenCalled()
|
|
|
|
assertNothingHappens = (calc, key) ->
|
|
spyOn(calc, 'showHint')
|
|
e = jQuery.Event('keydown', { keyCode: key });
|
|
value = calc.handleKeyDown(e)
|
|
|
|
expect(calc.showHint).not.toHaveBeenCalled
|
|
expect(value).toBeTruthy()
|
|
expect(e.isDefaultPrevented()).toBeFalsy()
|
|
|
|
it 'hint popup becomes hidden on press ENTER', ->
|
|
assertHintIsHidden(@calculator, KEY.ENTER)
|
|
|
|
it 'hint popup becomes visible on press ENTER', ->
|
|
assertHintIsVisible(@calculator, KEY.ENTER)
|
|
|
|
it 'hint popup becomes hidden on press SPACE', ->
|
|
assertHintIsHidden(@calculator, KEY.SPACE)
|
|
|
|
it 'hint popup becomes visible on press SPACE', ->
|
|
assertHintIsVisible(@calculator, KEY.SPACE)
|
|
|
|
it 'Nothing happens on press ALT', ->
|
|
assertNothingHappens(@calculator, KEY.ALT)
|
|
|
|
it 'Nothing happens on press any other button', ->
|
|
assertNothingHappens(@calculator, KEY.DOWN)
|
|
|
|
describe 'handleKeyDownOnHint', ->
|
|
it 'Navigation works in proper way', ->
|
|
calc = @calculator
|
|
|
|
eventToShowHint = jQuery.Event('keydown', { keyCode: KEY.ENTER } );
|
|
$('#calculator_hint').trigger(eventToShowHint);
|
|
|
|
spyOn(calc, 'hideHint')
|
|
spyOn(calc, 'prevHint')
|
|
spyOn(calc, 'nextHint')
|
|
spyOn($.fn, 'focus')
|
|
|
|
cases =
|
|
left:
|
|
event:
|
|
keyCode: KEY.LEFT
|
|
shiftKey: false
|
|
returnedValue: false
|
|
called:
|
|
'prevHint': calc
|
|
isPropagationStopped: true
|
|
|
|
leftWithShift:
|
|
returnedValue: true
|
|
event:
|
|
keyCode: KEY.LEFT
|
|
shiftKey: true
|
|
not_called:
|
|
'prevHint': calc
|
|
|
|
up:
|
|
event:
|
|
keyCode: KEY.UP
|
|
shiftKey: false
|
|
returnedValue: false
|
|
called:
|
|
'prevHint': calc
|
|
isPropagationStopped: true
|
|
|
|
upWithShift:
|
|
returnedValue: true
|
|
event:
|
|
keyCode: KEY.UP
|
|
shiftKey: true
|
|
not_called:
|
|
'prevHint': calc
|
|
|
|
right:
|
|
event:
|
|
keyCode: KEY.RIGHT
|
|
shiftKey: false
|
|
returnedValue: false
|
|
called:
|
|
'nextHint': calc
|
|
isPropagationStopped: true
|
|
|
|
rightWithShift:
|
|
returnedValue: true
|
|
event:
|
|
keyCode: KEY.RIGHT
|
|
shiftKey: true
|
|
not_called:
|
|
'nextHint': calc
|
|
|
|
down:
|
|
event:
|
|
keyCode: KEY.DOWN
|
|
shiftKey: false
|
|
returnedValue: false
|
|
called:
|
|
'nextHint': calc
|
|
isPropagationStopped: true
|
|
|
|
downWithShift:
|
|
returnedValue: true
|
|
event:
|
|
keyCode: KEY.DOWN
|
|
shiftKey: true
|
|
not_called:
|
|
'nextHint': calc
|
|
|
|
esc:
|
|
returnedValue: false
|
|
event:
|
|
keyCode: KEY.ESC
|
|
shiftKey: false
|
|
called:
|
|
'hideHint': calc
|
|
'focus': $.fn
|
|
isPropagationStopped: true
|
|
|
|
alt:
|
|
returnedValue: true
|
|
event:
|
|
which: KEY.ALT
|
|
not_called:
|
|
'hideHint': calc
|
|
'nextHint': calc
|
|
'prevHint': calc
|
|
|
|
$.each(cases, (key, data) ->
|
|
calc.hideHint.calls.reset()
|
|
calc.prevHint.calls.reset()
|
|
calc.nextHint.calls.reset()
|
|
$.fn.focus.calls.reset()
|
|
|
|
e = jQuery.Event('keydown', data.event or {});
|
|
value = calc.handleKeyDownOnHint(e)
|
|
|
|
if data.called
|
|
$.each(data.called, (method, obj) ->
|
|
expect(obj[method]).toHaveBeenCalled()
|
|
)
|
|
|
|
if data.not_called
|
|
$.each(data.not_called, (method, obj) ->
|
|
expect(obj[method]).not.toHaveBeenCalled()
|
|
)
|
|
|
|
if data.isPropagationStopped
|
|
expect(e.isPropagationStopped()).toBeTruthy()
|
|
else
|
|
expect(e.isPropagationStopped()).toBeFalsy()
|
|
|
|
expect(value).toBe(data.returnedValue)
|
|
)
|
|
|
|
describe 'calculate', ->
|
|
beforeEach ->
|
|
$('#calculator_input').val '1+2'
|
|
spyOn($, 'getWithPrefix').and.callFake (url, data, callback) ->
|
|
callback({ result: 3 })
|
|
@calculator.calculate()
|
|
|
|
it 'send data to /calculate', ->
|
|
expect($.getWithPrefix).toHaveBeenCalledWith '/calculate',
|
|
equation: '1+2'
|
|
, jasmine.any(Function)
|
|
|
|
it 'update the calculator output', ->
|
|
expect($('#calculator_output').val()).toEqual('3')
|