Files
edx-platform/lms/static/js/spec/calculator_spec.js
Michael Terry a34c8c8233 Drop remaining coffee use
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.
2018-04-13 14:10:40 -04:00

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'));
});
});