common.py 7.69 KB
Newer Older
1
# pylint: disable=missing-docstring
2
# pylint: disable=redefined-outer-name
3

4 5
from __future__ import absolute_import

6 7
import time

8
from lettuce import world, step, before
9
from lettuce.django import django_url
10
from django.contrib.auth.models import User
11
from django.core.urlresolvers import reverse
12
from student.models import CourseEnrollment
13
from xmodule.modulestore.django import modulestore
14 15
from xmodule.course_module import CourseDescriptor
from courseware.courses import get_course_by_id
16
from xmodule import seq_module, vertical_block
17 18 19
from logging import getLogger
logger = getLogger(__name__)

Will Daly committed
20

21 22 23 24 25 26 27
@step('I (.*) capturing of screenshots before and after each step$')
def configure_screenshots_for_all_steps(_step, action):
    """
    A step to be used in *.feature files. Enables/disables
    automatic saving of screenshots before and after each step in a
    scenario.
    """
28
    action = action.strip()
29 30 31 32 33 34 35
    if action == 'enable':
        world.auto_capture_screenshots = True
    elif action == 'disable':
        world.auto_capture_screenshots = False
    else:
        raise ValueError('Parameter `action` should be one of "enable" or "disable".')

36

37
@world.absorb
38 39 40 41 42 43 44
def capture_screenshot_before_after(func):
    """
    A decorator that will take a screenshot before and after the applied
    function is run. Use this if you do not want to capture screenshots
    for each step in a scenario, but rather want to debug a single function.
    """
    def inner(*args, **kwargs):
45
        prefix = round(time.time() * 1000)
46 47 48 49

        world.capture_screenshot("{}_{}_{}".format(
            prefix, func.func_name, 'before'
        ))
50
        ret_val = func(*args, **kwargs)
51 52 53 54 55 56 57
        world.capture_screenshot("{}_{}_{}".format(
            prefix, func.func_name, 'after'
        ))
        return ret_val
    return inner


58
@step(u'The course "([^"]*)" exists$')
59
def create_course(_step, course):
60 61 62 63

    # First clear the modulestore so we don't try to recreate
    # the same course twice
    # This also ensures that the necessary templates are loaded
64
    world.clear_courses()
65 66 67 68

    # Create the course
    # We always use the same org and display name,
    # but vary the course identifier (e.g. 600x or 191x)
69 70 71 72 73 74 75 76 77 78 79
    world.scenario_dict['COURSE'] = world.CourseFactory.create(
        org='edx',
        number=course,
        display_name='Test Course'
    )

    # Add a chapter to the course to contain problems
    world.scenario_dict['CHAPTER'] = world.ItemFactory.create(
        parent_location=world.scenario_dict['COURSE'].location,
        category='chapter',
        display_name='Test Chapter',
80
        publish_item=True,  # Not needed for direct-only but I'd rather the test didn't know that
81 82 83 84
    )

    world.scenario_dict['SECTION'] = world.ItemFactory.create(
        parent_location=world.scenario_dict['CHAPTER'].location,
85
        category='sequential',
86
        display_name='Test Section',
87
        publish_item=True,
88
    )
89

Will Daly committed
90

91
@step(u'I am registered for the course "([^"]*)"$')
92 93 94 95 96
def i_am_registered_for_the_course(step, course):
    # Create the course
    create_course(step, course)

    # Create the user
97
    world.create_user('robot', 'test')
98
    user = User.objects.get(username='robot')
99 100

    # If the user is not already enrolled, enroll the user.
Jay Zoldak committed
101
    # TODO: change to factory
102
    CourseEnrollment.enroll(user, course_id(course))
103

104
    world.log_in(username='robot', password='test')
Calen Pennington committed
105

Will Daly committed
106

107
@step(u'The course "([^"]*)" has extra tab "([^"]*)"$')
108 109 110 111 112
def add_tab_to_course(_step, course, extra_tab_name):
    world.ItemFactory.create(
        parent_location=course_location(course),
        category="static_tab",
        display_name=str(extra_tab_name))
113

Calen Pennington committed
114

115 116 117 118 119 120 121
@step(u'I am in a course$')
def go_into_course(step):
    step.given('I am registered for the course "6.002x"')
    step.given('And I am logged in')
    step.given('And I click on View Courseware')


122 123
# Do we really use these 3 w/ a different course than is in the scenario_dict? if so, why? If not,
# then get rid of the override arg
124
def course_id(course_num):
125
    return world.scenario_dict['COURSE'].id.replace(course=course_num)
126

Will Daly committed
127

128
def course_location(course_num):
129
    return world.scenario_dict['COURSE'].location.replace(course=course_num)
130

Will Daly committed
131

132
def section_location(course_num):
133
    return world.scenario_dict['SECTION'].location.replace(course=course_num)
134 135 136 137 138 139 140 141 142 143 144


def visit_scenario_item(item_key):
    """
    Go to the courseware page containing the item stored in `world.scenario_dict`
    under the key `item_key`
    """

    url = django_url(reverse(
        'jump_to',
        kwargs={
145 146
            'course_id': unicode(world.scenario_dict['COURSE'].id),
            'location': unicode(world.scenario_dict[item_key].location),
147 148 149 150
        }
    ))

    world.browser.visit(url)
151 152 153 154 155 156 157 158


def get_courses():
    '''
    Returns dict of lists of courses available, keyed by course.org (ie university).
    Courses are sorted by course.number.
    '''
    courses = [c for c in modulestore().get_courses()
159 160
               if isinstance(c, CourseDescriptor)]  # skip error descriptors
    courses = sorted(courses, key=lambda course: course.location.course)
161 162 163 164 165 166 167 168 169 170
    return courses


def get_courseware_with_tabs(course_id):
    """
    Given a course_id (string), return a courseware array of dictionaries for the
    top three levels of navigation. Same as get_courseware() except include
    the tabs on the right hand main navigation page.

    This hides the appropriate courseware as defined by the hide_from_toc field:
Calen Pennington committed
171
    chapter.hide_from_toc
172 173 174 175 176 177 178 179 180 181 182 183

    Example:

    [{
        'chapter_name': 'Overview',
        'sections': [{
            'clickable_tab_count': 0,
            'section_name': 'Welcome',
            'tab_classes': []
        }, {
            'clickable_tab_count': 1,
            'section_name': 'System Usage Sequence',
184
            'tab_classes': ['VerticalBlock']
185 186 187 188 189 190 191 192 193 194 195 196 197 198
        }, {
            'clickable_tab_count': 0,
            'section_name': 'Lab0: Using the tools',
            'tab_classes': ['HtmlDescriptor', 'HtmlDescriptor', 'CapaDescriptor']
        }, {
            'clickable_tab_count': 0,
            'section_name': 'Circuit Sandbox',
            'tab_classes': []
        }]
    }, {
        'chapter_name': 'Week 1',
        'sections': [{
            'clickable_tab_count': 4,
            'section_name': 'Administrivia and Circuit Elements',
199
            'tab_classes': ['VerticalBlock', 'VerticalBlock', 'VerticalBlock', 'VerticalBlock']
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
        }, {
            'clickable_tab_count': 0,
            'section_name': 'Basic Circuit Analysis',
            'tab_classes': ['CapaDescriptor', 'CapaDescriptor', 'CapaDescriptor']
        }, {
            'clickable_tab_count': 0,
            'section_name': 'Resistor Divider',
            'tab_classes': []
        }, {
            'clickable_tab_count': 0,
            'section_name': 'Week 1 Tutorials',
            'tab_classes': []
        }]
    }, {
        'chapter_name': 'Midterm Exam',
        'sections': [{
            'clickable_tab_count': 2,
            'section_name': 'Midterm Exam',
218
            'tab_classes': ['VerticalBlock', 'VerticalBlock']
219 220 221 222 223
        }]
    }]
    """

    course = get_course_by_id(course_id)
Calen Pennington committed
224
    chapters = [chapter for chapter in course.get_children() if not chapter.hide_from_toc]
225
    courseware = [{
226
        'chapter_name': c.display_name_with_default_escaped,
227
        'sections': [{
228
            'section_name': s.display_name_with_default_escaped,
229 230
            'clickable_tab_count': len(s.get_children()) if (type(s) == seq_module.SequenceDescriptor) else 0,
            'tabs': [{
231
                'children_count': len(t.get_children()) if (type(t) == vertical_block.VerticalBlock) else 0,
232 233 234 235
                'class': t.__class__.__name__} for t in s.get_children()
            ]
        } for s in c.get_children() if not s.hide_from_toc]
    } for c in chapters]
236 237

    return courseware