Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
d57fd0e4
Commit
d57fd0e4
authored
Jul 14, 2015
by
Matt Drayer
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #8847 from edx/ziafazal/SOL-1021
ziafazal/SOL-1021: Create Analytics events for certificate actions
parents
59e184a8
57f1dc92
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
118 additions
and
26 deletions
+118
-26
cms/djangoapps/contentstore/views/certificates.py
+33
-0
cms/djangoapps/contentstore/views/tests/test_certificates.py
+36
-4
common/test/acceptance/pages/studio/settings_certificates.py
+31
-17
common/test/acceptance/tests/studio/test_studio_settings_certificates.py
+5
-2
lms/djangoapps/certificates/api.py
+5
-1
lms/djangoapps/certificates/tests/test_api.py
+8
-2
No files found.
cms/djangoapps/contentstore/views/certificates.py
View file @
d57fd0e4
...
@@ -33,6 +33,7 @@ from django.views.decorators.http import require_http_methods
...
@@ -33,6 +33,7 @@ from django.views.decorators.http import require_http_methods
from
contentstore.utils
import
reverse_course_url
from
contentstore.utils
import
reverse_course_url
from
edxmako.shortcuts
import
render_to_response
from
edxmako.shortcuts
import
render_to_response
from
opaque_keys.edx.keys
import
CourseKey
,
AssetKey
from
opaque_keys.edx.keys
import
CourseKey
,
AssetKey
from
eventtracking
import
tracker
from
student.auth
import
has_studio_write_access
from
student.auth
import
has_studio_write_access
from
util.db
import
generate_int_id
,
MYSQL_MAX_INT
from
util.db
import
generate_int_id
,
MYSQL_MAX_INT
from
util.json_request
import
JsonResponse
from
util.json_request
import
JsonResponse
...
@@ -247,6 +248,20 @@ class CertificateManager(object):
...
@@ -247,6 +248,20 @@ class CertificateManager(object):
store
.
update_item
(
course
,
request
.
user
.
id
)
store
.
update_item
(
course
,
request
.
user
.
id
)
break
break
@staticmethod
def
track_event
(
event_name
,
event_data
):
"""Track certificate configuration event.
Arguments:
event_name (str): Name of the event to be logged.
event_data (dict): A Dictionary containing event data
Returns:
None
"""
event_name
=
'.'
.
join
([
'edx'
,
'certificate'
,
'configuration'
,
event_name
])
tracker
.
emit
(
event_name
,
event_data
)
class
Certificate
(
object
):
class
Certificate
(
object
):
"""
"""
...
@@ -296,6 +311,10 @@ def certificate_activation_handler(request, course_key_string):
...
@@ -296,6 +311,10 @@ def certificate_activation_handler(request, course_key_string):
break
break
store
.
update_item
(
course
,
request
.
user
.
id
)
store
.
update_item
(
course
,
request
.
user
.
id
)
cert_event_type
=
'activated'
if
is_active
else
'deactivated'
CertificateManager
.
track_event
(
cert_event_type
,
{
'course_id'
:
unicode
(
course
.
id
),
})
return
HttpResponse
(
status
=
200
)
return
HttpResponse
(
status
=
200
)
...
@@ -375,6 +394,10 @@ def certificates_list_handler(request, course_key_string):
...
@@ -375,6 +394,10 @@ def certificates_list_handler(request, course_key_string):
kwargs
=
{
'certificate_id'
:
new_certificate
.
id
}
# pylint: disable=no-member
kwargs
=
{
'certificate_id'
:
new_certificate
.
id
}
# pylint: disable=no-member
)
)
store
.
update_item
(
course
,
request
.
user
.
id
)
store
.
update_item
(
course
,
request
.
user
.
id
)
CertificateManager
.
track_event
(
'created'
,
{
'course_id'
:
unicode
(
course
.
id
),
'configuration_id'
:
new_certificate
.
id
})
course
=
_get_course_and_check_access
(
course_key
,
request
.
user
)
course
=
_get_course_and_check_access
(
course_key
,
request
.
user
)
return
response
return
response
else
:
else
:
...
@@ -414,12 +437,18 @@ def certificates_detail_handler(request, course_key_string, certificate_id):
...
@@ -414,12 +437,18 @@ def certificates_detail_handler(request, course_key_string, certificate_id):
return
JsonResponse
({
"error"
:
err
.
message
},
status
=
400
)
return
JsonResponse
({
"error"
:
err
.
message
},
status
=
400
)
serialized_certificate
=
CertificateManager
.
serialize_certificate
(
new_certificate
)
serialized_certificate
=
CertificateManager
.
serialize_certificate
(
new_certificate
)
cert_event_type
=
'created'
if
match_cert
:
if
match_cert
:
cert_event_type
=
'modified'
certificates_list
[
match_index
]
=
serialized_certificate
certificates_list
[
match_index
]
=
serialized_certificate
else
:
else
:
certificates_list
.
append
(
serialized_certificate
)
certificates_list
.
append
(
serialized_certificate
)
store
.
update_item
(
course
,
request
.
user
.
id
)
store
.
update_item
(
course
,
request
.
user
.
id
)
CertificateManager
.
track_event
(
cert_event_type
,
{
'course_id'
:
unicode
(
course
.
id
),
'configuration_id'
:
serialized_certificate
[
"id"
]
})
return
JsonResponse
(
serialized_certificate
,
status
=
201
)
return
JsonResponse
(
serialized_certificate
,
status
=
201
)
elif
request
.
method
==
"DELETE"
:
elif
request
.
method
==
"DELETE"
:
...
@@ -431,6 +460,10 @@ def certificates_detail_handler(request, course_key_string, certificate_id):
...
@@ -431,6 +460,10 @@ def certificates_detail_handler(request, course_key_string, certificate_id):
course
=
course
,
course
=
course
,
certificate_id
=
certificate_id
certificate_id
=
certificate_id
)
)
CertificateManager
.
track_event
(
'deleted'
,
{
'course_id'
:
unicode
(
course
.
id
),
'configuration_id'
:
certificate_id
})
return
JsonResponse
(
status
=
204
)
return
JsonResponse
(
status
=
204
)
...
...
cms/djangoapps/contentstore/views/tests/test_certificates.py
View file @
d57fd0e4
...
@@ -24,6 +24,7 @@ from student.tests.factories import UserFactory
...
@@ -24,6 +24,7 @@ from student.tests.factories import UserFactory
from
contentstore.views.certificates
import
CertificateManager
from
contentstore.views.certificates
import
CertificateManager
from
django.test.utils
import
override_settings
from
django.test.utils
import
override_settings
from
contentstore.utils
import
get_lms_link_for_certificate_web_view
from
contentstore.utils
import
get_lms_link_for_certificate_web_view
from
util.testing
import
EventTestMixin
FEATURES_WITH_CERTS_ENABLED
=
settings
.
FEATURES
.
copy
()
FEATURES_WITH_CERTS_ENABLED
=
settings
.
FEATURES
.
copy
()
FEATURES_WITH_CERTS_ENABLED
[
'CERTIFICATES_HTML_VIEW'
]
=
True
FEATURES_WITH_CERTS_ENABLED
[
'CERTIFICATES_HTML_VIEW'
]
=
True
...
@@ -194,7 +195,7 @@ class CertificatesBaseTestCase(object):
...
@@ -194,7 +195,7 @@ class CertificatesBaseTestCase(object):
# pylint: disable=no-member
# pylint: disable=no-member
@override_settings
(
FEATURES
=
FEATURES_WITH_CERTS_ENABLED
)
@override_settings
(
FEATURES
=
FEATURES_WITH_CERTS_ENABLED
)
class
CertificatesListHandlerTestCase
(
CourseTestCase
,
CertificatesBaseTestCase
,
HelperMethods
):
class
CertificatesListHandlerTestCase
(
EventTestMixin
,
CourseTestCase
,
CertificatesBaseTestCase
,
HelperMethods
):
"""
"""
Test cases for certificates_list_handler.
Test cases for certificates_list_handler.
"""
"""
...
@@ -202,7 +203,7 @@ class CertificatesListHandlerTestCase(CourseTestCase, CertificatesBaseTestCase,
...
@@ -202,7 +203,7 @@ class CertificatesListHandlerTestCase(CourseTestCase, CertificatesBaseTestCase,
"""
"""
Set up CertificatesListHandlerTestCase.
Set up CertificatesListHandlerTestCase.
"""
"""
super
(
CertificatesListHandlerTestCase
,
self
)
.
setUp
()
super
(
CertificatesListHandlerTestCase
,
self
)
.
setUp
(
'contentstore.views.certificates.tracker'
)
def
_url
(
self
):
def
_url
(
self
):
"""
"""
...
@@ -229,8 +230,13 @@ class CertificatesListHandlerTestCase(CourseTestCase, CertificatesBaseTestCase,
...
@@ -229,8 +230,13 @@ class CertificatesListHandlerTestCase(CourseTestCase, CertificatesBaseTestCase,
self
.
assertEqual
(
response
.
status_code
,
201
)
self
.
assertEqual
(
response
.
status_code
,
201
)
self
.
assertIn
(
"Location"
,
response
)
self
.
assertIn
(
"Location"
,
response
)
content
=
json
.
loads
(
response
.
content
)
content
=
json
.
loads
(
response
.
content
)
self
.
_remove_ids
(
content
)
# pylint: disable=unused-variable
certificate_id
=
self
.
_remove_ids
(
content
)
# pylint: disable=unused-variable
self
.
assertEqual
(
content
,
expected
)
self
.
assertEqual
(
content
,
expected
)
self
.
assert_event_emitted
(
'edx.certificate.configuration.created'
,
course_id
=
unicode
(
self
.
course
.
id
),
configuration_id
=
certificate_id
,
)
def
test_cannot_create_certificate_if_user_has_no_write_permissions
(
self
):
def
test_cannot_create_certificate_if_user_has_no_write_permissions
(
self
):
"""
"""
...
@@ -347,13 +353,19 @@ class CertificatesListHandlerTestCase(CourseTestCase, CertificatesBaseTestCase,
...
@@ -347,13 +353,19 @@ class CertificatesListHandlerTestCase(CourseTestCase, CertificatesBaseTestCase,
@ddt.ddt
@ddt.ddt
@override_settings
(
FEATURES
=
FEATURES_WITH_CERTS_ENABLED
)
@override_settings
(
FEATURES
=
FEATURES_WITH_CERTS_ENABLED
)
class
CertificatesDetailHandlerTestCase
(
CourseTestCase
,
CertificatesBaseTestCase
,
HelperMethods
):
class
CertificatesDetailHandlerTestCase
(
EventTestMixin
,
CourseTestCase
,
CertificatesBaseTestCase
,
HelperMethods
):
"""
"""
Test cases for CertificatesDetailHandlerTestCase.
Test cases for CertificatesDetailHandlerTestCase.
"""
"""
_id
=
0
_id
=
0
def
setUp
(
self
):
# pylint: disable=arguments-differ
"""
Set up CertificatesDetailHandlerTestCase.
"""
super
(
CertificatesDetailHandlerTestCase
,
self
)
.
setUp
(
'contentstore.views.certificates.tracker'
)
def
_url
(
self
,
cid
=-
1
):
def
_url
(
self
,
cid
=-
1
):
"""
"""
Return url for the handler.
Return url for the handler.
...
@@ -388,6 +400,11 @@ class CertificatesDetailHandlerTestCase(CourseTestCase, CertificatesBaseTestCase
...
@@ -388,6 +400,11 @@ class CertificatesDetailHandlerTestCase(CourseTestCase, CertificatesBaseTestCase
)
)
content
=
json
.
loads
(
response
.
content
)
content
=
json
.
loads
(
response
.
content
)
self
.
assertEqual
(
content
,
expected
)
self
.
assertEqual
(
content
,
expected
)
self
.
assert_event_emitted
(
'edx.certificate.configuration.created'
,
course_id
=
unicode
(
self
.
course
.
id
),
configuration_id
=
666
,
)
def
test_can_edit_certificate
(
self
):
def
test_can_edit_certificate
(
self
):
"""
"""
...
@@ -415,6 +432,11 @@ class CertificatesDetailHandlerTestCase(CourseTestCase, CertificatesBaseTestCase
...
@@ -415,6 +432,11 @@ class CertificatesDetailHandlerTestCase(CourseTestCase, CertificatesBaseTestCase
)
)
content
=
json
.
loads
(
response
.
content
)
content
=
json
.
loads
(
response
.
content
)
self
.
assertEqual
(
content
,
expected
)
self
.
assertEqual
(
content
,
expected
)
self
.
assert_event_emitted
(
'edx.certificate.configuration.modified'
,
course_id
=
unicode
(
self
.
course
.
id
),
configuration_id
=
1
,
)
self
.
reload_course
()
self
.
reload_course
()
# Verify that certificate is properly updated in the course.
# Verify that certificate is properly updated in the course.
...
@@ -440,6 +462,11 @@ class CertificatesDetailHandlerTestCase(CourseTestCase, CertificatesBaseTestCase
...
@@ -440,6 +462,11 @@ class CertificatesDetailHandlerTestCase(CourseTestCase, CertificatesBaseTestCase
HTTP_X_REQUESTED_WITH
=
"XMLHttpRequest"
,
HTTP_X_REQUESTED_WITH
=
"XMLHttpRequest"
,
)
)
self
.
assertEqual
(
response
.
status_code
,
204
)
self
.
assertEqual
(
response
.
status_code
,
204
)
self
.
assert_event_emitted
(
'edx.certificate.configuration.deleted'
,
course_id
=
unicode
(
self
.
course
.
id
),
configuration_id
=
'1'
,
)
self
.
reload_course
()
self
.
reload_course
()
# Verify that certificates are properly updated in the course.
# Verify that certificates are properly updated in the course.
certificates
=
self
.
course
.
certificates
[
'certificates'
]
certificates
=
self
.
course
.
certificates
[
'certificates'
]
...
@@ -553,6 +580,11 @@ class CertificatesDetailHandlerTestCase(CourseTestCase, CertificatesBaseTestCase
...
@@ -553,6 +580,11 @@ class CertificatesDetailHandlerTestCase(CourseTestCase, CertificatesBaseTestCase
course
=
self
.
store
.
get_course
(
self
.
course
.
id
)
course
=
self
.
store
.
get_course
(
self
.
course
.
id
)
certificates
=
course
.
certificates
[
'certificates'
]
certificates
=
course
.
certificates
[
'certificates'
]
self
.
assertEqual
(
certificates
[
0
]
.
get
(
'is_active'
),
is_active
)
self
.
assertEqual
(
certificates
[
0
]
.
get
(
'is_active'
),
is_active
)
cert_event_type
=
'activated'
if
is_active
else
'deactivated'
self
.
assert_event_emitted
(
'.'
.
join
([
'edx.certificate.configuration'
,
cert_event_type
]),
course_id
=
unicode
(
self
.
course
.
id
),
)
@ddt.data
(
True
,
False
)
@ddt.data
(
True
,
False
)
def
test_certificate_activation_without_write_permissions
(
self
,
activate
):
def
test_certificate_activation_without_write_permissions
(
self
,
activate
):
...
...
common/test/acceptance/pages/studio/settings_certificates.py
View file @
d57fd0e4
...
@@ -79,8 +79,18 @@ class CertificatesPage(CoursePage):
...
@@ -79,8 +79,18 @@ class CertificatesPage(CoursePage):
We can't use confirm_prompt because its wait_for_notification is flaky when asynchronous operation
We can't use confirm_prompt because its wait_for_notification is flaky when asynchronous operation
completed very quickly.
completed very quickly.
"""
"""
self
.
wait_for_element_visibility
(
'.prompt'
,
'Prompt is visible'
)
EmptyPromise
(
self
.
wait_for_element_visibility
(
'.prompt .action-primary'
,
'Confirmation button is visible'
)
lambda
:
self
.
q
(
css
=
'.prompt'
)
.
present
,
'Confirmation prompt is displayed'
)
.
fulfill
()
EmptyPromise
(
lambda
:
self
.
q
(
css
=
'.prompt .action-primary'
)
.
present
,
'Primary button is displayed'
)
.
fulfill
()
EmptyPromise
(
lambda
:
self
.
q
(
css
=
'.prompt .action-primary'
)
.
visible
,
'Primary button is visible'
)
.
fulfill
()
def
wait_for_first_certificate_button
(
self
):
def
wait_for_first_certificate_button
(
self
):
"""
"""
...
@@ -108,17 +118,23 @@ class CertificatesPage(CoursePage):
...
@@ -108,17 +118,23 @@ class CertificatesPage(CoursePage):
"""
"""
Clicks the 'Create your first certificate' button, which is only displayed at zero state
Clicks the 'Create your first certificate' button, which is only displayed at zero state
"""
"""
self
.
wait_for_first_certificate_button
()
self
.
q
(
css
=
self
.
certficate_css
+
" .new-button"
)
.
first
.
click
()
self
.
q
(
css
=
self
.
certficate_css
+
" .new-button"
)
.
first
.
click
()
def
click_add_certificate_button
(
self
):
def
click_add_certificate_button
(
self
):
"""
"""
Clicks the 'Add new certificate' button, which is displayed when certificates already exist
Clicks the 'Add new certificate' button, which is displayed when certificates already exist
"""
"""
self
.
wait_for_add_certificate_button
()
self
.
q
(
css
=
self
.
certficate_css
+
" .action-add"
)
.
first
.
click
()
self
.
q
(
css
=
self
.
certficate_css
+
" .action-add"
)
.
first
.
click
()
################
def
click_confirmation_prompt_primary_button
(
self
):
# Workflows
"""
################
Clicks the main action presented by the prompt (such as 'Delete')
"""
self
.
wait_for_confirmation_prompt
()
self
.
q
(
css
=
'a.button.action-primary'
)
.
first
.
click
()
self
.
wait_for_ajax
()
class
Certificate
(
object
):
class
Certificate
(
object
):
...
@@ -240,13 +256,19 @@ class Certificate(object):
...
@@ -240,13 +256,19 @@ class Certificate(object):
"""
"""
Returns whether or not the certificate delete icon is present.
Returns whether or not the certificate delete icon is present.
"""
"""
return
self
.
find_css
(
'.actions .delete'
)
.
present
EmptyPromise
(
lambda
:
self
.
find_css
(
'.actions .delete'
)
.
present
,
'Certificate delete button is displayed'
)
.
fulfill
()
def
wait_for_hide_details_toggle
(
self
):
def
wait_for_hide_details_toggle
(
self
):
"""
"""
Certificate details are expanded.
Certificate details are expanded.
"""
"""
return
self
.
find_css
(
'a.detail-toggle.hide-details'
)
.
present
EmptyPromise
(
lambda
:
self
.
find_css
(
'a.detail-toggle.hide-details'
)
.
present
,
'Certificate details are expanded'
)
.
fulfill
()
################
################
# Click Actions
# Click Actions
...
@@ -290,20 +312,12 @@ class Certificate(object):
...
@@ -290,20 +312,12 @@ class Certificate(object):
"""
"""
self
.
find_css
(
'a.detail-toggle'
)
.
first
.
click
()
self
.
find_css
(
'a.detail-toggle'
)
.
first
.
click
()
################
def
click_delete_certificate_button
(
self
):
# Workflows
################
def
delete_certificate
(
self
):
"""
"""
Delete the certificate
Remove the first (possibly the only) certificate from the set
"""
"""
self
.
wait_for_certificate_delete_button
()
self
.
wait_for_certificate_delete_button
()
self
.
find_css
(
'.actions .delete'
)
.
first
.
click
()
self
.
find_css
(
'.actions .delete'
)
.
first
.
click
()
self
.
page
.
wait_for_confirmation_prompt
()
self
.
page
.
q
(
css
=
'a.button.action-primary'
)
.
first
.
click
()
self
.
page
.
q
(
css
=
'a.button.action-primary'
)
.
first
.
click
()
self
.
page
.
wait_for_ajax
()
self
.
page
.
wait_for_ajax
()
...
...
common/test/acceptance/tests/studio/test_studio_settings_certificates.py
View file @
d57fd0e4
...
@@ -126,9 +126,12 @@ class CertificatesTest(StudioCourseTest):
...
@@ -126,9 +126,12 @@ class CertificatesTest(StudioCourseTest):
self
.
assertEqual
(
len
(
self
.
certificates_page
.
certificates
),
1
)
self
.
assertEqual
(
len
(
self
.
certificates_page
.
certificates
),
1
)
# Delete certificate
# Delete the certificate we just created
certificate
.
delete_certificate
()
certificate
.
click_delete_certificate_button
()
self
.
certificates_page
.
click_confirmation_prompt_primary_button
()
self
.
certificates_page
.
wait_for_first_certificate_button
()
# Reload the page and confirm there are no certificates
self
.
certificates_page
.
visit
()
self
.
certificates_page
.
visit
()
self
.
assertEqual
(
len
(
self
.
certificates_page
.
certificates
),
0
)
self
.
assertEqual
(
len
(
self
.
certificates_page
.
certificates
),
0
)
...
...
lms/djangoapps/certificates/api.py
View file @
d57fd0e4
...
@@ -154,7 +154,11 @@ def set_cert_generation_enabled(course_key, is_enabled):
...
@@ -154,7 +154,11 @@ def set_cert_generation_enabled(course_key, is_enabled):
"""
"""
CertificateGenerationCourseSetting
.
set_enabled_for_course
(
course_key
,
is_enabled
)
CertificateGenerationCourseSetting
.
set_enabled_for_course
(
course_key
,
is_enabled
)
cert_event_type
=
'enabled'
if
is_enabled
else
'disabled'
event_name
=
'.'
.
join
([
'edx'
,
'certificate'
,
'generation'
,
cert_event_type
])
tracker
.
emit
(
event_name
,
{
'course_id'
:
unicode
(
course_key
),
})
if
is_enabled
:
if
is_enabled
:
log
.
info
(
u"Enabled self-generated certificates for course '
%
s'."
,
unicode
(
course_key
))
log
.
info
(
u"Enabled self-generated certificates for course '
%
s'."
,
unicode
(
course_key
))
else
:
else
:
...
...
lms/djangoapps/certificates/tests/test_api.py
View file @
d57fd0e4
...
@@ -229,13 +229,13 @@ class GenerateUserCertificatesTest(EventTestMixin, ModuleStoreTestCase):
...
@@ -229,13 +229,13 @@ class GenerateUserCertificatesTest(EventTestMixin, ModuleStoreTestCase):
@attr
(
'shard_1'
)
@attr
(
'shard_1'
)
@ddt.ddt
@ddt.ddt
class
CertificateGenerationEnabledTest
(
TestCase
):
class
CertificateGenerationEnabledTest
(
EventTestMixin
,
TestCase
):
"""Test enabling/disabling self-generated certificates for a course. """
"""Test enabling/disabling self-generated certificates for a course. """
COURSE_KEY
=
CourseLocator
(
org
=
'test'
,
course
=
'test'
,
run
=
'test'
)
COURSE_KEY
=
CourseLocator
(
org
=
'test'
,
course
=
'test'
,
run
=
'test'
)
def
setUp
(
self
):
def
setUp
(
self
):
super
(
CertificateGenerationEnabledTest
,
self
)
.
setUp
()
super
(
CertificateGenerationEnabledTest
,
self
)
.
setUp
(
'certificates.api.tracker'
)
# Since model-based configuration is cached, we need
# Since model-based configuration is cached, we need
# to clear the cache before each test.
# to clear the cache before each test.
...
@@ -256,6 +256,12 @@ class CertificateGenerationEnabledTest(TestCase):
...
@@ -256,6 +256,12 @@ class CertificateGenerationEnabledTest(TestCase):
if
is_course_enabled
is
not
None
:
if
is_course_enabled
is
not
None
:
certs_api
.
set_cert_generation_enabled
(
self
.
COURSE_KEY
,
is_course_enabled
)
certs_api
.
set_cert_generation_enabled
(
self
.
COURSE_KEY
,
is_course_enabled
)
cert_event_type
=
'enabled'
if
is_course_enabled
else
'disabled'
event_name
=
'.'
.
join
([
'edx'
,
'certificate'
,
'generation'
,
cert_event_type
])
self
.
assert_event_emitted
(
event_name
,
course_id
=
unicode
(
self
.
COURSE_KEY
),
)
self
.
_assert_enabled_for_course
(
self
.
COURSE_KEY
,
expect_enabled
)
self
.
_assert_enabled_for_course
(
self
.
COURSE_KEY
,
expect_enabled
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment