diff --git a/common/lib/xmodule/xmodule/js/fixtures/test.mp4 b/common/lib/xmodule/xmodule/js/fixtures/test.mp4 index 81d11df5f2..38959d2a99 100644 Binary files a/common/lib/xmodule/xmodule/js/fixtures/test.mp4 and b/common/lib/xmodule/xmodule/js/fixtures/test.mp4 differ diff --git a/common/lib/xmodule/xmodule/js/fixtures/test.ogv b/common/lib/xmodule/xmodule/js/fixtures/test.ogv index e128d82b5c..d554470d50 100644 Binary files a/common/lib/xmodule/xmodule/js/fixtures/test.ogv and b/common/lib/xmodule/xmodule/js/fixtures/test.ogv differ diff --git a/common/lib/xmodule/xmodule/js/fixtures/test.webm b/common/lib/xmodule/xmodule/js/fixtures/test.webm index 42e2130ca4..15ff32164c 100644 Binary files a/common/lib/xmodule/xmodule/js/fixtures/test.webm and b/common/lib/xmodule/xmodule/js/fixtures/test.webm differ diff --git a/common/lib/xmodule/xmodule/js/fixtures/video.html b/common/lib/xmodule/xmodule/js/fixtures/video.html index ce520fd522..fa9de67d6a 100644 --- a/common/lib/xmodule/xmodule/js/fixtures/video.html +++ b/common/lib/xmodule/xmodule/js/fixtures/video.html @@ -4,7 +4,7 @@
diff --git a/common/lib/xmodule/xmodule/js/fixtures/video_all.html b/common/lib/xmodule/xmodule/js/fixtures/video_all.html index 40fe28548e..4850a5e9e5 100644 --- a/common/lib/xmodule/xmodule/js/fixtures/video_all.html +++ b/common/lib/xmodule/xmodule/js/fixtures/video_all.html @@ -4,7 +4,7 @@
diff --git a/common/lib/xmodule/xmodule/js/fixtures/video_html5.html b/common/lib/xmodule/xmodule/js/fixtures/video_html5.html index f82451e377..904b0babc4 100644 --- a/common/lib/xmodule/xmodule/js/fixtures/video_html5.html +++ b/common/lib/xmodule/xmodule/js/fixtures/video_html5.html @@ -4,7 +4,7 @@
diff --git a/common/lib/xmodule/xmodule/js/fixtures/video_no_captions.html b/common/lib/xmodule/xmodule/js/fixtures/video_no_captions.html index 267897e598..f2d0308dd1 100644 --- a/common/lib/xmodule/xmodule/js/fixtures/video_no_captions.html +++ b/common/lib/xmodule/xmodule/js/fixtures/video_no_captions.html @@ -4,7 +4,7 @@
diff --git a/common/lib/xmodule/xmodule/js/fixtures/video_with_bumper.html b/common/lib/xmodule/xmodule/js/fixtures/video_with_bumper.html index efada9d13f..f1ebfdb541 100644 --- a/common/lib/xmodule/xmodule/js/fixtures/video_with_bumper.html +++ b/common/lib/xmodule/xmodule/js/fixtures/video_with_bumper.html @@ -4,9 +4,9 @@
diff --git a/common/lib/xmodule/xmodule/js/fixtures/video_yt_multiple.html b/common/lib/xmodule/xmodule/js/fixtures/video_yt_multiple.html index 0af562049f..d4f5401785 100644 --- a/common/lib/xmodule/xmodule/js/fixtures/video_yt_multiple.html +++ b/common/lib/xmodule/xmodule/js/fixtures/video_yt_multiple.html @@ -4,7 +4,7 @@
@@ -38,7 +38,7 @@
@@ -68,7 +68,7 @@
diff --git a/common/lib/xmodule/xmodule/js/fixtures/youtube_iframe_api.js b/common/lib/xmodule/xmodule/js/fixtures/youtube_iframe_api.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/common/lib/xmodule/xmodule/js/js_test.yml b/common/lib/xmodule/xmodule/js/js_test.yml index 305536d996..73403b619b 100644 --- a/common/lib/xmodule/xmodule/js/js_test.yml +++ b/common/lib/xmodule/xmodule/js/js_test.yml @@ -36,8 +36,8 @@ lib_paths: - common_static/js/test/i18n.js - common_static/coffee/src/ajax_prefix.js - common_static/js/src/logger.js - - common_static/js/vendor/jasmine-jquery.js - common_static/js/vendor/jasmine-imagediff.js + - common_static/js/libs/jasmine-waituntil.js - common_static/js/vendor/requirejs/require.js - RequireJS-namespace-undefine.js - common_static/js/vendor/jquery.min.js diff --git a/common/lib/xmodule/xmodule/js/karma_xmodule.conf.js b/common/lib/xmodule/xmodule/js/karma_xmodule.conf.js index 1dab63f085..386170b57e 100644 --- a/common/lib/xmodule/xmodule/js/karma_xmodule.conf.js +++ b/common/lib/xmodule/xmodule/js/karma_xmodule.conf.js @@ -37,6 +37,7 @@ var files = [ {pattern: 'common_static/js/src/logger.js', included: true}, {pattern: 'common_static/js/vendor/jasmine-imagediff.js', included: true}, {pattern: 'common_static/js/libs/jasmine-waituntil.js', included: true}, + {pattern: 'common_static/js/libs/jasmine-extensions.js', included: true}, {pattern: 'common_static/js/vendor/requirejs/require.js', included: true}, {pattern: 'RequireJS-namespace-undefine.js', included: true}, {pattern: 'common_static/js/vendor/jquery-ui.min.js', included: true}, diff --git a/common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee b/common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee index 09f9408c84..9c6a396cc8 100644 --- a/common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee @@ -7,7 +7,7 @@ describe 'Problem', -> Hub: jasmine.createSpyObj('MathJax.Hub', ['getAllJax', 'Queue']) Callback: jasmine.createSpyObj('MathJax.Callback', ['After']) @stubbedJax = root: jasmine.createSpyObj('jax.root', ['toMathML']) - MathJax.Hub.getAllJax.andReturn [@stubbedJax] + MathJax.Hub.getAllJax.and.returnValue [@stubbedJax] window.update_schematics = -> spyOn SR, 'readElts' spyOn SR, 'readText' @@ -21,8 +21,8 @@ describe 'Problem', -> loadFixtures 'problem.html' spyOn Logger, 'log' - spyOn($.fn, 'load').andCallFake (url, callback) -> - $(@).html problem_content_default + spyOn($.fn, 'load').and.callFake (url, callback) -> + $(@).html readFixtures('problem_content.html') callback() describe 'constructor', -> @@ -46,7 +46,7 @@ describe 'Problem', -> describe 'bind', -> beforeEach -> spyOn window, 'update_schematics' - MathJax.Hub.getAllJax.andReturn [@stubbedJax] + MathJax.Hub.getAllJax.and.returnValue [@stubbedJax] @problem = new Problem($('.xblock-student_view')) it 'set mathjax typeset', -> @@ -76,7 +76,7 @@ describe 'Problem', -> describe 'bind_with_custom_input_id', -> beforeEach -> spyOn window, 'update_schematics' - MathJax.Hub.getAllJax.andReturn [@stubbedJax] + MathJax.Hub.getAllJax.and.returnValue [@stubbedJax] @problem = new Problem($('.xblock-student_view')) $(@).html readFixtures('problem_content_1240.html') @@ -137,7 +137,7 @@ describe 'Problem', -> describe 'with no content given', -> beforeEach -> - spyOn($, 'postWithPrefix').andCallFake (url, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> callback html: "Hello World" @problem.render() @@ -164,7 +164,7 @@ describe 'Problem', -> @problem.answers = 'foo=1&bar=2' it 'log the problem_check event', -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> promise = always: (callable) -> callable() done: (callable) -> callable() @@ -172,7 +172,7 @@ describe 'Problem', -> expect(Logger.log).toHaveBeenCalledWith 'problem_check', 'foo=1&bar=2' it 'log the problem_graded event, after the problem is done grading.', -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> response = success: 'correct' contents: 'mock grader response' @@ -184,7 +184,7 @@ describe 'Problem', -> expect(Logger.log).toHaveBeenCalledWith 'problem_graded', ['foo=1&bar=2', 'mock grader response'], @problem.id it 'submit the answer for check', -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> promise = always: (callable) -> callable() done: (callable) -> callable() @@ -194,58 +194,76 @@ describe 'Problem', -> describe 'when the response is correct', -> it 'call render with returned content', -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> - callback(success: 'correct', contents: 'Correct!') + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> + callback(success: 'correct', contents: 'Correct') promise = always: (callable) -> callable() done: (callable) -> callable() @problem.check() - expect(@problem.el.html()).toEqual 'Correct!' + expect(@problem.el.html()).toEqual 'Correct' expect(window.SR.readElts).toHaveBeenCalled() describe 'when the response is incorrect', -> it 'call render with returned content', -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> - callback(success: 'incorrect', contents: 'Incorrect!') + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> + callback(success: 'incorrect', contents: 'Incorrect') promise = always: (callable) -> callable() done: (callable) -> callable() @problem.check() - expect(@problem.el.html()).toEqual 'Incorrect!' + expect(@problem.el.html()).toEqual 'Incorrect' expect(window.SR.readElts).toHaveBeenCalled() - it 'tests if all the capa buttons are disabled while checking', -> - runs -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> - callback(success: 'incorrect', contents: 'Incorrect!') + it 'tests if all the capa buttons are disabled while checking', (done)-> + deferred = $.Deferred() + self = this + + runs = -> + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> + promise = undefined + callback + success: 'incorrect' + contents: 'Incorrect' promise = - always: (callable) -> callable() - done: (callable) -> callable() + always: (callable) -> + callable() + done: (callable) -> + callable() spyOn @problem, 'enableAllButtons' @problem.check() expect(@problem.enableAllButtons).toHaveBeenCalledWith false, true - waitsFor (-> - return jQuery.active == 0 - ), "jQuery requests finished", 1000 + if jQuery.active == 0 + deferred.resolve() + deferred.promise() - runs -> - expect(@problem.enableAllButtons).toHaveBeenCalledWith true, true + runs.call(self).then(-> + expect(self.problem.enableAllButtons).toHaveBeenCalledWith true, true + return + ).always done - it 'tests the expected change in text of check button', -> - runs -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> + it 'tests the expected change in text of check button', (done) -> + deferred = $.Deferred() + self = this + + runs = -> + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> + promise = undefined promise = - always: (callable) -> callable() - done: (callable) -> callable() + always: (callable) -> + callable() + done: (callable) -> + callable() spyOn @problem.checkButtonLabel, 'text' @problem.check() expect(@problem.checkButtonLabel.text).toHaveBeenCalledWith 'Checking...' - waitsFor (-> - return jQuery.active == 0 - ), "jQuery requests finished", 1000 + if jQuery.active == 0 + deferred.resolve() + deferred.promise() - runs -> - expect(@problem.checkButtonLabel.text).toHaveBeenCalledWith 'Check' + runs.call(self).then(-> + expect(self.problem.checkButtonLabel.text).toHaveBeenCalledWith 'Check' + return + ).always done describe 'check button on problems', -> beforeEach -> @@ -341,7 +359,7 @@ describe 'Problem', -> @problem = new Problem($('.xblock-student_view')) it 'log the problem_reset event', -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> promise = always: (callable) -> callable() @problem.answers = 'foo=1&bar=2' @@ -349,7 +367,7 @@ describe 'Problem', -> expect(Logger.log).toHaveBeenCalledWith 'problem_reset', 'foo=1&bar=2' it 'POST to the problem reset page', -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> promise = always: (callable) -> callable() @problem.reset() @@ -357,29 +375,34 @@ describe 'Problem', -> { id: 'i4x://edX/101/problem/Problem1' }, jasmine.any(Function) it 'render the returned content', -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> - callback html: "Reset!" + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> + callback html: "Reset" promise = always: (callable) -> callable() @problem.reset() - expect(@problem.el.html()).toEqual 'Reset!' + expect(@problem.el.html()).toEqual 'Reset' - it 'tests if all the buttons are disabled and the text of check button remains same while resetting', -> - runs -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> - promise = - always: (callable) -> callable() + it 'tests if all the buttons are disabled and the text of check button remains same while resetting', (done) -> + deferred = $.Deferred() + self = this + + runs = -> + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> + promise = undefined + promise = always: (callable) -> + callable() spyOn @problem, 'enableAllButtons' @problem.reset() expect(@problem.enableAllButtons).toHaveBeenCalledWith false, false expect(@problem.checkButtonLabel).toHaveText 'Check' - waitsFor (-> - return jQuery.active == 0 - ), "jQuery requests finished", 1000 + if jQuery.active == 0 + deferred.resolve() + deferred.promise() - runs -> - expect(@problem.enableAllButtons).toHaveBeenCalledWith true, false - expect(@problem.checkButtonLabel).toHaveText 'Check' + runs.call(self).then(-> + expect(self.problem.enableAllButtons).toHaveBeenCalledWith true, false + expect(self.problem.checkButtonLabel).toHaveText 'Check' + ).always done describe 'show', -> beforeEach -> @@ -402,20 +425,20 @@ describe 'Problem', -> jasmine.any(Function) it 'show the answers', -> - spyOn($, 'postWithPrefix').andCallFake (url, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> callback answers: '1_1': 'One', '1_2': 'Two' @problem.show() expect($('#answer_1_1')).toHaveHtml 'One' expect($('#answer_1_2')).toHaveHtml 'Two' it 'toggle the show answer button', -> - spyOn($, 'postWithPrefix').andCallFake (url, callback) -> callback(answers: {}) + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> callback(answers: {}) @problem.show() expect($('.show .show-label')).toHaveText 'Hide Answer' expect(window.SR.readElts).toHaveBeenCalled() it 'toggle the show answer button, answers are strings', -> - spyOn($, 'postWithPrefix').andCallFake (url, callback) -> callback(answers: '1_1': 'One', '1_2': 'Two') + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> callback(answers: '1_1': 'One', '1_2': 'Two') @problem.show() expect($('.show .show-label')).toHaveText 'Hide Answer' expect(window.SR.readElts).toHaveBeenCalledWith ['

Answer: One

', '

Answer: Two

'] @@ -423,27 +446,32 @@ describe 'Problem', -> it 'toggle the show answer button, answers are elements', -> answer1 = '
one
' answer2 = '
two
' - spyOn($, 'postWithPrefix').andCallFake (url, callback) -> callback(answers: '1_1': answer1, '1_2': answer2) + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> callback(answers: '1_1': answer1, '1_2': answer2) @problem.show() expect($('.show .show-label')).toHaveText 'Hide Answer' expect(window.SR.readElts).toHaveBeenCalledWith [jasmine.any(jQuery), jasmine.any(jQuery)] it 'add the showed class to element', -> - spyOn($, 'postWithPrefix').andCallFake (url, callback) -> callback(answers: {}) + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> callback(answers: {}) @problem.show() expect(@problem.el).toHaveClass 'showed' - it 'reads the answers', -> - runs -> - spyOn($, 'postWithPrefix').andCallFake (url, callback) -> callback(answers: 'answers') + it 'reads the answers', (done) -> + deferred = $.Deferred() + + runs = -> + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> + callback answers: + '1_1': 'answers' @problem.show() + if jQuery.active == 0 + deferred.resolve() + deferred.promise() - waitsFor (-> - return jQuery.active == 0 - ), "jQuery requests finished", 1000 - - runs -> + runs.call(this).then(-> expect(window.SR.readElts).toHaveBeenCalled() + return + ).always done describe 'multiple choice question', -> beforeEach -> @@ -455,7 +483,7 @@ describe 'Problem', -> ''' it 'set the correct_answer attribute on the choice', -> - spyOn($, 'postWithPrefix').andCallFake (url, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> callback answers: '1_1': [2, 3] @problem.show() expect($('label[for="input_1_1_1"]')).not.toHaveAttr 'correct_answer', 'true' @@ -496,7 +524,7 @@ describe 'Problem', -> @problem.el.prepend(radio_text_xml) it 'sets the correct class on the section for the correct choice', -> - spyOn($, 'postWithPrefix').andCallFake (url, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> callback answers: "1_2_1": ["1_2_1_choiceinput_0bc"], "1_2_1_choiceinput_0bc": "3" @problem.show() @@ -507,7 +535,7 @@ describe 'Problem', -> expect($('#answer_1_2_1_choiceinput_2bc').text()).toEqual('') it 'Should not disable input fields', -> - spyOn($, 'postWithPrefix').andCallFake (url, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> callback answers: "1_2_1": ["1_2_1_choiceinput_0bc"], "1_2_1_choiceinput_0bc": "3" @problem.show() expect($('input#1_2_1_choiceinput_0bc').attr('disabled')).not.toEqual('disabled') @@ -537,7 +565,7 @@ describe 'Problem', -> expect(img).toImageDiffEqual(el.find('canvas')[0]) stubRequest = (data) => - spyOn($, 'postWithPrefix').andCallFake (url, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> callback data getImage = (coords, c_width, c_height) => @@ -680,51 +708,61 @@ describe 'Problem', -> @problem.answers = 'foo=1&bar=2' it 'log the problem_save event', -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> promise = always: (callable) -> callable() @problem.save() expect(Logger.log).toHaveBeenCalledWith 'problem_save', 'foo=1&bar=2' it 'POST to save problem', -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> promise = always: (callable) -> callable() @problem.save() expect($.postWithPrefix).toHaveBeenCalledWith '/problem/Problem1/problem_save', 'foo=1&bar=2', jasmine.any(Function) - it 'reads the save message', -> - runs -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> - callback(success: 'OK') - promise = - always: (callable) -> callable() + it 'reads the save message', (done) -> + deferred = $.Deferred() + + runs = -> + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> + promise = undefined + callback success: 'OK' + promise = always: (callable) -> + callable() @problem.save() - waitsFor (-> - return jQuery.active == 0 - ), "jQuery requests finished", 1000 + if jQuery.active == 0 + deferred.resolve() + deferred.promise() - runs -> + runs.call(this).then(-> expect(window.SR.readElts).toHaveBeenCalled() + return + ).always done - it 'tests if all the buttons are disabled and the text of check button does not change while saving.', -> - runs -> - spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> - callback(success: 'OK') - promise = - always: (callable) -> callable() + it 'tests if all the buttons are disabled and the text of check button does not change while saving.', (done) -> + deferred = $.Deferred() + self = this + + runs = -> + spyOn($, 'postWithPrefix').and.callFake (url, answers, callback) -> + promise = undefined + callback success: 'OK' + promise = always: (callable) -> + callable() spyOn @problem, 'enableAllButtons' @problem.save() expect(@problem.enableAllButtons).toHaveBeenCalledWith false, false expect(@problem.checkButtonLabel).toHaveText 'Check' - waitsFor (-> - return jQuery.active == 0 - ), "jQuery requests finished", 1000 + if jQuery.active == 0 + deferred.resolve() + deferred.promise() - runs -> - expect(@problem.enableAllButtons).toHaveBeenCalledWith true, false - expect(@problem.checkButtonLabel).toHaveText 'Check' + runs.call(self).then(-> + expect(self.problem.enableAllButtons).toHaveBeenCalledWith true, false + expect(self.problem.checkButtonLabel).toHaveText 'Check' + ).always done describe 'refreshMath', -> beforeEach -> @@ -739,7 +777,7 @@ describe 'Problem', -> describe 'updateMathML', -> beforeEach -> @problem = new Problem($('.xblock-student_view')) - @stubbedJax.root.toMathML.andReturn '' + @stubbedJax.root.toMathML.and.returnValue '' describe 'when there is no exception', -> beforeEach -> @@ -750,7 +788,9 @@ describe 'Problem', -> describe 'when there is an exception', -> beforeEach -> - @stubbedJax.root.toMathML.andThrow {restart: true} + error = new Error() + error.restart = true + @stubbedJax.root.toMathML.and.throwError error @problem.updateMathML @stubbedJax, $('#input_example_1').get(0) it 'should queue up the exception', -> @@ -793,26 +833,29 @@ describe 'Problem', -> matlabinput_html = readFixtures('matlabinput_problem.html') beforeEach -> - spyOn($, 'postWithPrefix').andCallFake (url, callback) -> + spyOn($, 'postWithPrefix').and.callFake (url, callback) -> callback html: matlabinput_html - jasmine.Clock.useMock() + jasmine.clock().install() @problem = new Problem($('.xblock-student_view')) - spyOn(@problem, 'poll').andCallThrough() + spyOn(@problem, 'poll').and.callThrough() @problem.render(matlabinput_html) + afterEach -> + jasmine.clock().uninstall() + it 'check that we stop polling after a fixed amount of time', -> expect(@problem.poll).not.toHaveBeenCalled() - jasmine.Clock.tick(1) + jasmine.clock().tick(1) time_steps = [1000, 2000, 4000, 8000, 16000, 32000] num_calls = 1 for time_step in time_steps do (time_step) => - jasmine.Clock.tick(time_step) - expect(@problem.poll.callCount).toEqual(num_calls) + jasmine.clock().tick(time_step) + expect(@problem.poll.calls.count()).toEqual(num_calls) num_calls += 1 # jump the next step and verify that we are not still continuing to poll - jasmine.Clock.tick(64000) - expect(@problem.poll.callCount).toEqual(6) + jasmine.clock().tick(64000) + expect(@problem.poll.calls.count()).toEqual(6) expect($('.capa_alert').text()).toEqual("The grading process is still running. Refresh the page to see updates.") diff --git a/common/lib/xmodule/xmodule/js/spec/collapsible_spec.js b/common/lib/xmodule/xmodule/js/spec/collapsible_spec.js index 06a4aae63f..b942ee5088 100644 --- a/common/lib/xmodule/xmodule/js/spec/collapsible_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/collapsible_spec.js @@ -40,8 +40,8 @@ it('Default container initialized correctly', function () { initialize(html); - expect(el.find('.shortform')).toContain('.full-top'); - expect(el.find('.shortform')).toContain('.full-bottom'); + expect(el.find('.shortform')).toContainElement('.full-top'); + expect(el.find('.shortform')).toContainElement('.full-bottom'); expect(el.find('.longform')).toBeHidden(); expect(el.find('.full')).toHandle('click'); }); @@ -49,7 +49,7 @@ it('Custom container initialized correctly', function () { initialize(html_custom); - expect(el.find('.shortform-custom')).toContain('.full-custom'); + expect(el.find('.shortform-custom')).toContainElement('.full-custom'); expect(el.find('.full-custom')).toHaveText('Show shortform-custom'); expect(el.find('.longform')).toBeHidden(); expect(el.find('.full-custom')).toHandle('click'); diff --git a/common/lib/xmodule/xmodule/js/spec/helper.js b/common/lib/xmodule/xmodule/js/spec/helper.js index 9c83fd0063..1457c3e3db 100644 --- a/common/lib/xmodule/xmodule/js/spec/helper.js +++ b/common/lib/xmodule/xmodule/js/spec/helper.js @@ -1,5 +1,6 @@ (function () { 'use strict'; + var origAjax = $.ajax; var stubbedYT = { Player: function () { @@ -15,9 +16,9 @@ ] ); - Player.getDuration.andReturn(60); - Player.getAvailablePlaybackRates.andReturn([0.50, 1.0, 1.50, 2.0]); - Player.getAvailableQualityLevels.andReturn( + Player.getDuration.and.returnValue(60); + Player.getAvailablePlaybackRates.and.returnValue([0.50, 1.0, 1.50, 2.0]); + Player.getAvailableQualityLevels.and.returnValue( ['highres', 'hd1080', 'hd720', 'large', 'medium', 'small'] ); @@ -124,11 +125,11 @@ jasmine.stubRequests = function () { var spy = $.ajax; - - if (!($.ajax.isSpy)) { + if (!jasmine.isSpy($.ajax)) { spy = spyOn($, 'ajax'); } - return spy.andCallFake(function (settings) { + + return spy.and.callFake(function (settings) { var match = settings.url .match(/googleapis\.com\/.+\/videos\/\?id=(.+)&part=contentDetails/), status, callCallback; @@ -176,46 +177,16 @@ return; } else if (settings.url === '/save_user_state') { return {success: true}; + } else if(settings.url.match(new RegExp(jasmine.getFixtures().fixturesPath + ".+", 'g'))) { + return origAjax(settings); } else { - throw 'External request attempted for ' + - settings.url + - ', which is not defined.'; + $.ajax.and.callThrough(); } }); }; - // Add custom Jasmine matchers. - beforeEach(function () { - this.addMatchers({ - toHaveAttrs: function (attrs) { - var element; - - if ($.isEmptyObject(attrs)) { - return false; - } - - element = this.actual; - - return _.every(attrs, function (value, name) { - return element.attr(name) === value; - }); - }, - toBeInRange: function (min, max) { - return min <= this.actual && this.actual <= max; - }, - toBeInArray: function (array) { - return $.inArray(this.actual, array) > -1; - }, - toBeFocused: function () { - return $(this.actual)[0] === $(this.actual)[0].ownerDocument.activeElement; - } - }); - - return this.addMatchers(window.imagediff.jasmine); - }); - - // Stub jQuery.cookie module. - $.cookie = jasmine.createSpy('jQuery.cookie').andReturn('1.0'); + // Stub jQuery.cookie module. + $.cookie = jasmine.createSpy('jQuery.cookie').and.returnValue('1.0'); // # Stub jQuery.qtip module. $.fn.qtip = jasmine.createSpy('jQuery.qtip'); @@ -224,7 +195,7 @@ $.fn.scrollTo = jasmine.createSpy('jQuery.scrollTo'); // Stub window.Video.loadYouTubeIFrameAPI() - window.Video.loadYouTubeIFrameAPI = jasmine.createSpy('window.Video.loadYouTubeIFrameAPI').andReturn( + window.Video.loadYouTubeIFrameAPI = jasmine.createSpy('window.Video.loadYouTubeIFrameAPI').and.returnValue( function (scriptTag) { var event = document.createEvent('Event'); if (fixture === "video.html") { @@ -275,13 +246,13 @@ ], obj = {}, delta = { - add: jasmine.createSpy().andReturn(obj), - substract: jasmine.createSpy().andReturn(obj), - reset: jasmine.createSpy().andReturn(obj) + add: jasmine.createSpy().and.returnValue(obj), + substract: jasmine.createSpy().and.returnValue(obj), + reset: jasmine.createSpy().and.returnValue(obj) }; $.each(methods, function (index, method) { - obj[method] = jasmine.createSpy(method).andReturn(obj); + obj[method] = jasmine.createSpy(method).and.returnValue(obj); }); obj.delta = delta; diff --git a/common/lib/xmodule/xmodule/js/spec/html/edit_spec.coffee b/common/lib/xmodule/xmodule/js/spec/html/edit_spec.coffee index 19849b5764..91939d8e20 100644 --- a/common/lib/xmodule/xmodule/js/spec/html/edit_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/html/edit_spec.coffee @@ -10,21 +10,21 @@ describe 'HTMLEditingDescriptor', -> it 'Returns data from Visual Editor if text has changed', -> visualEditorStub = getContent: () -> 'from visual editor' - spyOn(@descriptor, 'getVisualEditor').andCallFake () -> + spyOn(@descriptor, 'getVisualEditor').and.callFake () -> visualEditorStub data = @descriptor.save().data expect(data).toEqual('from visual editor') it 'Returns data from Raw Editor if text has not changed', -> visualEditorStub = getContent: () -> '

original visual text

' - spyOn(@descriptor, 'getVisualEditor').andCallFake () -> + spyOn(@descriptor, 'getVisualEditor').and.callFake () -> visualEditorStub data = @descriptor.save().data expect(data).toEqual('raw text') it 'Performs link rewriting for static assets when saving', -> visualEditorStub = getContent: () -> 'from visual editor with /c4x/foo/bar/asset/image.jpg' - spyOn(@descriptor, 'getVisualEditor').andCallFake () -> + spyOn(@descriptor, 'getVisualEditor').and.callFake () -> visualEditorStub data = @descriptor.save().data expect(data).toEqual('from visual editor with /static/image.jpg') diff --git a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee index 771708d752..b3f7171a4f 100644 --- a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee @@ -24,7 +24,7 @@ describe 'MarkdownEditingDescriptor', -> it 'click on advanced editor should work', -> loadFixtures 'problem-with-markdown.html' @descriptor = new MarkdownEditingDescriptor($('.problem-editor')) - spyOn(@descriptor, 'confirmConversionToXml').andReturn(true) + spyOn(@descriptor, 'confirmConversionToXml').and.returnValue(true) expect(@descriptor.confirmConversionToXml).not.toHaveBeenCalled() e = jasmine.createSpyObj('e', [ 'preventDefault' ]) @descriptor.onShowXMLButton(e) diff --git a/common/lib/xmodule/xmodule/js/spec/tabs/edit.coffee b/common/lib/xmodule/xmodule/js/spec/tabs/edit.coffee index a80aa127a3..ae73009bf3 100644 --- a/common/lib/xmodule/xmodule/js/spec/tabs/edit.coffee +++ b/common/lib/xmodule/xmodule/js/spec/tabs/edit.coffee @@ -14,8 +14,8 @@ describe "TabsEditingDescriptor", -> TabsEditingDescriptor.Model.addModelUpdate(@html_id, 'Tab 1 Transcripts', @tab_1_modelUpdate) TabsEditingDescriptor.Model.addOnSwitch(@html_id, 'Tab 1 Transcripts', @tab_1_switch) - spyOn($.fn, 'hide').andCallThrough() - spyOn($.fn, 'show').andCallThrough() + spyOn($.fn, 'hide').and.callThrough() + spyOn($.fn, 'show').and.callThrough() spyOn(TabsEditingDescriptor.Model, 'initialize') spyOn(TabsEditingDescriptor.Model, 'updateValue') @@ -37,11 +37,11 @@ describe "TabsEditingDescriptor", -> expect(@tab_1_switch).toHaveBeenCalled() it "if click on current tab, nothing should happen", -> - spyOn($.fn, 'trigger').andCallThrough() + spyOn($.fn, 'trigger').and.callThrough() currentTab = @descriptor.$tabs.filter('.' + @isCurrent) @descriptor.$tabs.eq(0).trigger("click") expect(@descriptor.$tabs.filter('.' + @isCurrent)).toEqual(currentTab) - expect($.fn.trigger.calls.length).toEqual(1) + expect($.fn.trigger.calls.count()).toEqual(1) it "onSwitch function call", -> @descriptor.$tabs.eq(1).trigger("click") @@ -82,7 +82,7 @@ describe "TabsEditingDescriptor special save cases", -> expect(data).toEqual(null) it "case: no function in model update, but value presented", -> - @tab_0_modelUpdate = jasmine.createSpy('tab_0_modelUpdate').andReturn(1) + @tab_0_modelUpdate = jasmine.createSpy('tab_0_modelUpdate').and.returnValue(1) TabsEditingDescriptor.Model.addModelUpdate(@html_id, 'Tab 0 Editor', @tab_0_modelUpdate) @descriptor.$tabs.eq(1).trigger("click") expect(@tab_0_modelUpdate).toHaveBeenCalled() diff --git a/common/lib/xmodule/xmodule/js/spec/video/async_process_spec.js b/common/lib/xmodule/xmodule/js/spec/video/async_process_spec.js index c26ec7c8e7..7fb5bf97d8 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/async_process_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/async_process_spec.js @@ -15,82 +15,66 @@ function (AsyncProcess) { items = getArrayNthLength(1000); describe('AsyncProcess', function () { - it ('Array is processed successfully', function () { + it ('Array is processed successfully', function (done) { var processedArray, expectedArray = getArrayNthLength(1000, 2), process = function (item) { return 2 * item; }; - runs(function () { - AsyncProcess.array(items, process).done(function (result) { - processedArray = result; - }); + AsyncProcess.array(items, process).done(function (result) { + processedArray = result; }); - waitsFor(function () { + jasmine.waitUntil(function () { return processedArray; - }, 'Array processing takes too much time', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(processedArray).toEqual(expectedArray); - }); + }).always(done); }); - it ('If non-array is passed, error callback is called', function () { + it ('If non-array is passed, error callback is called', function (done) { var isError, process = function () {}; - runs(function () { - AsyncProcess.array('string', process).fail(function () { - isError = true; - }); + AsyncProcess.array('string', process).fail(function () { + isError = true; }); - waitsFor(function () { + jasmine.waitUntil(function () { return isError; - }, 'Error callback wasn\'t called', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(isError).toBeTruthy(); - }); + }).always(done); }); - it ('If an empty array is passed, returns initial array', function () { + it ('If an empty array is passed, returns initial array', function (done) { var processedArray, process = function () {}; - runs(function () { - AsyncProcess.array([], process).done(function (result) { - processedArray = result; - }); + AsyncProcess.array([], process).done(function (result) { + processedArray = result; }); - waitsFor(function () { + jasmine.waitUntil(function () { return processedArray; - }, 'Array processing takes too much time', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(processedArray).toEqual([]); - }); + }).always(done); }); - it ('If no process function passed, returns initial array', function () { + it ('If no process function passed, returns initial array', function (done) { var processedArray; - runs(function () { - AsyncProcess.array(items).done(function (result) { - processedArray = result; - }); + AsyncProcess.array(items).done(function (result) { + processedArray = result; }); - waitsFor(function () { + jasmine.waitUntil(function () { return processedArray; - }, 'Array processing takes too much time', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(processedArray).toEqual(items); - }); + }).always(done); }); }); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/events_spec.js b/common/lib/xmodule/xmodule/js/spec/video/events_spec.js index 437577c7dd..8f85970551 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/events_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/events_spec.js @@ -7,9 +7,7 @@ oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice') - .andReturn(null); - - jasmine.stubRequests(); + .and.returnValue(null); state = jasmine.initializePlayer(); @@ -20,26 +18,23 @@ $('source').remove(); window.onTouchBasedDevice = oldOTBD; state.storage.clear(); + state.videoPlayer.destroy(); }); - it('initialize', function () { - waitsFor(function () { + it('initialize', function (done) { + jasmine.waitUntil(function () { return state.el.hasClass('is-initialized'); - }, 'Player is not initialized.', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect('initialize').not.toHaveBeenTriggeredOn('.video'); - }); + }).always(done); }); - it('ready', function () { - waitsFor(function () { + it('ready', function (done) { + jasmine.waitUntil(function () { return state.el.hasClass('is-initialized'); - }, 'Player is not initialized.', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect('ready').not.toHaveBeenTriggeredOn('.video'); - }); + }).always(done); }); it('play', function () { @@ -86,9 +81,7 @@ oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice') - .andReturn(null); - - jasmine.stubRequests(); + .and.returnValue(null); state = jasmine.initializePlayerYouTube(); }); @@ -96,6 +89,8 @@ afterEach(function () { $('source').remove(); window.onTouchBasedDevice = oldOTBD; + state.storage.clear(); + state.videoPlayer.destroy(); }); it('qualitychange', function () { diff --git a/common/lib/xmodule/xmodule/js/spec/video/general_spec.js b/common/lib/xmodule/xmodule/js/spec/video/general_spec.js index f9c0eabf2d..cc188d1c34 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/general_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/general_spec.js @@ -2,26 +2,27 @@ describe('Video', function () { var oldOTBD, state; - beforeEach(function () { - jasmine.stubRequests(); - }); - afterEach(function () { $('source').remove(); window.VideoState = {}; window.VideoState.id = {}; + window.YT = jasmine.YT; }); describe('constructor', function () { describe('YT', function () { beforeEach(function () { loadFixtures('video.html'); - $.cookie.andReturn('0.50'); - this.state = jasmine.initializePlayerYouTube('video_html5.html'); + $.cookie.and.returnValue('0.50'); }); describe('by default', function () { + beforeEach(function () { + this.state = jasmine.initializePlayerYouTube('video_html5.html'); + }); + afterEach(function () { + this.state.storage.clear(); this.state.videoPlayer.destroy(); }); @@ -30,7 +31,7 @@ }); it('set the elements', function () { - expect(this.state.el).toBe('#video_id'); + expect(this.state.el).toEqual($('#video_id')); }); it('parse the videos', function () { @@ -55,13 +56,13 @@ var state; beforeEach(function () { - $.cookie.andReturn('0.75'); + $.cookie.and.returnValue('0.75'); state = jasmine.initializePlayer('video_html5.html'); }); afterEach(function () { + state.storage.clear(); state.videoPlayer.destroy(); - state = undefined; }); describe('by default', function () { @@ -70,7 +71,7 @@ }); it('set the elements', function () { - expect(state.el).toBe('#video_id'); + expect(state.el).toEqual($('#video_id')); }); it('doesn\'t have `videos` dictionary', function () { @@ -101,35 +102,34 @@ }); describe('YouTube API is not loaded', function () { + var state; beforeEach(function () { window.YT = undefined; state = jasmine.initializePlayerYouTube(); - }) + }); afterEach(function () { + state.storage.clear(); state.videoPlayer.destroy(); }); - it('callback, to be called after YouTube API loads, exists and is called', function () { - waitsFor(function () { - return state.youtubeApiAvailable === true; - }, 'YouTube API is loaded', 3000); - + it('callback, to be called after YouTube API loads, exists and is called', function (done) { window.YT = jasmine.YT; - // Call the callback that must be called when YouTube API is // loaded. By specification. window.onYouTubeIframeAPIReady(); - - runs(function () { + jasmine.waitUntil(function () { + return state.youtubeApiAvailable === true; + }).done(function(){ // If YouTube API is not loaded, then the code will should create // a global callback that will be called by API once it is loaded. expect(window.onYouTubeIframeAPIReady).not.toBeUndefined(); - }); + }).always(done); }); }); describe('checking start and end times', function () { + var state; var miniTestSuite = [ { itDescription: 'both times are proper', @@ -159,6 +159,7 @@ ]; afterEach(function () { + state.storage.clear(); state.videoPlayer.destroy(); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js b/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js index 2f9126cd8c..be4929df27 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js @@ -1,17 +1,19 @@ (function (undefined) { describe('Video HTML5Video', function () { + var STATUS = window.STATUS; var state, oldOTBD, playbackRates = [0.75, 1.0, 1.25, 1.5]; beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine - .createSpy('onTouchBasedDevice').andReturn(null); + .createSpy('onTouchBasedDevice').and.returnValue(null); + }); afterEach(function () { state.storage.clear(); state.videoPlayer.destroy(); - $.fn.scrollTo.reset(); + $.fn.scrollTo.calls.reset(); $('source').remove(); window.onTouchBasedDevice = oldOTBD; }); @@ -25,13 +27,13 @@ describe('events:', function () { beforeEach(function () { - spyOn(state.videoPlayer.player, 'callStateChangeCallback').andCallThrough(); + spyOn(state.videoPlayer.player, 'callStateChangeCallback').and.callThrough(); }); describe('[click]', function () { describe('when player is paused', function () { beforeEach(function () { - spyOn(state.videoPlayer.player.video, 'play').andCallThrough(); + spyOn(state.videoPlayer.player.video, 'play').and.callThrough(); state.videoPlayer.player.playerState = STATUS.PAUSED; $(state.videoPlayer.player.videoEl).trigger('click'); }); @@ -40,32 +42,25 @@ expect(state.videoPlayer.player.video.play).toHaveBeenCalled(); }); - it('player state was changed', function () { - waitsFor(function () { - return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED; - }, 'Player state should be changed', WAIT_TIMEOUT); - - runs(function () { - expect(state.videoPlayer.player.getPlayerState()) - .toBe(STATUS.PLAYING); - }); + it('player state was changed', function (done) { + jasmine.waitUntil(function () { + return state.videoPlayer.player.getPlayerState() === STATUS.PLAYING; + }).always(done); }); - it('callback was not called', function () { - waitsFor(function () { + // Flaky. Checking the parameters of calls to onStateChange() will likely be more reliable. + xit('callback was not called', function (done) { + jasmine.waitUntil(function () { return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED; - }, 'Player state should be changed', WAIT_TIMEOUT); - - runs(function () { - expect(state.videoPlayer.player.callStateChangeCallback) - .not.toHaveBeenCalled(); - }); + }).then(function () { + expect(state.videoPlayer.player.callStateChangeCallback).not.toHaveBeenCalled(); + }).always(done); }); }); describe('[player is playing]', function () { beforeEach(function () { - spyOn(state.videoPlayer.player.video, 'pause').andCallThrough(); + spyOn(state.videoPlayer.player.video, 'pause').and.callThrough(); state.videoPlayer.player.playerState = STATUS.PLAYING; $(state.videoPlayer.player.videoEl).trigger('click'); }); @@ -74,33 +69,29 @@ expect(state.videoPlayer.player.video.pause).toHaveBeenCalled(); }); - it('player state was changed', function () { - waitsFor(function () { + it('player state was changed', function (done) { + jasmine.waitUntil(function () { return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING; - }, 'Player state should be changed', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(state.videoPlayer.player.getPlayerState()) .toBe(STATUS.PAUSED); - }); + }).always(done); }); - it('callback was not called', function () { - waitsFor(function () { + it('callback was not called', function (done) { + jasmine.waitUntil(function () { return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING; - }, 'Player state should be changed', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(state.videoPlayer.player.callStateChangeCallback) .not.toHaveBeenCalled(); - }); + }).always(done); }); }); }); describe('[play]', function () { beforeEach(function () { - spyOn(state.videoPlayer.player.video, 'play').andCallThrough(); + spyOn(state.videoPlayer.player.video, 'play').and.callThrough(); state.videoPlayer.player.playerState = STATUS.PAUSED; state.videoPlayer.player.playVideo(); }); @@ -110,37 +101,35 @@ }); - it('player state was changed', function () { - waitsFor(function () { + it('player state was changed', function (done) { + jasmine.waitUntil(function () { return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED; - }, 'Player state should be changed', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(state.videoPlayer.player.getPlayerState()) .toBe(STATUS.BUFFERING); - }); + }).always(done); }); - it('callback was called', function () { - waitsFor(function () { + it('callback was called', function (done) { + jasmine.waitUntil(function () { return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED; - }, 'Player state should be changed', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(state.videoPlayer.player.callStateChangeCallback) .toHaveBeenCalled(); - }); + }).always(done); }); }); describe('[pause]', function () { - beforeEach(function () { - spyOn(state.videoPlayer.player.video, 'pause').andCallThrough(); + beforeEach(function (done) { + spyOn(state.videoPlayer.player.video, 'pause').and.callThrough(); state.videoPlayer.player.playerState = STATUS.UNSTARTED; state.videoPlayer.player.playVideo(); - waitsFor(function () { + + jasmine.waitUntil(function () { return state.videoPlayer.player.getPlayerState() !== STATUS.UNSTARTED; - }, 'Video never started playing', WAIT_TIMEOUT); + }).done(done); + state.videoPlayer.player.pauseVideo(); }); @@ -148,59 +137,54 @@ expect(state.videoPlayer.player.video.pause).toHaveBeenCalled(); }); - it('player state was changed', function () { - waitsFor(function () { + it('player state was changed', function (done) { + jasmine.waitUntil(function () { return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING; - }, 'Player state should be changed', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(state.videoPlayer.player.getPlayerState()) .toBe(STATUS.PAUSED); - }); + }).always(done); }); - it('callback was called', function () { - waitsFor(function () { + it('callback was called', function (done) { + jasmine.waitUntil(function () { return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING; - }, 'Player state should be changed', WAIT_TIMEOUT); - runs(function () { + }).then(function () { expect(state.videoPlayer.player.callStateChangeCallback) .toHaveBeenCalled(); - }); + }).always(done); }); }); describe('[loadedmetadata]', function () { it( 'player state was changed, start/end was defined, ' + - 'onReady called', function () + 'onReady called', function (done) { - waitsFor(function () { + jasmine.fireEvent(state.videoPlayer.player.video, 'loadedmetadata'); + jasmine.waitUntil(function () { return state.videoPlayer.player.getPlayerState() !== STATUS.UNSTARTED; - }, 'Video cannot be played', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(state.videoPlayer.player.getPlayerState()) .toBe(STATUS.PAUSED); expect(state.videoPlayer.player.video.currentTime).toBe(0); expect(state.videoPlayer.player.config.events.onReady) .toHaveBeenCalled(); - }); + }).always(done); }); }); describe('[ended]', function () { - beforeEach(function () { - waitsFor(function () { + beforeEach(function (done) { + state.videoPlayer.player.playVideo(); + jasmine.waitUntil(function () { return state.videoPlayer.player.getPlayerState() !== STATUS.UNSTARTED; - }, 'Video cannot be played', WAIT_TIMEOUT); + }).done(done); }); it('player state was changed', function () { - runs(function () { - jasmine.fireEvent(state.videoPlayer.player.video, 'ended'); - expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.ENDED); - }); + jasmine.fireEvent(state.videoPlayer.player.video, 'ended'); + expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.ENDED); }); it('callback was called', function () { @@ -215,98 +199,90 @@ var volume, seek, duration, playbackRate; beforeEach(function () { - waitsFor(function () { - volume = state.videoPlayer.player.video.volume; - seek = state.videoPlayer.player.video.currentTime; - return state.videoPlayer.player.playerState === STATUS.PAUSED; - }, 'Video cannot be played', WAIT_TIMEOUT); + volume = state.videoPlayer.player.video.volume; }); it('pauseVideo', function () { - runs(function () { - spyOn(state.videoPlayer.player.video, 'pause').andCallThrough(); - state.videoPlayer.player.pauseVideo(); - expect(state.videoPlayer.player.video.pause).toHaveBeenCalled(); - }); + spyOn(state.videoPlayer.player.video, 'pause').and.callThrough(); + state.videoPlayer.player.pauseVideo(); + expect(state.videoPlayer.player.video.pause).toHaveBeenCalled(); }); describe('seekTo', function () { - it('set new correct value', function () { - runs(function () { + it('set new correct value', function (done) { + state.videoPlayer.player.playVideo(); + jasmine.waitUntil(function () { + return state.videoPlayer.player.getPlayerState() === STATUS.PLAYING; + }).then(function() { state.videoPlayer.player.seekTo(2); expect(state.videoPlayer.player.getCurrentTime()).toBe(2); - }); + }).done(done); }); it('set new inccorrect values', function () { - runs(function () { - state.videoPlayer.player.seekTo(-50); - expect(state.videoPlayer.player.getCurrentTime()).toBe(seek); - state.videoPlayer.player.seekTo('5'); - expect(state.videoPlayer.player.getCurrentTime()).toBe(seek); - state.videoPlayer.player.seekTo(500000); - expect(state.videoPlayer.player.getCurrentTime()).toBe(seek); - }); + var seek = state.videoPlayer.player.video.currentTime; + state.videoPlayer.player.seekTo(-50); + expect(state.videoPlayer.player.getCurrentTime()).toBe(seek); + state.videoPlayer.player.seekTo('5'); + expect(state.videoPlayer.player.getCurrentTime()).toBe(seek); + state.videoPlayer.player.seekTo(500000); + expect(state.videoPlayer.player.getCurrentTime()).toBe(seek); }); }); describe('setVolume', function () { it('set new correct value', function () { - runs(function () { - state.videoPlayer.player.setVolume(50); - expect(state.videoPlayer.player.getVolume()).toBe(50 * 0.01); - }); + state.videoPlayer.player.setVolume(50); + expect(state.videoPlayer.player.getVolume()).toBe(50 * 0.01); }); it('set new incorrect values', function () { - runs(function () { - state.videoPlayer.player.setVolume(-50); - expect(state.videoPlayer.player.getVolume()).toBe(volume); - state.videoPlayer.player.setVolume('5'); - expect(state.videoPlayer.player.getVolume()).toBe(volume); - state.videoPlayer.player.setVolume(500000); - expect(state.videoPlayer.player.getVolume()).toBe(volume); - }); - }); - }); - - it('getCurrentTime', function () { - runs(function () { - state.videoPlayer.player.video.currentTime = 3; - expect(state.videoPlayer.player.getCurrentTime()) - .toBe(state.videoPlayer.player.video.currentTime); - }); - }); - - it('playVideo', function () { - runs(function () { - spyOn(state.videoPlayer.player.video, 'play').andCallThrough(); - state.videoPlayer.player.playVideo(); - expect(state.videoPlayer.player.video.play).toHaveBeenCalled(); - }); - }); - - it('getPlayerState', function () { - runs(function () { - state.videoPlayer.player.playerState = STATUS.PLAYING; - expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.PLAYING); - state.videoPlayer.player.playerState = STATUS.ENDED; - expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.ENDED); - }); - }); - - it('getVolume', function () { - runs(function () { - volume = state.videoPlayer.player.video.volume = 0.5; + state.videoPlayer.player.setVolume(-50); + expect(state.videoPlayer.player.getVolume()).toBe(volume); + state.videoPlayer.player.setVolume('5'); + expect(state.videoPlayer.player.getVolume()).toBe(volume); + state.videoPlayer.player.setVolume(500000); expect(state.videoPlayer.player.getVolume()).toBe(volume); }); }); - it('getDuration', function () { - runs(function () { + it('getCurrentTime', function (done) { + state.videoPlayer.player.playVideo(); + jasmine.waitUntil(function () { + return state.videoPlayer.player.getPlayerState() === STATUS.PLAYING; + }).then(function() { + state.videoPlayer.player.video.currentTime = 3; + expect(state.videoPlayer.player.getCurrentTime()) + .toBe(state.videoPlayer.player.video.currentTime); + }).done(done); + }); + + it('playVideo', function () { + spyOn(state.videoPlayer.player.video, 'play').and.callThrough(); + state.videoPlayer.player.playVideo(); + expect(state.videoPlayer.player.video.play).toHaveBeenCalled(); + }); + + it('getPlayerState', function () { + state.videoPlayer.player.playerState = STATUS.PLAYING; + expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.PLAYING); + state.videoPlayer.player.playerState = STATUS.ENDED; + expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.ENDED); + }); + + it('getVolume', function () { + volume = state.videoPlayer.player.video.volume = 0.5; + expect(state.videoPlayer.player.getVolume()).toBe(volume); + }); + + it('getDuration', function (done) { + state.videoPlayer.player.playVideo(); + jasmine.waitUntil(function () { + return state.videoPlayer.player.getPlayerState() === STATUS.PLAYING; + }).then(function () { duration = state.videoPlayer.player.video.duration; expect(state.videoPlayer.player.getDuration()).toBe(duration); - }); + }).always(done); }); describe('setPlaybackRate', function () { @@ -333,18 +309,21 @@ .toEqual(playbackRates); }); - it('_getLogs', function () { - runs(function () { + it('_getLogs', function (done) { + state.videoPlayer.player.playVideo(); + jasmine.waitUntil(function () { + return state.videoPlayer.player.getPlayerState() === STATUS.PLAYING; + }).then(function() { var logs = state.videoPlayer.player._getLogs(); expect(logs).toEqual(jasmine.any(Array)); expect(logs.length).toBeGreaterThan(0); - }); + }).done(done); }); }); }); it('native controls are used on iPhone', function () { - window.onTouchBasedDevice.andReturn(['iPhone']); + window.onTouchBasedDevice.and.returnValue(['iPhone']); state = jasmine.initializePlayer('video_html5.html'); diff --git a/common/lib/xmodule/xmodule/js/spec/video/initialize_spec.js b/common/lib/xmodule/xmodule/js/spec/video/initialize_spec.js index 0404005144..cc26892bd7 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/initialize_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/initialize_spec.js @@ -82,7 +82,7 @@ function (Initialize) { '1.50': 'videoId' }, youtubeId: Initialize.prototype.youtubeId, - isFlashMode: jasmine.createSpy().andReturn(false) + isFlashMode: jasmine.createSpy().and.returnValue(false) }; }); @@ -100,7 +100,7 @@ function (Initialize) { it('returns duration for current video', function () { var expected; - state.isFlashMode.andReturn(true); + state.isFlashMode.and.returnValue(true); expected = Initialize.prototype.getDuration.call(state); expect(expected).toEqual(100); @@ -110,7 +110,7 @@ function (Initialize) { it(msg, function () { var expected; - state.isFlashMode.andReturn(true); + state.isFlashMode.and.returnValue(true); state.speed = '2.0'; expected = Initialize.prototype.getDuration.call(state); @@ -128,7 +128,7 @@ function (Initialize) { '1.0': 'cogebirgzzM', '1.50': 'abcdefghijkl' }, - isFlashMode: jasmine.createSpy().andReturn(false) + isFlashMode: jasmine.createSpy().and.returnValue(false) }; }); @@ -148,7 +148,7 @@ function (Initialize) { it('return the video id for current speed', function () { var expected; - state.isFlashMode.andReturn(true); + state.isFlashMode.and.returnValue(true); expected = Initialize.prototype.youtubeId.call(state); expect(expected).toEqual('abcdefghijkl'); @@ -279,7 +279,7 @@ function (Initialize) { describe('isFlashMode', function () { it('returns `true` if player in `flash` mode', function () { var state = { - getPlayerMode: jasmine.createSpy().andReturn('flash'), + getPlayerMode: jasmine.createSpy().and.returnValue('flash'), }, isFlashMode = Initialize.prototype.isFlashMode, actual = isFlashMode.call(state); @@ -289,7 +289,7 @@ function (Initialize) { it('returns `false` if player is not in `flash` mode', function () { var state = { - getPlayerMode: jasmine.createSpy().andReturn('html5'), + getPlayerMode: jasmine.createSpy().and.returnValue('html5'), }, isFlashMode = Initialize.prototype.isFlashMode, actual = isFlashMode.call(state); @@ -301,7 +301,7 @@ function (Initialize) { describe('isHtml5Mode', function () { it('returns `true` if player in `html5` mode', function () { var state = { - getPlayerMode: jasmine.createSpy().andReturn('html5'), + getPlayerMode: jasmine.createSpy().and.returnValue('html5'), }, isHtml5Mode = Initialize.prototype.isHtml5Mode, actual = isHtml5Mode.call(state); @@ -311,7 +311,7 @@ function (Initialize) { it('returns `false` if player is not in `html5` mode', function () { var state = { - getPlayerMode: jasmine.createSpy().andReturn('flash'), + getPlayerMode: jasmine.createSpy().and.returnValue('flash'), }, isHtml5Mode = Initialize.prototype.isHtml5Mode, actual = isHtml5Mode.call(state); diff --git a/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js b/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js index 0064e71a42..23e149e824 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js @@ -139,7 +139,7 @@ function (Resizer) { .align() .alignByHeightOnly(); - expect(spiesList[0].calls.length).toEqual(1); + expect(spiesList[0].calls.count()).toEqual(1); }); it('all callbacks are removed', function () { @@ -180,7 +180,7 @@ function (Resizer) { resizer.callbacks[methodName](arg); expect(console.error).toHaveBeenCalledWith(errorMessage); //reset spy - console.log.reset(); + console.log.calls.reset(); }); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_accessible_menu_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_accessible_menu_spec.js index feae0e58f3..e80c3be79b 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_accessible_menu_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_accessible_menu_spec.js @@ -101,7 +101,7 @@ menuList = container.children('ol.a11y-menu-list'); menuItems = menuList.children('li.a11y-menu-item'); menuItemsLinks = menuItems.children('a.a11y-menu-item-link'); - spyOn($.fn, 'focus').andCallThrough(); + spyOn($.fn, 'focus').and.callThrough(); }); it('open/close the menu on mouseenter/mouseleave', function () { @@ -173,7 +173,7 @@ } // Test if each element has been called twice. - expect($.fn.focus.calls.length) + expect($.fn.focus.calls.count()) .toEqual(2*menuItemsLinks.length+1); }); @@ -258,7 +258,7 @@ beforeEach(function () { state = jasmine.initializePlayer(); state.videoSpeedControl.setSpeed(1.0); - spyOn(state.videoPlayer, 'onSpeedChange').andCallThrough(); + spyOn(state.videoPlayer, 'onSpeedChange').and.callThrough(); $('li[data-speed="0.75"] .speed-link').click(); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_bumper_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_bumper_spec.js index 0a355e918d..373f3e5274 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_bumper_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_bumper_spec.js @@ -3,19 +3,19 @@ describe('VideoBumper', function () { var state, oldOTBD, waitForPlaying; - waitForPlaying = function (state) { - waitsFor(function () { + waitForPlaying = function (state, done) { + jasmine.waitUntil(function () { return state.el.hasClass('is-playing'); - }, 'Player is not playing.', WAIT_TIMEOUT); + }).done(done); }; beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine - .createSpy('onTouchBasedDevice').andReturn(null); + .createSpy('onTouchBasedDevice').and.returnValue(null); state = jasmine.initializePlayer('video_with_bumper.html'); $('.poster .btn-play').click(); - jasmine.Clock.useMock(); + jasmine.clock().install(); }); afterEach(function () { @@ -28,45 +28,46 @@ state.videoPlayer.destroy(); } window.onTouchBasedDevice = oldOTBD; + jasmine.clock().uninstall(); }); it('can render the bumper video', function () { expect($('.is-bumper')).toExist(); }); - it('can show the main video on error', function () { + it('can show the main video on error', function (done) { state.el.trigger('error'); - jasmine.Clock.tick(20); + jasmine.clock().tick(20); expect($('.is-bumper')).not.toExist(); - waitForPlaying(state); + waitForPlaying(state, done); }); - it('can show the main video once bumper ends', function () { + it('can show the main video once bumper ends', function (done) { state.el.trigger('ended'); - jasmine.Clock.tick(20); + jasmine.clock().tick(20); expect($('.is-bumper')).not.toExist(); - waitForPlaying(state); + waitForPlaying(state, done); }); - it('can show the main video on skip', function () { + it('can show the main video on skip', function (done) { state.bumperState.videoBumper.skip(); - jasmine.Clock.tick(20); + jasmine.clock().tick(20); expect($('.is-bumper')).not.toExist(); - waitForPlaying(state); + waitForPlaying(state, done); }); - it('can stop the bumper video playing if it is too long', function () { + it('can stop the bumper video playing if it is too long', function (done) { state.el.trigger('timeupdate', [state.bumperState.videoBumper.maxBumperDuration + 1]); - jasmine.Clock.tick(20); + jasmine.clock().tick(20); expect($('.is-bumper')).not.toExist(); - waitForPlaying(state); + waitForPlaying(state, done); }); it('can save appropriate states correctly on ended', function () { var saveState = jasmine.createSpy('saveState'); state.bumperState.videoSaveStatePlugin.saveState = saveState; state.el.trigger('ended'); - jasmine.Clock.tick(20); + jasmine.clock().tick(20); expect(saveState).toHaveBeenCalledWith(true, { bumper_last_view_date: true}); }); @@ -76,7 +77,7 @@ state.bumperState.videoSaveStatePlugin.saveState = saveState; state.bumperState.videoBumper.skip(); expect(state.storage.getItem('isBumperShown')).toBeTruthy(); - jasmine.Clock.tick(20); + jasmine.clock().tick(20); expect(saveState).toHaveBeenCalledWith(true, { bumper_last_view_date: true}); }); @@ -86,7 +87,7 @@ state.bumperState.videoSaveStatePlugin.saveState = saveState; state.el.trigger('error'); expect(state.storage.getItem('isBumperShown')).toBeTruthy(); - jasmine.Clock.tick(20); + jasmine.clock().tick(20); expect(saveState).toHaveBeenCalledWith(true, { bumper_last_view_date: true}); }); @@ -96,7 +97,7 @@ state.bumperState.videoSaveStatePlugin.saveState = saveState; state.bumperState.videoBumper.skipAndDoNotShowAgain(); expect(state.storage.getItem('isBumperShown')).toBeTruthy(); - jasmine.Clock.tick(20); + jasmine.clock().tick(20); expect(saveState).toHaveBeenCalledWith(true, { bumper_last_view_date: true, bumper_do_not_show_again: true}); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js index 95bb6a879c..7442fdd8ff 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js @@ -1,13 +1,16 @@ (function (undefined) { describe('VideoCaption', function () { var state, oldOTBD; + var parseIntAttribute = function (element, attrName) { + return parseInt(element.attr(attrName)); + }; beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') - .andReturn(null); + .and.returnValue(null); - $.fn.scrollTo.reset(); + $.fn.scrollTo.calls.reset(); }); afterEach(function () { @@ -15,7 +18,7 @@ // had before. Removing of `source` tag, not `video` tag, stops // loading video source and clears the memory. $('source').remove(); - $.fn.scrollTo.reset(); + $.fn.scrollTo.calls.reset(); state.storage.clear(); state.videoPlayer.destroy(); @@ -27,17 +30,17 @@ describe('always', function () { beforeEach(function () { - spyOn($, 'ajaxWithPrefix').andCallThrough(); + spyOn($, 'ajaxWithPrefix').and.callThrough(); }); it('create the transcript element', function () { state = jasmine.initializePlayer(); - expect($('.video')).toContain('.subtitles'); + expect($('.video')).toContainElement('.subtitles'); }); it('add transcript control to video player', function () { state = jasmine.initializePlayer(); - expect($('.video')).toContain('.toggle-transcript'); + expect($('.video')).toContainElement('.toggle-transcript'); }); it('add ARIA attributes to transcript control', function () { @@ -50,20 +53,16 @@ it('adds the captioning control to the video player', function() { state = jasmine.initializePlayer(); - expect($('.video')).toContain('.toggle-captions'); - expect($('.video')).toContain('.closed-captions'); + expect($('.video')).toContainElement('.toggle-captions'); + expect($('.video')).toContainElement('.closed-captions'); }); - it('fetch the transcript in HTML5 mode', function () { - runs(function () { - state = jasmine.initializePlayer(); - }); + it('fetch the transcript in HTML5 mode', function (done) { + state = jasmine.initializePlayer(); - waitsFor(function () { + jasmine.waitUntil(function () { return state.videoCaption.loaded; - }, 'Expect transcript to be loaded.', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect($.ajaxWithPrefix).toHaveBeenCalledWith({ url: '/transcript/translation/en', notifyOnError: false, @@ -71,23 +70,19 @@ success: jasmine.any(Function), error: jasmine.any(Function) }); - expect($.ajaxWithPrefix.mostRecentCall.args[0].data) + expect($.ajaxWithPrefix.calls.mostRecent().args[0].data) .toBeUndefined(); - }); + }).always(done); }); - it('fetch the transcript in Flash mode', function () { - runs(function () { - state = jasmine.initializePlayerYouTube(); - spyOn(state, 'isFlashMode').andReturn(true); - state.videoCaption.fetchCaption(); - }); + it('fetch the transcript in Flash mode', function (done) { + state = jasmine.initializePlayerYouTube(); + spyOn(state, 'isFlashMode').and.returnValue(true); + state.videoCaption.fetchCaption(); - waitsFor(function () { + jasmine.waitUntil(function () { return state.videoCaption.loaded; - }, 'Expect transcript to be loaded.', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect($.ajaxWithPrefix).toHaveBeenCalledWith({ url: '/transcript/translation/en', notifyOnError: false, @@ -95,23 +90,19 @@ success: jasmine.any(Function), error: jasmine.any(Function) }); - expect($.ajaxWithPrefix.mostRecentCall.args[0].data) + expect($.ajaxWithPrefix.calls.mostRecent().args[0].data) .toEqual({ videoId: 'cogebirgzzM' }); - }); + }).always(done); }); - it('fetch the transcript in Youtube mode', function () { - runs(function () { - state = jasmine.initializePlayerYouTube(); - }); + it('fetch the transcript in Youtube mode', function (done) { + state = jasmine.initializePlayerYouTube(); - waitsFor(function () { + jasmine.waitUntil(function () { return state.videoCaption.loaded; - }, 'Expect transcript to be loaded.', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect($.ajaxWithPrefix).toHaveBeenCalledWith({ url: '/transcript/translation/en', notifyOnError: false, @@ -119,11 +110,11 @@ success: jasmine.any(Function), error: jasmine.any(Function) }); - expect($.ajaxWithPrefix.mostRecentCall.args[0].data) + expect($.ajaxWithPrefix.calls.mostRecent().args[0].data) .toEqual({ videoId: 'cogebirgzzM' }); - }); + }).always(done); }); it('bind the mouse movement', function () { @@ -148,7 +139,7 @@ state = jasmine.initializePlayer(); var plugin = state.videoCaption; - spyOn($.fn, 'off').andCallThrough(); + spyOn($.fn, 'off').and.callThrough(); state.videoCaption.destroy(); expect(state.videoCaption).toBeUndefined(); @@ -316,104 +307,90 @@ }); describe('when on a non touch-based device', function () { - beforeEach(function () { - runs(function () { - state = jasmine.initializePlayer(); - }); + beforeEach(function (done) { + state = jasmine.initializePlayer(); - waitsFor(function () { + jasmine.waitUntil(function () { return state.videoCaption.rendered; - }, 'Transcripts are not rendered', WAIT_TIMEOUT); + }).then(done); }); it('render the transcript', function () { - runs(function () { - var captionsData = jasmine.stubbedCaption, - items = $('.subtitles li[data-index]'); + var captionsData = jasmine.stubbedCaption, + items = $('.subtitles li[data-index]'); - _.each(captionsData.text, function (text, index) { - var item = items.eq(index); + _.each(captionsData.text, function (text, index) { + var item = items.eq(index); - expect(item).toHaveData('index', index); - expect(item).toHaveData( - 'start', captionsData.start[index] - ); - expect(item).toHaveAttr('tabindex', 0); - expect(item).toHaveText(text); - }); + expect(parseIntAttribute(item, 'data-index')).toEqual(index); + expect(parseIntAttribute(item, 'data-start')).toEqual(captionsData.start[index]); + expect(item.attr('tabindex')).toEqual(0); + expect(item.text().trim()).toEqual(captionsData.text[index]); }); }); it('add a padding element to transcript', function () { - runs(function () { - expect($('.subtitles li:first').hasClass('spacing')) - .toBe(true); - expect($('.subtitles li:last').hasClass('spacing')) - .toBe(true); - }); + expect($('.subtitles li:first').hasClass('spacing')) + .toBe(true); + expect($('.subtitles li:last').hasClass('spacing')) + .toBe(true); }); it('bind all the transcript link', function () { - runs(function () { - var handlerList = ['captionMouseOverOut', 'captionClick', - 'captionMouseDown', 'captionFocus', 'captionBlur', - 'captionKeyDown' - ]; + var handlerList = ['captionMouseOverOut', 'captionClick', + 'captionMouseDown', 'captionFocus', 'captionBlur', + 'captionKeyDown' + ]; - $.each(handlerList, function(index, handler) { - spyOn(state.videoCaption, handler); - }); - $('.subtitles li[data-index]').each( - function (index, link) { + $.each(handlerList, function(index, handler) { + spyOn(state.videoCaption, handler); + }); + $('.subtitles li[data-index]').each( + function (index, link) { - $(link).trigger('mouseover'); - expect(state.videoCaption.captionMouseOverOut).toHaveBeenCalled(); + $(link).trigger('mouseover'); + expect(state.videoCaption.captionMouseOverOut).toHaveBeenCalled(); - state.videoCaption.captionMouseOverOut.reset(); - $(link).trigger('mouseout'); - expect(state.videoCaption.captionMouseOverOut).toHaveBeenCalled(); + state.videoCaption.captionMouseOverOut.calls.reset(); + $(link).trigger('mouseout'); + expect(state.videoCaption.captionMouseOverOut).toHaveBeenCalled(); - $(this).click(); - expect(state.videoCaption.captionClick).toHaveBeenCalled(); + $(this).click(); + expect(state.videoCaption.captionClick).toHaveBeenCalled(); - $(this).trigger('mousedown'); - expect(state.videoCaption.captionMouseDown).toHaveBeenCalled(); + $(this).trigger('mousedown'); + expect(state.videoCaption.captionMouseDown).toHaveBeenCalled(); - $(this).trigger('focus'); - expect(state.videoCaption.captionFocus).toHaveBeenCalled(); + $(this).trigger('focus'); + expect(state.videoCaption.captionFocus).toHaveBeenCalled(); - $(this).trigger('blur'); - expect(state.videoCaption.captionBlur).toHaveBeenCalled(); + $(this).trigger('blur'); + expect(state.videoCaption.captionBlur).toHaveBeenCalled(); - $(this).trigger('keydown'); - expect(state.videoCaption.captionKeyDown).toHaveBeenCalled(); - }); + $(this).trigger('keydown'); + expect(state.videoCaption.captionKeyDown).toHaveBeenCalled(); }); }); - it('set rendered to true', function () { - runs(function () { - state = jasmine.initializePlayer(); - }); + it('set rendered to true', function (done) { + state = jasmine.initializePlayer(); - waitsFor(function () { + jasmine.waitUntil(function () { return state.videoCaption.rendered; - }, 'Transcripts are not rendered', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(state.videoCaption.rendered).toBeTruthy(); - }); + }).always(done); }); }); describe('when on a touch-based device', function () { beforeEach(function () { - window.onTouchBasedDevice.andReturn(['iPad']); + window.onTouchBasedDevice.and.returnValue(['iPad']); state = jasmine.initializePlayer(); - $.fn.scrollTo.reset(); + $.fn.scrollTo.calls.reset(); }); it('show explanation message', function () { @@ -422,30 +399,24 @@ ); }); - it('show transcript on play', function () { - runs(function () { - state.el.trigger('play'); - }); + it('show transcript on play', function (done) { + state.el.trigger('play'); - waitsFor(function () { + jasmine.waitUntil(function () { return state.videoCaption.rendered; - }, 'Transcripts are not rendered', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { var captionsData = jasmine.stubbedCaption, items = $('.subtitles li[data-index]'); _.each(captionsData.text, function (text, index) { var item = items.eq(index); - expect(item).toHaveData('index', index); - expect(item).toHaveData( - 'start', captionsData.start[index] - ); - expect(item).toHaveAttr('tabindex', 0); - expect(item).toHaveText(text); + expect(parseIntAttribute(item, 'data-index')).toEqual(index); + expect(parseIntAttribute(item, 'data-start')).toEqual(captionsData.start[index]); + expect(item.attr('tabindex')).toEqual(0); + expect(item.text().trim()).toEqual(text); }); - }); + }).always(done); }); it('does not set rendered to true', function () { @@ -467,62 +438,58 @@ }); }); + var originalClearTimeout; + describe('mouse movement', function () { - beforeEach(function () { - jasmine.Clock.useMock(); - spyOn(window, 'clearTimeout'); - - runs(function () { - state = jasmine.initializePlayer(); - jasmine.Clock.tick(50); - }); - - waitsFor(function () { + beforeEach(function (done) { + jasmine.clock().install(); + state = jasmine.initializePlayer(); + jasmine.clock().tick(50); + jasmine.waitUntil(function () { return state.videoCaption.rendered; - }, 'Transcripts are not rendered', WAIT_TIMEOUT); + }).then(done); + + // Why we can't use spyOn(): https://github.com/jasmine/jasmine/issues/826 + originalClearTimeout = window.clearTimeout; + window.clearTimeout = jasmine.createSpy().and.callFake(originalClearTimeout); + }); + + afterEach(function () { + window.clearTimeout = originalClearTimeout; + jasmine.clock().uninstall(); }); describe('when cursor is outside of the transcript box', function () { it('does not set freezing timeout', function () { - runs(function () { - expect(state.videoCaption.frozen).toBeFalsy(); - }); + expect(state.videoCaption.frozen).toBeFalsy(); }); }); describe('when cursor is in the transcript box', function () { beforeEach(function () { spyOn(state.videoCaption, 'onMouseLeave'); - runs(function () { - $(window).trigger(jQuery.Event('mousemove')); - jasmine.Clock.tick(state.config.captionsFreezeTime); - $('.subtitles-menu').trigger(jQuery.Event('mouseenter')); - jasmine.Clock.tick(state.config.captionsFreezeTime); - }); + $(window).trigger(jQuery.Event('mousemove')); + jasmine.clock().tick(state.config.captionsFreezeTime); + $('.subtitles-menu').trigger(jQuery.Event('mouseenter')); + jasmine.clock().tick(state.config.captionsFreezeTime); }); it('set the freezing timeout', function () { - runs(function () { - expect(state.videoCaption.frozen).not.toBeFalsy(); - expect(state.videoCaption.onMouseLeave).toHaveBeenCalled(); - }); + expect(state.videoCaption.frozen).not.toBeFalsy(); + expect(state.videoCaption.onMouseLeave).toHaveBeenCalled(); }); describe('when the cursor is moving', function () { it('reset the freezing timeout', function () { - runs(function () { - $('.subtitles-menu').trigger(jQuery.Event('mousemove')); - expect(window.clearTimeout).toHaveBeenCalled(); - }); + $('.subtitles-menu').trigger(jQuery.Event('mousemove')); + expect(window.clearTimeout).toHaveBeenCalled(); }); }); describe('when the mouse is scrolling', function () { it('reset the freezing timeout', function () { - runs(function () { - $('.subtitles-menu').trigger(jQuery.Event('mousewheel')); - expect(window.clearTimeout).toHaveBeenCalled(); - }); + $('.subtitles-menu').trigger(jQuery.Event('mousewheel')); + expect(window.clearTimeout).toHaveBeenCalled(); }); }); }); @@ -533,7 +500,7 @@ beforeEach(function () { state.videoCaption.frozen = 100; - $.fn.scrollTo.reset(); + $.fn.scrollTo.calls.reset(); }); describe('always', function () { @@ -582,12 +549,12 @@ beforeEach(function () { state = jasmine.initializePlayer(); Caption = state.videoCaption; - spyOn($, 'ajaxWithPrefix').andCallThrough(); + spyOn($, 'ajaxWithPrefix').and.callThrough(); spyOn(Caption, 'renderCaption'); spyOn(Caption, 'bindHandlers'); spyOn(Caption, 'updatePlayTime'); spyOn(Caption, 'hideCaptions'); - spyOn(state, 'youtubeId').andReturn('Z5KLxerq05Y'); + spyOn(state, 'youtubeId').and.returnValue('Z5KLxerq05Y'); }); it('show transcript on language change', function () { @@ -609,7 +576,7 @@ expect(Caption.hideCaptions).toHaveBeenCalledWith(false, false); Caption.loaded = false; - Caption.hideCaptions.reset(); + Caption.hideCaptions.calls.reset(); state.hide_captions = true; Caption.fetchCaption(); @@ -683,7 +650,7 @@ msg = 'on error: transcripts are hidden if there are no transcripts'; it(msg, function () { spyOn(Caption, 'fetchAvailableTranslations'); - $.ajax.andCallFake(function (settings) { + $.ajax.and.callFake(function (settings) { _.result(settings, 'error'); }); @@ -693,7 +660,7 @@ expect($.ajaxWithPrefix).toHaveBeenCalled(); expect(Caption.fetchAvailableTranslations).not.toHaveBeenCalled(); - expect(Caption.hideCaptions.mostRecentCall.args) + expect(Caption.hideCaptions.calls.mostRecent().args) .toEqual([true, false]); }); @@ -701,8 +668,8 @@ 'with youtubeId if there are no additional transcripts'; it(msg, function () { spyOn(Caption, 'fetchAvailableTranslations'); - spyOn(Caption, 'fetchCaption').andCallThrough(); - $.ajax.andCallFake(function (settings) { + spyOn(Caption, 'fetchCaption').and.callThrough(); + $.ajax.and.callFake(function (settings) { _.result(settings, 'error'); }); @@ -712,19 +679,19 @@ Caption.fetchCaption(); expect(Caption.fetchAvailableTranslations).not.toHaveBeenCalled(); - expect($.ajaxWithPrefix.mostRecentCall.args[0]['data']) + expect($.ajaxWithPrefix.calls.mostRecent().args[0].data) .toEqual({'videoId':'Z5KLxerq05Y'}); - expect(Caption.hideCaptions.mostRecentCall.args) + expect(Caption.hideCaptions.calls.mostRecent().args) .toEqual([true, false]); - expect(Caption.fetchCaption.mostRecentCall.args[0]).toEqual(true); - expect(Caption.fetchCaption.callCount).toEqual(2); + expect(Caption.fetchCaption.calls.mostRecent().args[0]).toEqual(true); + expect(Caption.fetchCaption.calls.count()).toEqual(2); }); msg = 'on success: when fetchCaption called with fetch_with_youtubeId to ' + 'get transcript with youtubeId for html5'; it(msg, function () { spyOn(Caption, 'fetchAvailableTranslations'); - spyOn(Caption, 'fetchCaption').andCallThrough(); + spyOn(Caption, 'fetchCaption').and.callThrough(); Caption.loaded = true; state.config.transcriptLanguages = {}; @@ -733,18 +700,18 @@ Caption.fetchCaption(true); expect(Caption.fetchAvailableTranslations).not.toHaveBeenCalled(); - expect($.ajaxWithPrefix.mostRecentCall.args[0]['data']) + expect($.ajaxWithPrefix.calls.mostRecent().args[0].data) .toEqual({'videoId':'Z5KLxerq05Y'}); expect(Caption.hideCaptions).toHaveBeenCalledWith(false); - expect(Caption.fetchCaption.mostRecentCall.args[0]).toEqual(true); - expect(Caption.fetchCaption.callCount).toEqual(1); + expect(Caption.fetchCaption.calls.mostRecent().args[0]).toEqual(true); + expect(Caption.fetchCaption.calls.count()).toEqual(1); }); msg = 'on error: fetch available translations if there are ' + 'additional transcripts'; it(msg, function () { $.ajax - .andCallFake(function (settings) { + .and.callFake(function (settings) { _.result(settings, 'error'); }); @@ -767,7 +734,7 @@ beforeEach(function () { state = jasmine.initializePlayer(); Caption = state.videoCaption; - spyOn($, 'ajaxWithPrefix').andCallThrough(); + spyOn($, 'ajaxWithPrefix').and.callThrough(); spyOn(Caption, 'hideCaptions'); spyOn(Caption, 'fetchCaption'); spyOn(Caption, 'renderLanguageMenu'); @@ -821,7 +788,7 @@ msg = 'on error: transcripts are hidden if there are no transcript'; it(msg, function () { - $.ajax.andCallFake(function (settings) { + $.ajax.and.callFake(function (settings) { _.result(settings, 'error'); }); Caption.fetchAvailableTranslations(); @@ -834,55 +801,44 @@ describe('play', function () { describe('when the transcript was not rendered', function () { - beforeEach(function () { - window.onTouchBasedDevice.andReturn(['iPad']); + beforeEach(function (done) { + window.onTouchBasedDevice.and.returnValue(['iPad']); - runs(function () { - state = jasmine.initializePlayer(); - state.videoCaption.play(); - }); + state = jasmine.initializePlayer(); + state.videoCaption.play(); - waitsFor(function () { + jasmine.waitUntil(function () { return state.videoCaption.rendered; - }, 'Transcripts are not rendered', WAIT_TIMEOUT); + }).then(function(){ + done(); + }); }); it('render the transcript', function () { - runs(function () { - var captionsData; + var captionsData; - captionsData = jasmine.stubbedCaption; - $('.subtitles li[data-index]').each( - function (index, link) { + captionsData = jasmine.stubbedCaption; - expect($(link)).toHaveData('index', index); - expect($(link)).toHaveData( - 'start', captionsData.start[index] - ); - expect($(link)).toHaveAttr('tabindex', 0); - expect($(link)).toHaveText(captionsData.text[index]); - }); + $('.subtitles li[data-index]').each( + function (index, item) { + expect(parseIntAttribute($(item), 'data-index')).toEqual(index); + expect(parseIntAttribute($(item), 'data-start')).toEqual(captionsData.start[index]); + expect($(item).attr('tabindex')).toEqual(0); + expect($(item).text().trim()).toEqual(captionsData.text[index]); }); - }); it('add a padding element to transcript', function () { - runs(function () { - expect($('.subtitles li:first')).toBe('.spacing'); - expect($('.subtitles li:last')).toBe('.spacing'); - }); + expect($('.subtitles li:first')).toHaveClass('spacing'); + expect($('.subtitles li:last')).toHaveClass('spacing'); }); it('set rendered to true', function () { - runs(function () { - expect(state.videoCaption.rendered).toBeTruthy(); - }); + expect(state.videoCaption.rendered).toBeTruthy(); }); it('set playing to true', function () { - runs(function () { - expect(state.videoCaption.playing).toBeTruthy(); - }); + expect(state.videoCaption.playing).toBeTruthy(); }); }); }); @@ -900,178 +856,148 @@ }); describe('updatePlayTime', function () { - beforeEach(function () { - runs(function () { - state = jasmine.initializePlayer(); - }); + beforeEach(function (done) { + state = jasmine.initializePlayer(); - waitsFor(function () { + jasmine.waitUntil(function () { return state.videoCaption.rendered; - }, 'Transcripts are not rendered', WAIT_TIMEOUT); + }).then(done); }); describe('when the video speed is 1.0x', function () { it('search the caption based on time', function () { - runs(function () { - state.videoCaption.updatePlayTime(25.000); - expect(state.videoCaption.currentIndex).toEqual(5); + state.videoCaption.updatePlayTime(25.000); + expect(state.videoCaption.currentIndex).toEqual(5); - // Flash mode - spyOn(state, 'isFlashMode').andReturn(true); - state.speed = '1.0'; - state.videoCaption.updatePlayTime(25.000); - expect(state.videoCaption.currentIndex).toEqual(5); - }); + // Flash mode + spyOn(state, 'isFlashMode').and.returnValue(true); + state.speed = '1.0'; + state.videoCaption.updatePlayTime(25.000); + expect(state.videoCaption.currentIndex).toEqual(5); }); }); describe('when the video speed is not 1.0x', function () { it('search the transcript based on 1.0x speed', function () { - runs(function () { - state.videoCaption.updatePlayTime(25.000); - expect(state.videoCaption.currentIndex).toEqual(5); + state.videoCaption.updatePlayTime(25.000); + expect(state.videoCaption.currentIndex).toEqual(5); - // To test speed, don't use start / end times. - state.config.startTime = 0; - state.config.endTime = null; + // To test speed, don't use start / end times. + state.config.startTime = 0; + state.config.endTime = null; - // Flash mode - state.speed = '2.0'; - spyOn(state, 'isFlashMode').andReturn(true); - state.videoCaption.updatePlayTime(25.000); - expect(state.videoCaption.currentIndex).toEqual(9); - state.speed = '0.75'; - state.videoCaption.updatePlayTime(25.000); - expect(state.videoCaption.currentIndex).toEqual(3); - }); + // Flash mode + state.speed = '2.0'; + spyOn(state, 'isFlashMode').and.returnValue(true); + state.videoCaption.updatePlayTime(25.000); + expect(state.videoCaption.currentIndex).toEqual(9); + state.speed = '0.75'; + state.videoCaption.updatePlayTime(25.000); + expect(state.videoCaption.currentIndex).toEqual(3); }); }); describe('when the index is not the same', function () { beforeEach(function () { - runs(function () { - state.videoCaption.currentIndex = 1; - $('.subtitles li[data-index=5]').addClass('current'); - state.videoCaption.updatePlayTime(25.000); - }); + state.videoCaption.currentIndex = 1; + $('.subtitles li[data-index=5]').addClass('current'); + state.videoCaption.updatePlayTime(25.000); }); it('deactivate the previous transcript', function () { - runs(function () { - expect($('.subtitles li[data-index=1]')) - .not.toHaveClass('current'); - }); + expect($('.subtitles li[data-index=1]')) + .not.toHaveClass('current'); }); it('activate new transcript', function () { - runs(function () { - expect($('.subtitles li[data-index=5]')) - .toHaveClass('current'); - }); + expect($('.subtitles li[data-index=5]')) + .toHaveClass('current'); }); it('save new index', function () { - runs(function () { - expect(state.videoCaption.currentIndex).toEqual(5); - }); + expect(state.videoCaption.currentIndex).toEqual(5); }); it('scroll transcript to new position', function () { - runs(function () { - expect($.fn.scrollTo).toHaveBeenCalled(); - }); + expect($.fn.scrollTo).toHaveBeenCalled(); }); }); describe('when the index is the same', function () { it('does not change current subtitle', function () { - runs(function () { - state.videoCaption.currentIndex = 1; - $('.subtitles li[data-index=3]').addClass('current'); - state.videoCaption.updatePlayTime(15.000); - expect($('.subtitles li[data-index=3]')) - .toHaveClass('current'); - }); + state.videoCaption.currentIndex = 1; + $('.subtitles li[data-index=3]').addClass('current'); + state.videoCaption.updatePlayTime(15.000); + expect($('.subtitles li[data-index=3]')) + .toHaveClass('current'); }); }); }); describe('resize', function () { - beforeEach(function () { - runs(function () { - state = jasmine.initializePlayer(); - }); + beforeEach(function (done) { + state = jasmine.initializePlayer(); - waitsFor(function () { + jasmine.waitUntil(function () { return state.videoCaption.rendered; - }, 'Transcripts are not rendered', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { videoControl = state.videoControl; $('.subtitles li[data-index=1]').addClass('current'); state.videoCaption.onResize(); - }); + }).always(done); }); describe('set the height of transcript container', function () { it('when transcript button is enabled', function () { - runs(function () { - var realHeight = parseInt( - $('.subtitles').css('maxHeight'), 10 - ), - shouldBeHeight = $('.video-wrapper').height(); + var realHeight = parseInt( + $('.subtitles').css('maxHeight'), 10 + ), + shouldBeHeight = $('.video-wrapper').height(); - // Because of some problems with rounding on different - // environments: Linux * Mac * FF * Chrome - expect(realHeight).toBeCloseTo(shouldBeHeight, 2); - }); + // Because of some problems with rounding on different + // environments: Linux * Mac * FF * Chrome + expect(realHeight).toBeCloseTo(shouldBeHeight, 2); }); it('when transcript button is disabled ', function () { - runs(function () { - var realHeight, videoWrapperHeight, progressSliderHeight, - controlHeight, shouldBeHeight; + var realHeight, videoWrapperHeight, progressSliderHeight, + controlHeight, shouldBeHeight; - state.captionsHidden = true; - state.videoCaption.setSubtitlesHeight(); + state.captionsHidden = true; + state.videoCaption.setSubtitlesHeight(); - realHeight = parseInt( - $('.subtitles').css('maxHeight'), 10 - ); - videoWrapperHeight = $('.video-wrapper').height(); - progressSliderHeight = state.el.find('.slider').height(); - controlHeight = state.el.find('.video-controls').height(); - shouldBeHeight = videoWrapperHeight - - 0.5 * progressSliderHeight - - controlHeight; + realHeight = parseInt( + $('.subtitles').css('maxHeight'), 10 + ); + videoWrapperHeight = $('.video-wrapper').height(); + progressSliderHeight = state.el.find('.slider').height(); + controlHeight = state.el.find('.video-controls').height(); + shouldBeHeight = videoWrapperHeight - + 0.5 * progressSliderHeight - + controlHeight; - expect(realHeight).toBe(shouldBeHeight); - }); + expect(realHeight).toBe(shouldBeHeight); }); }); it('set the height of transcript spacing', function () { - runs(function () { - var firstSpacing, lastSpacing; + var firstSpacing, lastSpacing; - firstSpacing = Math.abs(parseInt( - $('.subtitles .spacing:first').css('height'), 10 - )); - lastSpacing = Math.abs(parseInt( - $('.subtitles .spacing:last').css('height'), 10 - )); + firstSpacing = Math.abs(parseInt( + $('.subtitles .spacing:first').css('height'), 10 + )); + lastSpacing = Math.abs(parseInt( + $('.subtitles .spacing:last').css('height'), 10 + )); - expect(firstSpacing - state.videoCaption.topSpacingHeight()) - .toBeLessThan(1); - expect(lastSpacing - state.videoCaption.bottomSpacingHeight()) - .toBeLessThan(1); - }); + expect(firstSpacing - state.videoCaption.topSpacingHeight()) + .toBeLessThan(1); + expect(lastSpacing - state.videoCaption.bottomSpacingHeight()) + .toBeLessThan(1); }); it('scroll transcript to new position', function () { - runs(function () { - expect($.fn.scrollTo).toHaveBeenCalled(); - }); + expect($.fn.scrollTo).toHaveBeenCalled(); }); }); @@ -1193,7 +1119,11 @@ beforeEach(function () { state.el.addClass('closed'); state.videoCaption.toggle(jQuery.Event('click')); - jasmine.Clock.useMock(); + jasmine.clock().install(); + }); + + afterEach(function () { + jasmine.clock().uninstall(); }); it('show the transcript', function () { @@ -1204,7 +1134,7 @@ xit('scroll the transcript', function () { // After transcripts are shown, and the video plays for a // bit. - jasmine.Clock.tick(1000); + jasmine.clock().tick(1000); // The transcripts should have advanced by at least one // position. When they advance, the list scrolls. The @@ -1218,60 +1148,46 @@ }); describe('transcript accessibility', function () { - beforeEach(function () { - runs(function () { - state = jasmine.initializePlayer(); - }); + beforeEach(function (done) { + state = jasmine.initializePlayer(); - waitsFor(function () { + jasmine.waitUntil(function () { return state.videoCaption.rendered; - }, 'Transcripts are not rendered', WAIT_TIMEOUT); + }).then(done); }); describe('when getting focus through TAB key', function () { beforeEach(function () { - runs(function () { - state.videoCaption.isMouseFocus = false; - $('.subtitles li[data-index=0]').trigger( - jQuery.Event('focus') - ); - }); + state.videoCaption.isMouseFocus = false; + $('.subtitles li[data-index=0]').trigger( + jQuery.Event('focus') + ); }); it('shows an outline around the transcript', function () { - runs(function () { - expect($('.subtitles li[data-index=0]')) - .toHaveClass('focused'); - }); + expect($('.subtitles li[data-index=0]')) + .toHaveClass('focused'); }); it('has automatic scrolling disabled', function () { - runs(function () { - expect(state.videoCaption.autoScrolling).toBe(false); - }); + expect(state.videoCaption.autoScrolling).toBe(false); }); }); describe('when loosing focus through TAB key', function () { beforeEach(function () { - runs(function () { - $('.subtitles li[data-index=0]').trigger( - jQuery.Event('blur') - ); - }); + $('.subtitles li[data-index=0]').trigger( + jQuery.Event('blur') + ); }); it('does not show an outline around the transcript', function () { - runs(function () { - expect($('.subtitles li[data-index=0]')) - .not.toHaveClass('focused'); - }); + expect($('.subtitles li[data-index=0]')) + .not.toHaveClass('focused'); }); it('has automatic scrolling enabled', function () { - runs(function () { - expect(state.videoCaption.autoScrolling).toBe(true); - }); + expect(state.videoCaption.autoScrolling).toBe(true); }); }); @@ -1281,26 +1197,20 @@ function () { beforeEach(function () { - runs(function () { - state.videoCaption.isMouseFocus = false; - $('.subtitles li[data-index=0]') - .trigger(jQuery.Event('focus')); - $('.subtitles li[data-index=0]') - .trigger(jQuery.Event('mousedown')); - }); + state.videoCaption.isMouseFocus = false; + $('.subtitles li[data-index=0]') + .trigger(jQuery.Event('focus')); + $('.subtitles li[data-index=0]') + .trigger(jQuery.Event('mousedown')); }); it('does not show an outline around it', function () { - runs(function () { - expect($('.subtitles li[data-index=0]')) - .not.toHaveClass('focused'); - }); + expect($('.subtitles li[data-index=0]')) + .not.toHaveClass('focused'); }); it('has automatic scrolling enabled', function () { - runs(function () { - expect(state.videoCaption.autoScrolling).toBe(true); - }); + expect(state.videoCaption.autoScrolling).toBe(true); }); }); @@ -1312,37 +1222,29 @@ var subDataLiIdx__0, subDataLiIdx__1; beforeEach(function () { - runs(function () { - subDataLiIdx__0 = $('.subtitles li[data-index=0]'); - subDataLiIdx__1 = $('.subtitles li[data-index=1]'); + subDataLiIdx__0 = $('.subtitles li[data-index=0]'); + subDataLiIdx__1 = $('.subtitles li[data-index=1]'); - state.videoCaption.isMouseFocus = false; + state.videoCaption.isMouseFocus = false; - subDataLiIdx__0.trigger(jQuery.Event('focus')); - subDataLiIdx__0.trigger(jQuery.Event('blur')); + subDataLiIdx__0.trigger(jQuery.Event('focus')); + subDataLiIdx__0.trigger(jQuery.Event('blur')); - state.videoCaption.isMouseFocus = true; + state.videoCaption.isMouseFocus = true; - subDataLiIdx__1.trigger(jQuery.Event('mousedown')); - }); + subDataLiIdx__1.trigger(jQuery.Event('mousedown')); }); it('does not show an outline around the first', function () { - runs(function () { - expect(subDataLiIdx__0).not.toHaveClass('focused'); - }); + expect(subDataLiIdx__0).not.toHaveClass('focused'); }); it('does not show an outline around the second', function () { - runs(function () { - expect(subDataLiIdx__1).not.toHaveClass('focused'); - }); + expect(subDataLiIdx__1).not.toHaveClass('focused'); }); it('has automatic scrolling enabled', function () { - runs(function () { - expect(state.videoCaption.autoScrolling).toBe(true); - }); + expect(state.videoCaption.autoScrolling).toBe(true); }); }); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_context_menu_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_context_menu_spec.js index 96b854340b..ef4b20bccb 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_context_menu_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_context_menu_spec.js @@ -6,7 +6,6 @@ openMenu = function () { var container = $('.video'); - jasmine.Clock.useMock(); container.find('video').trigger('contextmenu'); menu = container.children('.contextmenu'); menuItems = menu.children('.menu-item').not('.submenu-item'); @@ -23,19 +22,19 @@ openSubmenuMouse = function (menuSubmenuItem) { menuSubmenuItem.mouseover(); - jasmine.Clock.tick(200); + jasmine.clock().tick(200); expect(menuSubmenuItem).toHaveClass('is-opened'); }; openSubmenuKeyboard = function (menuSubmenuItem, keyCode) { menuSubmenuItem.focus().trigger(keyPressEvent(keyCode || $.ui.keyCode.RIGHT)); expect(menuSubmenuItem).toHaveClass('is-opened'); - expect(menuSubmenuItem.children().first()).toBeFocused(); + expect(menuSubmenuItem.children().last().children().first()).toBeFocused(); }; closeSubmenuMouse = function (menuSubmenuItem) { menuSubmenuItem.mouseleave(); - jasmine.Clock.tick(200); + jasmine.clock().tick(200); expect(menuSubmenuItem).not.toHaveClass('is-opened'); }; @@ -46,20 +45,20 @@ }; beforeEach(function () { + jasmine.clock().install(); // $.cookie is mocked, make sure we have a state with an unmuted volume. - $.cookie.andReturn('100'); - this.addMatchers({ - toBeFocused: function () { + $.cookie.and.returnValue('100'); + jasmine.addMatchers({ + toHaveCorrectLabels: function () { return { - compare: function (actual) { - return { pass: $(actual)[0] === $(actual)[0].ownerDocument.activeElement }; + compare: function (actual, labelsList) { + return { + pass: _.difference(labelsList, _.map(actual, function (item) { + return $(item).text(); + })).length === 0 + }; } }; - }, - toHaveCorrectLabels: function (labelsList) { - return _.difference(labelsList, _.map(this.actual, function (item) { - return $(item).text(); - })).length === 0; } }); }); @@ -69,6 +68,7 @@ _.result(state.storage, 'clear'); _.result($('video').data('contextmenu'), 'destroy'); _.result(state.videoPlayer, 'destroy'); + jasmine.clock().uninstall(); }); describe('constructor', function () { @@ -89,7 +89,7 @@ */ // Only one context menu per video container - expect(menu).toExist(); + expect(menu).toBeInDOM(); expect(menu).toHaveClass('is-opened'); expect(menuItems).toHaveCorrectLabels(['Play', 'Mute', 'Fill browser']); expect(menuSubmenuItem.children('span')).toHaveText('Speed'); @@ -141,8 +141,8 @@ menuEvents = ['keydown', 'contextmenu', 'mouseleave', 'mouseover']; menu.data('menu').destroy(); - expect(menu).not.toExist(); - expect(overlay).not.toExist(); + expect(menu).not.toBeInDOM(); + expect(overlay).not.toBeInDOM(); _.each(menuitemEvents, function (eventName) { expect(menuItems.first()).not.toHandle(eventName); }) @@ -177,7 +177,7 @@ it('context menu opens', function () { expect(menu).toHaveClass('is-opened'); - expect(overlay).toExist(); + expect(overlay).toBeInDOM(); }); it('mouseover and mouseleave behave as expected', function () { @@ -193,25 +193,25 @@ // Left-click outside of open menu, for example on Play button playButton.click(); expect(menu).not.toHaveClass('is-opened'); - expect(overlay).not.toExist(); + expect(overlay).not.toBeInDOM(); }); it('mouse right-clicking outside of video will close it', function () { // Right-click outside of open menu for example on Play button playButton.trigger('contextmenu'); expect(menu).not.toHaveClass('is-opened'); - expect(overlay).not.toExist(); + expect(overlay).not.toBeInDOM(); }); it('mouse right-clicking inside video but outside of context menu will not close it', function () { - spyOn(menu.data('menu'), 'pointInContainerBox').andReturn(true); + spyOn(menu.data('menu'), 'pointInContainerBox').and.returnValue(true); overlay.trigger('contextmenu'); expect(menu).toHaveClass('is-opened'); - expect(overlay).toExist(); + expect(overlay).toBeInDOM(); }); it('mouse right-clicking inside video but outside of context menu will close submenus', function () { - spyOn(menu.data('menu'), 'pointInContainerBox').andReturn(true); + spyOn(menu.data('menu'), 'pointInContainerBox').and.returnValue(true); openSubmenuMouse(menuSubmenuItem); expect(menuSubmenuItem).toHaveClass('is-opened'); overlay.trigger('contextmenu'); @@ -221,12 +221,12 @@ it('mouse left/right-clicking behaves as expected on play/pause menu item', function () { var menuItem = menuItems.first(); spyOn(state.videoPlayer, 'isPlaying'); - spyOn(state.videoPlayer, 'play').andCallFake(function () { - state.videoPlayer.isPlaying.andReturn(true); + spyOn(state.videoPlayer, 'play').and.callFake(function () { + state.videoPlayer.isPlaying.and.returnValue(true); state.el.trigger('play'); }); - spyOn(state.videoPlayer, 'pause').andCallFake(function () { - state.videoPlayer.isPlaying.andReturn(false); + spyOn(state.videoPlayer, 'pause').and.callFake(function () { + state.videoPlayer.isPlaying.and.returnValue(false); state.el.trigger('pause'); }); // Left-click on play @@ -238,7 +238,7 @@ menuItem.click(); expect(state.videoPlayer.pause).toHaveBeenCalled(); expect(menuItem).toHaveText('Play'); - state.videoPlayer.play.reset(); + state.videoPlayer.play.calls.reset(); // Right-click on play menuItem.trigger('contextmenu'); expect(state.videoPlayer.play).toHaveBeenCalled(); @@ -355,14 +355,14 @@ it('close the menu on ESCAPE keydown', function () { menu.trigger(keyPressEvent($.ui.keyCode.ESCAPE)); expect(menu).not.toHaveClass('is-opened'); - expect(overlay).not.toExist(); + expect(overlay).not.toBeInDOM(); }); it('close the submenu on ESCAPE keydown', function () { openSubmenuKeyboard(menuSubmenuItem); menuSubmenuItem.trigger(keyPressEvent($.ui.keyCode.ESCAPE)); expect(menuSubmenuItem).not.toHaveClass('is-opened'); - expect(overlay).not.toExist(); + expect(overlay).not.toBeInDOM(); }); it('close the submenu on LEFT keydown on submenu items', function () { @@ -395,9 +395,9 @@ menuItems.eq(0).trigger(keyPressEvent($.ui.keyCode.UP)); expect(menuSubmenuItem).toBeFocused(); // Speed - menuSubmenuItem.trigger(keyPressEvent($.ui.keyCode.UP)); // Check if hidden item can be skipped correctly. menuItems.eq(2).hide(); // hide Fullscreen item + menuSubmenuItem.trigger(keyPressEvent($.ui.keyCode.UP)); expect(menuItems.eq(1)).toBeFocused(); // Mute menuItems.eq(1).trigger(keyPressEvent($.ui.keyCode.UP)); expect(menuItems.eq(0)).toBeFocused(); // Play diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js index 85794dc2d5..eb47c399ab 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js @@ -7,7 +7,7 @@ beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine - .createSpy('onTouchBasedDevice').andReturn(null); + .createSpy('onTouchBasedDevice').and.returnValue(null); }); afterEach(function () { @@ -24,7 +24,7 @@ }); it('render the video controls', function () { - expect($('.video-controls')).toContain( + expect($('.video-controls')).toContainElement( [ '.slider', 'ul.vcr', @@ -41,61 +41,52 @@ describe('constructor with start-time', function () { it( 'saved position is 0, timer slider and VCR set to start-time', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - savedVideoPosition: 0 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + savedVideoPosition: 0 }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); - - return isFinite(duration) && duration > 0 && - isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:10 / 1:00'); expectedValue = sliderEl.slider('option', 'value'); expect(expectedValue).toBe(10); - }); + }).always(done); }); it( 'saved position is after start-time, ' + 'timer slider and VCR set to saved position', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - savedVideoPosition: 15 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + savedVideoPosition: 15 }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:15 / 1:00'); @@ -103,34 +94,30 @@ expect(expectedValue).toBe(15); state.storage.clear(); - }); + }).always(done); }); it( 'saved position is negative, ' + 'timer slider and VCR set to start-time', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - savedVideoPosition: -15 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + savedVideoPosition: -15 }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:10 / 1:00'); @@ -138,34 +125,30 @@ expect(expectedValue).toBe(10); state.storage.clear(); - }); + }).always(done); }); it( 'saved position is not a number, ' + 'timer slider and VCR set to start-time', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - savedVideoPosition: 'a' - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + savedVideoPosition: 'a' }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:10 / 1:00'); @@ -173,34 +156,30 @@ expect(expectedValue).toBe(10); state.storage.clear(); - }); + }).always(done); }); it( 'saved position is greater than end-time, ' + 'timer slider and VCR set to start-time', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - savedVideoPosition: 10000 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + savedVideoPosition: 10000 }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:10 / 1:00'); @@ -208,7 +187,7 @@ expect(expectedValue).toBe(10); state.storage.clear(); - }); + }).always(done); }); }); @@ -216,28 +195,24 @@ it( 'saved position is 0, timer slider and VCR set to 0:00 ' + 'and ending at specified end-time', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - end: 20, - savedVideoPosition: 0 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + end: 20, + savedVideoPosition: 0 }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:00 / 0:20'); @@ -245,34 +220,30 @@ expect(expectedValue).toBe(0); state.storage.clear(); - }); + }).always(done); }); it( 'saved position is after start-time, ' + 'timer slider and VCR set to saved position', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - end: 20, - savedVideoPosition: 15 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + end: 20, + savedVideoPosition: 15 }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:15 / 0:20'); @@ -280,34 +251,30 @@ expect(expectedValue).toBe(15); state.storage.clear(); - }); + }).always(done); }); // TODO: Fix! it( 'saved position is negative, timer slider and VCR set to 0:00', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - end: 20, - savedVideoPosition: -15 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + end: 20, + savedVideoPosition: -15 }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:00 / 0:20'); @@ -315,34 +282,30 @@ expect(expectedValue).toBe(0); state.storage.clear(); - }); + }).always(done); }); it( 'saved position is not a number, ' + 'timer slider and VCR set to 0:00', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - end: 20, - savedVideoPosition: 'a' - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + end: 20, + savedVideoPosition: 'a' }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:00 / 0:20'); @@ -350,35 +313,31 @@ expect(expectedValue).toBe(0); state.storage.clear(); - }); + }).always(done); }); // TODO: Fix! it( 'saved position is greater than end-time, ' + 'timer slider and VCR set to 0:00', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - end: 20, - savedVideoPosition: 10000 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + end: 20, + savedVideoPosition: 10000 }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:00 / 0:20'); @@ -386,36 +345,32 @@ expect(expectedValue).toBe(0); state.storage.clear(); - }); + }).always(done); }); }); describe('constructor with start-time and end-time', function () { it( 'saved position is 0, timer slider and VCR set to appropriate start and end times', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - end: 20, - savedVideoPosition: 0 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + end: 20, + savedVideoPosition: 0 }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:10 / 0:20'); @@ -423,35 +378,31 @@ expect(expectedValue).toBe(10); state.storage.clear(); - }); + }).always(done); }); it( 'saved position is after start-time, ' + 'timer slider and VCR set to saved position', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - end: 20, - savedVideoPosition: 15 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + end: 20, + savedVideoPosition: 15 }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:15 / 0:20'); @@ -459,35 +410,31 @@ expect(expectedValue).toBe(15); state.storage.clear(); - }); + }).always(done); }); it( 'saved position is negative, ' + 'timer slider and VCR set to start-time', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - end: 20, - savedVideoPosition: -15 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + end: 20, + savedVideoPosition: -15 }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:10 / 0:20'); @@ -495,35 +442,31 @@ expect(expectedValue).toBe(10); state.storage.clear(); - }); + }).always(done); }); it( 'saved position is not a number, ' + 'timer slider and VCR set to start-time', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - end: 20, - savedVideoPosition: 'a' - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + end: 20, + savedVideoPosition: 'a' }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:10 / 0:20'); @@ -531,35 +474,31 @@ expect(expectedValue).toBe(10); state.storage.clear(); - }); + }).always(done); }); it( 'saved position is greater than end-time, ' + 'timer slider and VCR set to start-time', - function () + function (done) { var duration, sliderEl, expectedValue; - runs(function () { - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - end: 20, - savedVideoPosition: 10000 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').andReturn(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + end: 20, + savedVideoPosition: 10000 }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }, 'duration is set', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expectedValue = $('.video-controls').find('.vidtime'); expect(expectedValue).toHaveText('0:10 / 0:20'); @@ -567,7 +506,7 @@ expect(expectedValue).toBe(10); state.storage.clear(); - }); + }).always(done); }); }); @@ -587,16 +526,15 @@ expect(state.videoControl).toBeUndefined(); }); - it('can focus the first control', function () { + it('can focus the first control', function (done) { var btnPlay; state = jasmine.initializePlayer({focusFirstControl: true}); btnPlay = state.el.find('.video-controls .play'); - waitsFor(function () { + jasmine.waitUntil(function () { return state.el.hasClass('is-initialized'); - }, 'Player is not initialized', WAIT_TIMEOUT); - runs(function () { + }).then(function () { expect(btnPlay).toBeFocused(); - }); + }).always(done); }); }); }).call(this, window.WAIT_TIMEOUT); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_events_bumper_plugin_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_events_bumper_plugin_spec.js index e41b40e782..4a0f1177e2 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_events_bumper_plugin_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_events_bumper_plugin_spec.js @@ -1,20 +1,20 @@ (function (undefined) { 'use strict'; describe('VideoPlayer Events Bumper plugin', function () { + var Logger = window.Logger; var state, oldOTBD; beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice') - .andReturn(null); + .and.returnValue(null); - jasmine.stubRequests(); state = jasmine.initializePlayer('video_with_bumper.html'); spyOn(Logger, 'log'); $('.poster .btn-play').click(); - spyOn(state.bumperState.videoEventsBumperPlugin, 'getCurrentTime').andReturn(10); - spyOn(state.bumperState.videoEventsBumperPlugin, 'getDuration').andReturn(20); + spyOn(state.bumperState.videoEventsBumperPlugin, 'getCurrentTime').and.returnValue(10); + spyOn(state.bumperState.videoEventsBumperPlugin, 'getDuration').and.returnValue(20); }); afterEach(function () { @@ -33,7 +33,7 @@ state.el.trigger('ready'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.loaded', { host_component_id: 'id', - bumper_id: 'xmodule/include/fixtures/test.mp4', + bumper_id: '/base/fixtures/test.mp4', code: 'html5', duration: 20 }); @@ -43,7 +43,7 @@ state.el.trigger('play'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.played', { host_component_id: 'id', - bumper_id: 'xmodule/include/fixtures/test.mp4', + bumper_id: '/base/fixtures/test.mp4', code: 'html5', currentTime: 10, duration: 20 @@ -54,17 +54,17 @@ state.el.trigger('ended'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.stopped', { host_component_id: 'id', - bumper_id: 'xmodule/include/fixtures/test.mp4', + bumper_id: '/base/fixtures/test.mp4', code: 'html5', currentTime: 10, duration: 20 }); - Logger.log.reset(); + Logger.log.calls.reset(); state.el.trigger('stop'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.stopped', { host_component_id: 'id', - bumper_id: 'xmodule/include/fixtures/test.mp4', + bumper_id: '/base/fixtures/test.mp4', code: 'html5', currentTime: 10, duration: 20 @@ -75,7 +75,7 @@ state.el.trigger('skip', [false]); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.skipped', { host_component_id: 'id', - bumper_id: 'xmodule/include/fixtures/test.mp4', + bumper_id: '/base/fixtures/test.mp4', code: 'html5', currentTime: 10, duration: 20 @@ -86,7 +86,7 @@ state.el.trigger('skip', [true]); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.dismissed', { host_component_id: 'id', - bumper_id: 'xmodule/include/fixtures/test.mp4', + bumper_id: '/base/fixtures/test.mp4', code: 'html5', currentTime: 10, duration: 20 @@ -97,7 +97,7 @@ state.el.trigger('language_menu:show'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.transcript.menu.shown', { host_component_id: 'id', - bumper_id: 'xmodule/include/fixtures/test.mp4', + bumper_id: '/base/fixtures/test.mp4', code: 'html5', duration: 20 }); @@ -107,7 +107,7 @@ state.el.trigger('language_menu:hide'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.transcript.menu.hidden', { host_component_id: 'id', - bumper_id: 'xmodule/include/fixtures/test.mp4', + bumper_id: '/base/fixtures/test.mp4', code: 'html5', duration: 20 }); @@ -117,7 +117,7 @@ state.el.trigger('captions:show'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.transcript.shown', { host_component_id: 'id', - bumper_id: 'xmodule/include/fixtures/test.mp4', + bumper_id: '/base/fixtures/test.mp4', code: 'html5', currentTime: 10, duration: 20 @@ -128,7 +128,7 @@ state.el.trigger('captions:hide'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.transcript.hidden', { host_component_id: 'id', - bumper_id: 'xmodule/include/fixtures/test.mp4', + bumper_id: '/base/fixtures/test.mp4', code: 'html5', currentTime: 10, duration: 20 @@ -137,7 +137,7 @@ it('can destroy itself', function () { var plugin = state.bumperState.videoEventsBumperPlugin; - spyOn($.fn, 'off').andCallThrough(); + spyOn($.fn, 'off').and.callThrough(); plugin.destroy(); expect(state.bumperState.videoEventsBumperPlugin).toBeUndefined(); expect($.fn.off).toHaveBeenCalledWith({ diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_events_plugin_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_events_plugin_spec.js index b6896d19db..82f64b8c8d 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_events_plugin_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_events_plugin_spec.js @@ -7,12 +7,11 @@ oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice') - .andReturn(null); + .and.returnValue(null); - jasmine.stubRequests(); state = jasmine.initializePlayer(); spyOn(Logger, 'log'); - spyOn(state.videoEventsPlugin, 'getCurrentTime').andReturn(10); + spyOn(state.videoEventsPlugin, 'getCurrentTime').and.returnValue(10); }); afterEach(function () { @@ -90,7 +89,7 @@ }); expect(state.videoEventsPlugin.emitPlayVideoEvent).toBeTruthy(); - Logger.log.reset(); + Logger.log.calls.reset(); state.el.trigger('stop'); expect(Logger.log).toHaveBeenCalledWith('stop_video', { id: 'id', @@ -155,7 +154,7 @@ it('can destroy itself', function () { var plugin = state.videoEventsPlugin; - spyOn($.fn, 'off').andCallThrough(); + spyOn($.fn, 'off').and.callThrough(); state.videoEventsPlugin.destroy(); expect(state.videoEventsPlugin).toBeUndefined(); expect($.fn.off).toHaveBeenCalledWith({ diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js index 5f69d2c7c7..8dd9bceb40 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js @@ -15,17 +15,19 @@ // stack. jQuery.fx.off = true; + jasmine.stubRequests(); loadFixtures('video_html5.html'); state = new Video('#example'); spyOnEvent(state.el, 'mousemove'); - spyOn(state.focusGrabber, 'disableFocusGrabber').andCallThrough(); - spyOn(state.focusGrabber, 'enableFocusGrabber').andCallThrough(); + spyOn(state.focusGrabber, 'disableFocusGrabber').and.callThrough(); + spyOn(state.focusGrabber, 'enableFocusGrabber').and.callThrough(); }); afterEach(function () { // Turn jQuery animations back on. jQuery.fx.off = true; + state.storage.clear(); state.videoPlayer.destroy(); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_full_screen_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_full_screen_spec.js index 6aa858b73f..1bb36c82b4 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_full_screen_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_full_screen_spec.js @@ -6,7 +6,7 @@ beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine - .createSpy('onTouchBasedDevice').andReturn(null); + .createSpy('onTouchBasedDevice').and.returnValue(null); }); afterEach(function () { @@ -83,7 +83,7 @@ }); it('Controls height is actual on switch to fullscreen', function () { - spyOn($.fn, 'height').andCallFake(function (val) { + spyOn($.fn, 'height').and.callFake(function (val) { return _.isUndefined(val) ? 100: this; }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_play_pause_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_play_pause_control_spec.js index 0cbb23c1f1..dcb1fd4968 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_play_pause_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_play_pause_control_spec.js @@ -6,7 +6,7 @@ beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine - .createSpy('onTouchBasedDevice').andReturn(null); + .createSpy('onTouchBasedDevice').and.returnValue(null); state = jasmine.initializePlayer(); spyOn(state.videoCommands, 'execute'); spyOn(state.videoSaveStatePlugin, 'saveState'); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_play_placeholder_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_play_placeholder_spec.js index d99c12e24c..b7119dd9b4 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_play_placeholder_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_play_placeholder_spec.js @@ -6,7 +6,7 @@ beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine - .createSpy('onTouchBasedDevice').andReturn(['iPad']); + .createSpy('onTouchBasedDevice').and.returnValue(['iPad']); state = jasmine.initializePlayer(); spyOn(state.videoCommands, 'execute'); @@ -41,7 +41,7 @@ beforeEach(function () { jasmine.stubRequests(); - spyOn(window.YT, 'Player').andCallThrough(); + spyOn(window.YT, 'Player').and.callThrough(); }); it ('works correctly on calling proper methods', function () { @@ -77,7 +77,7 @@ it(message, function () { var btnPlay; - window.onTouchBasedDevice.andReturn(data.isTouch); + window.onTouchBasedDevice.and.returnValue(data.isTouch); state = jasmine.initializePlayer(); btnPlay = state.el.find('.btn-play'); @@ -97,7 +97,7 @@ { var btnPlay; - window.onTouchBasedDevice.andReturn([device]); + window.onTouchBasedDevice.and.returnValue([device]); state = jasmine.initializePlayer(); btnPlay = state.el.find('.btn-play'); @@ -113,7 +113,7 @@ { var btnPlay; - window.onTouchBasedDevice.andReturn([device]); + window.onTouchBasedDevice.and.returnValue([device]); state = jasmine.initializePlayer(); btnPlay = state.el.find('.btn-play'); @@ -128,7 +128,7 @@ { var btnPlay; - window.onTouchBasedDevice.andReturn([device]); + window.onTouchBasedDevice.and.returnValue([device]); state = jasmine.initializePlayerYouTube(); btnPlay = state.el.find('.btn-play'); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_play_skip_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_play_skip_control_spec.js index 7e15b597af..479de984ba 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_play_skip_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_play_skip_control_spec.js @@ -6,7 +6,7 @@ beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine - .createSpy('onTouchBasedDevice').andReturn(null); + .createSpy('onTouchBasedDevice').and.returnValue(null); state = jasmine.initializePlayer('video_with_bumper.html'); $('.poster .btn-play').click(); spyOn(state.bumperState.videoCommands, 'execute'); @@ -19,16 +19,19 @@ state.bumperState.videoPlayer.destroy(); } window.onTouchBasedDevice = oldOTBD; + if (state.videoPlayer) { + _.result(state.videoPlayer, 'destroy'); + } }); it('can render the control', function () { - expect($('.video_control.play')).toExist(); + expect($('.video_control.play')).toBeInDOM(); }); it('can update state on play', function () { state.el.trigger('play'); - expect($('.video_control.play')).not.toExist(); - expect($('.video_control.skip')).toExist(); + expect($('.video_control.play')).not.toBeInDOM(); + expect($('.video_control.skip')).toBeInDOM(); }); it('can start video playing on click', function () { @@ -38,7 +41,7 @@ it('can skip the video on click', function () { state.el.trigger('play'); - spyOn(state.bumperState.videoPlayer, 'isPlaying').andReturn(true); + spyOn(state.bumperState.videoPlayer, 'isPlaying').and.returnValue(true); $('.video_control.skip').first().click(); expect(state.bumperState.videoCommands.execute).toHaveBeenCalledWith('skip'); }); @@ -46,10 +49,10 @@ it('can destroy itself', function () { var plugin = state.bumperState.videoPlaySkipControl, el = plugin.el; - spyOn($.fn, 'off').andCallThrough(); + spyOn($.fn, 'off').and.callThrough(); plugin.destroy(); expect(state.bumperState.videoPlaySkipControl).toBeUndefined(); - expect(el).not.toExist(); + expect(el).not.toBeInDOM(); expect($.fn.off).toHaveBeenCalledWith('destroy', plugin.destroy); }); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js index a8f8fd789b..f5f15ba133 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js @@ -5,12 +5,16 @@ require( ['video/03_video_player.js'], function (VideoPlayer) { describe('VideoPlayer', function () { - var state, oldOTBD; + var state, oldOTBD, empty_arguments; + + (function () { + empty_arguments = arguments; + })(); beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') - .andReturn(null); + .and.returnValue(null); }); afterEach(function () { @@ -73,7 +77,7 @@ function (VideoPlayer) { var events; jasmine.stubRequests(); - spyOn(window.YT, 'Player').andCallThrough(); + spyOn(window.YT, 'Player').and.callThrough(); state = jasmine.initializePlayerYouTube(); state.videoEl = $('video, iframe'); @@ -107,9 +111,9 @@ function (VideoPlayer) { state = jasmine.initializePlayerYouTube(); state.videoEl = state.el.find('video, iframe').width(100); player = state.videoPlayer.player; - player.getAvailablePlaybackRates.andReturn([1]); + player.getAvailablePlaybackRates.and.returnValue([1]); state.currentPlayerMode = 'html5'; - spyOn(window.YT, 'Player').andCallThrough(); + spyOn(window.YT, 'Player').and.callThrough(); state.videoPlayer.onReady(); expect(YT.Player).toHaveBeenCalledWith('id', { @@ -137,7 +141,7 @@ function (VideoPlayer) { describe('when on a touch based device', function () { $.each(['iPad', 'Android'], function (index, device) { it('create video volume control on' + device, function () { - window.onTouchBasedDevice.andReturn([device]); + window.onTouchBasedDevice.and.returnValue([device]); state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); @@ -167,7 +171,7 @@ function (VideoPlayer) { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); - spyOn(state.videoPlayer, 'play').andCallThrough(); + spyOn(state.videoPlayer, 'play').and.callThrough(); state.videoPlayer.onReady(); }); @@ -204,7 +208,7 @@ function (VideoPlayer) { state = jasmine.initializePlayerYouTube(); state.videoEl = $('video, iframe'); - spyOn($.fn, 'trigger').andCallThrough(); + spyOn($.fn, 'trigger').and.callThrough(); state.videoPlayer.onStateChange({ data: YT.PlayerState.ENDED }); @@ -215,8 +219,8 @@ function (VideoPlayer) { }); it('trigger pause and ended events', function () { - expect($.fn.trigger).toHaveBeenCalledWith('pause', {}); - expect($.fn.trigger).toHaveBeenCalledWith('ended', {}); + expect($.fn.trigger).toHaveBeenCalledWith('pause', empty_arguments); + expect($.fn.trigger).toHaveBeenCalledWith('ended', empty_arguments); }); }); }); @@ -226,7 +230,7 @@ function (VideoPlayer) { beforeEach(function () { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); - spyOn($.fn, 'trigger').andCallThrough(); + spyOn($.fn, 'trigger').and.callThrough(); state.videoPlayer.onStateChange({ data: YT.PlayerState.PAUSED @@ -238,7 +242,7 @@ function (VideoPlayer) { }); it('pause the video caption', function () { - expect($.fn.trigger).toHaveBeenCalledWith('pause', {}); + expect($.fn.trigger).toHaveBeenCalledWith('pause', empty_arguments); }); }); @@ -250,15 +254,15 @@ function (VideoPlayer) { state = jasmine.initializePlayer(); oldState = state; - spyOn(oldState.videoPlayer, 'onPause').andCallThrough(); + spyOn(oldState.videoPlayer, 'onPause').and.callThrough(); // Now initialize a second instance. state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); - spyOn(window, 'setInterval').andReturn(100); - spyOn($.fn, 'trigger').andCallThrough(); + spyOn(window, 'setInterval').and.returnValue(100); + spyOn($.fn, 'trigger').and.callThrough(); state.videoPlayer.onStateChange({ data: YT.PlayerState.PLAYING @@ -277,7 +281,7 @@ function (VideoPlayer) { }); it('play the video caption', function () { - expect($.fn.trigger).toHaveBeenCalledWith('play', {}); + expect($.fn.trigger).toHaveBeenCalledWith('play', empty_arguments); }); }); @@ -289,7 +293,7 @@ function (VideoPlayer) { state.videoEl = $('video, iframe'); - spyOn($.fn, 'trigger').andCallThrough(); + spyOn($.fn, 'trigger').and.callThrough(); state.videoPlayer.onStateChange({ data: YT.PlayerState.PLAYING }); @@ -310,7 +314,7 @@ function (VideoPlayer) { }); it('pause the video caption', function () { - expect($.fn.trigger).toHaveBeenCalledWith('pause', {}); + expect($.fn.trigger).toHaveBeenCalledWith('pause', empty_arguments); }); }); @@ -319,7 +323,7 @@ function (VideoPlayer) { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); - spyOn($.fn, 'trigger').andCallThrough(); + spyOn($.fn, 'trigger').and.callThrough(); state.videoPlayer.onStateChange({ data: YT.PlayerState.ENDED }); @@ -330,7 +334,7 @@ function (VideoPlayer) { }); it('pause the video caption', function () { - expect($.fn.trigger).toHaveBeenCalledWith('ended', {}); + expect($.fn.trigger).toHaveBeenCalledWith('ended', empty_arguments); }); }); }); @@ -362,59 +366,51 @@ function (VideoPlayer) { describe('onSeek', function () { beforeEach(function () { // jasmine.Clock can't be used to fake out debounce with newer versions of underscore - spyOn(_, 'debounce').andCallFake(function (func) { + spyOn(_, 'debounce').and.callFake(function (func) { return function () { func.apply(this, arguments); }; }); state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); - spyOn(state.videoPlayer, 'duration').andReturn(120); + spyOn(state.videoPlayer, 'duration').and.returnValue(120); }); describe('when the video is playing', function () { - beforeEach(function () { - runs(function () { - state.videoPlayer.play(); - }); + beforeEach(function (done) { + state.videoPlayer.play(); - waitsFor(function () { + jasmine.waitUntil(function() { return state.videoPlayer.isPlaying(); - }, 'video didn\'t start playing', WAIT_TIMEOUT); + }).done(done); }); it('call runTimer in seekTo on player', function () { - runs(function () { - spyOn(state.videoPlayer, 'stopTimer'); - spyOn(state.videoPlayer, 'runTimer'); - state.videoPlayer.seekTo(10); - expect(state.videoPlayer.currentTime).toBe(10); - expect(state.videoPlayer.stopTimer).toHaveBeenCalled(); - expect(state.videoPlayer.runTimer).toHaveBeenCalled(); - }); + spyOn(state.videoPlayer, 'stopTimer').and.callThrough(); + spyOn(state.videoPlayer, 'runTimer').and.callThrough(); + state.videoPlayer.seekTo(10); + expect(state.videoPlayer.currentTime).toBe(10); + expect(state.videoPlayer.stopTimer).toHaveBeenCalled(); + expect(state.videoPlayer.runTimer).toHaveBeenCalled(); }); it('seek the player', function () { - runs(function () { - spyOn(state.videoPlayer.player, 'seekTo').andCallThrough(); - state.videoProgressSlider.onSlide( - jQuery.Event('slide'), { value: 30 } - ); - expect(state.videoPlayer.currentTime).toBe(30); - expect(state.videoPlayer.player.seekTo).toHaveBeenCalledWith(30, true); - }); + spyOn(state.videoPlayer.player, 'seekTo').and.callThrough(); + state.videoProgressSlider.onSlide( + jQuery.Event('slide'), { value: 30 } + ); + expect(state.videoPlayer.currentTime).toBe(30); + expect(state.videoPlayer.player.seekTo).toHaveBeenCalledWith(30, true); }); it('call updatePlayTime on player', function () { - runs(function () { - spyOn(state.videoPlayer, 'updatePlayTime').andCallThrough(); - state.videoProgressSlider.onSlide( - jQuery.Event('slide'), { value: 30 } - ); - expect(state.videoPlayer.currentTime).toBe(30); - expect(state.videoPlayer.updatePlayTime).toHaveBeenCalledWith(30, true); - }); + spyOn(state.videoPlayer, 'updatePlayTime').and.callThrough(); + state.videoProgressSlider.onSlide( + jQuery.Event('slide'), { value: 30 } + ); + expect(state.videoPlayer.currentTime).toBe(30); + expect(state.videoPlayer.updatePlayTime).toHaveBeenCalledWith(30, true); }); }); @@ -433,7 +429,7 @@ function (VideoPlayer) { describe('when the video is not playing', function () { beforeEach(function () { spyOn(state.videoPlayer, 'setPlaybackRate') - .andCallThrough(); + .and.callThrough(); }); it('video has a correct speed', function () { @@ -442,7 +438,7 @@ function (VideoPlayer) { expect(state.videoPlayer.setPlaybackRate) .toHaveBeenCalledWith('2.0', true); state.videoPlayer.onPlay(); - expect(state.videoPlayer.setPlaybackRate.calls.length) + expect(state.videoPlayer.setPlaybackRate.calls.count()) .toEqual(1); }); }); @@ -483,7 +479,7 @@ function (VideoPlayer) { state.videoEl = $('video, iframe'); - spyOn(state.videoPlayer, 'updatePlayTime').andCallThrough(); + spyOn(state.videoPlayer, 'updatePlayTime').and.callThrough(); }); describe( @@ -535,29 +531,26 @@ function (VideoPlayer) { state.videoEl = $('video, iframe'); - spyOn(state.videoPlayer, 'update').andCallThrough(); - spyOn(state.videoPlayer, 'pause').andCallThrough(); + spyOn(state.videoPlayer, 'update').and.callThrough(); + spyOn(state.videoPlayer, 'pause').and.callThrough(); spyOn(state.videoProgressSlider, 'notifyThroughHandleEnd') - .andCallThrough(); + .and.callThrough(); }); it( 'video is paused on first endTime, start & end time are reset', - function () + function (done) { var duration; - state.videoProgressSlider.notifyThroughHandleEnd.reset(); - state.videoPlayer.pause.reset(); + state.videoProgressSlider.notifyThroughHandleEnd.calls.reset(); + state.videoPlayer.pause.calls.reset(); state.videoPlayer.play(); - waitsFor(function () { + jasmine.waitUntil(function () { duration = Math.round(state.videoPlayer.currentTime); - - return state.videoPlayer.pause.calls.length === 1; - }, 'pause() has been called', WAIT_TIMEOUT); - - runs(function () { + return state.videoPlayer.pause.calls.count() === 1; + }).then(function () { expect(state.videoPlayer.startTime).toBe(0); expect(state.videoPlayer.endTime).toBe(null); @@ -565,7 +558,7 @@ function (VideoPlayer) { expect(state.videoProgressSlider.notifyThroughHandleEnd) .toHaveBeenCalledWith({end: true}); - }); + }).always(done); }); }); @@ -573,14 +566,14 @@ function (VideoPlayer) { beforeEach(function () { state = jasmine.initializePlayerYouTube(); state.videoEl = $('video, iframe'); - spyOn(state.videoCaption, 'updatePlayTime').andCallThrough(); - spyOn(state.videoProgressSlider, 'updatePlayTime').andCallThrough(); + spyOn(state.videoCaption, 'updatePlayTime').and.callThrough(); + spyOn(state.videoProgressSlider, 'updatePlayTime').and.callThrough(); }); - it('update the video playback time', function () { + it('update the video playback time', function (done) { var duration = 0; - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); if (duration > 0) { @@ -588,40 +581,34 @@ function (VideoPlayer) { } return false; - }, 'Video is fully loaded.', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { state.videoPlayer.goToStartTime = false; state.videoPlayer.updatePlayTime(60); expect($('.vidtime')).toHaveHtml('1:00 / 1:00'); - }); + }).always(done); }); - it('update the playback time on caption', function () { - waitsFor(function () { + it('update the playback time on caption', function (done) { + jasmine.waitUntil(function () { return state.videoPlayer.duration() > 0; - }, 'Video is fully loaded.', WAIT_TIMEOUT); - - runs(function () { + }, 1000).then(function () { state.videoPlayer.goToStartTime = false; state.videoPlayer.updatePlayTime(60); expect(state.videoCaption.updatePlayTime) .toHaveBeenCalledWith(60); - }); + }).always(done); }); - it('update the playback time on progress slider', function () { + it('update the playback time on progress slider', function (done) { var duration = 0; - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return duration > 0; - }, 'Video is fully loaded.', WAIT_TIMEOUT); - - runs(function () { + }, 1000).then(function () { state.videoPlayer.goToStartTime = false; state.videoPlayer.updatePlayTime(60); @@ -630,7 +617,7 @@ function (VideoPlayer) { time: 60, duration: duration }); - }); + }).always(done); }); }); @@ -652,15 +639,15 @@ function (VideoPlayer) { state.videoEl = $('video, iframe'); - spyOn(state.videoPlayer, 'updatePlayTime').andCallThrough(); - spyOn(state.videoPlayer.player, 'seekTo').andCallThrough(); + spyOn(state.videoPlayer, 'updatePlayTime').and.callThrough(); + spyOn(state.videoPlayer.player, 'seekTo').and.callThrough(); spyOn(state.videoProgressSlider, 'updateStartEndTimeRegion') - .andCallThrough(); + .and.callThrough(); }); it( 'when duration becomes available, updatePlayTime() is called', - function () + function (done) { var duration; @@ -669,14 +656,12 @@ function (VideoPlayer) { state.videoPlayer.play(); - waitsFor(function () { + jasmine.waitUntil(function () { duration = state.videoPlayer.duration(); return state.videoPlayer.isPlaying() && state.videoPlayer.initialSeekToStartTime === false; - }, 'duration becomes available', WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(state.videoPlayer.startTime).toBe(START_TIME); expect(state.videoPlayer.endTime).toBe(END_TIME); @@ -688,7 +673,7 @@ function (VideoPlayer) { expect(state.videoPlayer.seekToStartTimeOldSpeed) .toBe(state.speed); - }); + }).always(done); }); }); @@ -708,7 +693,7 @@ function (VideoPlayer) { seekTo: function () {} }, figureOutStartEndTime: jasmine.createSpy(), - figureOutStartingTime: jasmine.createSpy().andReturn(0) + figureOutStartingTime: jasmine.createSpy().and.returnValue(0) }, config: { savedVideoPosition: 0, @@ -723,7 +708,7 @@ function (VideoPlayer) { currentPlayerMode: 'html5', trigger: function () {}, browserIsFirefox: false, - isFlashMode: jasmine.createSpy().andReturn(false) + isFlashMode: jasmine.createSpy().and.returnValue(false) }; }); }); @@ -733,7 +718,7 @@ function (VideoPlayer) { beforeEach(function () { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); - spyOn($.fn, 'trigger').andCallThrough(); + spyOn($.fn, 'trigger').and.callThrough(); $('.add-fullscreen').click(); }); @@ -752,7 +737,7 @@ function (VideoPlayer) { beforeEach(function () { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); - spyOn($.fn, 'trigger').andCallThrough(); + spyOn($.fn, 'trigger').and.callThrough(); state.el.addClass('video-fullscreen'); state.videoFullScreen.fullScreenState = true; state.videoFullScreen.isFullScreen = true; @@ -779,7 +764,7 @@ function (VideoPlayer) { state.videoEl = $('video, iframe'); - spyOn(state.videoPlayer.player, 'getDuration').andCallThrough(); + spyOn(state.videoPlayer.player, 'getDuration').and.callThrough(); state.videoPlayer.duration(); }); @@ -801,11 +786,11 @@ function (VideoPlayer) { state.videoEl = $('video, iframe'); - spyOn(state, 'getDuration').andCallThrough(); + spyOn(state, 'getDuration').and.callThrough(); // When `state.videoPlayer.player.getDuration()` returns a `0`, // the fall-back function `state.getDuration()` will be called. - state.videoPlayer.player.getDuration.andReturn(0); + state.videoPlayer.player.getDuration.and.returnValue(0); }); it('getDuration is called as a fall-back', function () { @@ -821,7 +806,7 @@ function (VideoPlayer) { state.videoEl = $('video, iframe'); - spyOn(state.videoPlayer.player, 'getVolume').andCallThrough(); + spyOn(state.videoPlayer.player, 'getVolume').and.callThrough(); }); it('set the player volume', function () { @@ -841,7 +826,7 @@ function (VideoPlayer) { ['iPad', 'Android', 'iPhone'], function (index, device) { - window.onTouchBasedDevice.andReturn([device]); + window.onTouchBasedDevice.and.returnValue([device]); state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); @@ -851,7 +836,7 @@ function (VideoPlayer) { }); it('modules are not initialized on iPhone', function () { - window.onTouchBasedDevice.andReturn(['iPhone']); + window.onTouchBasedDevice.and.returnValue(['iPhone']); state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); @@ -870,34 +855,28 @@ function (VideoPlayer) { var message = 'controls become visible after playing starts ' + 'on ' + device; - it(message, function () { + it(message, function (done) { var controls; - window.onTouchBasedDevice.andReturn([device]); + window.onTouchBasedDevice.and.returnValue([device]); - runs(function () { - state = jasmine.initializePlayer(); - state.videoEl = $('video, iframe'); - controls = state.el.find('.video-controls'); - }); + state = jasmine.initializePlayer(); + state.videoEl = $('video, iframe'); + controls = state.el.find('.video-controls'); - waitsFor(function () { + jasmine.waitUntil(function () { return state.el.hasClass('is-initialized'); - },'Video is not initialized.' , WAIT_TIMEOUT); - - runs(function () { + }).then(function () { expect(controls).toHaveClass('is-hidden'); state.videoPlayer.play(); - }); - - waitsFor(function () { - var duration = state.videoPlayer.duration(); - - return duration > 0 && state.videoPlayer.isPlaying(); - },'Video does not play.' , WAIT_TIMEOUT); - - runs(function () { - expect(controls).not.toHaveClass('is-hidden'); + jasmine.waitUntil(function () { + // Firefox does not return duration for videos until they have reached the end. + // var duration = state.videoPlayer.duration(); + // return duration > 0 && state.videoPlayer.isPlaying(); + return state.videoPlayer.isPlaying(); + }).then(function () { + expect(controls).not.toHaveClass('is-hidden'); + }).always(done); }); }); }); @@ -916,13 +895,13 @@ function (VideoPlayer) { setPlaybackRate: jasmine.createSpy(), player: jasmine.createSpyObj('player', ['setPlaybackRate']) }, - isFlashMode: jasmine.createSpy().andReturn(false) + isFlashMode: jasmine.createSpy().and.returnValue(false) }; }); describe('always', function () { it('convert the current time to the new speed', function () { - state.isFlashMode.andReturn(true); + state.isFlashMode.and.returnValue(true); VideoPlayer.prototype.onSpeedChange.call(state, '0.75', false); expect(state.videoPlayer.currentTime).toBe('120.000'); }); @@ -939,17 +918,17 @@ function (VideoPlayer) { describe('setPlaybackRate', function () { beforeEach(function () { state = { - youtubeId: jasmine.createSpy().andReturn('videoId'), - isFlashMode: jasmine.createSpy().andReturn(false), - isHtml5Mode: jasmine.createSpy().andReturn(true), - isYoutubeType: jasmine.createSpy().andReturn(true), + youtubeId: jasmine.createSpy().and.returnValue('videoId'), + isFlashMode: jasmine.createSpy().and.returnValue(false), + isHtml5Mode: jasmine.createSpy().and.returnValue(true), + isYoutubeType: jasmine.createSpy().and.returnValue(true), setPlayerMode: jasmine.createSpy(), trigger: jasmine.createSpy(), videoPlayer: { currentTime: 60, isPlaying: jasmine.createSpy(), seekTo: jasmine.createSpy(), - duration: jasmine.createSpy().andReturn(60), + duration: jasmine.createSpy().and.returnValue(60), updatePlayTime: jasmine.createSpy(), setPlaybackRate: jasmine.createSpy(), player: jasmine.createSpyObj('player', [ @@ -960,9 +939,9 @@ function (VideoPlayer) { }); it('in Flash mode and video is playing', function () { - state.isFlashMode.andReturn(true); - state.isHtml5Mode.andReturn(false); - state.videoPlayer.isPlaying.andReturn(true); + state.isFlashMode.and.returnValue(true); + state.isHtml5Mode.and.returnValue(false); + state.videoPlayer.isPlaying.and.returnValue(true); VideoPlayer.prototype.setPlaybackRate.call(state, '0.75'); expect(state.videoPlayer.updatePlayTime).toHaveBeenCalledWith(60); expect(state.videoPlayer.player.loadVideoById) @@ -970,9 +949,9 @@ function (VideoPlayer) { }); it('in Flash mode and video not started', function () { - state.isFlashMode.andReturn(true); - state.isHtml5Mode.andReturn(false); - state.videoPlayer.isPlaying.andReturn(false); + state.isFlashMode.and.returnValue(true); + state.isHtml5Mode.and.returnValue(false); + state.videoPlayer.isPlaying.and.returnValue(false); VideoPlayer.prototype.setPlaybackRate.call(state, '0.75'); expect(state.videoPlayer.updatePlayTime).toHaveBeenCalledWith(60); expect(state.videoPlayer.seekTo).toHaveBeenCalledWith(60); @@ -986,7 +965,7 @@ function (VideoPlayer) { }); it('in HTML5 mode', function () { - state.isYoutubeType.andReturn(false); + state.isYoutubeType.and.returnValue(false); VideoPlayer.prototype.setPlaybackRate.call(state, '0.75'); expect(state.videoPlayer.player.setPlaybackRate).toHaveBeenCalledWith('0.75'); }); @@ -994,7 +973,7 @@ function (VideoPlayer) { it('Youtube video in FF, with new speed equal 1.0', function () { state.browserIsFirefox = true; - state.videoPlayer.isPlaying.andReturn(false); + state.videoPlayer.isPlaying.and.returnValue(false); VideoPlayer.prototype.setPlaybackRate.call(state, '1.0'); expect(state.videoPlayer.updatePlayTime).toHaveBeenCalledWith(60); expect(state.videoPlayer.player.cueVideoById) diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_poster_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_poster_spec.js index 18a6f6874c..d2505a11c7 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_poster_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_poster_spec.js @@ -6,7 +6,7 @@ beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine - .createSpy('onTouchBasedDevice').andReturn(null); + .createSpy('onTouchBasedDevice').and.returnValue(null); state = jasmine.initializePlayer('video_with_bumper.html'); }); @@ -27,11 +27,11 @@ expect($('.btn-play')).toExist(); }); - it('can start playing the video on click', function () { + it('can start playing the video on click', function (done) { $('.btn-play').click(); - waitsFor(function () { + jasmine.waitUntil(function() { return state.el.hasClass('is-playing'); - }, 'Player is not playing.', WAIT_TIMEOUT); + }).done(done); }); it('destroy itself on "play" event', function () { diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js index 491e98fae7..32cf02ba74 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js @@ -5,7 +5,7 @@ beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') - .andReturn(null); + .and.returnValue(null); }); afterEach(function () { @@ -18,26 +18,25 @@ describe('constructor', function () { describe('on a non-touch based device', function () { beforeEach(function () { - spyOn($.fn, 'slider').andCallThrough(); + spyOn($.fn, 'slider').and.callThrough(); state = jasmine.initializePlayer(); }); it('build the slider', function () { - expect(state.videoProgressSlider.slider).toBe('.slider'); + expect($('.slider')).toContain(state.videoProgressSlider.slider); expect($.fn.slider).toHaveBeenCalledWith({ range: 'min', min: 0, max: null, - change: state.videoProgressSlider.onChange, slide: state.videoProgressSlider.onSlide, stop: state.videoProgressSlider.onStop }); }); it('build the seek handle', function () { - expect(state.videoProgressSlider.handle) - .toBe('.slider .ui-slider-handle'); + expect($('.ui-slider-handle')) + .toContain(state.videoProgressSlider.handle); }); it('add ARIA attributes to time control', function () { @@ -56,7 +55,7 @@ describe('on a touch-based device', function () { it('does not build the slider on iPhone', function () { - window.onTouchBasedDevice.andReturn(['iPhone']); + window.onTouchBasedDevice.and.returnValue(['iPhone']); state = jasmine.initializePlayer(); @@ -67,7 +66,7 @@ }); $.each(['iPad', 'Android'], function (index, device) { it('build the slider on ' + device, function () { - window.onTouchBasedDevice.andReturn([device]); + window.onTouchBasedDevice.and.returnValue([device]); state = jasmine.initializePlayer(); @@ -87,12 +86,12 @@ beforeEach(function () { spy = spyOn(state.videoProgressSlider, 'buildSlider'); - spy.andCallThrough(); + spy.and.callThrough(); state.videoPlayer.play(); }); it('does not build the slider', function () { - expect(spy.callCount).toEqual(0); + expect(spy.calls.count()).toEqual(0); }); }); @@ -106,7 +105,7 @@ describe('when frozen', function () { beforeEach(function () { - spyOn($.fn, 'slider').andCallThrough(); + spyOn($.fn, 'slider').and.callThrough(); state.videoProgressSlider.frozen = true; state.videoProgressSlider.updatePlayTime(20, 120); }); @@ -118,7 +117,7 @@ describe('when not frozen', function () { beforeEach(function () { - spyOn($.fn, 'slider').andCallThrough(); + spyOn($.fn, 'slider').and.callThrough(); state.videoProgressSlider.frozen = false; state.videoProgressSlider.updatePlayTime({ time: 20, @@ -149,8 +148,8 @@ beforeEach(function () { state = jasmine.initializePlayer(); - spyOn($.fn, 'slider').andCallThrough(); - spyOn(state.videoPlayer, 'onSlideSeek').andCallThrough(); + spyOn($.fn, 'slider').and.callThrough(); + spyOn(state.videoPlayer, 'onSlideSeek').and.callThrough(); }); // Disabled 12/30/13 due to flakiness in master @@ -175,11 +174,15 @@ describe('onStop', function () { beforeEach(function () { - jasmine.Clock.useMock(); + jasmine.clock().install(); state = jasmine.initializePlayer(); - spyOn(state.videoPlayer, 'onSlideSeek').andCallThrough(); + spyOn(state.videoPlayer, 'onSlideSeek').and.callThrough(); + }); + + afterEach(function () { + jasmine.clock().uninstall(); }); // Disabled 12/30/13 due to flakiness in master @@ -206,7 +209,7 @@ jQuery.Event('stop'), { value: 20 } ); - jasmine.Clock.tick(200); + jasmine.clock().tick(200); expect(state.videoProgressSlider.frozen).toBeFalsy(); }); @@ -255,7 +258,7 @@ spyOnEvent(state.videoProgressSlider.handle, 'focus'); spyOn(state.videoProgressSlider, 'notifyThroughHandleEnd') - .andCallThrough(); + .and.callThrough(); }); it('params.end = true', function () { @@ -280,17 +283,14 @@ ); }); - it('is called when video plays', function () { + it('is called when video plays', function (done) { state.videoPlayer.play(); - - waitsFor(function () { + jasmine.waitUntil(function() { return state.videoPlayer.isPlaying(); - }, 'duration is set, video is playing', 5000); + }).done(function() { + expect(state.videoProgressSlider.notifyThroughHandleEnd).toHaveBeenCalledWith({end: false}); + }).always(done); - runs(function () { - expect(state.videoProgressSlider.notifyThroughHandleEnd) - .toHaveBeenCalledWith({end: false}); - }); }); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js index 5ce7375aee..251c59e8fa 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js @@ -19,7 +19,7 @@ // Define empty methods in YouTube stub player.quality = 'large'; - player.setPlaybackQuality.andCallFake(function (quality){ + player.setPlaybackQuality.and.callFake(function (quality){ player.quality = quality; }); }); @@ -46,13 +46,13 @@ }); it('calls fetchAvailableQualities only once', function () { - expect(player.getAvailableQualityLevels.calls.length) + expect(player.getAvailableQualityLevels.calls.count()) .toEqual(0); videoPlayer.onPlay(); videoPlayer.onPlay(); - expect(player.getAvailableQualityLevels.calls.length) + expect(player.getAvailableQualityLevels.calls.count()) .toEqual(1); }); @@ -71,7 +71,7 @@ it('leaves quality control hidden on play if HD is not available', function () { - player.getAvailableQualityLevels.andReturn( + player.getAvailableQualityLevels.and.returnValue( ['large', 'medium', 'small'] ); @@ -94,7 +94,7 @@ it('quality control is active if HD is available', function () { - player.getAvailableQualityLevels.andReturn( + player.getAvailableQualityLevels.and.returnValue( ['highres', 'hd1080', 'hd720'] ); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_save_state_plugin_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_save_state_plugin_spec.js index 7c101cdb32..85d174b215 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_save_state_plugin_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_save_state_plugin_spec.js @@ -7,14 +7,14 @@ oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice') - .andReturn(null); + .and.returnValue(null); - jasmine.stubRequests(); state = jasmine.initializePlayer(); spyOn(state.storage, 'setItem'); }); afterEach(function () { + $('source').remove(); window.onTouchBasedDevice = oldOTBD; state.storage.clear(); @@ -41,7 +41,7 @@ beforeEach(function () { state.videoPlayer.currentTime = videoPlayerCurrentTime; - spyOn(Time, 'formatFull').andCallThrough(); + spyOn(window.Time, 'formatFull').and.callThrough(); }); it('data is not an object, async is true', function () { @@ -172,7 +172,7 @@ }); it('can save state on page unload', function () { - $.ajax.reset(); + $.ajax.calls.reset(); state.videoSaveStatePlugin.onUnload(); expect($.ajax).toHaveBeenCalledWith({ url: state.config.saveStateUrl, @@ -212,7 +212,7 @@ it('can destroy itself', function () { var plugin = state.videoSaveStatePlugin; - spyOn($.fn, 'off').andCallThrough(); + spyOn($.fn, 'off').and.callThrough(); state.videoSaveStatePlugin.destroy(); expect(state.videoSaveStatePlugin).toBeUndefined(); expect($.fn.off).toHaveBeenCalledWith({ diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_skip_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_skip_control_spec.js index 1eca712477..2438dce8a2 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_skip_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_skip_control_spec.js @@ -6,10 +6,10 @@ beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine - .createSpy('onTouchBasedDevice').andReturn(null); + .createSpy('onTouchBasedDevice').and.returnValue(null); state = jasmine.initializePlayer('video_with_bumper.html'); $('.poster .btn-play').click(); - spyOn(state.bumperState.videoCommands, 'execute').andCallThrough(); + spyOn(state.bumperState.videoCommands, 'execute').and.callThrough(); }); afterEach(function () { diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js index 2ea4a7e365..2a8b5e8b67 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js @@ -6,7 +6,7 @@ beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') - .andReturn(null); + .and.returnValue(null); }); afterEach(function () { @@ -26,8 +26,8 @@ var secondaryControls = $('.secondary-controls'), li = secondaryControls.find('.video-speeds li'); - expect(secondaryControls).toContain('.speeds'); - expect(secondaryControls).toContain('.video-speeds'); + expect(secondaryControls).toContainElement('.speeds'); + expect(secondaryControls).toContainElement('.video-speeds'); expect(secondaryControls.find('.value').text()) .toBe('1.50x'); expect(li.filter('.is-active')).toHaveData( @@ -36,9 +36,7 @@ expect(li.length).toBe(state.speeds.length); $.each(li.toArray().reverse(), function (index, link) { - expect($(link)).toHaveData( - 'speed', state.speeds[index] - ); + expect($(link).attr('data-speed')).toEqual(state.speeds[index]); expect($(link).find('.speed-option').text()).toBe( state.speeds[index] + 'x' ); @@ -49,7 +47,7 @@ describe('when running on touch based device', function () { $.each(['iPad', 'Android'], function (index, device) { it('is not rendered on' + device, function () { - window.onTouchBasedDevice.andReturn([device]); + window.onTouchBasedDevice.and.returnValue([device]); state = jasmine.initializePlayer(); expect(state.el.find('.speeds')).not.toExist(); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_storage_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_storage_spec.js index 4a65e83c6f..8cbe133dbb 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_storage_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_storage_spec.js @@ -19,7 +19,7 @@ function (VideoStorage) { }); it('without namespace and id', function () { - spyOn(Number.prototype, 'toString').andReturn('0.abcdedg'); + spyOn(Number.prototype, 'toString').and.returnValue('0.abcdedg'); var storage = VideoStorage(); expect(window.VideoStorage).toBeDefined(); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js index 5c3f782e85..21037c2d9c 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js @@ -12,7 +12,7 @@ describe('VideoVolumeControl', function () { beforeEach(function () { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') - .andReturn(null); + .and.returnValue(null); }); afterEach(function () { @@ -23,7 +23,7 @@ describe('VideoVolumeControl', function () { }); it('Volume level has correct value even if cookie is broken', function () { - $.cookie.andReturn('broken_cookie'); + $.cookie.and.returnValue('broken_cookie'); state = jasmine.initializePlayer(); volumeControl = state.videoVolumeControl; expect(volumeControl.volume).toEqual(100); @@ -31,8 +31,8 @@ describe('VideoVolumeControl', function () { describe('constructor', function () { beforeEach(function () { - spyOn($.fn, 'slider').andCallThrough(); - $.cookie.andReturn('75'); + spyOn($.fn, 'slider').and.callThrough(); + $.cookie.and.returnValue('75'); state = jasmine.initializePlayer(); volumeControl = state.videoVolumeControl; }); @@ -46,7 +46,7 @@ describe('VideoVolumeControl', function () { }); it('create the slider', function () { - expect($.fn.slider.calls[2].args).toEqual([{ + expect($.fn.slider.calls.argsFor(2)).toEqual([{ orientation: 'vertical', range: 'min', min: 0, @@ -94,16 +94,23 @@ describe('VideoVolumeControl', function () { state = jasmine.initializePlayer(); volumeControl = state.videoVolumeControl; - this.addMatchers({ - assertLiveRegionState: function (volume, expectation) { - var region = $('.video-live-region'); + jasmine.addMatchers({ + assertLiveRegionState: function () { + return { + compare: function (actual, volume, expectation) { + var region = $('.video-live-region'); - var getExpectedText = function (text) { - return text + ' Volume.'; + var getExpectedText = function (text) { + return text + ' Volume.'; + }; + + actual.setVolume(volume, true, true); + return { + pass: region.text() === getExpectedText(expectation) + }; + + } }; - - this.actual.setVolume(volume, true, true); - return region.text() === getExpectedText(expectation); } }); }); diff --git a/common/lib/xmodule/xmodule/js/spec/xmodule_spec.js b/common/lib/xmodule/xmodule/js/spec/xmodule_spec.js index 0ae76b7215..35f21c401f 100644 --- a/common/lib/xmodule/xmodule/js/spec/xmodule_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/xmodule_spec.js @@ -36,7 +36,7 @@ window.Video = jasmine.createSpy('Video'); removeVideo = true; } - window.Video.andReturn(videoModule); + window.Video.and.returnValue(videoModule); editCallback = jasmine.createSpy('editCallback'); $(document).on('XModule.loaded.edit', editCallback); @@ -171,7 +171,7 @@ el = 'dummy object'; obj = new XModule.Descriptor(el); - spyOn(obj, 'save').andCallThrough(); + spyOn(obj, 'save').and.callThrough(); }); afterEach(function () { @@ -225,7 +225,7 @@ obj.onUpdate(callback1); obj.onUpdate(callback2); - obj.save.andReturn(testValue); + obj.save.and.returnValue(testValue); obj.update(); expect(callback1).toHaveBeenCalledWith(testValue); diff --git a/common/static/coffee/spec/discussion/discussion_spec_helper.coffee b/common/static/coffee/spec/discussion/discussion_spec_helper.coffee index 0b052bc7ba..bea233e0b5 100644 --- a/common/static/coffee/spec/discussion/discussion_spec_helper.coffee +++ b/common/static/coffee/spec/discussion/discussion_spec_helper.coffee @@ -13,7 +13,7 @@ class @DiscussionSpecHelper DiscussionUtil.roleIds["Moderator"].push(parseInt(DiscussionUtil.getUser().id)) @makeAjaxSpy = (fakeAjax) -> - spyOn($, "ajax").andCallFake( + spyOn($, "ajax").and.callFake( (params) -> fakeAjax(params) {always: ->} diff --git a/common/static/coffee/spec/discussion/utils_spec.coffee b/common/static/coffee/spec/discussion/utils_spec.coffee index c456855e06..35f4772998 100644 --- a/common/static/coffee/spec/discussion/utils_spec.coffee +++ b/common/static/coffee/spec/discussion/utils_spec.coffee @@ -6,8 +6,8 @@ describe 'DiscussionUtil', -> it "calls through to safeAjax with correct params, and reverts the model in case of failure", -> deferred = $.Deferred() - spyOn($, "ajax").andReturn(deferred) - spyOn(DiscussionUtil, "safeAjax").andCallThrough() + spyOn($, "ajax").and.returnValue(deferred) + spyOn(DiscussionUtil, "safeAjax").and.callThrough() model = new Backbone.Model({hello: false, number: 42}) updates = {hello: "world"} @@ -19,7 +19,7 @@ describe 'DiscussionUtil', -> # the error message callback should be set up correctly spyOn(DiscussionUtil, "discussionAlert") - DiscussionUtil.safeAjax.mostRecentCall.args[0].error() + DiscussionUtil.safeAjax.calls.mostRecent().args[0].error() expect(DiscussionUtil.discussionAlert).toHaveBeenCalledWith("Sorry", "error message") # if the ajax call ends in failure, the model state should be reverted @@ -27,7 +27,7 @@ describe 'DiscussionUtil', -> expect(model.attributes).toEqual({hello: false, number: 42}) it "rolls back the changes if the associated element is disabled", -> - spyOn(DiscussionUtil, "safeAjax").andCallThrough() + spyOn(DiscussionUtil, "safeAjax").and.callThrough() model = new Backbone.Model({hello: false, number: 42}) updates = {hello: "world"} @@ -35,7 +35,7 @@ describe 'DiscussionUtil', -> # This is the element that is disabled/enabled while the ajax request is # in progress $elem = jasmine.createSpyObj('$elem', ['attr']) - $elem.attr.andReturn(true) + $elem.attr.and.returnValue(true) res = DiscussionUtil.updateWithUndo(model, updates, {foo: "bar", $elem:$elem}, "error message") diff --git a/common/static/coffee/spec/discussion/view/discussion_thread_edit_view_spec.js b/common/static/coffee/spec/discussion/view/discussion_thread_edit_view_spec.js index 76487445bd..b319874b1e 100644 --- a/common/static/coffee/spec/discussion/view/discussion_thread_edit_view_spec.js +++ b/common/static/coffee/spec/discussion/view/discussion_thread_edit_view_spec.js @@ -27,7 +27,7 @@ }); testUpdate = function(view, thread, newTopicId, newTopicName) { - spyOn($, 'ajax').andCallFake(function(params) { + spyOn($, 'ajax').and.callFake(function(params) { expect(params.url.path()).toEqual(DiscussionUtil.urlFor('update_thread', 'dummy_id')); expect(params.data.thread_type).toBe('discussion'); expect(params.data.commentable_id).toBe(newTopicId); @@ -35,7 +35,10 @@ params.success(); return {always: function() {}}; }); - view.$el.find('a.topic-title[data-discussion-id="'+newTopicId+'"]').click(); // set new topic + + view.$el.find('a.topic-title').filter(function (idx, el) { + return $(el).data('discussionId') === newTopicId; + }).click(); // set new topic view.$('.edit-post-title').val('changed thread title'); // set new title view.$("label[for$='post-type-discussion']").click(); // set new thread type view.$('.post-update').click(); @@ -62,7 +65,7 @@ testCancel = function(view) { view.$('.post-cancel').click(); expect($('.edit-post-form')).not.toExist(); - } + }; it('can close the view in tab mode', function() { this.createEditView(); @@ -104,11 +107,11 @@ it('can save new data correctly for current discussion id with dots', function () { this.createEditView({topicId: "6.00.1x_General"}); - testUpdate(this.view, this.thread, "6>00'1x\"Basic_Question", "Basic Question"); + testUpdate(this.view, this.thread, "6>00\'1x\"Basic_Question", "Basic Question"); }); it('can save new data correctly for current discussion id with special characters', function () { - this.createEditView({topicId: "6>00'1x\"Basic_Question"}); + this.createEditView({topicId: "6>00\'1x\"Basic_Question"}); testUpdate(this.view, this.thread, "6.00.1x_General", "General"); }); }); diff --git a/common/static/coffee/spec/discussion/view/discussion_thread_list_view_spec.coffee b/common/static/coffee/spec/discussion/view/discussion_thread_list_view_spec.coffee index e27436bc01..740bc7ec2b 100644 --- a/common/static/coffee/spec/discussion/view/discussion_thread_list_view_spec.coffee +++ b/common/static/coffee/spec/discussion/view/discussion_thread_list_view_spec.coffee @@ -131,8 +131,8 @@ describe "DiscussionThreadListView", -> created_at: '2013-04-03T20:05:39Z', }), ] - - spyOn($, "ajax") + deferred = $.Deferred() + spyOn($, "ajax").and.returnValue(deferred); @discussion = new Discussion([]) @view = new DiscussionThreadListView( @@ -143,7 +143,7 @@ describe "DiscussionThreadListView", -> @view.render() setupAjax = (callback) -> - $.ajax.andCallFake( + $.ajax.and.callFake( (params) => if callback callback(params) @@ -162,7 +162,7 @@ describe "DiscussionThreadListView", -> ) expectFilter = (filterVal) -> - $.ajax.andCallFake((params) -> + $.ajax.and.callFake((params) -> _.each(["unread", "unanswered", "flagged"], (paramName)-> if paramName == filterVal expect(params.data[paramName]).toEqual(true) @@ -199,7 +199,7 @@ describe "DiscussionThreadListView", -> expectedGroupId = optionInfo.expectedGroupId @view.$(".forum-nav-filter-cohort-control").val(optionInfo.val).change() expect($.ajax).toHaveBeenCalled() - $.ajax.reset() + $.ajax.calls.reset() ) it "search should clear filter", -> @@ -255,7 +255,7 @@ describe "DiscussionThreadListView", -> sorted_threads = [threads[0], threads[3], threads[2], threads[1]] else if new_type == 'votes' sorted_threads = [threads[3], threads[0], threads[1], threads[2]] - $.ajax.andCallFake((params) => + $.ajax.and.callFake((params) => params.success( {"discussion_data":sorted_threads, page:1, num_pages:1} ) @@ -307,7 +307,7 @@ describe "DiscussionThreadListView", -> testCorrection = (view, correctedText) -> spyOn(view, "addSearchAlert") - $.ajax.andCallFake( + $.ajax.and.callFake( (params) => params.success( {discussion_data: [], page: 42, num_pages: 99, corrected_text: correctedText}, 'success' @@ -319,13 +319,13 @@ describe "DiscussionThreadListView", -> it "adds a search alert when an alternate term was searched", -> testCorrection(@view, "foo") - expect(@view.addSearchAlert.callCount).toEqual(1) - expect(@view.addSearchAlert.mostRecentCall.args[0]).toMatch(/foo/) + expect(@view.addSearchAlert.calls.count()).toEqual(1) + expect(@view.addSearchAlert.calls.mostRecent().args[0]).toMatch(/foo/) it "does not add a search alert when no alternate term was searched", -> testCorrection(@view, null) - expect(@view.addSearchAlert.callCount).toEqual(1) - expect(@view.addSearchAlert.mostRecentCall.args[0]).toMatch(/no threads matched/i) + expect(@view.addSearchAlert.calls.count()).toEqual(1) + expect(@view.addSearchAlert.calls.mostRecent().args[0]).toMatch(/no threads matched/i) it "clears search alerts when a new search is performed", -> spyOn(@view, "clearSearchAlerts") @@ -356,7 +356,7 @@ describe "DiscussionThreadListView", -> describe "username search", -> it "makes correct ajax calls", -> - $.ajax.andCallFake( + $.ajax.and.callFake( (params) => expect(params.data.username).toEqual("testing-username") expect(params.url.path()).toEqual(DiscussionUtil.urlFor("users")) @@ -371,7 +371,7 @@ describe "DiscussionThreadListView", -> setAjaxResults = (threadSuccess, userResult) -> # threadSuccess is a boolean indicating whether the thread search ajax call should succeed # userResult is the value that should be returned as data from the username search ajax call - $.ajax.andCallFake( + $.ajax.and.callFake( (params) => if params.data.text and threadSuccess params.success( @@ -387,14 +387,14 @@ describe "DiscussionThreadListView", -> ) it "gets called after a thread search succeeds", -> - spyOn(@view, "searchForUser").andCallThrough() + spyOn(@view, "searchForUser").and.callThrough() setAjaxResults(true, []) @view.searchFor("gizmo") expect(@view.searchForUser).toHaveBeenCalled() - expect($.ajax.mostRecentCall.args[0].data.username).toEqual("gizmo") + expect($.ajax.calls.mostRecent().args[0].data.username).toEqual("gizmo") it "does not get called after a thread search fails", -> - spyOn(@view, "searchForUser").andCallThrough() + spyOn(@view, "searchForUser").and.callThrough() setAjaxResults(false, []) @view.searchFor("gizmo") expect(@view.searchForUser).not.toHaveBeenCalled() @@ -405,7 +405,7 @@ describe "DiscussionThreadListView", -> @view.searchForUser("dummy") expect($.ajax).toHaveBeenCalled() expect(@view.addSearchAlert).toHaveBeenCalled() - expect(@view.addSearchAlert.mostRecentCall.args[0]).toMatch(/gizmo/) + expect(@view.addSearchAlert.calls.mostRecent().args[0]).toMatch(/gizmo/) it "does not add a search alert when no username was matched", -> spyOn(@view, "addSearchAlert") @@ -581,7 +581,7 @@ describe "DiscussionThreadListView", -> , "Following" ) - expect($.ajax.mostRecentCall.args[0].data.group_id).toBeUndefined(); + expect($.ajax.calls.mostRecent().args[0].data.group_id).toBeUndefined(); it "should get threads for the selected leaf", -> testSelectionRequest( diff --git a/common/static/coffee/spec/discussion/view/discussion_thread_profile_view_spec.coffee b/common/static/coffee/spec/discussion/view/discussion_thread_profile_view_spec.coffee index eddd792e23..48572f67ae 100644 --- a/common/static/coffee/spec/discussion/view/discussion_thread_profile_view_spec.coffee +++ b/common/static/coffee/spec/discussion/view/discussion_thread_profile_view_spec.coffee @@ -27,7 +27,7 @@ describe "DiscussionThreadProfileView", -> return thread spyConvertMath = (view) -> - spyOn(view, "convertMath").andCallFake( -> + spyOn(view, "convertMath").and.callFake( -> @model.set('markdownBody', @model.get('body')) ) diff --git a/common/static/coffee/spec/discussion/view/discussion_thread_show_view_spec.coffee b/common/static/coffee/spec/discussion/view/discussion_thread_show_view_spec.coffee index 14d75321d5..34036d847b 100644 --- a/common/static/coffee/spec/discussion/view/discussion_thread_show_view_spec.coffee +++ b/common/static/coffee/spec/discussion/view/discussion_thread_show_view_spec.coffee @@ -22,7 +22,7 @@ describe "DiscussionThreadShowView", -> @thread = new Thread(@threadData) @view = new DiscussionThreadShowView({ model: @thread }) @view.setElement($("#fixture-element")) - @spyOn(@view, "convertMath") + spyOn(@view, "convertMath") describe "voting", -> diff --git a/common/static/coffee/spec/discussion/view/discussion_thread_view_spec.coffee b/common/static/coffee/spec/discussion/view/discussion_thread_view_spec.coffee index 813f10c674..510f896a9a 100644 --- a/common/static/coffee/spec/discussion/view/discussion_thread_view_spec.coffee +++ b/common/static/coffee/spec/discussion/view/discussion_thread_view_spec.coffee @@ -3,11 +3,12 @@ describe "DiscussionThreadView", -> DiscussionSpecHelper.setUpGlobals() DiscussionSpecHelper.setUnderscoreFixtures() - jasmine.Clock.useMock() + jasmine.clock().install() @threadData = DiscussionViewSpecHelper.makeThreadWithProps({}) @thread = new Thread(@threadData) @discussion = new Discussion(@thread) - spyOn($, "ajax") + deferred = $.Deferred(); + spyOn($, "ajax").and.returnValue(deferred); # Avoid unnecessary boilerplate spyOn(DiscussionThreadShowView.prototype, "convertMath") spyOn(DiscussionContentView.prototype, "makeWmdEditor") @@ -15,8 +16,12 @@ describe "DiscussionThreadView", -> spyOn(DiscussionUtil, "setWmdContent") spyOn(ThreadResponseShowView.prototype, "convertMath") + afterEach -> + $.ajax.calls.reset() + jasmine.clock().uninstall() + renderWithContent = (view, content) -> - $.ajax.andCallFake((params) => + $.ajax.and.callFake((params) => params.success( createAjaxResponseJson(content, false), 'success' @@ -24,7 +29,7 @@ describe "DiscussionThreadView", -> {always: ->} ) view.render() - jasmine.Clock.tick(100) + jasmine.clock().tick(100) renderWithTestResponses = (view, count, options) -> renderWithContent( @@ -85,8 +90,8 @@ describe "DiscussionThreadView", -> postResponse = (view, index) -> testResponseJson = createTestResponseJson(index) responseText = testResponseJson.body - spyOn(view, "getWmdContent").andReturn(responseText) - $.ajax.andCallFake((params) => + spyOn(view, "getWmdContent").and.returnValue(responseText) + $.ajax.and.callFake((params) => expect(params.type).toEqual("POST") expect(params.data.body).toEqual(responseText) params.success( @@ -112,7 +117,7 @@ describe "DiscussionThreadView", -> renderWithTestResponses(view, 1) if mode == "inline" view.expand() - spyOn(DiscussionUtil, "updateWithUndo").andCallFake( + spyOn(DiscussionUtil, "updateWithUndo").and.callFake( (model, updates, safeAjaxParams, errorMsg) -> model.set(updates) ) @@ -240,16 +245,18 @@ describe "DiscussionThreadView", -> expect(@view.$el.find(".responses li").length).toEqual(0) describe "focus", -> - it "sends focus to the conversation when opened", -> + it "sends focus to the conversation when opened", (done) -> DiscussionViewSpecHelper.setNextResponseContent({resp_total: 0, children: []}) @view.render() @view.expand() - waitsFor (-> + self = @ + jasmine.waitUntil(-> # This is the implementation of "toBeFocused". However, simply calling that method # with no wait seems to be flaky. - article = @view.$el.find('.discussion-article') + article = self.view.$el.find('.discussion-article') return article[0] == article[0].ownerDocument.activeElement - ), "conversation did not receive focus", 3000 + ).then -> + done() describe "expand/collapse", -> it "shows/hides appropriate content", -> @@ -269,12 +276,12 @@ describe "DiscussionThreadView", -> @view.render() expect($(".post-body").text()).toEqual(expectedAbbreviation) expect(DiscussionThreadShowView.prototype.convertMath).toHaveBeenCalled() - DiscussionThreadShowView.prototype.convertMath.reset() + DiscussionThreadShowView.prototype.convertMath.calls.reset() @view.expand() expect($(".post-body").text()).toEqual(longBody) expect(DiscussionThreadShowView.prototype.convertMath).toHaveBeenCalled() - DiscussionThreadShowView.prototype.convertMath.reset() + DiscussionThreadShowView.prototype.convertMath.calls.reset() @view.collapse() expect($(".post-body").text()).toEqual(expectedAbbreviation) diff --git a/common/static/coffee/spec/discussion/view/discussion_user_profile_view_spec.coffee b/common/static/coffee/spec/discussion/view/discussion_user_profile_view_spec.coffee index 989893d64e..98d47d7205 100644 --- a/common/static/coffee/spec/discussion/view/discussion_user_profile_view_spec.coffee +++ b/common/static/coffee/spec/discussion/view/discussion_user_profile_view_spec.coffee @@ -193,10 +193,11 @@ describe "DiscussionUserProfileView", -> describe "pagination interaction", -> beforeEach -> @view = makeView(makeThreads(3), 1, 2) - spyOn($, "ajax") + deferred = $.Deferred(); + spyOn($, "ajax").and.returnValue(deferred); it "causes updated rendering", -> - $.ajax.andCallFake( + $.ajax.and.callFake( (params) => params.success( discussion_data: [{id: "on_page_42", body: "dummy body"}] @@ -211,7 +212,7 @@ describe "DiscussionUserProfileView", -> it "handles AJAX errors", -> spyOn(DiscussionUtil, "discussionAlert") - $.ajax.andCallFake( + $.ajax.and.callFake( (params) => params.error() {always: ->} diff --git a/common/static/coffee/spec/discussion/view/discussion_view_spec_helper.coffee b/common/static/coffee/spec/discussion/view/discussion_view_spec_helper.coffee index a263903bcc..d3150d7dfd 100644 --- a/common/static/coffee/spec/discussion/view/discussion_view_spec_helper.coffee +++ b/common/static/coffee/spec/discussion/view/discussion_view_spec_helper.coffee @@ -50,7 +50,7 @@ class @DiscussionViewSpecHelper triggerVoteEvent = (view, event, expectedUrl) -> deferred = $.Deferred() - spyOn($, "ajax").andCallFake((params) => + spyOn($, "ajax").and.callFake((params) => expect(params.url.toString()).toEqual(expectedUrl) return deferred ) @@ -80,10 +80,10 @@ class @DiscussionViewSpecHelper button.click() expect(spy).toHaveBeenCalled() - spy.reset() + spy.calls.reset() button.trigger($.Event("keydown", {which: 13})) expect(spy).not.toHaveBeenCalled() - spy.reset() + spy.calls.reset() button.trigger($.Event("keydown", {which: 32})) expect(spy).toHaveBeenCalled() @@ -91,7 +91,7 @@ class @DiscussionViewSpecHelper @checkButtonEvents(view, "toggleVote", ".action-vote") @setNextResponseContent = (content) -> - $.ajax.andCallFake( + $.ajax.and.callFake( (params) => params.success({"content": content}) {always: ->} diff --git a/common/static/coffee/spec/discussion/view/new_post_view_spec.coffee b/common/static/coffee/spec/discussion/view/new_post_view_spec.coffee index 6458c3cb3d..fb9f244897 100644 --- a/common/static/coffee/spec/discussion/view/new_post_view_spec.coffee +++ b/common/static/coffee/spec/discussion/view/new_post_view_spec.coffee @@ -4,7 +4,7 @@ describe "NewPostView", -> DiscussionSpecHelper.setUpGlobals() DiscussionSpecHelper.setUnderscoreFixtures() window.$$course_id = "edX/999/test" - spyOn(DiscussionUtil, "makeWmdEditor").andCallFake( + spyOn(DiscussionUtil, "makeWmdEditor").and.callFake( ($content, $local, cls_identifier) -> $local("." + cls_identifier).html("") ) @@ -91,7 +91,7 @@ describe "NewPostView", -> @view.$(".js-post-body textarea").val("dummy body") @view.$(".forum-new-post-form").submit() expect($.ajax).toHaveBeenCalled() - $.ajax.reset() + $.ajax.calls.reset() ) describe "always cohort inline discussions ", -> @@ -209,7 +209,7 @@ describe "NewPostView", -> it "posts to the correct URL", -> topicId = "test_topic" - spyOn($, "ajax").andCallFake( + spyOn($, "ajax").and.callFake( (params) -> expect(params.url.path()).toEqual(DiscussionUtil.urlFor("create_thread", topicId)) {always: ->} diff --git a/common/static/coffee/spec/discussion/view/response_comment_view_spec.coffee b/common/static/coffee/spec/discussion/view/response_comment_view_spec.coffee index 9f641a8b16..c25269ff4e 100644 --- a/common/static/coffee/spec/discussion/view/response_comment_view_spec.coffee +++ b/common/static/coffee/spec/discussion/view/response_comment_view_spec.coffee @@ -25,14 +25,14 @@ describe 'ResponseCommentView', -> spyOn(@view.$el, "remove") setAjaxResult = (isSuccess) -> - spyOn($, "ajax").andCallFake( + spyOn($, "ajax").and.callFake( (params) => (if isSuccess then params.success else params.error) {} {always: ->} ) it 'requires confirmation before deleting', -> - spyOn(window, "confirm").andReturn(false) + spyOn(window, "confirm").and.returnValue(false) setAjaxResult(true) @view._delete(@event) expect(window.confirm).toHaveBeenCalled() @@ -50,7 +50,7 @@ describe 'ResponseCommentView', -> @view._delete(@event) expect(@event.preventDefault).toHaveBeenCalled() expect($.ajax).toHaveBeenCalled() - expect($.ajax.mostRecentCall.args[0].url._parts.path).toEqual('/courses/edX/999/test/discussion/comments/01234567/delete') + expect($.ajax.calls.mostRecent().args[0].url._parts.path).toEqual('/courses/edX/999/test/discussion/comments/01234567/delete') it 'handles ajax errors', -> spyOn(DiscussionUtil, "discussionAlert") @@ -125,7 +125,7 @@ describe 'ResponseCommentView', -> @view.$el.find(".edit-comment-body").html($("")) @view.$el.find(".edit-comment-body textarea").val(@updatedBody) spyOn(@view, 'cancelEdit') - spyOn($, "ajax").andCallFake( + spyOn($, "ajax").and.callFake( (params) => if @ajaxSucceed params.success() @@ -138,8 +138,8 @@ describe 'ResponseCommentView', -> @ajaxSucceed = true @view.update(DiscussionSpecHelper.makeEventSpy()) expect($.ajax).toHaveBeenCalled() - expect($.ajax.mostRecentCall.args[0].url._parts.path).toEqual('/courses/edX/999/test/discussion/comments/01234567/update') - expect($.ajax.mostRecentCall.args[0].data.body).toEqual(@updatedBody) + expect($.ajax.calls.mostRecent().args[0].url._parts.path).toEqual('/courses/edX/999/test/discussion/comments/01234567/update') + expect($.ajax.calls.mostRecent().args[0].data.body).toEqual(@updatedBody) expect(@view.model.get("body")).toEqual(@updatedBody) expect(@view.cancelEdit).toHaveBeenCalled() @@ -148,8 +148,8 @@ describe 'ResponseCommentView', -> @ajaxSucceed = false @view.update(DiscussionSpecHelper.makeEventSpy()) expect($.ajax).toHaveBeenCalled() - expect($.ajax.mostRecentCall.args[0].url._parts.path).toEqual('/courses/edX/999/test/discussion/comments/01234567/update') - expect($.ajax.mostRecentCall.args[0].data.body).toEqual(@updatedBody) + expect($.ajax.calls.mostRecent().args[0].url._parts.path).toEqual('/courses/edX/999/test/discussion/comments/01234567/update') + expect($.ajax.calls.mostRecent().args[0].data.body).toEqual(@updatedBody) expect(@view.model.get("body")).toEqual(originalBody) expect(@view.cancelEdit).not.toHaveBeenCalled() expect(@view.$(".edit-comment-form-errors *").length).toEqual(1) diff --git a/common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee b/common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee index d03b42d83a..bdedff4789 100644 --- a/common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee +++ b/common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee @@ -108,6 +108,7 @@ describe "ThreadResponseShowView", -> expect(@view.$(".posted-details").text()).not.toMatch("\sby\s") it "re-renders correctly when endorsement changes", -> + spyOn($, "ajax").and.returnValue($.Deferred()) DiscussionUtil.loadRoles({"Moderator": [parseInt(window.user.id)]}) @thread.set("thread_type", "question") @view.render() @@ -118,6 +119,7 @@ describe "ThreadResponseShowView", -> expect(@view.$(".posted-details").text()).not.toMatch("marked as answer") it "allows a moderator to mark an answer in a question thread", -> + spyOn($, "ajax").and.returnValue($.Deferred()) DiscussionUtil.loadRoles({"Moderator": [parseInt(window.user.id)]}) @thread.set({ "thread_type": "question", @@ -131,6 +133,7 @@ describe "ThreadResponseShowView", -> expect(endorseButton).toHaveClass("is-checked") it "allows the author of a question thread to mark an answer", -> + spyOn($, "ajax").and.returnValue($.Deferred()) @thread.set({ "thread_type": "question", "user_id": window.user.id @@ -199,7 +202,7 @@ describe "ThreadResponseShowView", -> "username": "test_endorser", "time": new Date().toISOString() }) - spyOn(DiscussionUtil, 'urlFor').andReturn('test_endorser_url') + spyOn(DiscussionUtil, 'urlFor').and.returnValue('test_endorser_url') checkUserLink = (element, is_ta, is_staff) -> expect(element.find('a.username').length).toEqual(1) @@ -217,11 +220,11 @@ describe "ThreadResponseShowView", -> checkUserLink($el, false, false) it "renders correctly for a community TA-endorsed response", -> - spyOn(DiscussionUtil, 'isTA').andReturn(true) + spyOn(DiscussionUtil, 'isTA').and.returnValue(true) $el = $('#fixture-element').html(@view.getEndorserDisplay()) checkUserLink($el, true, false) it "renders correctly for a staff-endorsed response", -> - spyOn(DiscussionUtil, 'isStaff').andReturn(true) + spyOn(DiscussionUtil, 'isStaff').and.returnValue(true) $el = $('#fixture-element').html(@view.getEndorserDisplay()) checkUserLink($el, false, true) diff --git a/common/static/coffee/spec/xblock/core_spec.coffee b/common/static/coffee/spec/xblock/core_spec.coffee index 7e7c1e081a..e04184710a 100644 --- a/common/static/coffee/spec/xblock/core_spec.coffee +++ b/common/static/coffee/spec/xblock/core_spec.coffee @@ -28,14 +28,14 @@ describe "XBlock", -> window.TestRuntime = {} @runtimeA = {name: 'runtimeA'} @runtimeZ = {name: 'runtimeZ'} - TestRuntime.vA = jasmine.createSpy().andReturn(@runtimeA) - TestRuntime.vZ = jasmine.createSpy().andReturn(@runtimeZ) + TestRuntime.vA = jasmine.createSpy().and.returnValue(@runtimeA) + TestRuntime.vZ = jasmine.createSpy().and.returnValue(@runtimeZ) window.initFnA = jasmine.createSpy() window.initFnZ = jasmine.createSpy() @fakeChildren = ['list', 'of', 'children'] - spyOn(XBlock, 'initializeXBlocks').andReturn(@fakeChildren) + spyOn(XBlock, 'initializeXBlocks').and.returnValue(@fakeChildren) @vANode = $('#vA')[0] @vZNode = $('#vZ')[0] @@ -54,11 +54,11 @@ describe "XBlock", -> expect(window.initFnZ).toHaveBeenCalledWith(@runtimeZ, @vZNode, {}) it "loads when missing versions", -> - expect(@missingVersionBlock.element).toBe($('#missing-version')) + expect(@missingVersionBlock.element).toBe($('#missing-version')[0]) expect(@missingVersionBlock.name).toBe('no-version') it "loads when missing init fn", -> - expect(@missingInitBlock.element).toBe($('#missing-init')) + expect(@missingInitBlock.element).toBe($('#missing-init')[0]) expect(@missingInitBlock.name).toBe('no-init') it "adds names to blocks", -> diff --git a/common/static/common/js/spec/components/feedback_spec.js b/common/static/common/js/spec/components/feedback_spec.js index 9ed52894ce..d9703a9979 100644 --- a/common/static/common/js/spec/components/feedback_spec.js +++ b/common/static/common/js/spec/components/feedback_spec.js @@ -1,10 +1,17 @@ // Generated by CoffeeScript 1.6.1 (function() { - - define(["jquery", "common/js/components/views/feedback", "common/js/components/views/feedback_notification", "common/js/components/views/feedback_alert", "common/js/components/views/feedback_prompt", 'common/js/spec_helpers/view_helpers', "sinon", "jquery.simulate"], + 'use strict'; + define(["jquery", "common/js/components/views/feedback", "common/js/components/views/feedback_notification", + "common/js/components/views/feedback_alert", "common/js/components/views/feedback_prompt", + 'common/js/spec_helpers/view_helpers', "sinon", "jquery.simulate", "jasmine-waituntil"], function($, SystemFeedback, NotificationView, AlertView, PromptView, ViewHelpers, sinon) { var tpl; - tpl = readFixtures('system-feedback.underscore'); + tpl = readFixtures('common/templates/components/system-feedback.underscore'); + + var isFocused = function(actual) { + return $(actual)[0] === $(actual)[0].ownerDocument.activeElement; + }; + beforeEach(function() { setFixtures(sandbox({ id: "page-alert" @@ -19,30 +26,24 @@ id: "system-feedback-tpl", type: "text/template" }).text(tpl)); - return this.addMatchers({ + return jasmine.addMatchers({ toBeShown: function() { - return this.actual.hasClass("is-shown") && !this.actual.hasClass("is-hiding"); + return { + compare: function (actual) { + return { + pass: actual.hasClass("is-shown") && !actual.hasClass("is-hiding") + }; + } + }; }, toBeHiding: function() { - return this.actual.hasClass("is-hiding") && !this.actual.hasClass("is-shown"); - }, - toContainText: function(text) { - var trimmedText; - trimmedText = $.trim(this.actual.text()); - if (text && $.isFunction(text.test)) { - return text.test(trimmedText); - } else { - return trimmedText.indexOf(text) !== -1; - } - }, - toHaveBeenPrevented: function() { - var eventName, selector; - eventName = this.actual.eventName; - selector = this.actual.selector; - this.message = function() { - return ["Expected event " + eventName + " to have been prevented on " + selector, "Expected event " + eventName + " not to have been prevented on " + selector]; + return { + compare: function (actual) { + return { + pass: actual.hasClass("is-hiding") && !actual.hasClass("is-shown") + }; + } }; - return jasmine.JQuery.events.wasPrevented(selector, eventName); } }); }); @@ -52,9 +53,9 @@ title: "Portal", message: "Welcome to the Aperture Science Computer-Aided Enrichment Center" }; - this.renderSpy = spyOn(AlertView.Confirmation.prototype, 'render').andCallThrough(); - this.showSpy = spyOn(AlertView.Confirmation.prototype, 'show').andCallThrough(); - this.hideSpy = spyOn(AlertView.Confirmation.prototype, 'hide').andCallThrough(); + this.renderSpy = spyOn(AlertView.Confirmation.prototype, 'render').and.callThrough(); + this.showSpy = spyOn(AlertView.Confirmation.prototype, 'show').and.callThrough(); + this.hideSpy = spyOn(AlertView.Confirmation.prototype, 'hide').and.callThrough(); return this.clock = sinon.useFakeTimers(); }); afterEach(function() { @@ -122,30 +123,35 @@ actions: { primary: { text: "Yes, I'm sure.", - "class": "confirm-button", + "class": "confirm-button" }, secondary: { text: "Cancel", - "class": "cancel-button", + "class": "cancel-button" } } - } - this.inFocusSpy = spyOn(PromptView.Confirmation.prototype, 'inFocus').andCallThrough(); - return this.outFocusSpy = spyOn(PromptView.Confirmation.prototype, 'outFocus').andCallThrough(); + }; + this.inFocusSpy = spyOn(PromptView.Confirmation.prototype, 'inFocus').and.callThrough(); + this.outFocusSpy = spyOn(PromptView.Confirmation.prototype, 'outFocus').and.callThrough(); }); - it("is focused on show", function() { + it("is focused on show", function(done) { var view; view = new PromptView.Confirmation(this.options).show(); expect(this.inFocusSpy).toHaveBeenCalled(); - return ViewHelpers.verifyElementInFocus(view, ".wrapper-prompt") + jasmine.waitUntil(function () { + return isFocused(view.$(".wrapper-prompt")); + }).always(done); }); - it("is not focused on hide", function() { + it("is not focused on hide", function(done) { var view; view = new PromptView.Confirmation(this.options).hide(); expect(this.outFocusSpy).toHaveBeenCalled(); - return ViewHelpers.verifyElementNotInFocus(view, ".wrapper-prompt") + + jasmine.waitUntil(function () { + return !isFocused(view.$(".wrapper-prompt")); + }).always(done); }); - it("traps keyboard focus when moving forward", function() { + it("traps keyboard focus when moving forward", function(done) { var view; view = new PromptView.Confirmation(this.options).show(); expect(this.inFocusSpy).toHaveBeenCalled(); @@ -153,9 +159,12 @@ "keydown", { keyCode: $.simulate.keyCode.TAB } ); - return ViewHelpers.verifyElementInFocus(view, ".action-primary") + + jasmine.waitUntil(function () { + return isFocused(view.$(".action-primary")); + }).always(done); }); - it("traps keyboard focus when moving backward", function() { + it("traps keyboard focus when moving backward", function(done) { var view; view = new PromptView.Confirmation(this.options).show(); expect(this.inFocusSpy).toHaveBeenCalled(); @@ -163,7 +172,9 @@ "keydown", { keyCode: $.simulate.keyCode.TAB, shiftKey: true } ); - return ViewHelpers.verifyElementInFocus(view, ".action-secondary") + jasmine.waitUntil(function () { + return isFocused(view.$(".action-secondary")); + }).always(done); }); return it("changes class on body", function() { var view; @@ -175,14 +186,15 @@ }); }); describe("NotificationView.Mini", function() { + var view; beforeEach(function() { - return this.view = new NotificationView.Mini(); + view = new NotificationView.Mini(); }); it("should have minShown set to 1250 by default", function() { - return expect(this.view.options.minShown).toEqual(1250); + return expect(view.options.minShown).toEqual(1250); }); return it("should have closeIcon set to false by default", function() { - return expect(this.view.options.closeIcon).toBeFalsy(); + return expect(view.options.closeIcon).toBeFalsy(); }); }); xdescribe("SystemFeedback click events", function() { @@ -301,9 +313,9 @@ return describe("NotificationView minShown and maxShown", function() { beforeEach(function() { this.showSpy = spyOn(NotificationView.Confirmation.prototype, 'show'); - this.showSpy.andCallThrough(); + this.showSpy.and.callThrough(); this.hideSpy = spyOn(NotificationView.Confirmation.prototype, 'hide'); - this.hideSpy.andCallThrough(); + this.hideSpy.and.callThrough(); return this.clock = sinon.useFakeTimers(); }); afterEach(function() { diff --git a/common/static/common/js/spec/main_requirejs.js b/common/static/common/js/spec/main_requirejs.js index 13b7349648..ec2930ce8b 100644 --- a/common/static/common/js/spec/main_requirejs.js +++ b/common/static/common/js/spec/main_requirejs.js @@ -36,7 +36,9 @@ 'edxicons': 'edx-pattern-library/js/edx-icons', 'draggabilly': 'js/vendor/draggabilly', 'jasmine-stealth': 'js/libs/jasmine-stealth', - 'jasmine-waituntil': 'js/libs/jasmine-waituntil' + 'jasmine-waituntil': 'js/libs/jasmine-waituntil', + 'jasmine-extensions': 'js/libs/jasmine-extensions', + 'URI': 'js/vendor/URI.min' }, shim: { 'gettext': { @@ -145,6 +147,9 @@ 'jasmine-waituntil': { deps: ['jquery'] }, + 'jasmine-extensions': { + deps: ['jquery'] + }, "sinon": { exports: "sinon" }, diff --git a/common/static/common/js/spec_helpers/ajax_helpers.js b/common/static/common/js/spec_helpers/ajax_helpers.js index 056328e07e..253c94595d 100644 --- a/common/static/common/js/spec_helpers/ajax_helpers.js +++ b/common/static/common/js/spec_helpers/ajax_helpers.js @@ -28,10 +28,12 @@ define(['sinon', 'underscore', 'URI'], function(sinon, _, URI) { * Get a reference to the mocked server, and respond * to all requests with the specified statusCode. */ - fakeServer = function (that, response) { + fakeServer = function (response) { var server = sinon.fakeServer.create(); - that.after(function() { - server.restore(); + afterEach(function() { + if (server) { + server.restore(); + } }); server.respondWith(response); return server; @@ -42,16 +44,19 @@ define(['sinon', 'underscore', 'URI'], function(sinon, _, URI) { * return a reference to the Array. This allows tests * to respond for individual requests. */ - fakeRequests = function (that) { + fakeRequests = function () { var requests = [], - xhr = sinon.useFakeXMLHttpRequest(); + xhr = sinon.useFakeXMLHttpRequest(); + requests.currentIndex = 0; xhr.onCreate = function(request) { requests.push(request); }; - that.after(function() { - xhr.restore(); + afterEach(function() { + if (xhr && xhr.hasOwnProperty('restore')) { + xhr.restore(); + } }); return requests; }; @@ -88,11 +93,12 @@ define(['sinon', 'underscore', 'URI'], function(sinon, _, URI) { }; expectJsonRequest = function(requests, method, url, jsonRequest) { + jsonRequest = jsonRequest || null; var request = currentRequest(requests); expect(request.readyState).toEqual(XML_HTTP_READY_STATES.OPENED); expect(request.url).toEqual(url); expect(request.method).toEqual(method); - expect(JSON.parse(request.requestBody)).toEqual(jsonRequest); + expect(JSON.parse(request.requestBody)).toEqual(jsonRequest === undefined ? null : jsonRequest); }; /** diff --git a/common/static/common/js/spec_helpers/page_helpers.js b/common/static/common/js/spec_helpers/page_helpers.js index 033f0e9b6d..dec87b50c9 100644 --- a/common/static/common/js/spec_helpers/page_helpers.js +++ b/common/static/common/js/spec_helpers/page_helpers.js @@ -32,12 +32,12 @@ define(["backbone"], }; // Stub out the Backbone router so that the browser doesn't actually navigate - spyOn(Backbone.history, '_updateHash').andCallFake(function (location, fragment, replace) { + spyOn(Backbone.history, '_updateHash').and.callFake(function (location, fragment) { history.currentFragment = fragment; }); // Stub out getHash so that Backbone thinks that the browser has navigated - spyOn(Backbone.history, 'getHash').andCallFake(function () { + spyOn(Backbone.history, 'getHash').and.callFake(function () { return history.currentFragment; }); }; diff --git a/common/static/common/js/spec_helpers/view_helpers.js b/common/static/common/js/spec_helpers/view_helpers.js index 93b5827b89..f86d2bc206 100644 --- a/common/static/common/js/spec_helpers/view_helpers.js +++ b/common/static/common/js/spec_helpers/view_helpers.js @@ -10,16 +10,18 @@ define(["jquery", "common/js/components/views/feedback_notification", "common/js verifyFeedbackHidden, createNotificationSpy, verifyNotificationShowing, verifyNotificationHidden, createPromptSpy, confirmPrompt, inlineEdit, verifyInlineEditChange, installMockAnalytics, removeMockAnalytics, verifyPromptShowing, verifyPromptHidden, - clickDeleteItem, patchAndVerifyRequest, submitAndVerifyFormSuccess, submitAndVerifyFormError, - verifyElementInFocus, verifyElementNotInFocus; + clickDeleteItem, patchAndVerifyRequest, submitAndVerifyFormSuccess, submitAndVerifyFormError; installViewTemplates = function() { appendSetFixtures('
'); }; createFeedbackSpy = function(type, intent) { - var feedbackSpy = spyOnConstructor(type, intent, ['show', 'hide']); - feedbackSpy.show.andReturn(feedbackSpy); + var feedbackSpy = jasmine.stealth.spyOnConstructor(type, intent, ['show', 'hide']); + feedbackSpy.show.and.returnValue(feedbackSpy); + if (afterEach) { + afterEach(jasmine.stealth.clearSpies); + } return feedbackSpy; }; @@ -28,7 +30,7 @@ define(["jquery", "common/js/components/views/feedback_notification", "common/js expect(feedbackSpy.constructor).toHaveBeenCalled(); expect(feedbackSpy.show).toHaveBeenCalled(); expect(feedbackSpy.hide).not.toHaveBeenCalled(); - options = feedbackSpy.constructor.mostRecentCall.args[0]; + options = feedbackSpy.constructor.calls.mostRecent().args[0]; expect(options.title).toMatch(text); }; @@ -55,9 +57,9 @@ define(["jquery", "common/js/components/views/feedback_notification", "common/js confirmPrompt = function(promptSpy, pressSecondaryButton) { expect(promptSpy.constructor).toHaveBeenCalled(); if (pressSecondaryButton) { - promptSpy.constructor.mostRecentCall.args[0].actions.secondary.click(promptSpy); + promptSpy.constructor.calls.mostRecent().args[0].actions.secondary.click(promptSpy); } else { - promptSpy.constructor.mostRecentCall.args[0].actions.primary.click(promptSpy); + promptSpy.constructor.calls.mostRecent().args[0].actions.primary.click(promptSpy); } }; @@ -128,22 +130,6 @@ define(["jquery", "common/js/components/views/feedback_notification", "common/js verifyNotificationShowing(notificationSpy, /Saving/); }; - verifyElementInFocus = function(view, selector) { - waitsFor( - function() { return view.$(selector + ':focus').length === 1; }, - "element to have focus: " + selector, - 500 - ); - }; - - verifyElementNotInFocus = function(view, selector) { - waitsFor( - function() { return view.$(selector + ':focus').length === 0; }, - "element to not have focus: " + selector, - 500 - ); - }; - return { 'installViewTemplates': installViewTemplates, 'createNotificationSpy': createNotificationSpy, @@ -160,9 +146,7 @@ define(["jquery", "common/js/components/views/feedback_notification", "common/js 'clickDeleteItem': clickDeleteItem, 'patchAndVerifyRequest': patchAndVerifyRequest, 'submitAndVerifyFormSuccess': submitAndVerifyFormSuccess, - 'submitAndVerifyFormError': submitAndVerifyFormError, - 'verifyElementInFocus': verifyElementInFocus, - 'verifyElementNotInFocus': verifyElementNotInFocus + 'submitAndVerifyFormError': submitAndVerifyFormError }; }); }).call(this, define || RequireJS.define); diff --git a/common/static/js/capa/spec/formula_equation_preview_spec.js b/common/static/js/capa/spec/formula_equation_preview_spec.js index 4360d7513b..7a115ed9ce 100644 --- a/common/static/js/capa/spec/formula_equation_preview_spec.js +++ b/common/static/js/capa/spec/formula_equation_preview_spec.js @@ -1,15 +1,6 @@ -function callPeriodicallyUntil(block, delay, condition, i) { // i is optional - i = i || 0; - block(i); - waits(delay); - runs(function () { - if (!condition()) { - callPeriodicallyUntil(block, delay, condition, i + 1); - } - }); -} - describe("Formula Equation Preview", function () { + 'use strict'; + var formulaEquationPreview = window.formulaEquationPreview; beforeEach(function () { // Simulate an environment conducive to a FormulaEquationInput var $fixture = this.$fixture = $('\ @@ -37,7 +28,7 @@ describe("Formula Equation Preview", function () { // Call old function. return old$find.apply(this, arguments); - } + }; $.find.matchesSelector = old$find.matchesSelector; this.oldDGEBI = document.getElementById; @@ -50,8 +41,8 @@ describe("Formula Equation Preview", function () { this.oldProblem = window.Problem; window.Problem = {}; - Problem.inputAjax = jasmine.createSpy('Problem.inputAjax') - .andCallFake(function () { + window.Problem.inputAjax = jasmine.createSpy('Problem.inputAjax') + .and.callFake(function () { ajaxTimes.push(Date.now()); }); @@ -60,19 +51,19 @@ describe("Formula Equation Preview", function () { this.oldMathJax = window.MathJax; window.MathJax = {Hub: {}}; - MathJax.Hub.getAllJax = jasmine.createSpy('MathJax.Hub.getAllJax') - .andReturn([this.jax]); - MathJax.Hub.Queue = function (callback) { + window.MathJax.Hub.getAllJax = jasmine.createSpy('MathJax.Hub.getAllJax') + .and.returnValue([this.jax]); + window.MathJax.Hub.Queue = function (callback) { if (typeof (callback) == 'function') { callback(); } - } - spyOn(MathJax.Hub, 'Queue').andCallThrough() - MathJax.Hub.Startup = jasmine.createSpy('MathJax.Hub.Startup'); - MathJax.Hub.Startup.signal = jasmine.createSpy('MathJax.Hub.Startup.signal'); - MathJax.Hub.Startup.signal.Interest = function (callback) { + }; + spyOn(window.MathJax.Hub, 'Queue').and.callThrough(); + window.MathJax.Hub.Startup = jasmine.createSpy('MathJax.Hub.Startup'); + window.MathJax.Hub.Startup.signal = jasmine.createSpy('MathJax.Hub.Startup.signal'); + window.MathJax.Hub.Startup.signal.Interest = function (callback) { callback('End'); - } + }; }); it('(the test) is able to swap out the behavior of $', function () { @@ -90,22 +81,22 @@ describe("Formula Equation Preview", function () { }); describe('Ajax requests', function () { - beforeEach(function () { + beforeEach(function (done) { // This is common to all tests on ajax requests. formulaEquationPreview.enable(); // This part may be asynchronous, so wait. - waitsFor(function () { - return Problem.inputAjax.wasCalled; - }, "AJAX never called initially", 1000); + jasmine.waitUntil(function () { + return window.Problem.inputAjax.calls.count() > 0; + }).then(done); }); it('has an initial request with the correct parameters', function () { - expect(Problem.inputAjax.callCount).toEqual(1); + expect(window.Problem.inputAjax.calls.count()).toEqual(1); // Use `.toEqual` rather than `.toHaveBeenCalledWith` // since it supports `jasmine.any`. - expect(Problem.inputAjax.mostRecentCall.args).toEqual([ + expect(window.Problem.inputAjax.calls.mostRecent().args).toEqual([ "THE_URL", "THE_ID", "preview_formcalc", @@ -115,65 +106,59 @@ describe("Formula Equation Preview", function () { ]); }); - it('does not request again if the initial request has already been made', function () { + it('does not request again if the initial request has already been made', function (done) { // jshint undef:false - expect(Problem.inputAjax.callCount).toEqual(1); + expect(window.Problem.inputAjax.calls.count()).toEqual(1); // Reset the spy in order to check calls again. - Problem.inputAjax.reset(); + window.Problem.inputAjax.calls.reset(); // Enabling the formulaEquationPreview again to see if this will // reinitialize input request once again. formulaEquationPreview.enable(); // This part may be asynchronous, so wait. - waitsFor(function () { - return !Problem.inputAjax.wasCalled; - }, "times out in case of AJAX call", 1000); - - // Expect Problem.inputAjax was not called as input request was - // initialized before. - expect(Problem.inputAjax).not.toHaveBeenCalled(); + jasmine.waitUntil(function () { + return window.Problem.inputAjax.calls.count() === 0; + }).then(function () { + // Expect window.Problem.inputAjax was not called as input request was + // initialized before. + expect(window.Problem.inputAjax).not.toHaveBeenCalled(); + }).always(done); }); - it('makes a request on user input', function () { - Problem.inputAjax.reset(); + it('makes a request on user input', function (done) { + window.Problem.inputAjax.calls.reset(); $('#input_THE_ID').val('user_input').trigger('input'); // This part is probably asynchronous - waitsFor(function () { - return Problem.inputAjax.wasCalled; - }, "AJAX never called on user input", 1000); - - runs(function () { - expect(Problem.inputAjax.mostRecentCall.args[3].formula - ).toEqual('user_input'); - }); + jasmine.waitUntil(function () { + return window.Problem.inputAjax.calls.count() > 0; + }).then(function () { + expect(window.Problem.inputAjax.calls.mostRecent().args[3].formula).toEqual('user_input'); + }).always(done); }); - it("isn't requested for empty input", function () { - Problem.inputAjax.reset(); + it("isn't requested for empty input", function (done) { + window.Problem.inputAjax.calls.reset(); // When we make an input of '', $('#input_THE_ID').val('').trigger('input'); // Either it makes a request or jumps straight into displaying ''. - waitsFor(function () { + jasmine.waitUntil(function () { // (Short circuit if `inputAjax` is indeed called) - return Problem.inputAjax.wasCalled || // jshint ignore:line - MathJax.Hub.Queue.wasCalled; - }, "AJAX never called on user input", 1000); - - runs(function () { + return window.Problem.inputAjax.calls.count() > 0 || + window.MathJax.Hub.Queue.calls.count() > 0; + }).then(function () { // Expect the request not to have been called. - expect(Problem.inputAjax).not.toHaveBeenCalled(); - }); + expect(window.Problem.inputAjax).not.toHaveBeenCalled(); + }).always(done); }); - it('limits the number of requests per second', function () { + it('limits the number of requests per second', function (done) { var minDelay = formulaEquationPreview.minDelay; var end = Date.now() + minDelay * 1.1; - var step = 10; // ms var $input = $('#input_THE_ID'); var value; @@ -182,41 +167,42 @@ describe("Formula Equation Preview", function () { $input.val(value).trigger('input'); } - callPeriodicallyUntil(inputAnother, step, function () { + var self = this; + var iter = 0; + jasmine.waitUntil(function () { + inputAnother(iter++); return Date.now() > end; // Stop when we get to `end`. - }); + }).then(function () { + jasmine.waitUntil(function () { + return window.Problem.inputAjax.calls.count() > 0 && + window.Problem.inputAjax.calls.mostRecent().args[3].formula === value; + }).then(_.bind(function () { + // There should be 2 or 3 calls (depending on leading edge). + expect(window.Problem.inputAjax.calls.count()).not.toBeGreaterThan(3); - waitsFor(function () { - return Problem.inputAjax.wasCalled && - Problem.inputAjax.mostRecentCall.args[3].formula == value; - }, "AJAX never called with final value from input", 1000); - - runs(function () { - // There should be 2 or 3 calls (depending on leading edge). - expect(Problem.inputAjax.callCount).not.toBeGreaterThan(3); - - // The calls should happen approximately `minDelay` apart. - for (var i =1; i < this.ajaxTimes.length; i ++) { - var diff = this.ajaxTimes[i] - this.ajaxTimes[i - 1]; - expect(diff).toBeGreaterThan(minDelay - 10); - } + // The calls should happen approximately `minDelay` apart. + for (var i =1; i < this.ajaxTimes.length; i ++) { + var diff = this.ajaxTimes[i] - this.ajaxTimes[i - 1]; + expect(diff).toBeGreaterThan(minDelay - 10); + } + }, self)).then(function () { + done(); + }); }); }); }); describe("Visible results (icon and mathjax)", function () { - it('displays a loading icon when requests are open', function () { + it('displays a loading icon when requests are open', function (done) { var $img = $("img.loading"); expect($img.css('visibility')).toEqual('hidden'); formulaEquationPreview.enable(); expect($img.css('visibility')).toEqual('visible'); // This part could be asynchronous - waitsFor(function () { - return Problem.inputAjax.wasCalled; - }, "AJAX never called initially", 1000); - - runs(function () { + jasmine.waitUntil(function () { + return window.Problem.inputAjax.calls.count() > 0; + }).then(function () { expect($img.css('visibility')).toEqual('visible'); // Reset and send another request. @@ -224,23 +210,23 @@ describe("Formula Equation Preview", function () { $("#input_THE_ID").val("different").trigger('input'); expect($img.css('visibility')).toEqual('visible'); - }); - - // Don't let it fail later. - waitsFor(function () { - var args = Problem.inputAjax.mostRecentCall.args; - return args[3].formula == "different"; + }).then(function () { + return jasmine.waitUntil(function () { + var args = window.Problem.inputAjax.calls.mostRecent().args; + return args[3].formula === "different"; + }).then(done); }); }); - it('updates MathJax and loading icon on callback', function () { + it('updates MathJax and loading icon on callback', function (done) { formulaEquationPreview.enable(); - waitsFor(function () { - return Problem.inputAjax.wasCalled; - }, "AJAX never called initially", 1000); - runs(function () { - var args = Problem.inputAjax.mostRecentCall.args; + var jax = this.jax; + + jasmine.waitUntil(function () { + return window.Problem.inputAjax.calls.count() > 0; + }).then(function () { + var args = window.Problem.inputAjax.calls.mostRecent().args; var callback = args[4]; callback({ preview: 'THE_FORMULA', @@ -252,29 +238,27 @@ describe("Formula Equation Preview", function () { // We should look in the preview div for the MathJax. var previewDiv = $("#input_THE_ID_preview")[0]; - expect(MathJax.Hub.getAllJax).toHaveBeenCalledWith(previewDiv); + expect(window.MathJax.Hub.getAllJax).toHaveBeenCalledWith(previewDiv); // Refresh the MathJax. - expect(MathJax.Hub.Queue).toHaveBeenCalledWith( - ['Text', this.jax, 'THE_FORMULA'] + expect(window.MathJax.Hub.Queue).toHaveBeenCalledWith( + ['Text', jax, 'THE_FORMULA'] ); - }); + }).always(done); }); - it('finds alternatives if MathJax hasn\'t finished loading', function () { + it('finds alternatives if MathJax hasn\'t finished loading', function (done) { formulaEquationPreview.enable(); $('#input_THE_ID').val('user_input').trigger('input'); - waitsFor(function () { - return Problem.inputAjax.wasCalled; - }, "AJAX never called initially", 1000); - - runs(function () { - var args = Problem.inputAjax.mostRecentCall.args; + jasmine.waitUntil(function () { + return window.Problem.inputAjax.calls.count() > 0; + }).then(function () { + var args = window.Problem.inputAjax.calls.mostRecent().args; var callback = args[4]; // Cannot find MathJax. - MathJax.Hub.getAllJax.andReturn([]); + window.MathJax.Hub.getAllJax.and.returnValue([]); spyOn(console, 'log'); callback({ @@ -290,74 +274,68 @@ describe("Formula Equation Preview", function () { expect(previewElement.firstChild.data).toEqual("\\(THE_FORMULA\\)"); // Refresh the MathJax. - expect(MathJax.Hub.Queue).toHaveBeenCalledWith( + expect(window.MathJax.Hub.Queue).toHaveBeenCalledWith( ['Typeset', jasmine.any(Object), jasmine.any(Element)] ); - }); + }).always(done); }); - it('displays errors from the server well', function () { + it('displays errors from the server well', function (done) { var $img = $("img.loading"); - formulaEquationPreview.enable(); - waitsFor(function () { - return Problem.inputAjax.wasCalled; - }, "AJAX never called initially", 1000); + var jax = this.jax; - runs(function () { - var args = Problem.inputAjax.mostRecentCall.args; + formulaEquationPreview.enable(); + jasmine.waitUntil(function () { + return window.Problem.inputAjax.calls.count() > 0; + }).then(function () { + var args = window.Problem.inputAjax.calls.mostRecent().args; var callback = args[4]; callback({ error: 'OOPSIE', request_start: args[3].request_start }); - expect(MathJax.Hub.Queue).not.toHaveBeenCalled(); + expect(window.MathJax.Hub.Queue).not.toHaveBeenCalled(); expect($img.css('visibility')).toEqual('visible'); - }); - - var errorDelay = formulaEquationPreview.errorDelay * 1.1; - waitsFor(function () { - return MathJax.Hub.Queue.wasCalled; - }, "Error message never displayed", 2000); - - runs(function () { - // Refresh the MathJax. - expect(MathJax.Hub.Queue).toHaveBeenCalledWith( - ['Text', this.jax, '\\text{OOPSIE}'] - ); - expect($img.css('visibility')).toEqual('hidden'); + }).then(function () { + jasmine.waitUntil(function () { + return window.MathJax.Hub.Queue.calls.count() > 0; + }).then(function () { + // Refresh the MathJax. + expect(window.MathJax.Hub.Queue).toHaveBeenCalledWith( + ['Text', jax, '\\text{OOPSIE}'] + ); + expect($img.css('visibility')).toEqual('hidden'); + }).then(done); }); }); }); describe('Multiple callbacks', function () { - beforeEach(function () { + beforeEach(function (done) { formulaEquationPreview.enable(); - waitsFor(function () { - return Problem.inputAjax.wasCalled; - }); - - runs(function () { + var self = this; + jasmine.waitUntil(function () { + return window.Problem.inputAjax.calls.count() > 0; + }).then(function () { $('#input_THE_ID').val('different').trigger('input'); - }); + jasmine.waitUntil(function () { + return window.Problem.inputAjax.calls.count() > 1; + }).then(_.bind(function () { + var args0 = window.Problem.inputAjax.calls.argsFor(0); + var args1 = window.Problem.inputAjax.calls.argsFor(1); + var response0 = { + preview: 'THE_FORMULA_0', + request_start: args0[3].request_start + }; + var response1 = { + preview: 'THE_FORMULA_1', + request_start: args1[3].request_start + }; - waitsFor(function () { - return Problem.inputAjax.callCount > 1; - }); - - runs(function () { - var args = Problem.inputAjax.argsForCall; - var response0 = { - preview: 'THE_FORMULA_0', - request_start: args[0][3].request_start - }; - var response1 = { - preview: 'THE_FORMULA_1', - request_start: args[1][3].request_start - }; - - this.callbacks = [args[0][4], args[1][4]]; - this.responses = [response0, response1]; + this.callbacks = [args0[4], args0[4]]; + this.responses = [response0, response1]; + }, self)).then(done); }); }); @@ -367,13 +345,13 @@ describe("Formula Equation Preview", function () { expect($img.css('visibility')).toEqual('visible'); this.callbacks[0](this.responses[0]); - expect(MathJax.Hub.Queue).toHaveBeenCalledWith( + expect(window.MathJax.Hub.Queue).toHaveBeenCalledWith( ['Text', this.jax, 'THE_FORMULA_0'] ); expect($img.css('visibility')).toEqual('visible'); this.callbacks[1](this.responses[1]); - expect(MathJax.Hub.Queue).toHaveBeenCalledWith( + expect(window.MathJax.Hub.Queue).toHaveBeenCalledWith( ['Text', this.jax, 'THE_FORMULA_1'] ); expect($img.css('visibility')).toEqual('hidden'); @@ -386,40 +364,38 @@ describe("Formula Equation Preview", function () { // Switch the order (1 returns before 0) this.callbacks[1](this.responses[1]); - expect(MathJax.Hub.Queue).toHaveBeenCalledWith( + expect(window.MathJax.Hub.Queue).toHaveBeenCalledWith( ['Text', this.jax, 'THE_FORMULA_1'] ); expect($img.css('visibility')).toEqual('hidden'); - MathJax.Hub.Queue.reset(); + window.MathJax.Hub.Queue.calls.reset(); this.callbacks[0](this.responses[0]); - expect(MathJax.Hub.Queue).not.toHaveBeenCalled(); + expect(window.MathJax.Hub.Queue).not.toHaveBeenCalled(); expect($img.css('visibility')).toEqual('hidden'); }); - it("doesn't show an error if the responses are close together", - function () { - this.callbacks[0]({ - error: 'OOPSIE', - request_start: this.responses[0].request_start - }); - expect(MathJax.Hub.Queue).not.toHaveBeenCalled(); - // Error message waiting to be displayed + it("doesn't show an error if the responses are close together", function (done) { + this.callbacks[0]({ + error: 'OOPSIE', + request_start: this.responses[0].request_start + }); + expect(window.MathJax.Hub.Queue).not.toHaveBeenCalled(); - this.callbacks[1](this.responses[1]); - expect(MathJax.Hub.Queue).toHaveBeenCalledWith( - ['Text', this.jax, 'THE_FORMULA_1'] - ); + // Error message waiting to be displayed + this.callbacks[1](this.responses[1]); + expect(window.MathJax.Hub.Queue).toHaveBeenCalledWith( + ['Text', this.jax, 'THE_FORMULA_1'] + ); - // Make sure that it doesn't indeed show up later - MathJax.Hub.Queue.reset(); - var errorDelay = formulaEquationPreview.errorDelay * 1.1; - waits(errorDelay); - - runs(function () { - expect(MathJax.Hub.Queue).not.toHaveBeenCalled(); - }) - }); + // Make sure that it doesn't indeed show up later + window.MathJax.Hub.Queue.calls.reset(); + jasmine.waitUntil(function () { + return formulaEquationPreview.errorDelay * 1.1; + }).then(function () { + expect(window.MathJax.Hub.Queue).not.toHaveBeenCalled(); + }).then(done); + }); }); afterEach(function () { @@ -428,15 +404,15 @@ describe("Formula Equation Preview", function () { document.getElementById = this.oldDGEBI; // Return Problem - Problem = this.oldProblem; - if (Problem === undefined) { - delete Problem; + window.Problem = this.oldProblem; + if (window.Problem === undefined) { + delete window.Problem; } // Return MathJax - MathJax = this.oldMathJax; - if (MathJax === undefined) { - delete MathJax; + window.MathJax = this.oldMathJax; + if (window.MathJax === undefined) { + delete window.MathJax; } }); }); diff --git a/common/static/js/libs/jasmine-extensions.js b/common/static/js/libs/jasmine-extensions.js new file mode 100644 index 0000000000..47b95619ce --- /dev/null +++ b/common/static/js/libs/jasmine-extensions.js @@ -0,0 +1,248 @@ +// Extensions to Jasmine. +// +// This file adds the following: +// 1. Custom matchers that may be helpful project-wise. +// 2. Copies of some matchers from Jasmine-jQuery. +// Because Jasmine-Jquery uses its own version of JQuery, events registered in the code +// using the platform version of JQuery are not "noticed" by Jasmine-jQuery matchers. +// Similarly equality matching does not work either. So after the platform version of +// jQuery has been loaded, we set these matchers up again in this module. + +(function(root, factory) { + /* jshint strict: false */ + factory(root, root.jQuery); +}((function() { + /* jshint strict: false */ + return this; +}()), function(window, $) { + 'use strict'; + + // Add custom Jasmine matchers. + beforeEach(function() { + + jasmine.addMatchers(window.imagediff.jasmine); + + jasmine.addMatchers({ + toHaveAttrs: function() { + return { + compare: function(actual, attrs) { + var result = {}, + element = actual; + + if ($.isEmptyObject(attrs)) { + return { + pass: false + }; + } + + result.pass = _.every(attrs, function(value, name) { + return element.attr(name) === value; + }); + + return result; + } + }; + }, + toBeInRange: function() { + return { + compare: function(actual, min, max) { + return { + pass: min <= actual && actual <= max + }; + } + }; + }, + toBeInArray: function() { + return { + compare: function(actual, array) { + return { + pass: $.inArray(actual, array) > -1 + }; + } + }; + } + }); + }); + + /* jshint ignore:start */ + // All the code below is taken from: + // https://github.com/velesin/jasmine-jquery/blob/2.1.1/lib/jasmine-jquery.js + beforeEach(function() { + jasmine.addMatchers({ + toHandle: function() { + return { + compare: function(actual, event) { + if (!actual || actual.length === 0) return { + pass: false + }; + var events = $._data($(actual).get(0), "events"); + + if (!events || !event || typeof event !== "string") { + return { + pass: false + }; + } + + var namespaces = event.split("."), + eventType = namespaces.shift(), + sortedNamespaces = namespaces.slice(0).sort(), + namespaceRegExp = new RegExp("(^|\\.)" + sortedNamespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); + + if (events[eventType] && namespaces.length) { + for (var i = 0; i < events[eventType].length; i++) { + var namespace = events[eventType][i].namespace; + + if (namespaceRegExp.test(namespace)) + return { + pass: true + }; + } + } else { + return { + pass: (events[eventType] && events[eventType].length > 0) + }; + } + + return { + pass: false + }; + } + }; + }, + + toHandleWith: function() { + return { + compare: function(actual, eventName, eventHandler) { + if (!actual || actual.length === 0) return { + pass: false + }; + var normalizedEventName = eventName.split('.')[0], + stack = $._data($(actual).get(0), "events")[normalizedEventName]; + + for (var i = 0; i < stack.length; i++) { + if (stack[i].handler == eventHandler) return { + pass: true + }; + } + + return { + pass: false + }; + } + }; + } + }); + + jasmine.addCustomEqualityTester(function(a, b) { + if (a && b) { + if (a instanceof $ || jasmine.isDomNode(a)) { + var $a = $(a); + + if (b instanceof $) + return $a.length == b.length && a.is(b); + + return $a.is(b); + } + + if (b instanceof $ || jasmine.isDomNode(b)) { + var $b = $(b); + + if (a instanceof $) + return a.length == $b.length && $b.is(a); + + return $(b).is(a); + } + } + }); + + jasmine.addCustomEqualityTester(function(a, b) { + if (a instanceof $ && b instanceof $ && a.size() == b.size()) + return a.is(b); + }); + + }); + + var data = { + spiedEvents: {}, + handlers: [] + }; + + jasmine.jQuery.events = { + spyOn: function(selector, eventName) { + var handler = function(e) { + var calls = (typeof data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] !== 'undefined') ? data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)].calls : 0; + data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] = { + args: jasmine.util.argsToArray(arguments), + calls: ++calls + }; + }; + + $(selector).on(eventName, handler); + data.handlers.push(handler); + + return { + selector: selector, + eventName: eventName, + handler: handler, + reset: function() { + delete data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]; + }, + calls: { + count: function() { + return data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] ? + data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)].calls : 0; + }, + any: function() { + return data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] ? + !!data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)].calls : false; + } + } + }; + }, + + args: function(selector, eventName) { + var actualArgs = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)].args; + + if (!actualArgs) { + throw "There is no spy for " + eventName + " on " + selector.toString() + ". Make sure to create a spy using spyOnEvent."; + } + + return actualArgs; + }, + + wasTriggered: function(selector, eventName) { + return !!(data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]); + }, + + wasTriggeredWith: function(selector, eventName, expectedArgs, util, customEqualityTesters) { + var actualArgs = jasmine.jQuery.events.args(selector, eventName).slice(1); + + if (Object.prototype.toString.call(expectedArgs) !== '[object Array]') + actualArgs = actualArgs[0]; + + return util.equals(actualArgs, expectedArgs, customEqualityTesters); + }, + + wasPrevented: function(selector, eventName) { + var spiedEvent = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)], + args = (jasmine.util.isUndefined(spiedEvent)) ? {} : spiedEvent.args, + e = args ? args[0] : undefined; + + return e && e.isDefaultPrevented(); + }, + + wasStopped: function(selector, eventName) { + var spiedEvent = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)], + args = (jasmine.util.isUndefined(spiedEvent)) ? {} : spiedEvent.args, + e = args ? args[0] : undefined; + + return e && e.isPropagationStopped(); + }, + + cleanUp: function() { + data.spiedEvents = {}; + data.handlers = []; + } + }; + /* jshint ignore:end */ +})); diff --git a/common/static/js/libs/jasmine-stealth.js b/common/static/js/libs/jasmine-stealth.js new file mode 100644 index 0000000000..5ec68c04e9 --- /dev/null +++ b/common/static/js/libs/jasmine-stealth.js @@ -0,0 +1,64 @@ +// Custom library to replace the legacy non jasmine 2.0 compatible jasmine-stealth +// jshint ignore: start +(function (root, factory) { + factory(root, root.jasmine, root._); +}((function () { + return this; +}()), function (window, jasmine, _) { + var fake, clearSpies, spyOnConstructor, unfakes = []; + + clearSpies = function () { + _.each(unfakes, function (u) { + return u(); + }); + return unfakes = []; + }; + + fake = function (owner, thingToFake, newThing) { + var originalThing; + originalThing = owner[thingToFake]; + owner[thingToFake] = newThing; + return unfakes.push(function () { + return owner[thingToFake] = originalThing; + }); + }; + + spyOnConstructor = function (owner, classToFake, methodsToSpy) { + var fakeClass, spies; + + fakeClass = (function () { + function _Class() { + spies.constructor.apply(this, arguments); + } + + return _Class; + })(); + + if (!methodsToSpy) { + methodsToSpy = []; + } + + if (_.isString(methodsToSpy)) { + methodsToSpy = [methodsToSpy]; + } + + spies = { + constructor: jasmine.createSpy('' + classToFake + '\'s constructor') + }; + + _.each(methodsToSpy, function (methodName) { + spies[methodName] = jasmine.createSpy('' + classToFake + '#' + methodName); + return fakeClass.prototype[methodName] = function () { + return spies[methodName].apply(this, arguments); + }; + }); + + fake(owner, classToFake, fakeClass); + return spies; + }; + + jasmine.stealth = { + spyOnConstructor: spyOnConstructor, + clearSpies: clearSpies + }; +})); \ No newline at end of file diff --git a/common/static/js/libs/jasmine-waituntil.js b/common/static/js/libs/jasmine-waituntil.js new file mode 100644 index 0000000000..43060c4412 --- /dev/null +++ b/common/static/js/libs/jasmine-waituntil.js @@ -0,0 +1,48 @@ + +// Takes a latch function and optionally timeout and error message. +// Polls the latch function until the it returns true or the maximum timeout expires +// whichever comes first. +(function(root, factory) { + /* jshint strict: false */ + factory(root, root.jQuery); +}((function() { + /* jshint strict: false */ + return this; +}()), function(window, $) { + 'use strict'; + + var MAX_TIMEOUT = jasmine.DEFAULT_TIMEOUT_INTERVAL; + var realSetTimeout = setTimeout; + var realClearTimeout = clearTimeout; + jasmine.waitUntil = function(conditionalFn, maxTimeout, message) { + var deferred = $.Deferred(), + elapsedTimeInMs = 0, + timeout; + + maxTimeout = maxTimeout || MAX_TIMEOUT; + message = message || 'Timeout has expired'; + + var fn = function() { + elapsedTimeInMs += 50; + if (conditionalFn()) { + if (timeout) { realClearTimeout(timeout); } + deferred.resolve(); + } else { + if (elapsedTimeInMs >= maxTimeout) { + // explicitly fail the spec with the given message + fail(message); // jshint ignore:line + + // clear timeout and reject the promise + realClearTimeout(timeout); + deferred.reject(); + + return; + } + timeout = realSetTimeout(fn, 50); + } + }; + + realSetTimeout(fn, 50); + return deferred.promise(); + }; +})); diff --git a/common/static/js/spec/CSS3_workarounds_spec.js b/common/static/js/spec/CSS3_workarounds_spec.js index 107f08f4a4..8b6f746cb6 100644 --- a/common/static/js/spec/CSS3_workarounds_spec.js +++ b/common/static/js/spec/CSS3_workarounds_spec.js @@ -1,4 +1,6 @@ describe("CSS3 workarounds", function() { + 'use strict'; + var pointerEventsNone = window.pointerEventsNone; describe("pointer-events", function() { beforeEach(function() { var html = "What wondrous life in this I lead"; @@ -21,17 +23,7 @@ describe("CSS3 workarounds", function() { }); it("should prevent default when pointerEvents is not Supported", function() { - // mock document.body.style so it does not include 'pointerEvents' - var mockBodyStyle = {}, - bodyStyleKeys = Object.keys(document.body.style); - for (var index = 0; index < bodyStyleKeys.length; index++) { - var key = bodyStyleKeys[index]; - if (key !== "pointerEvents") { - mockBodyStyle[key] = document.body.style[key]; - }; - }; - - pointerEventsNone(".is-disabled", mockBodyStyle); + pointerEventsNone(".is-disabled", {}); spyOnEvent(".is-disabled", "click"); $(".is-disabled").click(); expect("click").toHaveBeenPreventedOn(".is-disabled"); diff --git a/common/static/js/spec/lang_edx_spec.js b/common/static/js/spec/lang_edx_spec.js index 3d8f4f48b9..b335bc1ddb 100644 --- a/common/static/js/spec/lang_edx_spec.js +++ b/common/static/js/spec/lang_edx_spec.js @@ -19,34 +19,34 @@ }); it("should make an AJAX request to the correct URL", function () { - spyOn($, 'ajax').andReturn(deferred); + spyOn($, 'ajax').and.returnValue(deferred); Language.init(); lang_selector.trigger('change'); - expect($.ajax.mostRecentCall.args[0].url).toEqual("/api/user/v1/preferences/test1/"); + expect($.ajax.calls.mostRecent().args[0].url).toEqual("/api/user/v1/preferences/test1/"); }); it("should make an AJAX request with correct type", function () { - spyOn($, 'ajax').andReturn(deferred); + spyOn($, 'ajax').and.returnValue(deferred); Language.init(); lang_selector.trigger('change'); - expect($.ajax.mostRecentCall.args[0].type).toEqual("PATCH"); + expect($.ajax.calls.mostRecent().args[0].type).toEqual("PATCH"); }); it("should make an AJAX request with correct data", function () { - spyOn($, 'ajax').andReturn(deferred); + spyOn($, 'ajax').and.returnValue(deferred); Language.init(); lang_selector.val('ar'); lang_selector.trigger('change'); - expect($.ajax.mostRecentCall.args[0].data).toEqual('{"pref-lang":"ar"}'); + expect($.ajax.calls.mostRecent().args[0].data).toEqual('{"pref-lang":"ar"}'); // change to 'en' from 'ar' lang_selector.val('en'); lang_selector.trigger('change'); - expect($.ajax.mostRecentCall.args[0].data).toEqual('{"pref-lang":"en"}'); + expect($.ajax.calls.mostRecent().args[0].data).toEqual('{"pref-lang":"en"}'); }); it("should call refresh on ajax failure", function () { - spyOn($, 'ajax').andCallFake(function () { + spyOn($, 'ajax').and.callFake(function () { var d = $.Deferred(); d.reject(); return d.promise(); diff --git a/common/static/js/spec/tooltip_manager_spec.js b/common/static/js/spec/tooltip_manager_spec.js index c4011b1f95..e6cd2d2c0e 100644 --- a/common/static/js/spec/tooltip_manager_spec.js +++ b/common/static/js/spec/tooltip_manager_spec.js @@ -11,24 +11,37 @@ describe('TooltipManager', function () { this.element = $('#test-id'); this.tooltip = new TooltipManager(document.body); - jasmine.Clock.useMock(); + jasmine.clock().install(); // Set default dimensions to make testing easer. $('.tooltip').height(HEIGHT).width(WIDTH); // Re-write default jasmine-jquery to consider opacity. - this.addMatchers({ + jasmine.addMatchers({ toBeVisible: function() { - return this.actual.is(':visible') || parseFloat(this.actual.css('opacity')); + return { + compare: function (actual) { + return { + pass: actual.is(':visible') || parseFloat(actual.css('opacity')) + }; + } + }; }, - toBeHidden: function() { - return this.actual.is(':hidden') || !parseFloat(this.actual.css('opacity')); - }, + toBeHidden: function () { + return { + compare: function (actual) { + return { + pass: actual.is(':hidden') || !parseFloat(actual.css('opacity')) + }; + } + }; + } }); }); afterEach(function () { this.tooltip.destroy(); + jasmine.clock().uninstall(); }); showTooltip = function (element) { @@ -36,7 +49,7 @@ describe('TooltipManager', function () { pageX: PAGE_X, pageY: PAGE_Y })); - jasmine.Clock.tick(500); + jasmine.clock().tick(500); }; it('can destroy itself', function () { @@ -58,7 +71,7 @@ describe('TooltipManager', function () { showTooltip(this.element); expect($('.tooltip')).toBeVisible(); this.element.trigger($.Event("mouseout")); - jasmine.Clock.tick(50); + jasmine.clock().tick(50); expect($('.tooltip')).toBeHidden(); }); @@ -66,7 +79,7 @@ describe('TooltipManager', function () { showTooltip(this.element); expect($('.tooltip')).toBeVisible(); this.element.trigger($.Event("click")); - jasmine.Clock.tick(50); + jasmine.clock().tick(50); expect($('.tooltip')).toBeHidden(); }); diff --git a/common/static/js/src/CSS3_workarounds.js b/common/static/js/src/CSS3_workarounds.js index 3608782683..b9c14a1dad 100644 --- a/common/static/js/src/CSS3_workarounds.js +++ b/common/static/js/src/CSS3_workarounds.js @@ -2,7 +2,7 @@ // supported in older browsers var pointerEventsNone = function (selector, supportedStyles) { - // Check to see if the brower supports 'pointer-events' css rule. + // Check to see if the browser supports 'pointer-events' css rule. // If it doesn't, use javascript to stop the link from working // when clicked. $(selector).click(function (event) { diff --git a/common/static/js/vendor/jasmine-imagediff.js b/common/static/js/vendor/jasmine-imagediff.js index 6460e59dc5..230fce0ff8 100644 --- a/common/static/js/vendor/jasmine-imagediff.js +++ b/common/static/js/vendor/jasmine-imagediff.js @@ -268,52 +268,71 @@ return element; } + function imageDiffEqualMessage (actual, expected) { + return function () { + var + div = get('div'), + a = get('div', '
Actual:
'), + b = get('div', '
Expected:
'), + c = get('div', '
Diff:
'), + diff = imagediff.diff(actual, expected), + canvas = getCanvas(), + context; + + canvas.height = diff.height; + canvas.width = diff.width; + + div.style.overflow = 'hidden'; + a.style.float = 'left'; + b.style.float = 'left'; + c.style.float = 'left'; + + context = canvas.getContext('2d'); + context.putImageData(diff, 0, 0); + + a.appendChild(toCanvas(actual)); + b.appendChild(toCanvas(expected)); + c.appendChild(canvas); + + div.appendChild(a); + div.appendChild(b); + div.appendChild(c); + + return div; + }; + } + jasmine = { toBeImageData : function () { - return imagediff.isImageData(this.actual); + return { + compare: function () { + return { + pass: imagediff.isImageData(this.actual) + } + } + }; }, - toImageDiffEqual : function (expected, tolerance) { - - if (typeof (document) !== UNDEFINED) { - this.message = function () { + toImageDiffEqual: function () { + return { + compare: function (actual, expected, tolerance) { var - div = get('div'), - a = get('div', '
Actual:
'), - b = get('div', '
Expected:
'), - c = get('div', '
Diff:
'), - diff = imagediff.diff(this.actual, expected), - canvas = getCanvas(), - context; + result = {}; - canvas.height = diff.height; - canvas.width = diff.width; - - div.style.overflow = 'hidden'; - a.style.float = 'left'; - b.style.float = 'left'; - c.style.float = 'left'; - - context = canvas.getContext('2d'); - context.putImageData(diff, 0, 0); - - a.appendChild(toCanvas(this.actual)); - b.appendChild(toCanvas(expected)); - c.appendChild(canvas); - - div.appendChild(a); - div.appendChild(b); - div.appendChild(c); - - return [ - div, - "Expected not to be equal." - ]; - }; - } - - return imagediff.equal(this.actual, expected, tolerance); + result.pass = imagediff.equal(actual, expected, tolerance); + if (typeof (document) !== UNDEFINED) { + result.message = imageDiffEqualMessage(actual, expected); + } + return result; + }, + negativeCompare: function (actual, expected, tolerance) { + return { + pass: !imagediff.equal(actual, expected, tolerance), + message: 'Expected not to be equal.' + }; + } + }; } }; diff --git a/common/static/js/vendor/jasmine-stealth.js b/common/static/js/vendor/jasmine-stealth.js deleted file mode 100644 index c3afc54f90..0000000000 --- a/common/static/js/vendor/jasmine-stealth.js +++ /dev/null @@ -1,244 +0,0 @@ -// Generated by CoffeeScript 1.3.3 - -/* -jasmine-stealth 0.0.12 -Makes Jasmine spies a bit more robust -site: https://github.com/searls/jasmine-stealth -*/ - - -(function() { - var Captor, fake, root, unfakes, whatToDoWhenTheSpyGetsCalled, _, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - - root = this; - - _ = function(obj) { - return { - each: function(iterator) { - var item, _i, _len, _results; - _results = []; - for (_i = 0, _len = obj.length; _i < _len; _i++) { - item = obj[_i]; - _results.push(iterator(item)); - } - return _results; - }, - isFunction: function() { - return Object.prototype.toString.call(obj) === "[object Function]"; - }, - isString: function() { - return Object.prototype.toString.call(obj) === "[object String]"; - } - }; - }; - - root.spyOnConstructor = function(owner, classToFake, methodsToSpy) { - var fakeClass, spies; - if (methodsToSpy == null) { - methodsToSpy = []; - } - if (_(methodsToSpy).isString()) { - methodsToSpy = [methodsToSpy]; - } - spies = { - constructor: jasmine.createSpy("" + classToFake + "'s constructor") - }; - fakeClass = (function() { - - function _Class() { - spies.constructor.apply(this, arguments); - } - - return _Class; - - })(); - _(methodsToSpy).each(function(methodName) { - spies[methodName] = jasmine.createSpy("" + classToFake + "#" + methodName); - return fakeClass.prototype[methodName] = function() { - return spies[methodName].apply(this, arguments); - }; - }); - fake(owner, classToFake, fakeClass); - return spies; - }; - - unfakes = []; - - afterEach(function() { - _(unfakes).each(function(u) { - return u(); - }); - return unfakes = []; - }); - - fake = function(owner, thingToFake, newThing) { - var originalThing; - originalThing = owner[thingToFake]; - owner[thingToFake] = newThing; - return unfakes.push(function() { - return owner[thingToFake] = originalThing; - }); - }; - - root.stubFor = root.spyOn; - - jasmine.createStub = jasmine.createSpy; - - jasmine.createStubObj = function(baseName, stubbings) { - var name, obj, stubbing; - if (stubbings.constructor === Array) { - return jasmine.createSpyObj(baseName, stubbings); - } else { - obj = {}; - for (name in stubbings) { - stubbing = stubbings[name]; - obj[name] = jasmine.createSpy(baseName + "." + name); - if (_(stubbing).isFunction()) { - obj[name].andCallFake(stubbing); - } else { - obj[name].andReturn(stubbing); - } - } - return obj; - } - }; - - whatToDoWhenTheSpyGetsCalled = function(spy) { - var matchesStub, priorStubbing; - matchesStub = function(stubbing, args, context) { - switch (stubbing.type) { - case "args": - return jasmine.getEnv().equals_(stubbing.ifThis, jasmine.util.argsToArray(args)); - case "context": - return jasmine.getEnv().equals_(stubbing.ifThis, context); - } - }; - priorStubbing = spy.plan(); - return spy.andCallFake(function() { - var i, stubbing; - i = 0; - while (i < spy._stealth_stubbings.length) { - stubbing = spy._stealth_stubbings[i]; - if (matchesStub(stubbing, arguments, this)) { - if (Object.prototype.toString.call(stubbing.thenThat) === "[object Function]") { - return stubbing.thenThat(); - } else { - return stubbing.thenThat; - } - } - i++; - } - return priorStubbing; - }); - }; - - jasmine.Spy.prototype.whenContext = function(context) { - var addStubbing, spy; - spy = this; - spy._stealth_stubbings || (spy._stealth_stubbings = []); - whatToDoWhenTheSpyGetsCalled(spy); - addStubbing = function(thenThat) { - spy._stealth_stubbings.push({ - type: 'context', - ifThis: context, - thenThat: thenThat - }); - return spy; - }; - return { - thenReturn: addStubbing, - thenCallFake: addStubbing - }; - }; - - jasmine.Spy.prototype.when = function() { - var addStubbing, ifThis, spy; - spy = this; - ifThis = jasmine.util.argsToArray(arguments); - spy._stealth_stubbings || (spy._stealth_stubbings = []); - whatToDoWhenTheSpyGetsCalled(spy); - addStubbing = function(thenThat) { - spy._stealth_stubbings.push({ - type: 'args', - ifThis: ifThis, - thenThat: thenThat - }); - return spy; - }; - return { - thenReturn: addStubbing, - thenCallFake: addStubbing - }; - }; - - jasmine.Spy.prototype.mostRecentCallThat = function(callThat, context) { - var i; - i = this.calls.length - 1; - while (i >= 0) { - if (callThat.call(context || this, this.calls[i]) === true) { - return this.calls[i]; - } - i--; - } - }; - - jasmine.Matchers.ArgThat = (function(_super) { - - __extends(ArgThat, _super); - - function ArgThat(matcher) { - this.matcher = matcher; - } - - ArgThat.prototype.jasmineMatches = function(actual) { - return this.matcher(actual); - }; - - return ArgThat; - - })(jasmine.Matchers.Any); - - jasmine.Matchers.ArgThat.prototype.matches = jasmine.Matchers.ArgThat.prototype.jasmineMatches; - - jasmine.argThat = function(expected) { - return new jasmine.Matchers.ArgThat(expected); - }; - - jasmine.Matchers.Capture = (function(_super) { - - __extends(Capture, _super); - - function Capture(captor) { - this.captor = captor; - } - - Capture.prototype.jasmineMatches = function(actual) { - this.captor.value = actual; - return true; - }; - - return Capture; - - })(jasmine.Matchers.Any); - - jasmine.Matchers.Capture.prototype.matches = jasmine.Matchers.Capture.prototype.jasmineMatches; - - Captor = (function() { - - function Captor() {} - - Captor.prototype.capture = function() { - return new jasmine.Matchers.Capture(this); - }; - - return Captor; - - })(); - - jasmine.captor = function() { - return new Captor(); - }; - -}).call(this); diff --git a/common/static/js/vendor/jasmine.async.js b/common/static/js/vendor/jasmine.async.js deleted file mode 100644 index fb54f88114..0000000000 --- a/common/static/js/vendor/jasmine.async.js +++ /dev/null @@ -1,51 +0,0 @@ -// Jasmine.Async, v0.1.0 -// Copyright (c)2012 Muted Solutions, LLC. All Rights Reserved. -// Distributed under MIT license -// http://github.com/derickbailey/jasmine.async -this.AsyncSpec = (function(global){ - - // Private Methods - // --------------- - - function runAsync(block){ - return function(){ - var done = false; - var complete = function(){ done = true; }; - - runs(function(){ - block(complete); - }); - - waitsFor(function(){ - return done; - }); - }; - } - - // Constructor Function - // -------------------- - - function AsyncSpec(spec){ - this.spec = spec; - } - - // Public API - // ---------- - - AsyncSpec.prototype.beforeEach = function(block){ - this.spec.beforeEach(runAsync(block)); - }; - - AsyncSpec.prototype.afterEach = function(block){ - this.spec.afterEach(runAsync(block)); - }; - - AsyncSpec.prototype.it = function(description, block){ - // For some reason, `it` is not attached to the current - // test suite, so it has to be called from the global - // context. - global.it(description, runAsync(block)); - }; - - return AsyncSpec; -})(this); \ No newline at end of file diff --git a/common/static/js/vendor/mock-ajax.js b/common/static/js/vendor/mock-ajax.js index ed97652b4e..50c3bd1e22 100644 --- a/common/static/js/vendor/mock-ajax.js +++ b/common/static/js/vendor/mock-ajax.js @@ -1,199 +1,752 @@ /* - Jasmine-Ajax : a set of helpers for testing AJAX requests under the Jasmine - BDD framework for JavaScript. - Supports jQuery. +Jasmine-Ajax - v3.2.0: a set of helpers for testing AJAX requests under the Jasmine +BDD framework for JavaScript. - http://github.com/pivotal/jasmine-ajax +http://github.com/jasmine/jasmine-ajax - Jasmine Home page: http://pivotal.github.com/jasmine +Jasmine Home page: http://jasmine.github.io/ - Copyright (c) 2008-2013 Pivotal Labs +Copyright (c) 2008-2015 Pivotal Labs - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ +*/ -// Jasmine-Ajax interface -var ajaxRequests = []; +//Module wrapper to support both browser and CommonJS environment +(function (root, factory) { + if (typeof exports === 'object' && typeof exports.nodeName !== 'string') { + // CommonJS + var jasmineRequire = require('jasmine-core'); + module.exports = factory(root, function() { + return jasmineRequire; + }); + } else { + // Browser globals + window.MockAjax = factory(root, getJasmineRequireObj); + } +}(typeof window !== 'undefined' ? window : global, function (global, getJasmineRequireObj) { -function mostRecentAjaxRequest() { - if (ajaxRequests.length > 0) { - return ajaxRequests[ajaxRequests.length - 1]; - } else { - return null; +// +getJasmineRequireObj().ajax = function(jRequire) { + var $ajax = {}; + + $ajax.RequestStub = jRequire.AjaxRequestStub(); + $ajax.RequestTracker = jRequire.AjaxRequestTracker(); + $ajax.StubTracker = jRequire.AjaxStubTracker(); + $ajax.ParamParser = jRequire.AjaxParamParser(); + $ajax.event = jRequire.AjaxEvent(); + $ajax.eventBus = jRequire.AjaxEventBus($ajax.event); + $ajax.fakeRequest = jRequire.AjaxFakeRequest($ajax.eventBus); + $ajax.MockAjax = jRequire.MockAjax($ajax); + + return $ajax.MockAjax; +}; + +getJasmineRequireObj().AjaxEvent = function() { + function now() { + return new Date().getTime(); } -} -function clearAjaxRequests() { - ajaxRequests = []; -} + function noop() { + } -// Fake XHR for mocking Ajax Requests & Responses -function FakeXMLHttpRequest() { - var extend = Object.extend || jQuery.extend; - extend(this, { - requestHeaders: {}, + // Event object + // https://dom.spec.whatwg.org/#concept-event + function XMLHttpRequestEvent(xhr, type) { + this.type = type; + this.bubbles = false; + this.cancelable = false; + this.timeStamp = now(); - open: function() { - this.method = arguments[0]; - this.url = arguments[1]; - this.username = arguments[3]; - this.password = arguments[4]; - this.readyState = 1; + this.isTrusted = false; + this.defaultPrevented = false; + + // Event phase should be "AT_TARGET" + // https://dom.spec.whatwg.org/#dom-event-at_target + this.eventPhase = 2; + + this.target = xhr; + this.currentTarget = xhr; + } + + XMLHttpRequestEvent.prototype.preventDefault = noop; + XMLHttpRequestEvent.prototype.stopPropagation = noop; + XMLHttpRequestEvent.prototype.stopImmediatePropagation = noop; + + function XMLHttpRequestProgressEvent() { + XMLHttpRequestEvent.apply(this, arguments); + + this.lengthComputable = false; + this.loaded = 0; + this.total = 0; + } + + // Extend prototype + XMLHttpRequestProgressEvent.prototype = XMLHttpRequestEvent.prototype; + + return { + event: function(xhr, type) { + return new XMLHttpRequestEvent(xhr, type); }, - setRequestHeader: function(header, value) { - this.requestHeaders[header] = value; - }, + progressEvent: function(xhr, type) { + return new XMLHttpRequestProgressEvent(xhr, type); + } + }; +}; +getJasmineRequireObj().AjaxEventBus = function(eventFactory) { + function EventBus(source) { + this.eventList = {}; + this.source = source; + } - abort: function() { - this.readyState = 0; - }, + function ensureEvent(eventList, name) { + eventList[name] = eventList[name] || []; + return eventList[name]; + } - readyState: 0, + function findIndex(list, thing) { + if (list.indexOf) { + return list.indexOf(thing); + } - onload: function() { - }, - - onreadystatechange: function(isTimeout) { - }, - - status: null, - - send: function(data) { - this.params = data; - this.readyState = 2; - }, - - data: function() { - var data = {}; - if (typeof this.params !== 'string') return data; - var params = this.params.split('&'); - - for (var i = 0; i < params.length; ++i) { - var kv = params[i].replace(/\+/g, ' ').split('='); - var key = decodeURIComponent(kv[0]); - data[key] = data[key] || []; - data[key].push(decodeURIComponent(kv[1])); - data[key].sort(); + for(var i = 0; i < list.length; i++) { + if (thing === list[i]) { + return i; } - return data; - }, + } - getResponseHeader: function(name) { - return this.responseHeaders[name]; - }, + return -1; + } - getAllResponseHeaders: function() { - var responseHeaders = []; - for (var i in this.responseHeaders) { - if (this.responseHeaders.hasOwnProperty(i)) { - responseHeaders.push(i + ': ' + this.responseHeaders[i]); + EventBus.prototype.addEventListener = function(event, callback) { + ensureEvent(this.eventList, event).push(callback); + }; + + EventBus.prototype.removeEventListener = function(event, callback) { + var index = findIndex(this.eventList[event], callback); + + if (index >= 0) { + this.eventList[event].splice(index, 1); + } + }; + + EventBus.prototype.trigger = function(event) { + var evt; + + // Event 'readystatechange' is should be a simple event. + // Others are progress event. + // https://xhr.spec.whatwg.org/#events + if (event === 'readystatechange') { + evt = eventFactory.event(this.source, event); + } else { + evt = eventFactory.progressEvent(this.source, event); + } + + var eventListeners = this.eventList[event]; + + if (eventListeners) { + for (var i = 0; i < eventListeners.length; i++) { + eventListeners[i].call(this.source, evt); + } + } + }; + + return function(source) { + return new EventBus(source); + }; +}; + +getJasmineRequireObj().AjaxFakeRequest = function(eventBusFactory) { + function extend(destination, source, propertiesToSkip) { + propertiesToSkip = propertiesToSkip || []; + for (var property in source) { + if (!arrayContains(propertiesToSkip, property)) { + destination[property] = source[property]; + } + } + return destination; + } + + function arrayContains(arr, item) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] === item) { + return true; + } + } + return false; + } + + function wrapProgressEvent(xhr, eventName) { + return function() { + if (xhr[eventName]) { + xhr[eventName].apply(xhr, arguments); + } + }; + } + + function initializeEvents(xhr) { + xhr.eventBus.addEventListener('readystatechange', wrapProgressEvent(xhr, 'onreadystatechange')); + xhr.eventBus.addEventListener('loadstart', wrapProgressEvent(xhr, 'onloadstart')); + xhr.eventBus.addEventListener('load', wrapProgressEvent(xhr, 'onload')); + xhr.eventBus.addEventListener('loadend', wrapProgressEvent(xhr, 'onloadend')); + xhr.eventBus.addEventListener('progress', wrapProgressEvent(xhr, 'onprogress')); + xhr.eventBus.addEventListener('error', wrapProgressEvent(xhr, 'onerror')); + xhr.eventBus.addEventListener('abort', wrapProgressEvent(xhr, 'onabort')); + xhr.eventBus.addEventListener('timeout', wrapProgressEvent(xhr, 'ontimeout')); + } + + function unconvertibleResponseTypeMessage(type) { + var msg = [ + "Can't build XHR.response for XHR.responseType of '", + type, + "'.", + "XHR.response must be explicitly stubbed" + ]; + return msg.join(' '); + } + + function fakeRequest(global, requestTracker, stubTracker, paramParser) { + function FakeXMLHttpRequest() { + requestTracker.track(this); + this.eventBus = eventBusFactory(this); + initializeEvents(this); + this.requestHeaders = {}; + this.overriddenMimeType = null; + } + + function findHeader(name, headers) { + name = name.toLowerCase(); + for (var header in headers) { + if (header.toLowerCase() === name) { + return headers[header]; } } - return responseHeaders.join('\r\n'); - }, - - responseText: null, - - response: function(response) { - this.status = response.status; - this.responseText = response.responseText || ""; - this.readyState = 4; - this.responseHeaders = response.responseHeaders || - {"Content-type": response.contentType || "application/json" }; - // uncomment for jquery 1.3.x support - // jasmine.Clock.tick(20); - - this.onload(); - this.onreadystatechange(); - }, - responseTimeout: function() { - this.readyState = 4; - jasmine.Clock.tick(jQuery.ajaxSettings.timeout || 30000); - this.onreadystatechange('timeout'); } - }); - return this; -} + function normalizeHeaders(rawHeaders, contentType) { + var headers = []; + if (rawHeaders) { + if (rawHeaders instanceof Array) { + headers = rawHeaders; + } else { + for (var headerName in rawHeaders) { + if (rawHeaders.hasOwnProperty(headerName)) { + headers.push({ name: headerName, value: rawHeaders[headerName] }); + } + } + } + } else { + headers.push({ name: "Content-Type", value: contentType || "application/json" }); + } -jasmine.Ajax = { - - isInstalled: function() { - return jasmine.Ajax.installed === true; - }, - - assertInstalled: function() { - if (!jasmine.Ajax.isInstalled()) { - throw new Error("Mock ajax is not installed, use jasmine.Ajax.useMock()"); + return headers; } - }, - useMock: function() { - if (!jasmine.Ajax.isInstalled()) { - var spec = jasmine.getEnv().currentSpec; - spec.after(jasmine.Ajax.uninstallMock); - - jasmine.Ajax.installMock(); + function parseXml(xmlText, contentType) { + if (global.DOMParser) { + return (new global.DOMParser()).parseFromString(xmlText, 'text/xml'); + } else { + var xml = new global.ActiveXObject("Microsoft.XMLDOM"); + xml.async = "false"; + xml.loadXML(xmlText); + return xml; + } } - }, - installMock: function() { - if (typeof jQuery != 'undefined') { - jasmine.Ajax.installJquery(); - } else { - throw new Error("jasmine.Ajax currently only supports jQuery"); + var xmlParsables = ['text/xml', 'application/xml']; + + function getResponseXml(responseText, contentType) { + if (arrayContains(xmlParsables, contentType.toLowerCase())) { + return parseXml(responseText, contentType); + } else if (contentType.match(/\+xml$/)) { + return parseXml(responseText, 'text/xml'); + } + return null; } - jasmine.Ajax.installed = true; - }, - installJquery: function() { - jasmine.Ajax.mode = 'jQuery'; - jasmine.Ajax.real = jQuery.ajaxSettings.xhr; - jQuery.ajaxSettings.xhr = jasmine.Ajax.jQueryMock; + var iePropertiesThatCannotBeCopied = ['responseBody', 'responseText', 'responseXML', 'status', 'statusText', 'responseTimeout', 'responseURL']; + extend(FakeXMLHttpRequest.prototype, new global.XMLHttpRequest(), iePropertiesThatCannotBeCopied); + extend(FakeXMLHttpRequest.prototype, { + open: function() { + this.method = arguments[0]; + this.url = arguments[1]; + this.username = arguments[3]; + this.password = arguments[4]; + this.readyState = 1; + this.requestHeaders = {}; + this.eventBus.trigger('readystatechange'); + }, - }, + setRequestHeader: function(header, value) { + if(this.requestHeaders.hasOwnProperty(header)) { + this.requestHeaders[header] = [this.requestHeaders[header], value].join(', '); + } else { + this.requestHeaders[header] = value; + } + }, - uninstallMock: function() { - jasmine.Ajax.assertInstalled(); - if (jasmine.Ajax.mode == 'jQuery') { - jQuery.ajaxSettings.xhr = jasmine.Ajax.real; - } - jasmine.Ajax.reset(); - }, + overrideMimeType: function(mime) { + this.overriddenMimeType = mime; + }, - reset: function() { - jasmine.Ajax.installed = false; - jasmine.Ajax.mode = null; - jasmine.Ajax.real = null; - }, + abort: function() { + this.readyState = 0; + this.status = 0; + this.statusText = "abort"; + this.eventBus.trigger('readystatechange'); + this.eventBus.trigger('progress'); + this.eventBus.trigger('abort'); + this.eventBus.trigger('loadend'); + }, - jQueryMock: function() { - var newXhr = new FakeXMLHttpRequest(); - ajaxRequests.push(newXhr); - return newXhr; - }, + readyState: 0, - installed: false, - mode: null + onloadstart: null, + onprogress: null, + onabort: null, + onerror: null, + onload: null, + ontimeout: null, + onloadend: null, + onreadystatechange: null, + + addEventListener: function() { + this.eventBus.addEventListener.apply(this.eventBus, arguments); + }, + + removeEventListener: function(event, callback) { + this.eventBus.removeEventListener.apply(this.eventBus, arguments); + }, + + status: null, + + send: function(data) { + this.params = data; + this.eventBus.trigger('loadstart'); + + var stub = stubTracker.findStub(this.url, data, this.method); + if (stub) { + if (stub.isReturn()) { + this.respondWith(stub); + } else if (stub.isError()) { + this.responseError(); + } else if (stub.isTimeout()) { + this.responseTimeout(); + } + } + }, + + contentType: function() { + return findHeader('content-type', this.requestHeaders); + }, + + data: function() { + if (!this.params) { + return {}; + } + + return paramParser.findParser(this).parse(this.params); + }, + + getResponseHeader: function(name) { + name = name.toLowerCase(); + var resultHeader; + for(var i = 0; i < this.responseHeaders.length; i++) { + var header = this.responseHeaders[i]; + if (name === header.name.toLowerCase()) { + if (resultHeader) { + resultHeader = [resultHeader, header.value].join(', '); + } else { + resultHeader = header.value; + } + } + } + return resultHeader; + }, + + getAllResponseHeaders: function() { + var responseHeaders = []; + for (var i = 0; i < this.responseHeaders.length; i++) { + responseHeaders.push(this.responseHeaders[i].name + ': ' + + this.responseHeaders[i].value); + } + return responseHeaders.join('\r\n') + '\r\n'; + }, + + responseText: null, + response: null, + responseType: null, + responseURL: null, + + responseValue: function() { + switch(this.responseType) { + case null: + case "": + case "text": + return this.readyState >= 3 ? this.responseText : ""; + case "json": + return JSON.parse(this.responseText); + case "arraybuffer": + throw unconvertibleResponseTypeMessage('arraybuffer'); + case "blob": + throw unconvertibleResponseTypeMessage('blob'); + case "document": + return this.responseXML; + } + }, + + + respondWith: function(response) { + if (this.readyState === 4) { + throw new Error("FakeXMLHttpRequest already completed"); + } + + this.status = response.status; + this.statusText = response.statusText || ""; + this.responseHeaders = normalizeHeaders(response.responseHeaders, response.contentType); + this.readyState = 2; + this.eventBus.trigger('readystatechange'); + + this.responseText = response.responseText || ""; + this.responseType = response.responseType || ""; + this.responseURL = response.responseURL || null; + this.readyState = 4; + this.responseXML = getResponseXml(response.responseText, this.getResponseHeader('content-type') || ''); + if (this.responseXML) { + this.responseType = 'document'; + } + + if ('response' in response) { + this.response = response.response; + } else { + this.response = this.responseValue(); + } + + this.eventBus.trigger('readystatechange'); + this.eventBus.trigger('progress'); + this.eventBus.trigger('load'); + this.eventBus.trigger('loadend'); + }, + + responseTimeout: function() { + if (this.readyState === 4) { + throw new Error("FakeXMLHttpRequest already completed"); + } + this.readyState = 4; + jasmine.clock().tick(30000); + this.eventBus.trigger('readystatechange'); + this.eventBus.trigger('progress'); + this.eventBus.trigger('timeout'); + this.eventBus.trigger('loadend'); + }, + + responseError: function() { + if (this.readyState === 4) { + throw new Error("FakeXMLHttpRequest already completed"); + } + this.readyState = 4; + this.eventBus.trigger('readystatechange'); + this.eventBus.trigger('progress'); + this.eventBus.trigger('error'); + this.eventBus.trigger('loadend'); + } + }); + + return FakeXMLHttpRequest; + } + + return fakeRequest; }; + +getJasmineRequireObj().MockAjax = function($ajax) { + function MockAjax(global) { + var requestTracker = new $ajax.RequestTracker(), + stubTracker = new $ajax.StubTracker(), + paramParser = new $ajax.ParamParser(), + realAjaxFunction = global.XMLHttpRequest, + mockAjaxFunction = $ajax.fakeRequest(global, requestTracker, stubTracker, paramParser); + + this.install = function() { + if (global.XMLHttpRequest === mockAjaxFunction) { + throw "MockAjax is already installed."; + } + + global.XMLHttpRequest = mockAjaxFunction; + }; + + this.uninstall = function() { + if (global.XMLHttpRequest !== mockAjaxFunction) { + throw "MockAjax not installed."; + } + global.XMLHttpRequest = realAjaxFunction; + + this.stubs.reset(); + this.requests.reset(); + paramParser.reset(); + }; + + this.stubRequest = function(url, data, method) { + var stub = new $ajax.RequestStub(url, data, method); + stubTracker.addStub(stub); + return stub; + }; + + this.withMock = function(closure) { + this.install(); + try { + closure(); + } finally { + this.uninstall(); + } + }; + + this.addCustomParamParser = function(parser) { + paramParser.add(parser); + }; + + this.requests = requestTracker; + this.stubs = stubTracker; + } + + return MockAjax; +}; + +getJasmineRequireObj().AjaxParamParser = function() { + function ParamParser() { + var defaults = [ + { + test: function(xhr) { + return (/^application\/json/).test(xhr.contentType()); + }, + parse: function jsonParser(paramString) { + return JSON.parse(paramString); + } + }, + { + test: function(xhr) { + return true; + }, + parse: function naiveParser(paramString) { + var data = {}; + var params = paramString.split('&'); + + for (var i = 0; i < params.length; ++i) { + var kv = params[i].replace(/\+/g, ' ').split('='); + var key = decodeURIComponent(kv[0]); + data[key] = data[key] || []; + data[key].push(decodeURIComponent(kv[1])); + } + return data; + } + } + ]; + var paramParsers = []; + + this.add = function(parser) { + paramParsers.unshift(parser); + }; + + this.findParser = function(xhr) { + for(var i in paramParsers) { + var parser = paramParsers[i]; + if (parser.test(xhr)) { + return parser; + } + } + }; + + this.reset = function() { + paramParsers = []; + for(var i in defaults) { + paramParsers.push(defaults[i]); + } + }; + + this.reset(); + } + + return ParamParser; +}; + +getJasmineRequireObj().AjaxRequestStub = function() { + var RETURN = 0, + ERROR = 1, + TIMEOUT = 2; + + function RequestStub(url, stubData, method) { + var normalizeQuery = function(query) { + return query ? query.split('&').sort().join('&') : undefined; + }; + + if (url instanceof RegExp) { + this.url = url; + this.query = undefined; + } else { + var split = url.split('?'); + this.url = split[0]; + this.query = split.length > 1 ? normalizeQuery(split[1]) : undefined; + } + + this.data = (stubData instanceof RegExp) ? stubData : normalizeQuery(stubData); + this.method = method; + + this.andReturn = function(options) { + this.action = RETURN; + this.status = options.status || 200; + + this.contentType = options.contentType; + this.response = options.response; + this.responseText = options.responseText; + this.responseHeaders = options.responseHeaders; + this.responseURL = options.responseURL; + }; + + this.isReturn = function() { + return this.action === RETURN; + }; + + this.andError = function() { + this.action = ERROR; + }; + + this.isError = function() { + return this.action === ERROR; + }; + + this.andTimeout = function() { + this.action = TIMEOUT; + }; + + this.isTimeout = function() { + return this.action === TIMEOUT; + }; + + this.matches = function(fullUrl, data, method) { + var urlMatches = false; + fullUrl = fullUrl.toString(); + if (this.url instanceof RegExp) { + urlMatches = this.url.test(fullUrl); + } else { + var urlSplit = fullUrl.split('?'), + url = urlSplit[0], + query = urlSplit[1]; + urlMatches = this.url === url && this.query === normalizeQuery(query); + } + var dataMatches = false; + if (this.data instanceof RegExp) { + dataMatches = this.data.test(data); + } else { + dataMatches = !this.data || this.data === normalizeQuery(data); + } + return urlMatches && dataMatches && (!this.method || this.method === method); + }; + } + + return RequestStub; +}; + +getJasmineRequireObj().AjaxRequestTracker = function() { + function RequestTracker() { + var requests = []; + + this.track = function(request) { + requests.push(request); + }; + + this.first = function() { + return requests[0]; + }; + + this.count = function() { + return requests.length; + }; + + this.reset = function() { + requests = []; + }; + + this.mostRecent = function() { + return requests[requests.length - 1]; + }; + + this.at = function(index) { + return requests[index]; + }; + + this.filter = function(url_to_match) { + var matching_requests = []; + + for (var i = 0; i < requests.length; i++) { + + if (url_to_match instanceof RegExp && + url_to_match.test(requests[i].url)) { + matching_requests.push(requests[i]); + } else if (url_to_match instanceof Function && + url_to_match(requests[i])) { + matching_requests.push(requests[i]); + } else { + if (requests[i].url === url_to_match) { + matching_requests.push(requests[i]); + } + } + } + + return matching_requests; + }; + } + + return RequestTracker; +}; + +getJasmineRequireObj().AjaxStubTracker = function() { + function StubTracker() { + var stubs = []; + + this.addStub = function(stub) { + stubs.push(stub); + }; + + this.reset = function() { + stubs = []; + }; + + this.findStub = function(url, data, method) { + for (var i = stubs.length - 1; i >= 0; i--) { + var stub = stubs[i]; + if (stub.matches(url, data, method)) { + return stub; + } + } + }; + } + + return StubTracker; +}; + + + var jRequire = getJasmineRequireObj(); + var MockAjax = jRequire.ajax(jRequire); + jasmine.Ajax = new MockAjax(global); + + return MockAjax; +})); \ No newline at end of file diff --git a/common/static/js_test.yml b/common/static/js_test.yml index 13cea1b163..f30e2719d2 100644 --- a/common/static/js_test.yml +++ b/common/static/js_test.yml @@ -29,8 +29,8 @@ prepend_path: common/static # Paths to library JavaScript files (optional) lib_paths: - js/vendor/jquery.min.js - - js/vendor/jasmine-jquery.js - js/vendor/jasmine-imagediff.js + - js/libs/jasmine-waituntil.js - js/vendor/jquery.truncate.js - js/vendor/mustache.js - common/js/vendor/underscore.js diff --git a/common/static/js_test_requirejs.yml b/common/static/js_test_requirejs.yml index 123bd99827..e0e47a4e86 100644 --- a/common/static/js_test_requirejs.yml +++ b/common/static/js_test_requirejs.yml @@ -29,8 +29,9 @@ prepend_path: common/static # Paths to library JavaScript files (optional) lib_paths: - js/vendor/jquery.min.js - - js/vendor/jasmine-jquery.js - js/vendor/jasmine-imagediff.js + - js/libs/jasmine-stealth.js + - js/libs/jasmine-waituntil.js - js/vendor/jquery.simulate.js - js/vendor/jquery.truncate.js - common/js/vendor/underscore.js @@ -45,7 +46,6 @@ lib_paths: - coffee/src/jquery.immediateDescendents.js - js/vendor/requirejs/text.js - js/vendor/sinon-1.17.0.js - - js/vendor/jasmine-stealth.js # Paths to source JavaScript files src_paths: diff --git a/common/static/karma_common.conf.js b/common/static/karma_common.conf.js index aa57a78cab..7d4f81b81c 100644 --- a/common/static/karma_common.conf.js +++ b/common/static/karma_common.conf.js @@ -34,6 +34,7 @@ var files = [ {pattern: 'js/vendor/jquery.min.js', included: true}, {pattern: 'js/vendor/jasmine-imagediff.js', included: true}, {pattern: 'js/libs/jasmine-waituntil.js', included: true}, + {pattern: 'js/libs/jasmine-extensions.js', included: true}, {pattern: 'js/vendor/jquery.truncate.js', included: true}, {pattern: 'js/vendor/mustache.js', included: true}, {pattern: 'common/js/vendor/underscore.js', included: true}, @@ -45,6 +46,7 @@ var files = [ {pattern: 'js/test/add_ajax_prefix.js', included: true}, {pattern: 'js/test/i18n.js', included: true}, {pattern: 'coffee/src/jquery.immediateDescendents.js', included: true}, + {pattern: 'js/vendor/jquery.leanModal.js', included: true}, // Paths to source JavaScript files {pattern: 'js/xblock/**/*.js', included: true, nocache: true}, diff --git a/common/static/karma_common_requirejs.conf.js b/common/static/karma_common_requirejs.conf.js index 0e27aa8b9f..f88d88d222 100644 --- a/common/static/karma_common_requirejs.conf.js +++ b/common/static/karma_common_requirejs.conf.js @@ -32,6 +32,7 @@ var files = [ {pattern: 'js/vendor/jasmine-imagediff.js', included: false}, {pattern: 'js/libs/jasmine-stealth.js', included: false}, {pattern: 'js/libs/jasmine-waituntil.js', included: false}, + {pattern: 'js/libs/jasmine-extensions.js', included: false}, {pattern: 'js/vendor/jquery.simulate.js', included: false}, {pattern: 'js/vendor/jquery.truncate.js', included: false}, {pattern: 'common/js/vendor/underscore.js', included: false},