Merge pull request #662 from edx/db/requirejs

requirejs in Studio
This commit is contained in:
David Baumgold
2013-10-04 11:42:07 -07:00
196 changed files with 7442 additions and 5902 deletions

View File

@@ -99,6 +99,7 @@ def click_on_sequence(step, sequence):
@step(u'I should see the content of (?:sub)?section "([^"]*)"$')
def see_section_content(step, section):
world.wait(0.5)
if section == "2":
text = 'The correct answer is Option 2'
elif section == "1":

View File

@@ -377,6 +377,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
system = ModuleSystem(
track_function=track_function,
render_template=render_to_string,
static_url=settings.STATIC_URL,
ajax_url=ajax_url,
xqueue=xqueue,
# TODO (cpennington): Figure out how to share info between systems

View File

@@ -18,7 +18,7 @@ CACHE_SETTINGS = {
# Configure settings so Django will let us import its cache wrapper
# Caching is the only part of Django being tested
from django.conf import settings
from django.conf import settings
settings.configure(CACHES=CACHE_SETTINGS)
from django.core.cache import cache
@@ -32,6 +32,7 @@ TEST_SCRIPT = textwrap.dedent("""
# Submissions submitted by the student
TEST_SUBMISSIONS = [random.randint(-100, 100) for i in range(100)]
class TestContext(object):
""" One-time set up for the test that is shared across transactions.
Uses a Singleton design pattern."""
@@ -48,6 +49,7 @@ class TestContext(object):
# Create a mock ModuleSystem, installing our cache
system = mock.MagicMock(ModuleSystem)
system.STATIC_URL = '/dummy-static/'
system.render_template = lambda template, context: "<div>%s</div>" % template
system.cache = cache
system.filestore = mock.MagicMock(fs.osfs.OSFS)
@@ -86,6 +88,7 @@ class TestContext(object):
""" Return one of a small number of student submissions """
return random.choice(TEST_SUBMISSIONS)
class Transaction(object):
""" User script that submits a response to a CustomResponse problem """
@@ -95,15 +98,15 @@ class Transaction(object):
# Get the context (re-used across transactions)
self.context = TestContext.singleton()
# Create a new custom response problem
# Create a new custom response problem
# using one of a small number of unique seeds
# We're assuming that the capa module is limiting the number
# of seeds (currently not the case for certain settings)
self.problem = lcp.LoncapaProblem(self.context.xml,
'1',
state=None,
seed=self.context.random_seed(),
system=self.context.system)
self.problem = lcp.LoncapaProblem(
self.context.xml, '1',
state=None, seed=self.context.random_seed(),
system=self.context.system,
)
def run(self):
""" Submit a response to the CustomResponse problem """

View File

@@ -126,6 +126,7 @@ def combined_notifications(course, user):
#Define a mock modulesystem
system = ModuleSystem(
static_url="/static",
ajax_url=None,
track_function=None,
get_module = None,

View File

@@ -70,6 +70,7 @@ class StaffGradingService(GradingService):
def __init__(self, config):
config['system'] = ModuleSystem(
static_url='/static',
ajax_url=None,
track_function=None,
get_module = None,

View File

@@ -35,6 +35,7 @@ from courseware.tests import factories
from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE
from courseware.tests.helpers import LoginEnrollmentTestCase, check_for_get_code, check_for_post_code
class EmptyStaffGradingService(object):
"""
A staff grading service that does not return a problem list from get_problem_list.
@@ -47,6 +48,7 @@ class EmptyStaffGradingService(object):
"""
return json.dumps({'success': True, 'error': 'No problems found.'})
def make_instructor(course, user_email):
"""
Makes a given user an instructor in a course.
@@ -55,6 +57,7 @@ def make_instructor(course, user_email):
group = Group.objects.create(name=group_name)
group.user_set.add(User.objects.get(email=user_email))
class StudentProblemListMockQuery(object):
"""
Mock controller query service for testing student problem list functionality.
@@ -98,6 +101,7 @@ class StudentProblemListMockQuery(object):
)
return grading_status_list
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
class TestStaffGradingService(ModuleStoreTestCase, LoginEnrollmentTestCase):
'''
@@ -241,6 +245,7 @@ class TestPeerGradingService(ModuleStoreTestCase, LoginEnrollmentTestCase):
field_data = DictFieldData({'data': "<peergrading/>", 'location': location, 'category':'peergrading'})
self.mock_service = peer_grading_service.MockPeerGradingService()
self.system = ModuleSystem(
static_url=settings.STATIC_URL,
ajax_url=location,
track_function=None,
get_module=None,
@@ -408,6 +413,7 @@ class TestPanel(ModuleStoreTestCase):
response = views.student_problem_list(request, self.course.id)
self.assertRegexpMatches(response.content, "Here is a list of open ended problems for this course.")
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
class TestPeerGradingFound(ModuleStoreTestCase):
"""
@@ -427,6 +433,7 @@ class TestPeerGradingFound(ModuleStoreTestCase):
found, url = views.find_peer_grading_module(self.course)
self.assertEqual(found, False)
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
class TestStudentProblemList(ModuleStoreTestCase):
"""
@@ -464,5 +471,3 @@ class TestStudentProblemList(ModuleStoreTestCase):
self.assertEqual(len(valid_problems), 2)
# Ensure that human names are being set properly.
self.assertEqual(valid_problems[0]['grader_type_display_name'], "Instructor Assessment")

View File

@@ -24,19 +24,21 @@ GRADER_DISPLAY_NAMES = {
'NA': _("Not yet available"),
'BC': _("Automatic Checker"),
'IN': _("Instructor Assessment"),
}
}
STUDENT_ERROR_MESSAGE = _("Error occurred while contacting the grading service. Please notify course staff.")
STAFF_ERROR_MESSAGE = _("Error occurred while contacting the grading service. Please notify your edX point of contact.")
system = ModuleSystem(
static_url='/static',
ajax_url=None,
track_function=None,
get_module=None,
render_template=render_to_string,
replace_urls=None,
xmodule_field_data=DictFieldData({}),
)
)
def generate_problem_url(problem_url_parts, base_course_url):
"""
@@ -53,6 +55,7 @@ def generate_problem_url(problem_url_parts, base_course_url):
problem_url += part + "/"
return problem_url
def does_location_exist(course_id, location):
"""
Checks to see if a valid module exists at a given location (ie has not been deleted)
@@ -74,6 +77,7 @@ def does_location_exist(course_id, location):
"Ensure that the location is valid.").format(location))
return False
def create_controller_query_service():
"""
Return an instance of a service that can query edX ORA.
@@ -81,6 +85,7 @@ def create_controller_query_service():
return ControllerQueryService(settings.OPEN_ENDED_GRADING_INTERFACE, system)
class StudentProblemList(object):
"""
Get a list of problems that the student has attempted from ORA.

View File

@@ -613,10 +613,9 @@ courseware_js = (
sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/modules/**/*.js'))
)
# 'js/vendor/RequireJS.js' - Require JS wrapper.
# See https://edx-wiki.atlassian.net/wiki/display/LMS/Integration+of+Require+JS+into+the+system
main_vendor_js = [
'js/vendor/RequireJS.js',
'js/vendor/require.js',
'js/RequireJS-namespace-undefine.js',
'js/vendor/json2.js',
'js/vendor/jquery.min.js',
'js/vendor/jquery-ui.min.js',

View File

@@ -1,89 +1,89 @@
describe "RequireJS namespacing", ->
beforeEach ->
beforeEach ->
# Jasmine does not provide a way to use the typeof operator. We need
# to create our own custom matchers so that a TypeError is not thrown.
@addMatchers
requirejsTobeUndefined: ->
typeof requirejs is "undefined"
# Jasmine does not provide a way to use the typeof operator. We need
# to create our own custom matchers so that a TypeError is not thrown.
@addMatchers
requirejsTobeUndefined: ->
typeof requirejs is "undefined"
requireTobeUndefined: ->
typeof require is "undefined"
requireTobeUndefined: ->
typeof require is "undefined"
defineTobeUndefined: ->
typeof define is "undefined"
defineTobeUndefined: ->
typeof define is "undefined"
it "check that the RequireJS object is present in the global namespace", ->
expect(RequireJS).toEqual jasmine.any(Object)
expect(window.RequireJS).toEqual jasmine.any(Object)
it "check that the RequireJS object is present in the global namespace", ->
expect(RequireJS).toEqual jasmine.any(Object)
expect(window.RequireJS).toEqual jasmine.any(Object)
it "check that requirejs(), require(), and define() are not in the global namespace", ->
it "check that requirejs(), require(), and define() are not in the global namespace", ->
# The custom matchers that we defined in the beforeEach() function do
# not operate on an object. We pass a dummy empty object {} not to
# confuse Jasmine.
expect({}).requirejsTobeUndefined()
expect({}).requireTobeUndefined()
expect({}).defineTobeUndefined()
expect(window.requirejs).not.toBeDefined()
expect(window.require).not.toBeDefined()
expect(window.define).not.toBeDefined()
# The custom matchers that we defined in the beforeEach() function do
# not operate on an object. We pass a dummy empty object {} not to
# confuse Jasmine.
expect({}).requirejsTobeUndefined()
expect({}).requireTobeUndefined()
expect({}).defineTobeUndefined()
expect(window.requirejs).not.toBeDefined()
expect(window.require).not.toBeDefined()
expect(window.define).not.toBeDefined()
describe "RequireJS module creation", ->
inDefineCallback = undefined
inRequireCallback = undefined
it "check that we can use RequireJS to define() and require() a module", ->
inDefineCallback = undefined
inRequireCallback = undefined
it "check that we can use RequireJS to define() and require() a module", ->
# Because Require JS works asynchronously when defining and requiring
# modules, we need to use the special Jasmine functions runs(), and
# waitsFor() to set up this test.
runs ->
# Because Require JS works asynchronously when defining and requiring
# modules, we need to use the special Jasmine functions runs(), and
# waitsFor() to set up this test.
runs ->
# Initialize the variable that we will test for. They will be set
# to true in the appropriate callback functions called by Require
# JS. If their values do not change, this will mean that something
# is not working as is intended.
inDefineCallback = false
inRequireCallback = false
# Initialize the variable that we will test for. They will be set
# to true in the appropriate callback functions called by Require
# JS. If their values do not change, this will mean that something
# is not working as is intended.
inDefineCallback = false
inRequireCallback = false
# Define our test module.
RequireJS.define "test_module", [], ->
inDefineCallback = true
# Define our test module.
RequireJS.define "test_module", [], ->
inDefineCallback = true
# This module returns an object. It can be accessed via the
# Require JS require() function.
module_status: "OK"
# This module returns an object. It can be accessed via the
# Require JS require() function.
module_status: "OK"
# Require our defined test module.
RequireJS.require ["test_module"], (test_module) ->
inRequireCallback = true
# Require our defined test module.
RequireJS.require ["test_module"], (test_module) ->
inRequireCallback = true
# If our test module was defined properly, then we should
# be able to get the object it returned, and query some
# property.
expect(test_module.module_status).toBe "OK"
# If our test module was defined properly, then we should
# be able to get the object it returned, and query some
# property.
expect(test_module.module_status).toBe "OK"
# We will wait for a specified amount of time (1 second), before
# checking if our module was defined and that we were able to
# require() the module.
waitsFor (->
# We will wait for a specified amount of time (1 second), before
# checking if our module was defined and that we were able to
# require() the module.
waitsFor (->
# If at least one of the callback functions was not reached, we
# fail this test.
return false if (inDefineCallback isnt true) or (inRequireCallback isnt true)
# If at least one of the callback functions was not reached, we
# fail this test.
return false if (inDefineCallback isnt true) or (inRequireCallback isnt true)
# Both of the callbacks were reached.
true
), "We should eventually end up in the defined callback", 1000
# Both of the callbacks were reached.
true
), "We should eventually end up in the defined callback", 1000
# The final test behavior, after waitsFor() finishes waiting.
runs ->
expect(inDefineCallback).toBeTruthy()
expect(inRequireCallback).toBeTruthy()
# The final test behavior, after waitsFor() finishes waiting.
runs ->
expect(inDefineCallback).toBeTruthy()
expect(inRequireCallback).toBeTruthy()

View File

@@ -0,0 +1 @@
../../../common/static/js/RequireJS-namespace-undefine.js

View File

@@ -30,22 +30,17 @@ prepend_path: lms/static
lib_paths:
- xmodule_js/common_static/coffee/src/ajax_prefix.js
- xmodule_js/common_static/coffee/src/logger.js
- xmodule_js/common_static/js/vendor/RequireJS.js
- xmodule_js/common_static/js/vendor/json2.js
- xmodule_js/common_static/js/vendor/jasmine-jquery.js
- xmodule_js/common_static/js/vendor/require.js
- js/RequireJS-namespace-undefine.js
- xmodule_js/common_static/js/vendor/jquery.min.js
- xmodule_js/common_static/js/vendor/jquery-ui.min.js
- xmodule_js/common_static/js/vendor/jquery.cookie.js
- xmodule_js/common_static/js/vendor/jquery.qtip.min.js
- xmodule_js/common_static/js/vendor/swfobject/swfobject.js
- xmodule_js/common_static/js/vendor/jquery.ba-bbq.min.js
- xmodule_js/common_static/js/vendor/annotator.min.js
- xmodule_js/common_static/js/vendor/annotator.store.min.js
- xmodule_js/common_static/js/vendor/annotator.tags.min.js
- xmodule_js/common_static/js/vendor/jasmine-jquery.js
- xmodule_js/common_static/js/vendor/jquery.leanModal.min.js
- xmodule_js/common_static/js/vendor/flot/jquery.flot.js
- xmodule_js/src
- xmodule_js/common_static/js/test/add_ajax_prefix.js
- xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js
- xmodule_js/src/capa/
- xmodule_js/src/video/
- xmodule_js/src/xmodule.js
# Paths to source JavaScript files
src_paths:
@@ -54,7 +49,6 @@ src_paths:
# Paths to spec (test) JavaScript files
spec_paths:
- coffee/spec/helper.js
- coffee/spec
# Paths to fixture files (optional)
@@ -73,7 +67,7 @@ fixture_paths:
# appearing in the test runner page.
# Files are included by default, which means that they
# are loaded using a <script> tag in the test runner page.
# When loading many files, this can be slow, so
# When loading many files, this can be slow, so
# exclude any files you don't need.
#exclude_from_page:
# - path/to/lib/exclude/*
@@ -85,4 +79,4 @@ fixture_paths:
# You can use this to exclude all files in a directory,
# but make an exception for particular files.
#include_in_page:
# - path/to/lib/exclude/exception_*.js
# - path/to/lib/include/*