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
import time
7
from logging import getLogger
8

9
from django.contrib.auth.models import User
10
from django.core.urlresolvers import reverse
11 12 13
from lettuce import before, step, world
from lettuce.django import django_url

14
from courseware.courses import get_course_by_id
15
from student.models import CourseEnrollment
16
from xmodule import seq_module, vertical_block
17 18 19
from xmodule.course_module import CourseDescriptor
from xmodule.modulestore.django import modulestore

20 21
logger = getLogger(__name__)

Will Daly committed
22

23 24 25 26 27 28 29
@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.
    """
30
    action = action.strip()
31 32 33 34 35 36 37
    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".')

38

39
@world.absorb
40 41 42 43 44 45 46
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):
47
        prefix = round(time.time() * 1000)
48 49 50 51

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


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

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

    # Create the course
    # We always use the same org and display name,
    # but vary the course identifier (e.g. 600x or 191x)
71 72 73 74 75 76 77 78 79 80 81
    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',
82
        publish_item=True,  # Not needed for direct-only but I'd rather the test didn't know that
83 84 85 86
    )

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

Will Daly committed
92

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

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

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

106
    world.log_in(username='robot', password='test')
Calen Pennington committed
107

Will Daly committed
108

109
@step(u'The course "([^"]*)" has extra tab "([^"]*)"$')
110 111 112 113 114
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))
115

Calen Pennington committed
116

117 118 119 120 121 122 123
@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')


124 125
# 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
126
def course_id(course_num):
127
    return world.scenario_dict['COURSE'].id.replace(course=course_num)
128

Will Daly committed
129

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

Will Daly committed
133

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


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={
147 148
            'course_id': unicode(world.scenario_dict['COURSE'].id),
            'location': unicode(world.scenario_dict[item_key].location),
149 150 151 152
        }
    ))

    world.browser.visit(url)
153 154 155 156 157 158 159 160


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()
161 162
               if isinstance(c, CourseDescriptor)]  # skip error descriptors
    courses = sorted(courses, key=lambda course: course.location.course)
163 164 165 166 167 168 169 170 171 172
    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
173
    chapter.hide_from_toc
174 175 176 177 178 179 180 181 182 183 184 185

    Example:

    [{
        'chapter_name': 'Overview',
        'sections': [{
            'clickable_tab_count': 0,
            'section_name': 'Welcome',
            'tab_classes': []
        }, {
            'clickable_tab_count': 1,
            'section_name': 'System Usage Sequence',
186
            'tab_classes': ['VerticalBlock']
187 188 189 190 191 192 193 194 195 196 197 198 199 200
        }, {
            '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',
201
            'tab_classes': ['VerticalBlock', 'VerticalBlock', 'VerticalBlock', 'VerticalBlock']
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
        }, {
            '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',
220
            'tab_classes': ['VerticalBlock', 'VerticalBlock']
221 222 223 224 225
        }]
    }]
    """

    course = get_course_by_id(course_id)
Calen Pennington committed
226
    chapters = [chapter for chapter in course.get_children() if not chapter.hide_from_toc]
227
    courseware = [{
228
        'chapter_name': c.display_name_with_default_escaped,
229
        'sections': [{
230
            'section_name': s.display_name_with_default_escaped,
231 232
            'clickable_tab_count': len(s.get_children()) if (type(s) == seq_module.SequenceDescriptor) else 0,
            'tabs': [{
233
                'children_count': len(t.get_children()) if (type(t) == vertical_block.VerticalBlock) else 0,
234 235 236 237
                '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]
238 239

    return courseware