Commit 141e0a93 by Brian Beggs

Merge branch 'master' into dj18-release-merge

parents 0e66fad1 290de455
......@@ -35,9 +35,6 @@ var CourseDetails = Backbone.Model.extend({
if (newattrs.start_date === null) {
errors.start_date = gettext("The course must have an assigned start date.");
}
if (this.hasChanged("start_date") && this.get("has_cert_config") === false){
errors.start_date = gettext("The course must have at least one active certificate configuration before it can be started.");
}
if (newattrs.start_date && newattrs.end_date && newattrs.start_date >= newattrs.end_date) {
errors.end_date = gettext("The course end date must be later than the course start date.");
}
......
......@@ -72,13 +72,6 @@ define([
);
});
it('Changing course start date without active certificate configuration should result in error', function () {
this.view.$el.find('#course-start-date')
.val('10/06/2014')
.trigger('change');
expect(this.view.$el.find('span.message-error').text()).toContain("course must have at least one active certificate configuration");
});
it('Selecting a course in pre-requisite drop down should save it as part of course details', function () {
var pre_requisite_courses = ['test/CSS101/2012_T1'];
var requests = AjaxHelpers.requests(this),
......
......@@ -3,6 +3,9 @@
Tests the "preview" selector in the LMS that allows changing between Staff, Student, and Content Groups.
"""
from nose.plugins.attrib import attr
from ..helpers import UniqueCourseTest, create_user_partition_json
from ...pages.studio.auto_auth import AutoAuthPage
from ...pages.lms.courseware import CoursewarePage
......@@ -14,6 +17,7 @@ from xmodule.partitions.partitions import Group
from textwrap import dedent
@attr('shard_3')
class StaffViewTest(UniqueCourseTest):
"""
Tests that verify the staff view.
......@@ -51,6 +55,7 @@ class StaffViewTest(UniqueCourseTest):
return staff_page
@attr('shard_3')
class CourseWithoutContentGroupsTest(StaffViewTest):
"""
Setup for tests that have no content restricted to specific content groups.
......@@ -81,6 +86,7 @@ class CourseWithoutContentGroupsTest(StaffViewTest):
)
@attr('shard_3')
class StaffViewToggleTest(CourseWithoutContentGroupsTest):
"""
Tests for the staff view toggle button.
......@@ -97,6 +103,7 @@ class StaffViewToggleTest(CourseWithoutContentGroupsTest):
self.assertFalse(course_page.has_tab('Instructor'))
@attr('shard_3')
class StaffDebugTest(CourseWithoutContentGroupsTest):
"""
Tests that verify the staff debug info.
......@@ -228,6 +235,7 @@ class StaffDebugTest(CourseWithoutContentGroupsTest):
'for user {}'.format(self.USERNAME), msg)
@attr('shard_3')
class CourseWithContentGroupsTest(StaffViewTest):
"""
Verifies that changing the "View this course as" selector works properly for content groups.
......
"""
Acceptance tests for the Import and Export pages
"""
from nose.plugins.attrib import attr
from datetime import datetime
from abc import abstractmethod
......@@ -33,6 +34,7 @@ class ExportTestMixin(object):
self.assertTrue(is_tarball_mimetype)
@attr('shard_4')
class TestCourseExport(ExportTestMixin, StudioCourseTest):
"""
Export tests for courses.
......@@ -55,6 +57,7 @@ class TestCourseExport(ExportTestMixin, StudioCourseTest):
self.assertEqual(self.export_page.header_text, 'Course Export')
@attr('shard_4')
class TestLibraryExport(ExportTestMixin, StudioLibraryTest):
"""
Export tests for libraries.
......@@ -103,6 +106,7 @@ class BadExportMixin(object):
)
@attr('shard_4')
class TestLibraryBadExport(BadExportMixin, StudioLibraryTest):
"""
Verify exporting a bad library causes an error.
......@@ -126,6 +130,7 @@ class TestLibraryBadExport(BadExportMixin, StudioLibraryTest):
)
@attr('shard_4')
class TestCourseBadExport(BadExportMixin, StudioCourseTest):
"""
Verify exporting a bad course causes an error.
......@@ -157,6 +162,7 @@ class TestCourseBadExport(BadExportMixin, StudioCourseTest):
)
@attr('shard_4')
class ImportTestMixin(object):
"""
Tests to run for both course and library import pages.
......@@ -271,6 +277,7 @@ class ImportTestMixin(object):
self.import_page.wait_for_tasks(fail_on='Updating')
@attr('shard_4')
class TestEntranceExamCourseImport(ImportTestMixin, StudioCourseTest):
"""
Tests the Course import page
......@@ -316,6 +323,7 @@ class TestEntranceExamCourseImport(ImportTestMixin, StudioCourseTest):
)
@attr('shard_4')
class TestCourseImport(ImportTestMixin, StudioCourseTest):
"""
Tests the Course import page
......@@ -357,6 +365,7 @@ class TestCourseImport(ImportTestMixin, StudioCourseTest):
self.assertEqual(self.import_page.header_text, 'Course Import')
@attr('shard_4')
class TestLibraryImport(ImportTestMixin, StudioLibraryTest):
"""
Tests the Library import page
......
......@@ -312,6 +312,7 @@ class EditContainerTest(NestedVerticalTest):
self.assertEqual(component.student_content, "modified content")
@attr('shard_3')
class EditVisibilityModalTest(ContainerBase):
"""
Tests of the visibility settings modal for components on the unit
......@@ -397,6 +398,7 @@ class EditVisibilityModalTest(ContainerBase):
# Re-open the modal and inspect its selected inputs
visibility_editor = self.edit_component_visibility(component)
self.verify_selected_labels(visibility_editor, expected_labels)
visibility_editor.save()
def verify_component_validation_error(self, component):
"""
......@@ -427,14 +429,13 @@ class EditVisibilityModalTest(ContainerBase):
self.browser.refresh()
self.container_page.wait_for_page()
def remove_missing_groups(self, component):
def remove_missing_groups(self, visibility_editor, component):
"""
Deselect the missing groups for a component. After save,
verify that there are no missing group messages in the modal
and that there is no validation error on the component.
"""
visibility_editor = self.edit_component_visibility(component)
for option in self.edit_component_visibility(component).selected_options:
for option in visibility_editor.selected_options:
if option.text == self.MISSING_GROUP_LABEL:
option.click()
visibility_editor.save()
......@@ -541,7 +542,7 @@ class EditVisibilityModalTest(ContainerBase):
self.verify_component_validation_error(self.html_component)
visibility_editor = self.edit_component_visibility(self.html_component)
self.verify_selected_labels(visibility_editor, [self.MISSING_GROUP_LABEL] * 2)
self.remove_missing_groups(self.html_component)
self.remove_missing_groups(visibility_editor, self.html_component)
self.verify_visibility_set(self.html_component, False)
def test_found_and_missing_groups(self):
......@@ -565,7 +566,7 @@ class EditVisibilityModalTest(ContainerBase):
self.verify_component_validation_error(self.html_component)
visibility_editor = self.edit_component_visibility(self.html_component)
self.verify_selected_labels(visibility_editor, ['Dogs', 'Cats'] + [self.MISSING_GROUP_LABEL] * 2)
self.remove_missing_groups(self.html_component)
self.remove_missing_groups(visibility_editor, self.html_component)
visibility_editor = self.edit_component_visibility(self.html_component)
self.verify_selected_labels(visibility_editor, ['Dogs', 'Cats'])
self.verify_visibility_set(self.html_component, True)
......@@ -1041,6 +1042,7 @@ class UnitPublishingTest(ContainerBase):
# self.assertEqual('discussion', self.courseware.xblock_component_type(1))
@attr('shard_3')
class DisplayNameTest(ContainerBase):
"""
Test consistent use of display_name_with_default
......@@ -1077,6 +1079,7 @@ class DisplayNameTest(ContainerBase):
self.assertEqual(container.name, title_on_unit_page)
@attr('shard_3')
class ProblemCategoryTabsTest(ContainerBase):
"""
Test to verify tabs in problem category.
......
......@@ -1755,6 +1755,7 @@ class DeprecationWarningMessageTest(CourseOutlineTest):
)
@attr('shard_4')
class SelfPacedOutlineTest(CourseOutlineTest):
"""Test the course outline for a self-paced course."""
......
......@@ -2,6 +2,7 @@
Acceptance tests for Studio's Settings Details pages
"""
from datetime import datetime, timedelta
from nose.plugins.attrib import attr
from unittest import skip
from .base_studio_test import StudioCourseTest
......@@ -18,6 +19,7 @@ from ..helpers import (
)
@attr('shard_4')
class StudioSettingsDetailsTest(StudioCourseTest):
"""Base class for settings and details page tests."""
......@@ -35,6 +37,7 @@ class StudioSettingsDetailsTest(StudioCourseTest):
self.assertTrue(self.settings_detail.is_browser_on_page())
@attr('shard_4')
class SettingsMilestonesTest(StudioSettingsDetailsTest):
"""
Tests for milestones feature in Studio's settings tab
......@@ -201,6 +204,7 @@ class SettingsMilestonesTest(StudioSettingsDetailsTest):
))
@attr('shard_4')
class CoursePacingTest(StudioSettingsDetailsTest):
"""Tests for setting a course to self-paced."""
......
......@@ -38,6 +38,11 @@ class BadgeAssertionFactory(DjangoModelFactory):
model = BadgeAssertion
mode = 'honor'
data = {
'image': 'http://www.example.com/image.png',
'json': {'id': 'http://www.example.com/assertion.json'},
'issuer': 'http://www.example.com/issuer.json',
}
class BadgeImageConfigurationFactory(DjangoModelFactory):
......@@ -75,7 +80,8 @@ class CertificateHtmlViewConfigurationFactory(DjangoModelFactory):
},
"honor": {
"certificate_type": "Honor Code",
"certificate_title": "Certificate of Achievement"
"certificate_title": "Certificate of Achievement",
"logo_url": "http://www.edx.org/honor_logo.png"
},
"verified": {
"certificate_type": "Verified",
......@@ -84,6 +90,13 @@ class CertificateHtmlViewConfigurationFactory(DjangoModelFactory):
"xseries": {
"certificate_title": "XSeries Certificate of Achievement",
"certificate_type": "XSeries"
},
"microsites": {
"testmicrosite": {
"company_about_url": "http://www.testmicrosite.org/about-us",
"company_privacy_url": "http://www.testmicrosite.org/edx-privacy-policy",
"company_tos_url": "http://www.testmicrosite.org/edx-terms-service"
}
}
}"""
......
......@@ -187,16 +187,6 @@ class UpdateExampleCertificateViewTest(TestCase):
self.assertEqual(content['return_code'], 0)
def fakemicrosite(name, default=None):
"""
This is a test mocking function to return a microsite configuration
"""
if name == 'microsite_config_key':
return 'test_microsite'
else:
return default
@attr('shard_1')
class MicrositeCertificatesViewsTests(ModuleStoreTestCase):
"""
......@@ -270,7 +260,6 @@ class MicrositeCertificatesViewsTests(ModuleStoreTestCase):
self.course.save()
self.store.update_item(self.course, self.user.id)
@patch("microsite_configuration.microsite.get_value", fakemicrosite)
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
def test_html_view_for_microsite(self):
test_configuration_string = """{
......@@ -285,18 +274,20 @@ class MicrositeCertificatesViewsTests(ModuleStoreTestCase):
"logo_src": "/static/certificates/images/logo-edx.svg",
"logo_url": "http://www.edx.org"
},
"test_microsite": {
"accomplishment_class_append": "accomplishment-certificate",
"platform_name": "platform_microsite",
"company_about_url": "http://www.microsite.org/about-us",
"company_privacy_url": "http://www.microsite.org/edx-privacy-policy",
"company_tos_url": "http://www.microsite.org/microsite-terms-service",
"company_verified_certificate_url": "http://www.microsite.org/verified-certificate",
"document_stylesheet_url_application": "/static/certificates/sass/main-ltr.css",
"logo_src": "/static/certificates/images/logo-microsite.svg",
"logo_url": "http://www.microsite.org",
"company_about_description": "This is special microsite aware company_about_description content",
"company_about_title": "Microsite title"
"microsites": {
"testmicrosite": {
"accomplishment_class_append": "accomplishment-certificate",
"platform_name": "platform_microsite",
"company_about_url": "http://www.microsite.org/about-us",
"company_privacy_url": "http://www.microsite.org/edx-privacy-policy",
"company_tos_url": "http://www.microsite.org/microsite-terms-service",
"company_verified_certificate_url": "http://www.microsite.org/verified-certificate",
"document_stylesheet_url_application": "/static/certificates/sass/main-ltr.css",
"logo_src": "/static/certificates/images/logo-microsite.svg",
"logo_url": "http://www.microsite.org",
"company_about_description": "This is special microsite aware company_about_description content",
"company_about_title": "Microsite title"
}
},
"honor": {
"certificate_type": "Honor Code"
......@@ -310,13 +301,12 @@ class MicrositeCertificatesViewsTests(ModuleStoreTestCase):
course_id=unicode(self.course.id)
)
self._add_course_certificates(count=1, signatory_count=2)
response = self.client.get(test_url)
response = self.client.get(test_url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)
self.assertIn('platform_microsite', response.content)
self.assertIn('http://www.microsite.org', response.content)
self.assertIn('This is special microsite aware company_about_description content', response.content)
self.assertIn('Microsite title', response.content)
@patch("microsite_configuration.microsite.get_value", fakemicrosite)
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
def test_html_view_microsite_configuration_missing(self):
test_configuration_string = """{
......@@ -343,7 +333,7 @@ class MicrositeCertificatesViewsTests(ModuleStoreTestCase):
course_id=unicode(self.course.id)
)
self._add_course_certificates(count=1, signatory_count=2)
response = self.client.get(test_url)
response = self.client.get(test_url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)
self.assertIn('edX', response.content)
self.assertNotIn('platform_microsite', response.content)
self.assertNotIn('http://www.microsite.org', response.content)
......
......@@ -23,7 +23,6 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from certificates.api import get_certificate_url
from certificates.models import (
GeneratedCertificate,
BadgeAssertion,
CertificateStatuses,
CertificateSocialNetworks,
CertificateTemplate,
......@@ -33,6 +32,7 @@ from certificates.models import (
from certificates.tests.factories import (
CertificateHtmlViewConfigurationFactory,
LinkedInAddToProfileConfigurationFactory,
BadgeAssertionFactory,
)
from util import organizations_helpers as organizations_api
from django.test.client import RequestFactory
......@@ -222,6 +222,104 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase):
self.assertIn('logo_test1.png', response.content)
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
@patch.dict("django.conf.settings.SOCIAL_SHARING_SETTINGS", {
"CERTIFICATE_TWITTER": True,
"CERTIFICATE_FACEBOOK": True,
})
def test_rendering_maximum_data(self):
"""
Tests at least one data item from different context update methods to
make sure every context update method is invoked while rendering certificate template.
"""
long_org_name = 'Long org name'
short_org_name = 'short_org_name'
test_organization_data = {
'name': long_org_name,
'short_name': short_org_name,
'description': 'Test Organization Description',
'active': True,
'logo': '/logo_test1.png'
}
test_org = organizations_api.add_organization(organization_data=test_organization_data)
organizations_api.add_organization_course(organization_data=test_org, course_id=unicode(self.course.id))
self._add_course_certificates(count=1, signatory_count=1, is_active=True)
BadgeAssertionFactory.create(
user=self.user, course_id=self.course_id,
)
self.course.cert_html_view_overrides = {
"logo_src": "/static/certificates/images/course_override_logo.png"
}
self.course.save()
self.store.update_item(self.course, self.user.id)
test_url = get_certificate_url(
user_id=self.user.id,
course_id=unicode(self.course.id)
)
response = self.client.get(test_url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)
# Test an item from basic info
self.assertIn(
'Terms of Service & Honor Code',
response.content
)
self.assertIn(
'Certificate ID Number',
response.content
)
# Test an item from html cert configuration
self.assertIn(
'<a class="logo" href="http://www.edx.org/honor_logo.png">',
response.content
)
# Test an item from course info
self.assertIn(
'course_title_0',
response.content
)
# Test an item from user info
self.assertIn(
"{fullname}, you've earned a certificate!".format(fullname=self.user.profile.name),
response.content
)
# Test an item from social info
self.assertIn(
"Post on Facebook",
response.content
)
self.assertIn(
"Share on Twitter",
response.content
)
# Test an item from certificate/org info
self.assertIn(
"a course of study offered by {partner_short_name}, "
"an online learning initiative of {partner_long_name} "
"through {platform_name}.".format(
partner_short_name=short_org_name,
partner_long_name=long_org_name,
platform_name='Test Microsite'
),
response.content
)
# Test item from badge info
self.assertIn(
"Add to Mozilla Backpack",
response.content
)
# Test item from microsite info
self.assertIn(
"http://www.testmicrosite.org/about-us",
response.content
)
# Test course overrides
self.assertIn(
"/static/certificates/images/course_override_logo.png",
response.content
)
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
def test_render_html_view_valid_certificate(self):
test_url = get_certificate_url(
user_id=self.user.id,
......@@ -398,7 +496,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase):
course_id=unicode(self.course.id)
)
response = self.client.get(test_url + '?preview=honor')
#accessing certificate web view in preview mode without
# accessing certificate web view in preview mode without
# staff or instructor access should show invalid certificate
self.assertIn('Cannot Find Certificate', response.content)
......@@ -495,16 +593,9 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase):
test_url = '{}?evidence_visit=1'.format(cert_url)
self._add_course_certificates(count=1, signatory_count=2)
self.recreate_tracker()
assertion = BadgeAssertion(
user=self.user, course_id=self.course_id, mode='honor',
data={
'image': 'http://www.example.com/image.png',
'json': {'id': 'http://www.example.com/assertion.json'},
'issuer': 'http://www.example.com/issuer.json',
}
assertion = BadgeAssertionFactory.create(
user=self.user, course_id=self.course_id,
)
assertion.save()
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
assert_event_matches(
......
......@@ -25,13 +25,7 @@ from discussion_api.permissions import (
get_initializable_thread_fields,
)
from discussion_api.serializers import CommentSerializer, ThreadSerializer, get_context
from django_comment_client.base.views import (
THREAD_CREATED_EVENT_NAME,
get_comment_created_event_data,
get_comment_created_event_name,
get_thread_created_event_data,
track_forum_event,
)
from django_comment_client.base.views import track_comment_created_event, track_thread_created_event
from django_comment_common.signals import (
thread_created,
thread_edited,
......@@ -566,13 +560,7 @@ def create_thread(request, thread_data):
api_thread = serializer.data
_do_extra_actions(api_thread, cc_thread, thread_data.keys(), actions_form, context)
track_forum_event(
request,
THREAD_CREATED_EVENT_NAME,
course,
cc_thread,
get_thread_created_event_data(cc_thread, followed=actions_form.cleaned_data["following"])
)
track_thread_created_event(request, course, cc_thread, actions_form.cleaned_data["following"])
return api_thread
......@@ -616,13 +604,7 @@ def create_comment(request, comment_data):
api_comment = serializer.data
_do_extra_actions(api_comment, cc_comment, comment_data.keys(), actions_form, context)
track_forum_event(
request,
get_comment_created_event_name(cc_comment),
context["course"],
cc_comment,
get_comment_created_event_data(cc_comment, cc_thread["commentable_id"], followed=False)
)
track_comment_created_event(request, context["course"], cc_comment, cc_thread["commentable_id"], followed=False)
return api_comment
......
......@@ -13,7 +13,7 @@ from django.core.urlresolvers import reverse
from request_cache.middleware import RequestCache
from mock import patch, ANY, Mock
from nose.tools import assert_true, assert_equal # pylint: disable=no-name-in-module
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from opaque_keys.edx.keys import CourseKey
from lms.lib.comment_client import Thread
from common.test.utils import MockSignalHandlerMixin, disable_signal
......@@ -1641,6 +1641,40 @@ class ForumEventTestCase(ModuleStoreTestCase, MockRequestSetupMixin):
self.assertEqual(name, event_name)
self.assertEqual(event['team_id'], team.team_id)
@ddt.data(
('vote_for_thread', 'thread_id', 'thread'),
('undo_vote_for_thread', 'thread_id', 'thread'),
('vote_for_comment', 'comment_id', 'response'),
('undo_vote_for_comment', 'comment_id', 'response'),
)
@ddt.unpack
@patch('eventtracking.tracker.emit')
@patch('lms.lib.comment_client.utils.requests.request')
def test_thread_voted_event(self, view_name, obj_id_name, obj_type, mock_request, mock_emit):
undo = view_name.startswith('undo')
self._set_mock_request_data(mock_request, {
'closed': False,
'commentable_id': 'test_commentable_id',
'username': 'gumprecht',
})
request = RequestFactory().post('dummy_url', {})
request.user = self.student
request.view_name = view_name
view_function = getattr(views, view_name)
kwargs = dict(course_id=unicode(self.course.id))
kwargs[obj_id_name] = obj_id_name
if not undo:
kwargs.update(value='up')
view_function(request, **kwargs)
self.assertTrue(mock_emit.called)
event_name, event = mock_emit.call_args[0]
self.assertEqual(event_name, 'edx.forum.{}.voted'.format(obj_type))
self.assertEqual(event['target_username'], 'gumprecht')
self.assertEqual(event['undo_vote'], undo)
self.assertEqual(event['vote_value'], 'up')
class UsersEndpointTestCase(ModuleStoreTestCase, MockRequestSetupMixin):
......@@ -1699,7 +1733,7 @@ class UsersEndpointTestCase(ModuleStoreTestCase, MockRequestSetupMixin):
self.assertNotIn("users", content)
def test_course_does_not_exist(self):
course_id = SlashSeparatedCourseKey.from_deprecated_string("does/not/exist")
course_id = CourseKey.from_string("does/not/exist")
response = self.make_request(course_id=course_id, username="other")
self.assertEqual(response.status_code, 404)
......
from django.core.management.base import BaseCommand, CommandError
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from courseware.courses import get_course
......@@ -16,10 +15,7 @@ class Command(BaseCommand):
raise CommandError("Only one course id may be specifiied")
course_id = args[0]
try:
course_key = CourseKey.from_string(course_id)
except InvalidKeyError:
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
course_key = CourseKey.from_string(course_id)
course = get_course(course_key)
if not course:
......
......@@ -3,7 +3,7 @@ Management command to seed default permissions and roles.
"""
from django.core.management.base import BaseCommand, CommandError
from django_comment_common.utils import seed_permissions_roles
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from opaque_keys.edx.keys import CourseKey
class Command(BaseCommand):
......@@ -15,6 +15,6 @@ class Command(BaseCommand):
raise CommandError("Please provide a course id")
if len(args) > 1:
raise CommandError("Too many arguments")
course_id = SlashSeparatedCourseKey.from_deprecated_string(args[0])
course_id = CourseKey.from_string(args[0])
seed_permissions_roles(course_id)
......@@ -3,7 +3,7 @@ Tests for the django comment client integration models
"""
from django.test.testcases import TestCase
from nose.plugins.attrib import attr
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from opaque_keys.edx.keys import CourseKey
from xmodule.modulestore.tests.django_utils import TEST_DATA_MIXED_TOY_MODULESTORE
import django_comment_common.models as models
......@@ -23,7 +23,7 @@ class RoleClassTestCase(ModuleStoreTestCase):
# For course ID, syntax edx/classname/classdate is important
# because xmodel.course_module.id_to_location looks for a string to split
self.course_id = SlashSeparatedCourseKey("edX", "toy", "2012_Fall")
self.course_id = CourseKey.from_string("edX/toy/2012_Fall")
self.student_role = models.Role.objects.get_or_create(name="Student",
course_id=self.course_id)[0]
self.student_role.add_permission("delete_thread")
......@@ -31,7 +31,7 @@ class RoleClassTestCase(ModuleStoreTestCase):
course_id=self.course_id)[0]
self.TA_role = models.Role.objects.get_or_create(name="Community TA",
course_id=self.course_id)[0]
self.course_id_2 = SlashSeparatedCourseKey("edx", "6.002x", "2012_Fall")
self.course_id_2 = CourseKey.from_string("edX/6.002x/2012_Fall")
self.TA_role_2 = models.Role.objects.get_or_create(name="Community TA",
course_id=self.course_id_2)[0]
......
......@@ -206,6 +206,16 @@ define([
expectPaymentButtonEnabled( true );
});
it('displays an error if no payment processors are available', function () {
var view = createView({processors: []});
expect(view.errorModel.get('shown')).toBe(true);
expect(view.errorModel.get('errorTitle')).toEqual(
'All payment options are currently unavailable.'
);
expect(view.errorModel.get('errorMsg')).toEqual(
'Try the transaction again in a few minutes.'
);
});
});
}
);
......@@ -56,7 +56,8 @@ define(['jquery', 'common/js/spec_helpers/template_helpers', 'js/verify_student/
var createView = function( displaySteps, currentStep ) {
return new PayAndVerifyView({
displaySteps: displaySteps,
currentStep: currentStep
currentStep: currentStep,
errorModel: new ( Backbone.Model.extend({}) )()
}).render();
};
......
......@@ -105,10 +105,20 @@ var edx = edx || {};
self._getProductText( templateContext.courseModeSlug, templateContext.upgrade )
);
// create a button for each payment processor
_.each(processors.reverse(), function(processorName) {
$( 'div.payment-buttons' ).append( self._getPaymentButtonHtml(processorName) );
});
if (processors.length === 0) {
// No payment processors are enabled at the moment, so show an error message
this.errorModel.set({
errorTitle: gettext('All payment options are currently unavailable.'),
errorMsg: gettext('Try the transaction again in a few minutes.'),
shown: true
})
}
else {
// create a button for each payment processor
_.each(processors.reverse(), function(processorName) {
$( 'div.payment-buttons' ).append( self._getPaymentButtonHtml(processorName) );
});
}
// Handle payment submission
$( '.payment-button' ).on( 'click', _.bind( this.createOrder, this ) );
......
......@@ -273,8 +273,8 @@ def run_jshint(options):
_prepare_report_dir(jshint_report_dir)
sh(
"jshint {root} --config .jshintrc >> {jshint_report}".format(
root=Env.REPO_ROOT, jshint_report=jshint_report
"jshint . --config .jshintrc >> {jshint_report}".format(
jshint_report=jshint_report
),
ignore_error=True
)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment