This basically commits the transpiled CoffeeScript JS (with minor cleanup) and removes coffee build support. A tiny amount of support for xblocks exists, because external users may have xblocks with coffee. But no coffee in our tree anyway.
431 lines
12 KiB
JavaScript
431 lines
12 KiB
JavaScript
describe('Calculator', function() {
|
|
|
|
const KEY = {
|
|
TAB : 9,
|
|
ENTER : 13,
|
|
ALT : 18,
|
|
ESC : 27,
|
|
SPACE : 32,
|
|
LEFT : 37,
|
|
UP : 38,
|
|
RIGHT : 39,
|
|
DOWN : 40
|
|
};
|
|
|
|
beforeEach(function() {
|
|
loadFixtures('coffee/fixtures/calculator.html');
|
|
this.calculator = new Calculator;
|
|
});
|
|
|
|
describe('bind', function() {
|
|
it('bind the calculator button', function() {
|
|
expect($('.calc')).toHandleWith('click', this.calculator.toggle);
|
|
});
|
|
|
|
it('bind key up on calculator', function() {
|
|
expect($('#calculator_wrapper')).toHandle('keyup', this.calculator.handleKeyUpOnHint);
|
|
});
|
|
|
|
it('bind the help button', () =>
|
|
// This events is bind by $.click()
|
|
expect($('#calculator_hint')).toHandle('click')
|
|
);
|
|
|
|
it('bind the calculator submit', function() {
|
|
expect($('form#calculator')).toHandleWith('submit', this.calculator.calculate);
|
|
});
|
|
|
|
xit('prevent default behavior on form submit', function() {
|
|
jasmine.stubRequests();
|
|
$('form#calculator').submit(function(e) {
|
|
expect(e.isDefaultPrevented()).toBeTruthy();
|
|
return e.preventDefault();
|
|
});
|
|
return $('form#calculator').submit();
|
|
});
|
|
});
|
|
|
|
describe('toggle', function() {
|
|
it('focuses the input when toggled', function(done){
|
|
|
|
const self = this;
|
|
const focus = function(){
|
|
const 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"));
|
|
|
|
return deferred.promise();
|
|
};
|
|
|
|
focus().then(
|
|
() => expect($('#calculator_wrapper #calculator_input').focus).toHaveBeenCalled()).always(done);
|
|
});
|
|
|
|
it('toggle the close button on the calculator button', function() {
|
|
this.calculator.toggle(jQuery.Event("click"));
|
|
expect($('.calc')).toHaveClass('closed');
|
|
|
|
this.calculator.toggle(jQuery.Event("click"));
|
|
expect($('.calc')).not.toHaveClass('closed');
|
|
});
|
|
});
|
|
|
|
describe('showHint', () =>
|
|
it('show the help overlay', function() {
|
|
this.calculator.showHint();
|
|
expect($('.help')).toHaveClass('shown');
|
|
expect($('.help')).toHaveAttr('aria-hidden', 'false');
|
|
})
|
|
);
|
|
|
|
|
|
describe('hideHint', () =>
|
|
it('show the help overlay', function() {
|
|
this.calculator.hideHint();
|
|
expect($('.help')).not.toHaveClass('shown');
|
|
expect($('.help')).toHaveAttr('aria-hidden', 'true');
|
|
})
|
|
);
|
|
|
|
describe('handleClickOnHintButton', () =>
|
|
it('on click hint button hint popup becomes visible ', function() {
|
|
const 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', function() {
|
|
this.calculator.showHint();
|
|
const e = jQuery.Event('click');
|
|
$(document).trigger(e);
|
|
expect($('.help')).not.toHaveClass('shown');
|
|
})
|
|
);
|
|
|
|
describe('handleClickOnHintPopup', () =>
|
|
it('on click of hint popup it remains visible', function() {
|
|
this.calculator.showHint();
|
|
const e = jQuery.Event('click');
|
|
$('#calculator_input_help').trigger(e);
|
|
expect($('.help')).toHaveClass('shown');
|
|
})
|
|
);
|
|
|
|
describe('selectHint', function() {
|
|
it('select correct hint item', function() {
|
|
spyOn($.fn, 'focus');
|
|
const element = $('.hint-item').eq(1);
|
|
this.calculator.selectHint(element);
|
|
|
|
expect(element.focus).toHaveBeenCalled();
|
|
expect(this.calculator.activeHint).toEqual(element);
|
|
expect(this.calculator.hintPopup).toHaveAttr('data-calculator-hint', element.attr('id'));
|
|
});
|
|
|
|
it('select the first hint if argument element is not passed', function() {
|
|
this.calculator.selectHint();
|
|
expect(this.calculator.activeHint.attr('id')).toEqual($('.hint-item').first().attr('id'));
|
|
});
|
|
|
|
it('select the first hint if argument element is empty', function() {
|
|
this.calculator.selectHint([]);
|
|
expect(this.calculator.activeHint.attr('id')).toBe($('.hint-item').first().attr('id'));
|
|
});
|
|
});
|
|
|
|
describe('prevHint', function() {
|
|
|
|
it('Prev hint item is selected', function() {
|
|
this.calculator.activeHint = $('.hint-item').eq(1);
|
|
this.calculator.prevHint();
|
|
|
|
expect(this.calculator.activeHint.attr('id')).toBe($('.hint-item').eq(0).attr('id'));
|
|
});
|
|
|
|
it('if this was the second item, select the first one', function() {
|
|
this.calculator.activeHint = $('.hint-item').eq(1);
|
|
this.calculator.prevHint();
|
|
|
|
expect(this.calculator.activeHint.attr('id')).toBe($('.hint-item').eq(0).attr('id'));
|
|
});
|
|
|
|
it('if this was the first item, select the last one', function() {
|
|
this.calculator.activeHint = $('.hint-item').eq(0);
|
|
this.calculator.prevHint();
|
|
|
|
expect(this.calculator.activeHint.attr('id')).toBe($('.hint-item').eq(2).attr('id'));
|
|
});
|
|
|
|
it('if this was the last item, select the second last', function() {
|
|
this.calculator.activeHint = $('.hint-item').eq(2);
|
|
this.calculator.prevHint();
|
|
|
|
expect(this.calculator.activeHint.attr('id')).toBe($('.hint-item').eq(1).attr('id'));
|
|
});
|
|
});
|
|
|
|
describe('nextHint', function() {
|
|
|
|
it('if this was the first item, select the second one', function() {
|
|
this.calculator.activeHint = $('.hint-item').eq(0);
|
|
this.calculator.nextHint();
|
|
|
|
expect(this.calculator.activeHint.attr('id')).toBe($('.hint-item').eq(1).attr('id'));
|
|
});
|
|
|
|
it('If this was the second item, select the last one', function() {
|
|
this.calculator.activeHint = $('.hint-item').eq(1);
|
|
this.calculator.nextHint();
|
|
|
|
expect(this.calculator.activeHint.attr('id')).toBe($('.hint-item').eq(2).attr('id'));
|
|
});
|
|
|
|
it('If this was the last item, select the first one', function() {
|
|
this.calculator.activeHint = $('.hint-item').eq(2);
|
|
this.calculator.nextHint();
|
|
|
|
expect(this.calculator.activeHint.attr('id')).toBe($('.hint-item').eq(0).attr('id'));
|
|
});
|
|
});
|
|
|
|
describe('handleKeyDown', function() {
|
|
const assertHintIsHidden = function(calc, key) {
|
|
spyOn(calc, 'hideHint');
|
|
calc.showHint();
|
|
const e = jQuery.Event('keydown', { keyCode: key });
|
|
const value = calc.handleKeyDown(e);
|
|
|
|
expect(calc.hideHint).toHaveBeenCalled;
|
|
expect(value).toBeFalsy();
|
|
expect(e.isDefaultPrevented()).toBeTruthy();
|
|
};
|
|
|
|
const assertHintIsVisible = function(calc, key) {
|
|
spyOn(calc, 'showHint');
|
|
spyOn($.fn, 'focus');
|
|
const e = jQuery.Event('keydown', { keyCode: key });
|
|
const value = calc.handleKeyDown(e);
|
|
|
|
expect(calc.showHint).toHaveBeenCalled;
|
|
expect(value).toBeFalsy();
|
|
expect(e.isDefaultPrevented()).toBeTruthy();
|
|
expect(calc.activeHint.focus).toHaveBeenCalled();
|
|
};
|
|
|
|
const assertNothingHappens = function(calc, key) {
|
|
spyOn(calc, 'showHint');
|
|
const e = jQuery.Event('keydown', { keyCode: key });
|
|
const value = calc.handleKeyDown(e);
|
|
|
|
expect(calc.showHint).not.toHaveBeenCalled;
|
|
expect(value).toBeTruthy();
|
|
expect(e.isDefaultPrevented()).toBeFalsy();
|
|
};
|
|
|
|
it('hint popup becomes hidden on press ENTER', function() {
|
|
assertHintIsHidden(this.calculator, KEY.ENTER);
|
|
});
|
|
|
|
it('hint popup becomes visible on press ENTER', function() {
|
|
assertHintIsVisible(this.calculator, KEY.ENTER);
|
|
});
|
|
|
|
it('hint popup becomes hidden on press SPACE', function() {
|
|
assertHintIsHidden(this.calculator, KEY.SPACE);
|
|
});
|
|
|
|
it('hint popup becomes visible on press SPACE', function() {
|
|
assertHintIsVisible(this.calculator, KEY.SPACE);
|
|
});
|
|
|
|
it('Nothing happens on press ALT', function() {
|
|
assertNothingHappens(this.calculator, KEY.ALT);
|
|
});
|
|
|
|
it('Nothing happens on press any other button', function() {
|
|
assertNothingHappens(this.calculator, KEY.DOWN);
|
|
});
|
|
});
|
|
|
|
describe('handleKeyDownOnHint', () =>
|
|
it('Navigation works in proper way', function() {
|
|
const calc = this.calculator;
|
|
|
|
const eventToShowHint = jQuery.Event('keydown', { keyCode: KEY.ENTER } );
|
|
$('#calculator_hint').trigger(eventToShowHint);
|
|
|
|
spyOn(calc, 'hideHint');
|
|
spyOn(calc, 'prevHint');
|
|
spyOn(calc, 'nextHint');
|
|
spyOn($.fn, 'focus');
|
|
|
|
const 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, function(key, data) {
|
|
calc.hideHint.calls.reset();
|
|
calc.prevHint.calls.reset();
|
|
calc.nextHint.calls.reset();
|
|
$.fn.focus.calls.reset();
|
|
|
|
const e = jQuery.Event('keydown', data.event || {});
|
|
const 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', function() {
|
|
beforeEach(function() {
|
|
$('#calculator_input').val('1+2');
|
|
spyOn($, 'getWithPrefix').and.callFake((url, data, callback) => callback({ result: 3 }));
|
|
this.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'));
|
|
});
|
|
});
|