diff --git a/common/djangoapps/terrain/course_helpers.py b/common/djangoapps/terrain/course_helpers.py index 22222d30a4..cd454016f2 100644 --- a/common/djangoapps/terrain/course_helpers.py +++ b/common/djangoapps/terrain/course_helpers.py @@ -2,7 +2,7 @@ # pylint: disable=W0621 from lettuce import world -from django.contrib.auth.models import User +from django.contrib.auth.models import User, Group from student.models import CourseEnrollment from xmodule.modulestore.django import editable_modulestore from xmodule.contentstore.django import contentstore @@ -41,14 +41,28 @@ def log_in(username='robot', password='test', email='robot@edx.org', name='Robot @world.absorb -def register_by_course_id(course_id, is_staff=False): - create_user('robot', 'password') - u = User.objects.get(username='robot') +def register_by_course_id(course_id, username='robot', password='test', is_staff=False): + create_user(username, password) + user = User.objects.get(username=username) if is_staff: u.is_staff = True u.save() CourseEnrollment.enroll(u, course_id) +@world.absorb +def add_to_course_staff(username, course_num): + """ + Add the user with `username` to the course staff group + for `course_num`. + """ + # Based on code in lms/djangoapps/courseware/access.py + group_name = "instructor_{}".format(course_num) + group, _ = Group.objects.get_or_create(name=group_name) + group.save() + + user = User.objects.get(username=username) + user.groups.add(group) + @world.absorb def clear_courses(): diff --git a/common/djangoapps/terrain/ui_helpers.py b/common/djangoapps/terrain/ui_helpers.py index e400ca9b95..f143973c46 100644 --- a/common/djangoapps/terrain/ui_helpers.py +++ b/common/djangoapps/terrain/ui_helpers.py @@ -45,8 +45,29 @@ def is_css_not_present(css_selector, wait_time=5): world.browser.driver.implicitly_wait(world.IMPLICIT_WAIT) @world.absorb -def css_has_text(css_selector, text, index=0): - return world.css_text(css_selector, index=index) == text +def css_has_text(css_selector, text, index=0, strip=False): + """ + Return a boolean indicating whether the element with `css_selector` + has `text`. + + If `strip` is True, strip whitespace at beginning/end of both + strings before comparing. + + If there are multiple elements matching the css selector, + use `index` to indicate which one. + """ + # If we're expecting a non-empty string, give the page + # a chance to fill in text fields. + if text: + world.wait_for(lambda _: world.css_text(css_selector, index=index)) + + actual_text = world.css_text(css_selector, index=index) + + if strip: + actual_text = actual_text.strip() + text = text.strip() + + return actual_text == text @world.absorb diff --git a/lms/djangoapps/instructor/features/bulk_email.feature b/lms/djangoapps/instructor/features/bulk_email.feature new file mode 100644 index 0000000000..7b46d1ec9b --- /dev/null +++ b/lms/djangoapps/instructor/features/bulk_email.feature @@ -0,0 +1,16 @@ +@shard_2 +Feature: Bulk Email + As an instructor, + In order to communicate with students and staff + I want to send email to staff and students in a course. + + Scenario: Send bulk email + Given I am an instructor for a course + When I send email to "" + Then Email is sent to "" + + Examples: + | Recipient | + | myself | + | course staff | + | students, staff, and instructors | diff --git a/lms/djangoapps/instructor/features/bulk_email.py b/lms/djangoapps/instructor/features/bulk_email.py new file mode 100644 index 0000000000..6706f0f430 --- /dev/null +++ b/lms/djangoapps/instructor/features/bulk_email.py @@ -0,0 +1,165 @@ +""" +Define steps for bulk email acceptance test. +""" + +from lettuce import world, step +from lettuce.django import mail +from nose.tools import assert_in, assert_true, assert_equal +from django.core.management import call_command + + +@step(u'I am an instructor for a course') +def i_am_an_instructor(step): + + # Clear existing courses to avoid conflicts + world.clear_courses() + + # Create a new course + course = world.CourseFactory.create( + org='edx', + number='999', + display_name='Test Course' + ) + + # Register the instructor as staff for the course + world.register_by_course_id( + 'edx/999/Test_Course', + username='instructor', + password='password', + is_staff=True + ) + world.add_to_course_staff('instructor', '999') + + # Register another staff member + world.register_by_course_id( + 'edx/999/Test_Course', + username='staff', + password='password', + is_staff=True + ) + world.add_to_course_staff('staff', '999') + + # Register a student + world.register_by_course_id( + 'edx/999/Test_Course', + username='student', + password='password', + is_staff=False + ) + + # Log in as the instructor for the course + world.log_in( + username='instructor', + password='password', + email="instructor@edx.org", + name="Instructor" + ) + + +# Dictionary mapping a description of the email recipient +# to the corresponding