fix js:test for OSX, plugins, and dynamic manifest
no more maintaining spec/javascripts/supports/specs.js to tell the runner which specs to run. instead, the runner is built from an erb that determines the list of specs to run from the filesystem. this new way is also plugin friendly by maintaining a plugin symlink to include plugin specs in the spec/coffeescripts tree. second, give the runner page to the phantomjs execution as a file:/// path rather than just a local path. the latter worked on the build machine, but failed with the phantomjs installed viw macbrew. third, clean up/out some slightly broken specs. * ENVSpec fails when the specs are reordered by the dynamic globbing, but is no longer necessary anyways (since ENV is global now) * the 'specs/helpers/' path in TemplateSpec doesn't work with the new setup, but just 'helpers/' does and is what it should have been using before anyways. * asyncTest is not reliable. once the specs started running in a slightly different order (thanks to the initial point), they started failing with asyncTest race conditions. use fakeTimers and fakeServers instead when appropriate. * found and fixed a minor bug in BackoffPoller while converting/fixing its asyncTests test-plan: - run rake js:test; should run completely as before - add a plugin with a spec in spec_canvas/coffeescripts then run rake js:test again; the plugin's spec should be executed. Change-Id: I9ce5a038829a9e747df26d878ce86dbb7da8c384 Reviewed-on: https://gerrit.instructure.com/9411 Reviewed-by: Jon Jensen <jon@instructure.com> Tested-by: Hudson <hudson@instructure.com>
This commit is contained in:
parent
fbf9aab150
commit
aba524e43f
|
@ -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/
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 =>
|
||||
@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'
|
||||
start()
|
||||
, 300
|
||||
|
||||
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]
|
||||
|
||||
setTimeout =>
|
||||
@clock.tick 300
|
||||
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
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
define [
|
||||
'specs/helpers/testTemplate'
|
||||
'helpers/testTemplate'
|
||||
'compiled/Template'
|
||||
], (_,Template) ->
|
||||
|
||||
|
|
|
@ -12,7 +12,15 @@ require [
|
|||
@$holder = $('<table />').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", ->
|
||||
|
|
|
@ -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 = $('<a class="help_dialog_trigger" />').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"
|
||||
|
|
|
@ -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 =>
|
||||
# let the first interval expire, and then respond to the request
|
||||
@clock.tick 10
|
||||
@server.respond()
|
||||
|
||||
ok poller.running, "poller should be running"
|
||||
poller.stop(false)
|
||||
start()
|
||||
, 100
|
||||
|
||||
asyncTest 'should reset polling when it gets a "reset"', ->
|
||||
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 =>
|
||||
# let the first interval expire, and then respond to the request
|
||||
@clock.tick 10
|
||||
@server.respond()
|
||||
|
||||
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
|
||||
|
||||
asyncTest 'should stop polling when it gets a "stop"', ->
|
||||
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 =>
|
||||
# let the four 'continue' intervals expire, responding after each
|
||||
for i in [0...4]
|
||||
@clock.tick 10
|
||||
@server.respond()
|
||||
|
||||
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"
|
||||
start()
|
||||
, 100
|
||||
|
||||
asyncTest 'should abort polling when it hits maxAttempts', ->
|
||||
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 =>
|
||||
# let the first two intervals expire, responding after each
|
||||
for i in [0...2]
|
||||
@clock.tick 10
|
||||
@server.respond()
|
||||
|
||||
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"
|
||||
start()
|
||||
, 100
|
||||
|
||||
asyncTest 'should abort polling when it gets anything else', ->
|
||||
count = 0
|
||||
test 'should abort polling when it gets anything else', ->
|
||||
poller = new BackoffPoller 'fixtures/ok.json', ->
|
||||
'omgwtfbbq'
|
||||
, baseInterval: 10
|
||||
|
||||
poller.start().then(@callback)
|
||||
|
||||
setTimeout =>
|
||||
# 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"
|
||||
start()
|
||||
, 100
|
||||
|
|
|
@ -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'
|
||||
},
|
||||
]
|
||||
};
|
||||
</script>
|
||||
|
@ -86,7 +84,7 @@
|
|||
<script>
|
||||
// don't run specs until they are all loaded
|
||||
stop();
|
||||
require(['specs'], function() {
|
||||
require(<%= Dir["spec/javascripts/**/*Spec.js"].map{ |file| file.sub(/\.js$/, '') }.inspect %>, function() {
|
||||
// run specs once they've all loaded
|
||||
start();
|
||||
});
|
|
@ -1,21 +0,0 @@
|
|||
require([
|
||||
'specs/TemplateSpec',
|
||||
'specs/CustomListSpec',
|
||||
'specs/invokerSpec',
|
||||
'specs/class/cacheSpec',
|
||||
'specs/xhr/remoteSelectSpec',
|
||||
'specs/jQuery.instructureMiscPluginsSpec',
|
||||
'specs/userNamePartsSpec',
|
||||
'specs/objectCollectionSpec',
|
||||
'specs/helpDialogSpec',
|
||||
'specs/paginatedListSpec',
|
||||
'specs/util/BackoffPollerSpec',
|
||||
'specs/jQuery.instructureJqueryPatchesSpec',
|
||||
'specs/ENVSpec',
|
||||
'specs/calendar/TimeBlockListManagerSpec',
|
||||
'specs/calendar/TimeBlockListSpec',
|
||||
'specs/calendar/TimeBlockRowSpec',
|
||||
'specs/util/processMigrationItemSelectionsSpec',
|
||||
'specs/util/processItemSelectionsSpec'
|
||||
]);
|
||||
|
Loading…
Reference in New Issue