Merge pull request #1053 from MITx/feature/jzoldak/common-jasmine-tests
Capa Problem jasmine tests running independently
This commit is contained in:
1
common/lib/.gitignore
vendored
Normal file
1
common/lib/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*/jasmine_test_runner.html
|
||||
44
common/lib/xmodule/jasmine_test_runner.html.erb
Normal file
44
common/lib/xmodule/jasmine_test_runner.html.erb
Normal file
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Jasmine Test Runner</title>
|
||||
<link rel="stylesheet" type="text/css" href="<%= phantom_jasmine_path %>/vendor/jasmine-1.2.0/jasmine.css">
|
||||
<script type="text/javascript" src="<%= phantom_jasmine_path %>/vendor/jasmine-1.2.0/jasmine.js"></script>
|
||||
<script type="text/javascript" src="<%= phantom_jasmine_path %>/vendor/jasmine-1.2.0/jasmine-html.js"></script>
|
||||
|
||||
<script type="text/javascript" src="<%= phantom_jasmine_path %>/lib/console-runner.js"></script>
|
||||
<script type="text/javascript" src="<%= common_coffee_root %>/ajax_prefix.js"></script>
|
||||
<script type="text/javascript" src="<%= common_coffee_root %>/logger.js"></script>
|
||||
<script type="text/javascript" src="<%= common_js_root %>/vendor/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="<%= common_js_root %>/vendor/jasmine-jquery.js"></script>
|
||||
<script type="text/javascript" src="<%= common_js_root %>/vendor/mathjax-MathJax-c9db6ac/MathJax.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
AjaxPrefix.addAjaxPrefix(jQuery, function() {
|
||||
return "";
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- SOURCE FILES -->
|
||||
<% for src in js_source %>
|
||||
<script type="text/javascript" src="<%= src %>"></script>
|
||||
<% end %>
|
||||
|
||||
<!-- SPEC FILES -->
|
||||
<% for src in js_specs %>
|
||||
<script type="text/javascript" src="<%= src %>"></script>
|
||||
<% end %>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
var console_reporter = new jasmine.ConsoleReporter()
|
||||
jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
|
||||
jasmine.getEnv().addReporter(console_reporter);
|
||||
jasmine.getEnv().execute();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
<section id="problem_1" class="problems-wrapper" data-url="/problem/url/"></section>
|
||||
<section class='xmodule_display xmodule_CapaModule' data-type='Problem'>
|
||||
<section id='problem_1'
|
||||
class='problems-wrapper'
|
||||
data-problem-id='i4x://edX/101/problem/Problem1'
|
||||
data-url='/problem/Problem1'>
|
||||
</section>
|
||||
</section>
|
||||
@@ -8,25 +8,43 @@ describe 'Problem', ->
|
||||
MathJax.Hub.getAllJax.andReturn [@stubbedJax]
|
||||
window.update_schematics = ->
|
||||
|
||||
# Load this function from spec/helper.coffee
|
||||
# Note that if your test fails with a message like:
|
||||
# 'External request attempted for blah, which is not defined.'
|
||||
# this msg is coming from the stubRequests function else clause.
|
||||
jasmine.stubRequests()
|
||||
|
||||
# note that the fixturesPath is set in spec/helper.coffee
|
||||
loadFixtures 'problem.html'
|
||||
|
||||
spyOn Logger, 'log'
|
||||
spyOn($.fn, 'load').andCallFake (url, callback) ->
|
||||
$(@).html readFixtures('problem_content.html')
|
||||
callback()
|
||||
jasmine.stubRequests()
|
||||
|
||||
describe 'constructor', ->
|
||||
beforeEach ->
|
||||
@problem = new Problem 1, "problem_1", "/problem/url/"
|
||||
|
||||
it 'set the element', ->
|
||||
expect(@problem.el).toBe '#problem_1'
|
||||
it 'set the element from html', ->
|
||||
@problem999 = new Problem ("
|
||||
<section class='xmodule_display xmodule_CapaModule' data-type='Problem'>
|
||||
<section id='problem_999'
|
||||
class='problems-wrapper'
|
||||
data-problem-id='i4x://edX/999/problem/Quiz'
|
||||
data-url='/problem/quiz/'>
|
||||
</section>
|
||||
</section>
|
||||
")
|
||||
expect(@problem999.element_id).toBe 'problem_999'
|
||||
|
||||
it 'set the element from loadFixtures', ->
|
||||
@problem1 = new Problem($('.xmodule_display'))
|
||||
expect(@problem1.element_id).toBe 'problem_1'
|
||||
|
||||
describe 'bind', ->
|
||||
beforeEach ->
|
||||
spyOn window, 'update_schematics'
|
||||
MathJax.Hub.getAllJax.andReturn [@stubbedJax]
|
||||
@problem = new Problem 1, "problem_1", "/problem/url/"
|
||||
@problem = new Problem($('.xmodule_display'))
|
||||
|
||||
it 'set mathjax typeset', ->
|
||||
expect(MathJax.Hub.Queue).toHaveBeenCalled()
|
||||
@@ -38,7 +56,7 @@ describe 'Problem', ->
|
||||
expect($('section.action input:button')).toHandleWith 'click', @problem.refreshAnswers
|
||||
|
||||
it 'bind the check button', ->
|
||||
expect($('section.action input.check')).toHandleWith 'click', @problem.check
|
||||
expect($('section.action input.check')).toHandleWith 'click', @problem.check_fd
|
||||
|
||||
it 'bind the reset button', ->
|
||||
expect($('section.action input.reset')).toHandleWith 'click', @problem.reset
|
||||
@@ -60,7 +78,7 @@ describe 'Problem', ->
|
||||
|
||||
describe 'render', ->
|
||||
beforeEach ->
|
||||
@problem = new Problem 1, "problem_1", "/problem/url/"
|
||||
@problem = new Problem($('.xmodule_display'))
|
||||
@bind = @problem.bind
|
||||
spyOn @problem, 'bind'
|
||||
|
||||
@@ -86,9 +104,13 @@ describe 'Problem', ->
|
||||
it 're-bind the content', ->
|
||||
expect(@problem.bind).toHaveBeenCalled()
|
||||
|
||||
describe 'check_fd', ->
|
||||
xit 'should have specs written for this functionality', ->
|
||||
expect(false)
|
||||
|
||||
describe 'check', ->
|
||||
beforeEach ->
|
||||
@problem = new Problem 1, "problem_1", "/problem/url/"
|
||||
@problem = new Problem($('.xmodule_display'))
|
||||
@problem.answers = 'foo=1&bar=2'
|
||||
|
||||
it 'log the problem_check event', ->
|
||||
@@ -98,30 +120,34 @@ describe 'Problem', ->
|
||||
it 'submit the answer for check', ->
|
||||
spyOn $, 'postWithPrefix'
|
||||
@problem.check()
|
||||
expect($.postWithPrefix).toHaveBeenCalledWith '/modx/1/problem_check', 'foo=1&bar=2', jasmine.any(Function)
|
||||
expect($.postWithPrefix).toHaveBeenCalledWith '/problem/Problem1/problem_check',
|
||||
'foo=1&bar=2', jasmine.any(Function)
|
||||
|
||||
describe 'when the response is correct', ->
|
||||
it 'call render with returned content', ->
|
||||
spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> callback(success: 'correct', contents: 'Correct!')
|
||||
spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) ->
|
||||
callback(success: 'correct', contents: 'Correct!')
|
||||
@problem.check()
|
||||
expect(@problem.el.html()).toEqual 'Correct!'
|
||||
|
||||
describe 'when the response is incorrect', ->
|
||||
it 'call render with returned content', ->
|
||||
spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> callback(success: 'incorrect', contents: 'Correct!')
|
||||
spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) ->
|
||||
callback(success: 'incorrect', contents: 'Incorrect!')
|
||||
@problem.check()
|
||||
expect(@problem.el.html()).toEqual 'Correct!'
|
||||
expect(@problem.el.html()).toEqual 'Incorrect!'
|
||||
|
||||
describe 'when the response is undetermined', ->
|
||||
it 'alert the response', ->
|
||||
spyOn window, 'alert'
|
||||
spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> callback(success: 'Number Only!')
|
||||
spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) ->
|
||||
callback(success: 'Number Only!')
|
||||
@problem.check()
|
||||
expect(window.alert).toHaveBeenCalledWith 'Number Only!'
|
||||
|
||||
describe 'reset', ->
|
||||
beforeEach ->
|
||||
@problem = new Problem 1, "problem_1", "/problem/url/"
|
||||
@problem = new Problem($('.xmodule_display'))
|
||||
|
||||
it 'log the problem_reset event', ->
|
||||
@problem.answers = 'foo=1&bar=2'
|
||||
@@ -131,7 +157,8 @@ describe 'Problem', ->
|
||||
it 'POST to the problem reset page', ->
|
||||
spyOn $, 'postWithPrefix'
|
||||
@problem.reset()
|
||||
expect($.postWithPrefix).toHaveBeenCalledWith '/modx/1/problem_reset', { id: 1 }, jasmine.any(Function)
|
||||
expect($.postWithPrefix).toHaveBeenCalledWith '/problem/Problem1/problem_reset',
|
||||
{ id: 'i4x://edX/101/problem/Problem1' }, jasmine.any(Function)
|
||||
|
||||
it 'render the returned content', ->
|
||||
spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) ->
|
||||
@@ -141,7 +168,7 @@ describe 'Problem', ->
|
||||
|
||||
describe 'show', ->
|
||||
beforeEach ->
|
||||
@problem = new Problem 1, "problem_1", "/problem/url/"
|
||||
@problem = new Problem($('.xmodule_display'))
|
||||
@problem.el.prepend '<div id="answer_1_1" /><div id="answer_1_2" />'
|
||||
|
||||
describe 'when the answer has not yet shown', ->
|
||||
@@ -150,12 +177,14 @@ describe 'Problem', ->
|
||||
|
||||
it 'log the problem_show event', ->
|
||||
@problem.show()
|
||||
expect(Logger.log).toHaveBeenCalledWith 'problem_show', problem: 1
|
||||
expect(Logger.log).toHaveBeenCalledWith 'problem_show',
|
||||
problem: 'i4x://edX/101/problem/Problem1'
|
||||
|
||||
it 'fetch the answers', ->
|
||||
spyOn $, 'postWithPrefix'
|
||||
@problem.show()
|
||||
expect($.postWithPrefix).toHaveBeenCalledWith '/modx/1/problem_show', jasmine.any(Function)
|
||||
expect($.postWithPrefix).toHaveBeenCalledWith '/problem/Problem1/problem_show',
|
||||
jasmine.any(Function)
|
||||
|
||||
it 'show the answers', ->
|
||||
spyOn($, 'postWithPrefix').andCallFake (url, callback) ->
|
||||
@@ -220,7 +249,7 @@ describe 'Problem', ->
|
||||
|
||||
describe 'save', ->
|
||||
beforeEach ->
|
||||
@problem = new Problem 1, "problem_1", "/problem/url/"
|
||||
@problem = new Problem($('.xmodule_display'))
|
||||
@problem.answers = 'foo=1&bar=2'
|
||||
|
||||
it 'log the problem_save event', ->
|
||||
@@ -230,7 +259,8 @@ describe 'Problem', ->
|
||||
it 'POST to save problem', ->
|
||||
spyOn $, 'postWithPrefix'
|
||||
@problem.save()
|
||||
expect($.postWithPrefix).toHaveBeenCalledWith '/modx/1/problem_save', 'foo=1&bar=2', jasmine.any(Function)
|
||||
expect($.postWithPrefix).toHaveBeenCalledWith '/problem/Problem1/problem_save',
|
||||
'foo=1&bar=2', jasmine.any(Function)
|
||||
|
||||
it 'alert to the user', ->
|
||||
spyOn window, 'alert'
|
||||
@@ -240,7 +270,7 @@ describe 'Problem', ->
|
||||
|
||||
describe 'refreshMath', ->
|
||||
beforeEach ->
|
||||
@problem = new Problem 1, "problem_1", "/problem/url/"
|
||||
@problem = new Problem($('.xmodule_display'))
|
||||
$('#input_example_1').val 'E=mc^2'
|
||||
@problem.refreshMath target: $('#input_example_1').get(0)
|
||||
|
||||
@@ -250,7 +280,7 @@ describe 'Problem', ->
|
||||
|
||||
describe 'updateMathML', ->
|
||||
beforeEach ->
|
||||
@problem = new Problem 1, "problem_1", "/problem/url/"
|
||||
@problem = new Problem($('.xmodule_display'))
|
||||
@stubbedJax.root.toMathML.andReturn '<MathML>'
|
||||
|
||||
describe 'when there is no exception', ->
|
||||
@@ -270,7 +300,7 @@ describe 'Problem', ->
|
||||
|
||||
describe 'refreshAnswers', ->
|
||||
beforeEach ->
|
||||
@problem = new Problem 1, "problem_1", "/problem/url/"
|
||||
@problem = new Problem($('.xmodule_display'))
|
||||
@problem.el.html '''
|
||||
<textarea class="CodeMirror" />
|
||||
<input id="input_1_1" name="input_1_1" class="schematic" value="one" />
|
||||
@@ -293,3 +323,6 @@ describe 'Problem', ->
|
||||
it 'serialize all answers', ->
|
||||
@problem.refreshAnswers()
|
||||
expect(@problem.answers).toEqual "input_1_1=one&input_1_2=two"
|
||||
|
||||
|
||||
|
||||
|
||||
76
common/lib/xmodule/xmodule/js/spec/helper.coffee
Normal file
76
common/lib/xmodule/xmodule/js/spec/helper.coffee
Normal file
@@ -0,0 +1,76 @@
|
||||
jasmine.getFixtures().fixturesPath = 'xmodule/js/fixtures'
|
||||
|
||||
jasmine.stubbedMetadata =
|
||||
slowerSpeedYoutubeId:
|
||||
id: 'slowerSpeedYoutubeId'
|
||||
duration: 300
|
||||
normalSpeedYoutubeId:
|
||||
id: 'normalSpeedYoutubeId'
|
||||
duration: 200
|
||||
bogus:
|
||||
duration: 100
|
||||
|
||||
jasmine.stubbedCaption =
|
||||
start: [0, 10000, 20000, 30000]
|
||||
text: ['Caption at 0', 'Caption at 10000', 'Caption at 20000', 'Caption at 30000']
|
||||
|
||||
jasmine.stubRequests = ->
|
||||
spyOn($, 'ajax').andCallFake (settings) ->
|
||||
if match = settings.url.match /youtube\.com\/.+\/videos\/(.+)\?v=2&alt=jsonc/
|
||||
settings.success data: jasmine.stubbedMetadata[match[1]]
|
||||
else if match = settings.url.match /static\/subs\/(.+)\.srt\.sjson/
|
||||
settings.success jasmine.stubbedCaption
|
||||
else if settings.url.match /.+\/problem_get$/
|
||||
settings.success html: readFixtures('problem_content.html')
|
||||
else if settings.url == '/calculate' ||
|
||||
settings.url.match(/.+\/goto_position$/) ||
|
||||
settings.url.match(/event$/) ||
|
||||
settings.url.match(/.+\/problem_(check|reset|show|save)$/)
|
||||
# do nothing
|
||||
else
|
||||
throw "External request attempted for #{settings.url}, which is not defined."
|
||||
|
||||
jasmine.stubYoutubePlayer = ->
|
||||
YT.Player = -> jasmine.createSpyObj 'YT.Player', ['cueVideoById', 'getVideoEmbedCode',
|
||||
'getCurrentTime', 'getPlayerState', 'getVolume', 'setVolume', 'loadVideoById',
|
||||
'playVideo', 'pauseVideo', 'seekTo']
|
||||
|
||||
jasmine.stubVideoPlayer = (context, enableParts, createPlayer=true) ->
|
||||
enableParts = [enableParts] unless $.isArray(enableParts)
|
||||
|
||||
suite = context.suite
|
||||
currentPartName = suite.description while suite = suite.parentSuite
|
||||
enableParts.push currentPartName
|
||||
|
||||
for part in ['VideoCaption', 'VideoSpeedControl', 'VideoVolumeControl', 'VideoProgressSlider']
|
||||
unless $.inArray(part, enableParts) >= 0
|
||||
spyOn window, part
|
||||
|
||||
loadFixtures 'video.html'
|
||||
jasmine.stubRequests()
|
||||
YT.Player = undefined
|
||||
context.video = new Video 'example', '.75:slowerSpeedYoutubeId,1.0:normalSpeedYoutubeId'
|
||||
jasmine.stubYoutubePlayer()
|
||||
if createPlayer
|
||||
return new VideoPlayer(video: context.video)
|
||||
|
||||
spyOn(window, 'onunload')
|
||||
|
||||
# Stub Youtube API
|
||||
window.YT =
|
||||
PlayerState:
|
||||
UNSTARTED: -1
|
||||
ENDED: 0
|
||||
PLAYING: 1
|
||||
PAUSED: 2
|
||||
BUFFERING: 3
|
||||
CUED: 5
|
||||
|
||||
# Stub jQuery.cookie
|
||||
$.cookie = jasmine.createSpy('jQuery.cookie').andReturn '1.0'
|
||||
|
||||
# Stub jQuery.qtip
|
||||
$.fn.qtip = jasmine.createSpy 'jQuery.qtip'
|
||||
|
||||
# Stub jQuery.scrollTo
|
||||
$.fn.scrollTo = jasmine.createSpy 'jQuery.scrollTo'
|
||||
76
rakefile
76
rakefile
@@ -3,6 +3,8 @@ require 'tempfile'
|
||||
require 'net/http'
|
||||
require 'launchy'
|
||||
require 'colorize'
|
||||
require 'erb'
|
||||
require 'tempfile'
|
||||
|
||||
# Build Constants
|
||||
REPO_ROOT = File.dirname(__FILE__)
|
||||
@@ -79,6 +81,31 @@ def django_for_jasmine(system, django_reload)
|
||||
end
|
||||
end
|
||||
|
||||
def template_jasmine_runner(lib)
|
||||
coffee_files = Dir["#{lib}/**/js/**/*.coffee", "common/static/coffee/src/**/*.coffee"]
|
||||
if !coffee_files.empty?
|
||||
sh("coffee -c #{coffee_files.join(' ')}")
|
||||
end
|
||||
phantom_jasmine_path = File.expand_path("common/test/phantom-jasmine")
|
||||
common_js_root = File.expand_path("common/static/js")
|
||||
common_coffee_root = File.expand_path("common/static/coffee/src")
|
||||
|
||||
# Get arrays of spec and source files, ordered by how deep they are nested below the library
|
||||
# (and then alphabetically) and expanded from a relative to an absolute path
|
||||
spec_glob = File.join("#{lib}", "**", "spec", "**", "*.js")
|
||||
src_glob = File.join("#{lib}", "**", "src", "**", "*.js")
|
||||
js_specs = Dir[spec_glob].sort_by {|p| [p.split('/').length, p]} .map {|f| File.expand_path(f)}
|
||||
js_source = Dir[src_glob].sort_by {|p| [p.split('/').length, p]} .map {|f| File.expand_path(f)}
|
||||
|
||||
template = ERB.new(File.read("#{lib}/jasmine_test_runner.html.erb"))
|
||||
template_output = "#{lib}/jasmine_test_runner.html"
|
||||
File.open(template_output, 'w') do |f|
|
||||
f.write(template.result(binding))
|
||||
end
|
||||
yield File.expand_path(template_output)
|
||||
end
|
||||
|
||||
|
||||
def report_dir_path(dir)
|
||||
return File.join(REPORT_DIR, dir.to_s)
|
||||
end
|
||||
@@ -126,22 +153,6 @@ end
|
||||
end
|
||||
task :pylint => "pylint_#{system}"
|
||||
|
||||
desc "Open jasmine tests in your default browser"
|
||||
task "browse_jasmine_#{system}" do
|
||||
django_for_jasmine(system, true) do |jasmine_url|
|
||||
Launchy.open(jasmine_url)
|
||||
puts "Press ENTER to terminate".red
|
||||
$stdin.gets
|
||||
end
|
||||
end
|
||||
|
||||
desc "Use phantomjs to run jasmine tests from the console"
|
||||
task "phantomjs_jasmine_#{system}" do
|
||||
phantomjs = ENV['PHANTOMJS_PATH'] || 'phantomjs'
|
||||
django_for_jasmine(system, false) do |jasmine_url|
|
||||
sh("#{phantomjs} common/test/phantom-jasmine/lib/run_jasmine_test.coffee #{jasmine_url}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
$failed_tests = 0
|
||||
@@ -210,6 +221,23 @@ TEST_TASK_DIRS = []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Open jasmine tests for #{system} in your default browser"
|
||||
task "browse_jasmine_#{system}" do
|
||||
django_for_jasmine(system, true) do |jasmine_url|
|
||||
Launchy.open(jasmine_url)
|
||||
puts "Press ENTER to terminate".red
|
||||
$stdin.gets
|
||||
end
|
||||
end
|
||||
|
||||
desc "Use phantomjs to run jasmine tests for #{system} from the console"
|
||||
task "phantomjs_jasmine_#{system}" do
|
||||
phantomjs = ENV['PHANTOMJS_PATH'] || 'phantomjs'
|
||||
django_for_jasmine(system, false) do |jasmine_url|
|
||||
sh("#{phantomjs} common/test/phantom-jasmine/lib/run_jasmine_test.coffee #{jasmine_url}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Reset the relational database used by django. WARNING: this will delete all of your existing users"
|
||||
@@ -245,6 +273,22 @@ Dir["common/lib/*"].select{|lib| File.directory?(lib)}.each do |lib|
|
||||
sh("nosetests #{lib}")
|
||||
end
|
||||
|
||||
desc "Open jasmine tests for #{lib} in your default browser"
|
||||
task "browse_jasmine_#{lib}" do
|
||||
template_jasmine_runner(lib) do |f|
|
||||
sh("python -m webbrowser -t 'file://#{f}'")
|
||||
puts "Press ENTER to terminate".red
|
||||
$stdin.gets
|
||||
end
|
||||
end
|
||||
|
||||
desc "Use phantomjs to run jasmine tests for #{lib} from the console"
|
||||
task "phantomjs_jasmine_#{lib}" do
|
||||
phantomjs = ENV['PHANTOMJS_PATH'] || 'phantomjs'
|
||||
template_jasmine_runner(lib) do |f|
|
||||
sh("#{phantomjs} common/test/phantom-jasmine/lib/run_jasmine_test.coffee #{f}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
task :report_dirs
|
||||
|
||||
Reference in New Issue
Block a user