diff --git a/.gitignore b/.gitignore index 3630fde963b..04ba4c897fa 100644 --- a/.gitignore +++ b/.gitignore @@ -54,7 +54,10 @@ public/doc/api/* .yardoc/* spec/javascripts/*Spec.js spec/javascripts/*/*Spec.js -spec/javascripts/helpers/* +spec/javascripts/*/*/*Spec.js +spec/javascripts/helpers/ +spec/javascripts/plugins/ +spec/javascripts/runner.html public/optimized !node_modules chromedriver.log @@ -62,3 +65,4 @@ public/plugins/ app/coffeescripts/plugins/ app/views/jst/plugins/ app/stylesheets/plugins/ +spec/coffeescripts/plugins/ diff --git a/app/coffeescripts/discussions/Topic.coffee b/app/coffeescripts/discussions/Topic.coffee index 02b81ddb279..4bb6be99de8 100644 --- a/app/coffeescripts/discussions/Topic.coffee +++ b/app/coffeescripts/discussions/Topic.coffee @@ -33,7 +33,7 @@ define [ initialDelay: false # we'll abort after about 10 minutes baseInterval: 2000 - maxAttempts: 11 + maxAttempts: 12 backoffFactor: 1.6 loader.start() diff --git a/app/coffeescripts/util/BackoffPoller.coffee b/app/coffeescripts/util/BackoffPoller.coffee index da14c5de635..f3242f9e92b 100644 --- a/app/coffeescripts/util/BackoffPoller.coffee +++ b/app/coffeescripts/util/BackoffPoller.coffee @@ -73,7 +73,7 @@ define [ return @poll() if not @initialDelay else @nextInterval = parseInt(@nextInterval * @backoffFactor) - return @stop() if @attempts > @maxAttempts + return @stop() if @attempts >= @maxAttempts @running = setTimeout @poll, @nextInterval diff --git a/config/initializers/plugin_symlinks.rb b/config/initializers/plugin_symlinks.rb index 0a373f9262f..983f89843ac 100644 --- a/config/initializers/plugin_symlinks.rb +++ b/config/initializers/plugin_symlinks.rb @@ -1,9 +1,10 @@ -def maintain_plugin_symlinks(relative_path) - Dir.glob("vendor/plugins/*/#{relative_path}").each do |plugin_dir| - Dir.mkdir("#{relative_path}/plugins") unless File.exists?("#{relative_path}/plugins") - plugin = plugin_dir.gsub(%r{^vendor/plugins/(.*)/#{relative_path}$}, '\1') - source = "#{relative_path}/plugins/#{plugin}" - target = "#{relative_path.gsub(%r{[^/]+}, '..')}/../#{plugin_dir}" +def maintain_plugin_symlinks(local_path, plugin_path=nil) + plugin_path ||= local_path + Dir.glob("vendor/plugins/*/#{plugin_path}").each do |plugin_dir| + Dir.mkdir("#{local_path}/plugins") unless File.exists?("#{local_path}/plugins") + plugin = plugin_dir.gsub(%r{^vendor/plugins/(.*)/#{plugin_path}$}, '\1') + source = "#{local_path}/plugins/#{plugin}" + target = "#{local_path.gsub(%r{[^/]+}, '..')}/../#{plugin_dir}" unless File.symlink?(source) && File.readlink(source) == target File.unlink(source) if File.exists?(source) File.symlink(target, source) @@ -15,3 +16,4 @@ maintain_plugin_symlinks('public') maintain_plugin_symlinks('app/coffeescripts') maintain_plugin_symlinks('app/views/jst') maintain_plugin_symlinks('app/stylesheets') +maintain_plugin_symlinks('spec/coffeescripts', 'spec_canvas/coffeescripts') diff --git a/lib/tasks/js.rake b/lib/tasks/js.rake index cd4920368fb..c371b9e735d 100644 --- a/lib/tasks/js.rake +++ b/lib/tasks/js.rake @@ -8,7 +8,8 @@ namespace :js do Rake::Task['js:generate'].invoke end puts "--> executing phantomjs tests" - phantomjs_output = `phantomjs spec/javascripts/support/qunit/test.js spec/javascripts/runner.html` + `erb spec/javascripts/runner.html.erb > spec/javascripts/runner.html` + phantomjs_output = `phantomjs spec/javascripts/support/qunit/test.js file:///#{Dir.pwd}/spec/javascripts/runner.html` exit_status = $?.exitstatus puts phantomjs_output raise "PhantomJS tests failed" if exit_status != 0 @@ -35,8 +36,13 @@ namespace :js do # files that don't map to any source file anymore FileUtils.rm_rf('public/javascripts/compiled') FileUtils.rm_rf('public/javascripts/jst') - FileUtils.rm_rf('public/plugins/*/javascripts/compiled') - FileUtils.rm_rf('public/plugins/*/javascripts/jst') + Dir.glob('spec/javascripts/**/*Spec.js') do |compiled_spec| + FileUtils.rm_f(compiled_spec) + end + Dir.glob('public/plugins/*/javascripts') do |plugin_dir| + FileUtils.rm_rf(plugin_dir + '/compiled') + FileUtils.rm_rf(plugin_dir + '/javascripts/jst') + end puts "--> Pre-compiling all handlebars templates" Rake::Task['jst:compile'].invoke diff --git a/spec/coffeescripts/CustomListSpec.coffee b/spec/coffeescripts/CustomListSpec.coffee index 63da6637313..34b0f51d8c4 100644 --- a/spec/coffeescripts/CustomListSpec.coffee +++ b/spec/coffeescripts/CustomListSpec.coffee @@ -20,17 +20,22 @@ define [ appendTarget: @fixture.find('#customList') @list.open() @lis = @fixture.find('.customListItem') + @clock = sinon.useFakeTimers() teardown: -> + @clock.restore() @fixture.detach() test 'should open and close', -> @list.close() + @clock.tick 1 equal @list.wrapper.is(':visible'), false, 'starts hidden' + @list.open() + @clock.tick 1 equal @list.wrapper.is(':visible'), true, 'displays on open' - asyncTest 'should remove and add the first item', 2, -> + test 'should remove and add the first item', -> # store original length to compare to later originalLength = @list.targetList.children().length @@ -40,44 +45,45 @@ define [ # this next click should get ignored because the previous element is animating simulateClick( @lis[1] ) - setTimeout => - expectedLength = originalLength - 1 - equal @list.pinned.length, expectedLength, 'only one item should have been removed' - simulateClick( @lis[0] ) - equal @list.pinned.length, originalLength, 'item should be restored' - start() - , 300 + @clock.tick 300 + expectedLength = originalLength - 1 + equal @list.pinned.length, expectedLength, 'only one item should have been removed' + + simulateClick( @lis[0] ) + @clock.tick 300 + equal @list.pinned.length, originalLength, 'item should be restored' test 'should cancel pending add request on remove', -> # Add one that doesn't exist el = jQuery @lis[16] @list.add(16, el) + @clock.tick 300 ok @list.requests.add[16], 'create an "add" request' # then immediately remove it before the request has time to come back item = @list.pinned.findBy 'id', 16 @list.remove item, el + @clock.tick 300 equal @list.requests.add[16], undefined, 'delete "add" request' test 'should cancel pending remove request on add', -> el = jQuery @lis[1] item = @list.pinned.findBy('id', 1) @list.remove(item, el) + @clock.tick 300 ok @list.requests.remove[1], 'create a "remove" request' @list.add 1, el + @clock.tick 300 equal @list.requests.remove[1], undefined, 'delete "remove" request' - asyncTest 'should reset', 2, -> + test 'should reset', -> originalLength = @list.targetList.children().length simulateClick @lis[0] + @clock.tick 300 + ok originalLength isnt @list.targetList.children().length, 'length should be different' - setTimeout => - ok originalLength isnt @list.targetList.children().length, 'length should be different' - - @list.reset() - length = @list.targetList.children().length - equal length, originalLength, 'targetList items restored' - start() - , 300 + @list.reset() + length = @list.targetList.children().length + equal length, originalLength, 'targetList items restored' diff --git a/spec/coffeescripts/ENVSpec.coffee b/spec/coffeescripts/ENVSpec.coffee deleted file mode 100644 index e608fc59486..00000000000 --- a/spec/coffeescripts/ENVSpec.coffee +++ /dev/null @@ -1,16 +0,0 @@ -define ['require'], (require) -> - - module 'ENV' - - asyncTest 'simple', -> - require ['ENV'], (env1) -> - env1.thing1 = 3 - require ['ENV'], (env2) -> - env2.thing2 = 4 - equal env1.thing1, 3 - equal env1.thing2, 4 - equal env2.thing1, 3 - equal env2.thing2, 4 - strictEqual env1, env2 - start() - diff --git a/spec/coffeescripts/TemplateSpec.coffee b/spec/coffeescripts/TemplateSpec.coffee index ecdc3192449..e4809d04103 100644 --- a/spec/coffeescripts/TemplateSpec.coffee +++ b/spec/coffeescripts/TemplateSpec.coffee @@ -1,5 +1,5 @@ define [ - 'specs/helpers/testTemplate' + 'helpers/testTemplate' 'compiled/Template' ], (_,Template) -> diff --git a/spec/coffeescripts/calendar/TimeBlockRowSpec.coffee b/spec/coffeescripts/calendar/TimeBlockRowSpec.coffee index 6c49d1bc7c1..fa9094a59a1 100644 --- a/spec/coffeescripts/calendar/TimeBlockRowSpec.coffee +++ b/spec/coffeescripts/calendar/TimeBlockRowSpec.coffee @@ -12,7 +12,15 @@ require [ @$holder = $('').appendTo(document.body) @timeBlockList = new TimeBlockList(@$holder) + # fakeTimer'd because the tests with failed validations add an error box + # that is faded in. if we don't tick past the fade-in, other unrelated + # tests that use fake timers fail. + @clock = sinon.useFakeTimers((new Date()).valueOf()) + teardown: -> + # tick past any remaining errorBox fade-ins + @clock.tick 250 + @clock.restore() @$holder.detach() test "should init properly", -> diff --git a/spec/coffeescripts/helpDialogSpec.coffee b/spec/coffeescripts/helpDialogSpec.coffee index 78b2cbc1da9..2df8452d929 100644 --- a/spec/coffeescripts/helpDialogSpec.coffee +++ b/spec/coffeescripts/helpDialogSpec.coffee @@ -2,8 +2,6 @@ require [ 'compiled/helpDialog' 'vendor/jquery.ba-tinypubsub' 'helpers/fakeENV' - 'helpers/ajax_mocks/help_links' - 'helpers/ajax_mocks/api/v1/courses' ], (helpDialog)-> @@ -14,23 +12,39 @@ require [ ie: true version: 8 - module 'HelpDialog Static methods' + module 'HelpDialog', - test 'init', 1, -> + setup: -> + @clock = sinon.useFakeTimers() + @server = sinon.fakeServer.create() + @server.respondWith '/help_links', '[]' + @server.respondWith '/api/v1/courses.json', '[]' + + teardown: -> + @server.restore() + + # if we don't close it after each test, subsequent tests get messed up. + # additionally, closing it starts an animation, so tick past that. + if helpDialog.$dialog? + helpDialog.$dialog.dialog('close') #cleanup + @clock.tick 200 + @clock.restore() + + # reset the shared object + helpDialog.dialogInited = false + helpDialog.teacherFeedbackInited = false + + test 'init', -> $tester = $('').appendTo('body') helpDialog.initTriggers() $tester.click() ok $('.ui-dialog-content').is(':visible'), "help dialog appears when you click 'help' link" - module 'HelpDialog' - - asyncTest 'teacher feedback', 1, -> - $(helpDialog).bind 'ready', -> - helpDialog.switchTo "#teacher_feedback" - setTimeout -> - ok helpDialog.$dialog.find('#teacher-feedback-body').is(':visible'), "textarea shows up" - helpDialog.$dialog.dialog('close') #cleanup - start() - , 101 + test 'teacher feedback', -> helpDialog.open() + @server.respond() + helpDialog.switchTo "#teacher_feedback" + @clock.tick 200 + + ok helpDialog.$dialog.find('#teacher-feedback-body').is(':visible'), "textarea shows up" diff --git a/spec/coffeescripts/util/BackoffPollerSpec.coffee b/spec/coffeescripts/util/BackoffPollerSpec.coffee index 8166137b949..b0362c068e1 100644 --- a/spec/coffeescripts/util/BackoffPollerSpec.coffee +++ b/spec/coffeescripts/util/BackoffPollerSpec.coffee @@ -5,70 +5,91 @@ define ['compiled/util/BackoffPoller'], (BackoffPoller)-> @ran_callback = false @callback = => @ran_callback = true + @clock = sinon.useFakeTimers() + @server = sinon.fakeServer.create() + @server.respondWith 'fixtures/ok.json', '{"status":"ok"}' - asyncTest 'should keep polling when it gets a "continue"', -> + teardown: -> + @clock.restore() + @server.restore() + + test 'should keep polling when it gets a "continue"', -> poller = new BackoffPoller 'fixtures/ok.json', -> 'continue' , backoffFactor: 1, baseInterval: 10, maxAttempts: 100 - poller.start().then(@callback) - setTimeout => - ok poller.running, "poller should be running" - poller.stop(false) - start() - , 100 + # let the first interval expire, and then respond to the request + @clock.tick 10 + @server.respond() - asyncTest 'should reset polling when it gets a "reset"', -> + ok poller.running, "poller should be running" + poller.stop(false) + + test 'should reset polling when it gets a "reset"', -> poller = new BackoffPoller 'fixtures/ok.json', -> 'reset' , backoffFactor: 1, baseInterval: 10, maxAttempts: 100 poller.start().then(@callback) - setTimeout => - ok poller.running, "poller should be running" - ok poller.attempts <= 1, "counter should be reset" # either zero or one, depending on whether we're waiting for a timeout or an ajax call - poller.stop(false) - start() - , 100 + # let the first interval expire, and then respond to the request + @clock.tick 10 + @server.respond() - asyncTest 'should stop polling when it gets a "stop"', -> + ok poller.running, "poller should be running" + ok poller.attempts <= 1, "counter should be reset" # either zero or one, depending on whether we're waiting for a timeout or an ajax call + poller.stop(false) + + test 'should stop polling when it gets a "stop"', -> count = 0 poller = new BackoffPoller 'fixtures/ok.json', -> if count++ > 3 then 'stop' else 'continue' , backoffFactor: 1, baseInterval: 10 - poller.start().then(@callback) - setTimeout => - ok not poller.running, "poller should be stopped" - ok @ran_callback, "poller should have run callbacks" - start() - , 100 + # let the four 'continue' intervals expire, responding after each + for i in [0...4] + @clock.tick 10 + @server.respond() - asyncTest 'should abort polling when it hits maxAttempts', -> + ok poller.running, "poller should be running" + + # let the final 'stop' interval expire, and then respond to the request + @clock.tick 10 + @server.respond() + + ok not poller.running, "poller should be stopped" + ok @ran_callback, "poller should have run callbacks" + + test 'should abort polling when it hits maxAttempts', -> poller = new BackoffPoller 'fixtures/ok.json', -> 'continue' , backoffFactor: 1, baseInterval: 10, maxAttempts: 3 - poller.start().then(@callback) - setTimeout => - ok not poller.running, "poller should be stopped" - ok not @ran_callback, "poller should not have run callbacks" - start() - , 100 + # let the first two intervals expire, responding after each + for i in [0...2] + @clock.tick 10 + @server.respond() - asyncTest 'should abort polling when it gets anything else', -> - count = 0 + ok poller.running, "poller should be running" + + # let the final interval expire, and then respond to the request + @clock.tick 10 + @server.respond() + + ok not poller.running, "poller should be stopped" + ok not @ran_callback, "poller should not have run callbacks" + + test 'should abort polling when it gets anything else', -> poller = new BackoffPoller 'fixtures/ok.json', -> 'omgwtfbbq' , baseInterval: 10 - poller.start().then(@callback) - setTimeout => - ok not poller.running, "poller should be stopped" - ok not @ran_callback, "poller should not have run callbacks" - start() - , 100 + # let the interval expire, and then respond to the request + @clock.tick 10 + @server.respond() + + ok not poller.running, "poller should be stopped" + ok not @ran_callback, "poller should not have run callbacks" diff --git a/spec/javascripts/runner.html b/spec/javascripts/runner.html.erb similarity index 91% rename from spec/javascripts/runner.html rename to spec/javascripts/runner.html.erb index 80ddd32b5e5..d81942dd5e3 100644 --- a/spec/javascripts/runner.html +++ b/spec/javascripts/runner.html.erb @@ -61,12 +61,6 @@ name: 'jqueryui', location: 'vendor/jqueryui' }, - { - name: 'specs', - location: '../../spec/javascripts', - main: 'support/specs', - lib: './' - }, { name: 'helpers', location: '../../spec/javascripts/helpers', @@ -78,7 +72,11 @@ location: '../../spec/javascripts/support', main: 'support', lib: './' - } + }, + { + name: 'spec', + location: '../../spec' + }, ] }; @@ -86,7 +84,7 @@