diff --git a/xmodule/js/spec/capa/display_spec.js b/xmodule/js/spec/capa/display_spec.js deleted file mode 100644 index 385bd2d24333..000000000000 --- a/xmodule/js/spec/capa/display_spec.js +++ /dev/null @@ -1,1105 +0,0 @@ -/* - * decaffeinate suggestions: - * DS101: Remove unnecessary use of Array.from - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -describe('Problem', function() { - const problem_content_default = readFixtures('problem_content.html'); - - beforeEach(function() { - // Stub MathJax - window.MathJax = { - Hub: jasmine.createSpyObj('MathJax.Hub', ['getAllJax', 'Queue']), - Callback: jasmine.createSpyObj('MathJax.Callback', ['After']) - }; - this.stubbedJax = {root: jasmine.createSpyObj('jax.root', ['toMathML'])}; - MathJax.Hub.getAllJax.and.returnValue([this.stubbedJax]); - window.update_schematics = function() {}; - spyOn(SR, 'readText'); - spyOn(SR, 'readTexts'); - - // Load this function from spec/helper.js - // Note that if your test fails with a message like: - // 'External request attempted for blah, which is not defined.' - // this msg is coming from the stubRequests function else clause. - jasmine.stubRequests(); - - loadFixtures('problem.html'); - - spyOn(Logger, 'log'); - spyOn($.fn, 'load').and.callFake(function(url, callback) { - $(this).html(readFixtures('problem_content.html')); - return callback(); - }); - }); - - describe('constructor', function() { - - it('set the element from html', function() { - this.problem999 = new Problem((`\ -
\ -
\ -
\ -
\ -`) - ); - expect(this.problem999.element_id).toBe('problem_999'); - }); - - it('set the element from loadFixtures', function() { - this.problem1 = new Problem($('.xblock-student_view')); - expect(this.problem1.element_id).toBe('problem_1'); - }); - }); - - describe('bind', function() { - beforeEach(function() { - spyOn(window, 'update_schematics'); - MathJax.Hub.getAllJax.and.returnValue([this.stubbedJax]); - this.problem = new Problem($('.xblock-student_view')); - }); - - it('set mathjax typeset', () => expect(MathJax.Hub.Queue).toHaveBeenCalled()); - - it('update schematics', () => expect(window.update_schematics).toHaveBeenCalled()); - - it('bind answer refresh on button click', function() { - expect($('div.action button')).toHandleWith('click', this.problem.refreshAnswers); - }); - - it('bind the submit button', function() { - expect($('.action .submit')).toHandleWith('click', this.problem.submit_fd); - }); - - it('bind the reset button', function() { - expect($('div.action button.reset')).toHandleWith('click', this.problem.reset); - }); - - it('bind the show button', function() { - expect($('.action .show')).toHandleWith('click', this.problem.show); - }); - - it('bind the save button', function() { - expect($('div.action button.save')).toHandleWith('click', this.problem.save); - }); - - it('bind the math input', function() { - expect($('input.math')).toHandleWith('keyup', this.problem.refreshMath); - }); - }); - - describe('bind_with_custom_input_id', function() { - beforeEach(function() { - spyOn(window, 'update_schematics'); - MathJax.Hub.getAllJax.and.returnValue([this.stubbedJax]); - this.problem = new Problem($('.xblock-student_view')); - return $(this).html(readFixtures('problem_content_1240.html')); - }); - - it('bind the submit button', function() { - expect($('.action .submit')).toHandleWith('click', this.problem.submit_fd); - }); - - it('bind the show button', function() { - expect($('div.action button.show')).toHandleWith('click', this.problem.show); - }); - }); - - - describe('renderProgressState', function() { - beforeEach(function() { - this.problem = new Problem($('.xblock-student_view')); - }); - - const testProgessData = function(problem, score, total_possible, attempts, graded, expected_progress_after_render) { - problem.el.data('problem-score', score); - problem.el.data('problem-total-possible', total_possible); - problem.el.data('attempts-used', attempts); - problem.el.data('graded', graded); - expect(problem.$('.problem-progress').html()).toEqual(""); - problem.renderProgressState(); - expect(problem.$('.problem-progress').html()).toEqual(expected_progress_after_render); - }; - - describe('with a status of "none"', function() { - it('reports the number of points possible and graded', function() { - testProgessData(this.problem, 0, 1, 0, "True", "1 point possible (graded)"); - }); - - it('displays the number of points possible when rendering happens with the content', function() { - testProgessData(this.problem, 0, 2, 0, "True", "2 points possible (graded)"); - }); - - it('reports the number of points possible and ungraded', function() { - testProgessData(this.problem, 0, 1, 0, "False", "1 point possible (ungraded)"); - }); - - it('displays ungraded if number of points possible is 0', function() { - testProgessData(this.problem, 0, 0, 0, "False", "0 points possible (ungraded)"); - }); - - it('displays ungraded if number of points possible is 0, even if graded value is True', function() { - testProgessData(this.problem, 0, 0, 0, "True", "0 points possible (ungraded)"); - }); - - it('reports the correct score with status none and >0 attempts', function() { - testProgessData(this.problem, 0, 1, 1, "True", "0/1 point (graded)"); - }); - - it('reports the correct score with >1 weight, status none, and >0 attempts', function() { - testProgessData(this.problem, 0, 2, 2, "True", "0/2 points (graded)"); - }); - }); - - describe('with any other valid status', function() { - - it('reports the current score', function() { - testProgessData(this.problem, 1, 1, 1, "True", "1/1 point (graded)"); - }); - - it('shows current score when rendering happens with the content', function() { - testProgessData(this.problem, 2, 2, 1, "True", "2/2 points (graded)"); - }); - - it('reports the current score even if problem is ungraded', function() { - testProgessData(this.problem, 1, 1, 1, "False", "1/1 point (ungraded)"); - }); - }); - - describe('with valid status and string containing an integer like "0" for detail', () => - // These tests are to address a failure specific to Chrome 51 and 52 + - it('shows 0 points possible for the detail', function() { - testProgessData(this.problem, 0, 0, 1, "False", "0 points possible (ungraded)"); - }) - ); - - describe('with a score of null (show_correctness == false)', function() { - it('reports the number of points possible and graded, results hidden', function() { - testProgessData(this.problem, null, 1, 0, "True", "1 point possible (graded, results hidden)"); - }); - - it('reports the number of points possible (plural) and graded, results hidden', function() { - testProgessData(this.problem, null, 2, 0, "True", "2 points possible (graded, results hidden)"); - }); - - it('reports the number of points possible and ungraded, results hidden', function() { - testProgessData(this.problem, null, 1, 0, "False", "1 point possible (ungraded, results hidden)"); - }); - - it('displays ungraded if number of points possible is 0, results hidden', function() { - testProgessData(this.problem, null, 0, 0, "False", "0 points possible (ungraded, results hidden)"); - }); - - it('displays ungraded if number of points possible is 0, even if graded value is True, results hidden', function() { - testProgessData(this.problem, null, 0, 0, "True", "0 points possible (ungraded, results hidden)"); - }); - - it('reports the correct score with status none and >0 attempts, results hidden', function() { - testProgessData(this.problem, null, 1, 1, "True", "1 point possible (graded, results hidden)"); - }); - - it('reports the correct score with >1 weight, status none, and >0 attempts, results hidden', function() { - testProgessData(this.problem, null, 2, 2, "True", "2 points possible (graded, results hidden)"); - }); - }); - }); - - describe('render', function() { - beforeEach(function() { - this.problem = new Problem($('.xblock-student_view')); - this.bind = this.problem.bind; - spyOn(this.problem, 'bind'); - }); - - describe('with content given', function() { - beforeEach(function() { - this.problem.render('Hello World'); - }); - - it('render the content', function() { - expect(this.problem.el.html()).toEqual('Hello World'); - }); - - it('re-bind the content', function() { - expect(this.problem.bind).toHaveBeenCalled(); - }); - }); - - describe('with no content given', function() { - beforeEach(function() { - spyOn($, 'postWithPrefix').and.callFake((url, callback) => callback({html: "Hello World"})); - this.problem.render(); - }); - - it('load the content via ajax', function() { - expect(this.problem.el.html()).toEqual('Hello World'); - }); - - it('re-bind the content', function() { - expect(this.problem.bind).toHaveBeenCalled(); - }); - }); - }); - - describe('submit_fd', function() { - beforeEach(function() { - // Insert an input of type file outside of the problem. - $('.xblock-student_view').after(''); - this.problem = new Problem($('.xblock-student_view')); - spyOn(this.problem, 'submit'); - }); - - it('submit method is called if input of type file is not in problem', function() { - this.problem.submit_fd(); - expect(this.problem.submit).toHaveBeenCalled(); - }); - }); - - describe('submit', function() { - beforeEach(function() { - this.problem = new Problem($('.xblock-student_view')); - this.problem.answers = 'foo=1&bar=2'; - }); - - it('log the problem_check event', function() { - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - let promise; - promise = { - always(callable) { return callable(); }, - done(callable) { return callable(); } - }; - return promise; - }); - this.problem.submit(); - expect(Logger.log).toHaveBeenCalledWith('problem_check', 'foo=1&bar=2'); - }); - - it('log the problem_graded event, after the problem is done grading.', function() { - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - let promise; - const response = { - success: 'correct', - contents: 'mock grader response' - }; - callback(response); - promise = { - always(callable) { return callable(); }, - done(callable) { return callable(); } - }; - return promise; - }); - this.problem.submit(); - expect(Logger.log).toHaveBeenCalledWith('problem_graded', ['foo=1&bar=2', 'mock grader response'], this.problem.id); - }); - - it('submit the answer for submit', function() { - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - let promise; - promise = { - always(callable) { return callable(); }, - done(callable) { return callable(); } - }; - return promise; - }); - this.problem.submit(); - expect($.postWithPrefix).toHaveBeenCalledWith('/problem/Problem1/problem_check', - 'foo=1&bar=2', jasmine.any(Function)); - }); - - describe('when the response is correct', () => - it('call render with returned content', function() { - const contents = '

Correctexcellent

' + - '

Yepcorrect

'; - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - let promise; - callback({success: 'correct', contents}); - promise = { - always(callable) { return callable(); }, - done(callable) { return callable(); } - }; - return promise; - }); - this.problem.submit(); - expect(this.problem.el).toHaveHtml(contents); - expect(window.SR.readTexts).toHaveBeenCalledWith(['Question 1: excellent', 'Question 2: correct']); - }) - ); - - describe('when the response is incorrect', () => - it('call render with returned content', function() { - const contents = '

Incorrectno, try again

'; - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - let promise; - callback({success: 'incorrect', contents}); - promise = { - always(callable) { return callable(); }, - done(callable) { return callable(); } - }; - return promise; - }); - this.problem.submit(); - expect(this.problem.el).toHaveHtml(contents); - expect(window.SR.readTexts).toHaveBeenCalledWith(['no, try again']); - }) - ); - - it('tests if the submit button is disabled while submitting and the text changes on the button', function() { - const self = this; - const curr_html = this.problem.el.html(); - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - // At this point enableButtons should have been called, making the submit button disabled with text 'submitting' - let promise; - expect(self.problem.submitButton).toHaveAttr('disabled'); - expect(self.problem.submitButtonLabel.text()).toBe('Submitting'); - callback({ - success: 'incorrect', // does not matter if correct or incorrect here - contents: curr_html - }); - promise = { - always(callable) { return callable(); }, - done(callable) { return callable(); } - }; - return promise; - }); - // Make sure the submit button is enabled before submitting - $('#input_example_1').val('test').trigger('input'); - expect(this.problem.submitButton).not.toHaveAttr('disabled'); - this.problem.submit(); - // After submit, the button should not be disabled and should have text as 'Submit' - expect(this.problem.submitButtonLabel.text()).toBe('Submit'); - expect(this.problem.submitButton).not.toHaveAttr('disabled'); - }); - }); - - describe('submit button on problems', function() { - - beforeEach(function() { - this.problem = new Problem($('.xblock-student_view')); - this.submitDisabled = disabled => { - if (disabled) { - expect(this.problem.submitButton).toHaveAttr('disabled'); - } else { - expect(this.problem.submitButton).not.toHaveAttr('disabled'); - } - }; - }); - - describe('some basic tests for submit button', () => - it('should become enabled after a value is entered into the text box', function() { - $('#input_example_1').val('test').trigger('input'); - this.submitDisabled(false); - $('#input_example_1').val('').trigger('input'); - this.submitDisabled(true); - }) - ); - - describe('some advanced tests for submit button', function() { - const radioButtonProblemHtml = readFixtures('radiobutton_problem.html'); - const checkboxProblemHtml = readFixtures('checkbox_problem.html'); - - it('should become enabled after a checkbox is checked', function() { - $('#input_example_1').replaceWith(checkboxProblemHtml); - this.problem.submitAnswersAndSubmitButton(true); - this.submitDisabled(true); - $('#input_1_1_1').click(); - this.submitDisabled(false); - $('#input_1_1_1').click(); - this.submitDisabled(true); - }); - - it('should become enabled after a radiobutton is checked', function() { - $('#input_example_1').replaceWith(radioButtonProblemHtml); - this.problem.submitAnswersAndSubmitButton(true); - this.submitDisabled(true); - $('#input_1_1_1').attr('checked', true).trigger('click'); - this.submitDisabled(false); - $('#input_1_1_1').attr('checked', false).trigger('click'); - this.submitDisabled(true); - }); - - it('should become enabled after a value is selected in a selector', function() { - const html = `\ -
- -
\ -`; - $('#input_example_1').replaceWith(html); - this.problem.submitAnswersAndSubmitButton(true); - this.submitDisabled(true); - $("#problem_sel select").val("val2").trigger('change'); - this.submitDisabled(false); - $("#problem_sel select").val("val0").trigger('change'); - this.submitDisabled(true); - }); - - it('should become enabled after a radiobutton is checked and a value is entered into the text box', function() { - $(radioButtonProblemHtml).insertAfter('#input_example_1'); - this.problem.submitAnswersAndSubmitButton(true); - this.submitDisabled(true); - $('#input_1_1_1').attr('checked', true).trigger('click'); - this.submitDisabled(true); - $('#input_example_1').val('111').trigger('input'); - this.submitDisabled(false); - $('#input_1_1_1').attr('checked', false).trigger('click'); - this.submitDisabled(true); - }); - - it('should become enabled if there are only hidden input fields', function() { - const html = `\ -\ -`; - $('#input_example_1').replaceWith(html); - this.problem.submitAnswersAndSubmitButton(true); - this.submitDisabled(false); - }); - }); - }); - - describe('reset', function() { - beforeEach(function() { - this.problem = new Problem($('.xblock-student_view')); - }); - - it('log the problem_reset event', function() { - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - let promise; - promise = - {always(callable) { return callable(); }}; - return promise; - }); - this.problem.answers = 'foo=1&bar=2'; - this.problem.reset(); - expect(Logger.log).toHaveBeenCalledWith('problem_reset', 'foo=1&bar=2'); - }); - - it('POST to the problem reset page', function() { - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - let promise; - promise = - {always(callable) { return callable(); }}; - return promise; - }); - this.problem.reset(); - expect($.postWithPrefix).toHaveBeenCalledWith('/problem/Problem1/problem_reset', - { id: 'i4x://edX/101/problem/Problem1' }, jasmine.any(Function)); - }); - - it('render the returned content', function() { - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - let promise; - callback({html: "Reset", success: true}); - promise = - {always(callable) { return callable(); }}; - return promise; - }); - this.problem.reset(); - expect(this.problem.el.html()).toEqual('Reset'); - }); - - it('sends a message to the window SR element', function() { - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - let promise; - callback({html: "Reset", success: true}); - promise = - {always(callable) { return callable(); }}; - return promise; - }); - this.problem.reset(); - expect(window.SR.readText).toHaveBeenCalledWith('This problem has been reset.'); - }); - - it('shows a notification on error', function() { - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - let promise; - callback({msg: "Error on reset.", success: false}); - promise = - {always(callable) { return callable(); }}; - return promise; - }); - this.problem.reset(); - expect($('.notification-gentle-alert .notification-message').text()).toEqual("Error on reset."); - }); - - it('tests that reset does not enable submit or modify the text while resetting', function() { - const self = this; - const curr_html = this.problem.el.html(); - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - // enableButtons should have been called at this point to set them to all disabled - let promise; - expect(self.problem.submitButton).toHaveAttr('disabled'); - expect(self.problem.submitButtonLabel.text()).toBe('Submit'); - callback({success: 'correct', html: curr_html}); - promise = - {always(callable) { return callable(); }}; - return promise; - }); - // Submit should be disabled - expect(this.problem.submitButton).toHaveAttr('disabled'); - this.problem.reset(); - // Submit should remain disabled - expect(self.problem.submitButton).toHaveAttr('disabled'); - expect(self.problem.submitButtonLabel.text()).toBe('Submit'); - }); - }); - - describe('show problem with column in id', function() { - beforeEach(function () { - this.problem = new Problem($('.xblock-student_view')); - this.problem.el.prepend('
'); - }); - - it('log the problem_show event', function() { - this.problem.show(); - expect(Logger.log).toHaveBeenCalledWith('problem_show', - {problem: 'i4x://edX/101/problem/Problem1'}); - }); - - it('fetch the answers', function() { - spyOn($, 'postWithPrefix'); - this.problem.show(); - expect($.postWithPrefix).toHaveBeenCalledWith('/problem/Problem1/problem_show', - jasmine.any(Function)); - }); - - it('show the answers', function() { - spyOn($, 'postWithPrefix').and.callFake( - (url, callback) => callback({answers: {'1_1:11': 'One', '1_2:12': 'Two'}}) - ); - this.problem.show(); - expect($("#answer_1_1\\:11")).toHaveHtml('One'); - expect($("#answer_1_2\\:12")).toHaveHtml('Two'); - }); - - it('disables the show answer button', function() { - spyOn($, 'postWithPrefix').and.callFake((url, callback) => callback({answers: {}})); - this.problem.show(); - expect(this.problem.el.find('.show').attr('disabled')).toEqual('disabled'); - }); - }); - - describe('show', function() { - beforeEach(function() { - this.problem = new Problem($('.xblock-student_view')); - this.problem.el.prepend('
'); - }); - - describe('when the answer has not yet shown', function() { - beforeEach(function() { - expect(this.problem.el.find('.show').attr('disabled')).not.toEqual('disabled'); - }); - - it('log the problem_show event', function() { - this.problem.show(); - expect(Logger.log).toHaveBeenCalledWith('problem_show', - {problem: 'i4x://edX/101/problem/Problem1'}); - }); - - it('fetch the answers', function() { - spyOn($, 'postWithPrefix'); - this.problem.show(); - expect($.postWithPrefix).toHaveBeenCalledWith('/problem/Problem1/problem_show', - jasmine.any(Function)); - }); - - it('show the answers', function() { - spyOn($, 'postWithPrefix').and.callFake((url, callback) => callback({answers: {'1_1': 'One', '1_2': 'Two'}})); - this.problem.show(); - expect($('#answer_1_1')).toHaveHtml('One'); - expect($('#answer_1_2')).toHaveHtml('Two'); - }); - - it('disables the show answer button', function() { - spyOn($, 'postWithPrefix').and.callFake((url, callback) => callback({answers: {}})); - this.problem.show(); - expect(this.problem.el.find('.show').attr('disabled')).toEqual('disabled'); - }); - - describe('radio text question', function() { - const radio_text_xml=`\ -
-

- -
-
- -
-
-
- - -

- -
- - -

-
-
- - -

-
-
-
\ -`; - beforeEach(function() { - // Append a radiotextresponse problem to the problem, so we can check it's javascript functionality - this.problem.el.prepend(radio_text_xml); - }); - - it('sets the correct class on the section for the correct choice', function() { - spyOn($, 'postWithPrefix').and.callFake((url, callback) => callback({answers: {"1_2_1": ["1_2_1_choiceinput_0bc"], "1_2_1_choiceinput_0bc": "3"}})); - this.problem.show(); - - expect($('#forinput1_2_1_choiceinput_0bc').attr('class')).toEqual( - 'choicetextgroup_show_correct'); - expect($('#answer_1_2_1_choiceinput_0bc').text()).toEqual('3'); - expect($('#answer_1_2_1_choiceinput_1bc').text()).toEqual(''); - expect($('#answer_1_2_1_choiceinput_2bc').text()).toEqual(''); - }); - - it('Should not disable input fields', function() { - spyOn($, 'postWithPrefix').and.callFake((url, callback) => callback({answers: {"1_2_1": ["1_2_1_choiceinput_0bc"], "1_2_1_choiceinput_0bc": "3"}})); - this.problem.show(); - expect($('input#1_2_1_choiceinput_0bc').attr('disabled')).not.toEqual('disabled'); - expect($('input#1_2_1_choiceinput_1bc').attr('disabled')).not.toEqual('disabled'); - expect($('input#1_2_1_choiceinput_2bc').attr('disabled')).not.toEqual('disabled'); - expect($('input#1_2_1').attr('disabled')).not.toEqual('disabled'); - }); - }); - - describe('imageinput', function() { - let el, height, width; - const imageinput_html = readFixtures('imageinput.underscore'); - - const DEFAULTS = { - id: '12345', - width: '300', - height: '400' - }; - - beforeEach(function() { - this.problem = new Problem($('.xblock-student_view')); - this.problem.el.prepend(_.template(imageinput_html)(DEFAULTS)); - }); - - const assertAnswer = (problem, data) => { - stubRequest(data); - problem.show(); - - $.each(data['answers'], (id, answer) => { - const img = getImage(answer); - el = $(`#inputtype_${id}`); - expect(img).toImageDiffEqual(el.find('canvas')[0]); - }); - }; - - var stubRequest = data => { - spyOn($, 'postWithPrefix').and.callFake((url, callback) => callback(data)); - }; - - var getImage = (coords, c_width, c_height) => { - let ctx, reg; - const types = { - rectangle: coords => { - reg = /^\(([0-9]+),([0-9]+)\)-\(([0-9]+),([0-9]+)\)$/; - const rects = coords.replace(/\s*/g, '').split(/;/); - - $.each(rects, (index, rect) => { - const { abs } = Math; - const points = reg.exec(rect); - if (points) { - width = abs(points[3] - points[1]); - height = abs(points[4] - points[2]); - - return ctx.rect(points[1], points[2], width, height); - } - }); - - ctx.stroke(); - ctx.fill(); - }, - - regions: coords => { - const parseCoords = coords => { - reg = JSON.parse(coords); - - if (typeof reg[0][0][0] === "undefined") { - reg = [reg]; - } - - return reg; - }; - - return $.each(parseCoords(coords), (index, region) => { - ctx.beginPath(); - $.each(region, (index, point) => { - if (index === 0) { - return ctx.moveTo(point[0], point[1]); - } else { - return ctx.lineTo(point[0], point[1]); - } - }); - - ctx.closePath(); - ctx.stroke(); - ctx.fill(); - }); - } - }; - - const canvas = document.createElement('canvas'); - canvas.width = c_width || 100; - canvas.height = c_height || 100; - - if (canvas.getContext) { - ctx = canvas.getContext('2d'); - } else { - console.log('Canvas is not supported.'); - } - - ctx.fillStyle = 'rgba(255,255,255,.3)'; - ctx.strokeStyle = "#FF0000"; - ctx.lineWidth = "2"; - - $.each(coords, (key, value) => { - if ((types[key] != null) && value) { return types[key](value); } - }); - - return canvas; - }; - - it('rectangle is drawn correctly', function() { - assertAnswer(this.problem, { - 'answers': { - '12345': { - 'rectangle': '(10,10)-(30,30)', - 'regions': null - } - } - }); - }); - - it('region is drawn correctly', function() { - assertAnswer(this.problem, { - 'answers': { - '12345': { - 'rectangle': null, - 'regions': '[[10,10],[30,30],[70,30],[20,30]]' - } - } - }); - }); - - it('mixed shapes are drawn correctly', function() { - assertAnswer(this.problem, { - 'answers': {'12345': { - 'rectangle': '(10,10)-(30,30);(5,5)-(20,20)', - 'regions': `[ - [[50,50],[40,40],[70,30],[50,70]], - [[90,95],[95,95],[90,70],[70,70]] -]` - } - } - }); - }); - - it('multiple image inputs draw answers on separate canvases', function() { - const data = { - id: '67890', - width: '400', - height: '300' - }; - - this.problem.el.prepend(_.template(imageinput_html)(data)); - assertAnswer(this.problem, { - 'answers': { - '12345': { - 'rectangle': null, - 'regions': '[[10,10],[30,30],[70,30],[20,30]]' - }, - '67890': { - 'rectangle': '(10,10)-(30,30)', - 'regions': null - } - } - }); - }); - - it('dictionary with answers doesn\'t contain answer for current id', function() { - spyOn(console, 'log'); - stubRequest({'answers':{}}); - this.problem.show(); - el = $('#inputtype_12345'); - expect(el.find('canvas')).not.toExist(); - expect(console.log).toHaveBeenCalledWith('Answer is absent for image input with id=12345'); - }); - }); - }); - }); - - describe('save', function() { - beforeEach(function() { - this.problem = new Problem($('.xblock-student_view')); - this.problem.answers = 'foo=1&bar=2'; - }); - - it('log the problem_save event', function() { - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - let promise; - promise = - {always(callable) { return callable(); }}; - return promise; - }); - this.problem.save(); - expect(Logger.log).toHaveBeenCalledWith('problem_save', 'foo=1&bar=2'); - }); - - it('POST to save problem', function() { - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - let promise; - promise = - {always(callable) { return callable(); }}; - return promise; - }); - this.problem.save(); - expect($.postWithPrefix).toHaveBeenCalledWith('/problem/Problem1/problem_save', - 'foo=1&bar=2', jasmine.any(Function)); - }); - - it('tests that save does not enable the submit button or change the text when submit is originally disabled', function() { - const self = this; - const curr_html = this.problem.el.html(); - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - // enableButtons should have been called at this point and the submit button should be unaffected - let promise; - expect(self.problem.submitButton).toHaveAttr('disabled'); - expect(self.problem.submitButtonLabel.text()).toBe('Submit'); - callback({success: 'correct', html: curr_html}); - promise = - {always(callable) { return callable(); }}; - return promise; - }); - // Expect submit to be disabled and labeled properly at the start - expect(this.problem.submitButton).toHaveAttr('disabled'); - expect(this.problem.submitButtonLabel.text()).toBe('Submit'); - this.problem.save(); - // Submit button should have the same state after save has completed - expect(this.problem.submitButton).toHaveAttr('disabled'); - expect(this.problem.submitButtonLabel.text()).toBe('Submit'); - }); - - it('tests that save does not disable the submit button or change the text when submit is originally enabled', function() { - const self = this; - const curr_html = this.problem.el.html(); - spyOn($, 'postWithPrefix').and.callFake(function(url, answers, callback) { - // enableButtons should have been called at this point, and the submit button should be disabled while submitting - let promise; - expect(self.problem.submitButton).toHaveAttr('disabled'); - expect(self.problem.submitButtonLabel.text()).toBe('Submit'); - callback({success: 'correct', html: curr_html}); - promise = - {always(callable) { return callable(); }}; - return promise; - }); - // Expect submit to be enabled and labeled properly at the start after adding an input - $('#input_example_1').val('test').trigger('input'); - expect(this.problem.submitButton).not.toHaveAttr('disabled'); - expect(this.problem.submitButtonLabel.text()).toBe('Submit'); - this.problem.save(); - // Submit button should have the same state after save has completed - expect(this.problem.submitButton).not.toHaveAttr('disabled'); - expect(this.problem.submitButtonLabel.text()).toBe('Submit'); - }); - }); - - describe('refreshMath', function() { - beforeEach(function() { - this.problem = new Problem($('.xblock-student_view')); - $('#input_example_1').val('E=mc^2'); - this.problem.refreshMath({target: $('#input_example_1').get(0)}); - }); - - it('should queue the conversion and MathML element update', function() { - expect(MathJax.Hub.Queue).toHaveBeenCalledWith(['Text', this.stubbedJax, 'E=mc^2'], - [this.problem.updateMathML, this.stubbedJax, $('#input_example_1').get(0)]); - }); -}); - - describe('updateMathML', function() { - beforeEach(function() { - this.problem = new Problem($('.xblock-student_view')); - this.stubbedJax.root.toMathML.and.returnValue(''); - }); - - describe('when there is no exception', function() { - beforeEach(function() { - this.problem.updateMathML(this.stubbedJax, $('#input_example_1').get(0)); - }); - - it('convert jax to MathML', () => expect($('#input_example_1_dynamath')).toHaveValue('')); - }); - - describe('when there is an exception', function() { - beforeEach(function() { - const error = new Error(); - error.restart = true; - this.stubbedJax.root.toMathML.and.throwError(error); - this.problem.updateMathML(this.stubbedJax, $('#input_example_1').get(0)); - }); - - it('should queue up the exception', function() { - expect(MathJax.Callback.After).toHaveBeenCalledWith([this.problem.refreshMath, this.stubbedJax], true); - }); - }); - }); - - describe('refreshAnswers', function() { - beforeEach(function() { - this.problem = new Problem($('.xblock-student_view')); - this.problem.el.html(`\ -