Merge pull request #1874 from MITx/fix/zoldak/upgrade-lettuce
Upgrade lettuce and factory boy versions, fix CMS lettuce tests to run under phantomjs or tag them to skip
This commit is contained in:
@@ -11,6 +11,7 @@ Feature: Advanced (manual) course policy
|
||||
Given I am on the Advanced Course Settings page in Studio
|
||||
Then the settings are alphabetized
|
||||
|
||||
@skip-phantom
|
||||
Scenario: Test cancel editing key value
|
||||
Given I am on the Advanced Course Settings page in Studio
|
||||
When I edit the value of a policy key
|
||||
@@ -19,6 +20,7 @@ Feature: Advanced (manual) course policy
|
||||
And I reload the page
|
||||
Then the policy key value is unchanged
|
||||
|
||||
@skip-phantom
|
||||
Scenario: Test editing key value
|
||||
Given I am on the Advanced Course Settings page in Studio
|
||||
When I edit the value of a policy key and save
|
||||
@@ -26,6 +28,7 @@ Feature: Advanced (manual) course policy
|
||||
And I reload the page
|
||||
Then the policy key value is changed
|
||||
|
||||
@skip-phantom
|
||||
Scenario: Test how multi-line input appears
|
||||
Given I am on the Advanced Course Settings page in Studio
|
||||
When I create a JSON object as a value
|
||||
@@ -33,6 +36,7 @@ Feature: Advanced (manual) course policy
|
||||
And I reload the page
|
||||
Then it is displayed as formatted
|
||||
|
||||
@skip-phantom
|
||||
Scenario: Test automatic quoting of non-JSON values
|
||||
Given I am on the Advanced Course Settings page in Studio
|
||||
When I create a non-JSON value not in quotes
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
|
||||
from lettuce import world, step
|
||||
from common import *
|
||||
import time
|
||||
from terrain.steps import reload_the_page
|
||||
|
||||
from nose.tools import assert_true, assert_false, assert_equal
|
||||
from nose.tools import assert_false, assert_equal
|
||||
|
||||
"""
|
||||
http://selenium.googlecode.com/svn/trunk/docs/api/py/webdriver/selenium.webdriver.common.keys.html
|
||||
@@ -18,8 +15,8 @@ VALUE_CSS = 'textarea.json'
|
||||
DISPLAY_NAME_KEY = "display_name"
|
||||
DISPLAY_NAME_VALUE = '"Robot Super Course"'
|
||||
|
||||
############### ACTIONS ####################
|
||||
|
||||
############### ACTIONS ####################
|
||||
@step('I select the Advanced Settings$')
|
||||
def i_select_advanced_settings(step):
|
||||
expand_icon_css = 'li.nav-course-settings i.icon-expand'
|
||||
@@ -38,7 +35,7 @@ def i_am_on_advanced_course_settings(step):
|
||||
@step(u'I press the "([^"]*)" notification button$')
|
||||
def press_the_notification_button(step, name):
|
||||
css = 'a.%s-button' % name.lower()
|
||||
world.css_click_at(css)
|
||||
world.css_click(css)
|
||||
|
||||
|
||||
@step(u'I edit the value of a policy key$')
|
||||
@@ -52,7 +49,7 @@ def edit_the_value_of_a_policy_key(step):
|
||||
|
||||
|
||||
@step(u'I edit the value of a policy key and save$')
|
||||
def edit_the_value_of_a_policy_key(step):
|
||||
def edit_the_value_of_a_policy_key_and_save(step):
|
||||
change_display_name_value(step, '"foo"')
|
||||
|
||||
|
||||
@@ -90,7 +87,7 @@ def it_is_formatted(step):
|
||||
|
||||
|
||||
@step('it is displayed as a string')
|
||||
def it_is_formatted(step):
|
||||
def it_is_displayed_as_string(step):
|
||||
assert_policy_entries([DISPLAY_NAME_KEY], ['"quote me"'])
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ Feature: Course checklists
|
||||
Then I can check and uncheck tasks in a checklist
|
||||
And They are correctly selected after I reload the page
|
||||
|
||||
@skip-phantom
|
||||
@skip-firefox
|
||||
Scenario: A task can link to a location within Studio
|
||||
Given I have opened Checklists
|
||||
When I select a link to the course outline
|
||||
@@ -17,8 +19,9 @@ Feature: Course checklists
|
||||
And I press the browser back button
|
||||
Then I am brought back to the course outline in the correct state
|
||||
|
||||
@skip-phantom
|
||||
@skip-firefox
|
||||
Scenario: A task can link to a location outside Studio
|
||||
Given I have opened Checklists
|
||||
When I select a link to help page
|
||||
Then I am brought to the help page in a new window
|
||||
|
||||
|
||||
@@ -89,8 +89,6 @@ def i_am_brought_to_help_page_in_new_window(step):
|
||||
assert_equal('http://help.edge.edx.org/', world.browser.url)
|
||||
|
||||
|
||||
|
||||
|
||||
############### HELPER METHODS ####################
|
||||
def verifyChecklist2Status(completed, total, percentage):
|
||||
def verify_count(driver):
|
||||
@@ -107,9 +105,11 @@ def verifyChecklist2Status(completed, total, percentage):
|
||||
|
||||
|
||||
def toggleTask(checklist, task):
|
||||
world.css_click('#course-checklist' + str(checklist) +'-task' + str(task))
|
||||
world.css_click('#course-checklist' + str(checklist) + '-task' + str(task))
|
||||
|
||||
|
||||
# TODO: figure out a way to do this in phantom and firefox
|
||||
# For now we will mark the scenerios that use this method as skipped
|
||||
def clickActionLink(checklist, task, actionText):
|
||||
# toggle checklist item to make sure that the link button is showing
|
||||
toggleTask(checklist, task)
|
||||
@@ -121,4 +121,3 @@ def clickActionLink(checklist, task, actionText):
|
||||
|
||||
world.wait_for(verify_action_link_text)
|
||||
action_link.click()
|
||||
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
Feature: Course Settings
|
||||
As a course author, I want to be able to configure my course settings.
|
||||
|
||||
@skip-phantom
|
||||
Scenario: User can set course dates
|
||||
Given I have opened a new course in Studio
|
||||
When I select Schedule and Details
|
||||
And I set course dates
|
||||
Then I see the set dates on refresh
|
||||
|
||||
@skip-phantom
|
||||
Scenario: User can clear previously set course dates (except start date)
|
||||
Given I have set course dates
|
||||
And I clear all the dates except start
|
||||
Then I see cleared dates on refresh
|
||||
|
||||
@skip-phantom
|
||||
Scenario: User cannot clear the course start date
|
||||
Given I have set course dates
|
||||
And I clear the course start date
|
||||
|
||||
@@ -3,6 +3,7 @@ Feature: Create Section
|
||||
As a course author
|
||||
I want to create and edit sections
|
||||
|
||||
@skip-phantom
|
||||
Scenario: Add a new section to a course
|
||||
Given I have opened a new course in Studio
|
||||
When I click the New Section link
|
||||
|
||||
@@ -1,32 +1,33 @@
|
||||
Feature: Overview Toggle Section
|
||||
In order to quickly view the details of a course's section or to scan the inventory of sections
|
||||
As a course author
|
||||
I want to toggle the visibility of each section's subsection details in the overview listing
|
||||
As a course author
|
||||
I want to toggle the visibility of each section's subsection details in the overview listing
|
||||
|
||||
Scenario: The default layout for the overview page is to show sections in expanded view
|
||||
Given I have a course with multiple sections
|
||||
When I navigate to the course overview page
|
||||
Then I see the "Collapse All Sections" link
|
||||
And all sections are expanded
|
||||
When I navigate to the course overview page
|
||||
Then I see the "Collapse All Sections" link
|
||||
And all sections are expanded
|
||||
|
||||
Scenario: Expand /collapse for a course with no sections
|
||||
Given I have a course with no sections
|
||||
When I navigate to the course overview page
|
||||
Then I do not see the "Collapse All Sections" link
|
||||
When I navigate to the course overview page
|
||||
Then I do not see the "Collapse All Sections" link
|
||||
|
||||
@skip-phantom
|
||||
Scenario: Collapse link appears after creating first section of a course
|
||||
Given I have a course with no sections
|
||||
When I navigate to the course overview page
|
||||
And I add a section
|
||||
Then I see the "Collapse All Sections" link
|
||||
And all sections are expanded
|
||||
When I navigate to the course overview page
|
||||
And I add a section
|
||||
Then I see the "Collapse All Sections" link
|
||||
And all sections are expanded
|
||||
|
||||
@skip-phantom
|
||||
Scenario: Collapse link is not removed after last section of a course is deleted
|
||||
Given I have a course with 1 section
|
||||
And I navigate to the course overview page
|
||||
When I press the "section" delete icon
|
||||
And I confirm the alert
|
||||
And I navigate to the course overview page
|
||||
When I press the "section" delete icon
|
||||
And I confirm the alert
|
||||
Then I see the "Collapse All Sections" link
|
||||
|
||||
Scenario: Collapsing all sections when all sections are expanded
|
||||
@@ -57,4 +58,4 @@ Feature: Overview Toggle Section
|
||||
When I expand the first section
|
||||
And I click the "Expand All Sections" link
|
||||
Then I see the "Collapse All Sections" link
|
||||
And all sections are expanded
|
||||
And all sections are expanded
|
||||
|
||||
@@ -3,13 +3,15 @@ Feature: Create Subsection
|
||||
As a course author
|
||||
I want to create and edit subsections
|
||||
|
||||
Scenario: Add a new subsection to a section
|
||||
@skip-phantom
|
||||
Scenario: Add a new subsection to a section
|
||||
Given I have opened a new course section in Studio
|
||||
When I click the New Subsection link
|
||||
And I enter the subsection name and click save
|
||||
Then I see my subsection on the Courseware page
|
||||
|
||||
Scenario: Add a new subsection (with a name containing a quote) to a section (bug #216)
|
||||
@skip-phantom
|
||||
Scenario: Add a new subsection (with a name containing a quote) to a section (bug #216)
|
||||
Given I have opened a new course section in Studio
|
||||
When I click the New Subsection link
|
||||
And I enter a subsection name with a quote and click save
|
||||
@@ -17,7 +19,7 @@ Feature: Create Subsection
|
||||
And I click to edit the subsection name
|
||||
Then I see the complete subsection name with a quote in the editor
|
||||
|
||||
Scenario: Assign grading type to a subsection and verify it is still shown after refresh (bug #258)
|
||||
Scenario: Assign grading type to a subsection and verify it is still shown after refresh (bug #258)
|
||||
Given I have opened a new course section in Studio
|
||||
And I have added a new subsection
|
||||
And I mark it as Homework
|
||||
@@ -25,20 +27,19 @@ Feature: Create Subsection
|
||||
And I reload the page
|
||||
Then I see it marked as Homework
|
||||
|
||||
Scenario: Set a due date in a different year (bug #256)
|
||||
@skip-phantom
|
||||
Scenario: Set a due date in a different year (bug #256)
|
||||
Given I have opened a new subsection in Studio
|
||||
And I have set a release date and due date in different years
|
||||
Then I see the correct dates
|
||||
And I reload the page
|
||||
Then I see the correct dates
|
||||
|
||||
@skip-phantom
|
||||
Scenario: Delete a subsection
|
||||
@skip-phantom
|
||||
Scenario: Delete a subsection
|
||||
Given I have opened a new course section in Studio
|
||||
And I have added a new subsection
|
||||
And I see my subsection on the Courseware page
|
||||
When I press the "subsection" delete icon
|
||||
And I confirm the alert
|
||||
Then the subsection does not exist
|
||||
|
||||
|
||||
|
||||
@@ -36,3 +36,4 @@ DATABASES = {
|
||||
INSTALLED_APPS += ('lettuce.django',)
|
||||
LETTUCE_APPS = ('contentstore',)
|
||||
LETTUCE_SERVER_PORT = 8001
|
||||
LETTUCE_BROWSER = 'chrome'
|
||||
|
||||
@@ -2,17 +2,17 @@ from student.models import (User, UserProfile, Registration,
|
||||
CourseEnrollmentAllowed, CourseEnrollment)
|
||||
from django.contrib.auth.models import Group
|
||||
from datetime import datetime
|
||||
from factory import Factory, SubFactory, post_generation
|
||||
from factory import DjangoModelFactory, Factory, SubFactory, PostGenerationMethodCall
|
||||
from uuid import uuid4
|
||||
|
||||
|
||||
class GroupFactory(Factory):
|
||||
class GroupFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = Group
|
||||
|
||||
name = 'staff_MITx/999/Robot_Super_Course'
|
||||
|
||||
|
||||
class UserProfileFactory(Factory):
|
||||
class UserProfileFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = UserProfile
|
||||
|
||||
user = None
|
||||
@@ -23,19 +23,20 @@ class UserProfileFactory(Factory):
|
||||
goals = 'World domination'
|
||||
|
||||
|
||||
class RegistrationFactory(Factory):
|
||||
class RegistrationFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = Registration
|
||||
|
||||
user = None
|
||||
activation_key = uuid4().hex
|
||||
|
||||
|
||||
class UserFactory(Factory):
|
||||
class UserFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = User
|
||||
|
||||
username = 'robot'
|
||||
email = 'robot+test@edx.org'
|
||||
password = 'test'
|
||||
password = PostGenerationMethodCall('set_password',
|
||||
'test')
|
||||
first_name = 'Robot'
|
||||
last_name = 'Test'
|
||||
is_staff = False
|
||||
@@ -44,26 +45,19 @@ class UserFactory(Factory):
|
||||
last_login = datetime(2012, 1, 1)
|
||||
date_joined = datetime(2011, 1, 1)
|
||||
|
||||
@post_generation
|
||||
def set_password(self, create, extracted, **kwargs):
|
||||
self._raw_password = self.password
|
||||
self.set_password(self.password)
|
||||
if create:
|
||||
self.save()
|
||||
|
||||
|
||||
class AdminFactory(UserFactory):
|
||||
is_staff = True
|
||||
|
||||
|
||||
class CourseEnrollmentFactory(Factory):
|
||||
class CourseEnrollmentFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = CourseEnrollment
|
||||
|
||||
user = SubFactory(UserFactory)
|
||||
course_id = 'edX/toy/2012_Fall'
|
||||
|
||||
|
||||
class CourseEnrollmentAllowedFactory(Factory):
|
||||
class CourseEnrollmentAllowedFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = CourseEnrollmentAllowed
|
||||
|
||||
email = 'test@edx.org'
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from lettuce import before, after, world
|
||||
from splinter.browser import Browser
|
||||
from logging import getLogger
|
||||
from django.core.management import call_command
|
||||
from django.conf import settings
|
||||
|
||||
# Let the LMS and CMS do their one-time setup
|
||||
# For example, setting up mongo caches
|
||||
@@ -10,18 +12,14 @@ from cms import one_time_startup
|
||||
logger = getLogger(__name__)
|
||||
logger.info("Loading the lettuce acceptance testing terrain file...")
|
||||
|
||||
from django.core.management import call_command
|
||||
|
||||
|
||||
@before.harvest
|
||||
def initial_setup(server):
|
||||
'''
|
||||
Launch the browser once before executing the tests
|
||||
'''
|
||||
# Launch the browser app (choose one of these below)
|
||||
world.browser = Browser('chrome')
|
||||
# world.browser = Browser('phantomjs')
|
||||
# world.browser = Browser('firefox')
|
||||
browser_driver = getattr(settings, 'LETTUCE_BROWSER', 'chrome')
|
||||
world.browser = Browser(browser_driver)
|
||||
|
||||
|
||||
@before.each_scenario
|
||||
@@ -34,6 +32,15 @@ def reset_data(scenario):
|
||||
call_command('flush', interactive=False)
|
||||
|
||||
|
||||
@after.each_scenario
|
||||
def screenshot_on_error(scenario):
|
||||
'''
|
||||
Save a screenshot to help with debugging
|
||||
'''
|
||||
if scenario.failed:
|
||||
world.browser.driver.save_screenshot('/tmp/last_failed_scenario.png')
|
||||
|
||||
|
||||
@after.all
|
||||
def teardown_browser(total):
|
||||
'''
|
||||
|
||||
@@ -132,6 +132,8 @@ def i_am_logged_in(step):
|
||||
world.create_user('robot')
|
||||
world.log_in('robot', 'test')
|
||||
world.browser.visit(django_url('/'))
|
||||
# You should not see the login link
|
||||
assert_equals(world.browser.find_by_css('a#login'), [])
|
||||
|
||||
|
||||
@step(u'I am an edX user$')
|
||||
|
||||
@@ -1,62 +1,85 @@
|
||||
import factory
|
||||
from student.models import (User, UserProfile, Registration,
|
||||
CourseEnrollmentAllowed)
|
||||
from courseware.models import StudentModule
|
||||
from django.contrib.auth.models import Group
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
import json
|
||||
from functools import partial
|
||||
|
||||
from factory import DjangoModelFactory, SubFactory
|
||||
from student.tests.factories import UserFactory as StudentUserFactory
|
||||
from student.tests.factories import GroupFactory as StudentGroupFactory
|
||||
from student.tests.factories import UserProfileFactory as StudentUserProfileFactory
|
||||
from student.tests.factories import CourseEnrollmentAllowedFactory as StudentCourseEnrollmentAllowedFactory
|
||||
from student.tests.factories import RegistrationFactory as StudentRegistrationFactory
|
||||
from courseware.models import StudentModule, XModuleContentField, XModuleSettingsField
|
||||
from courseware.models import XModuleStudentInfoField, XModuleStudentPrefsField
|
||||
|
||||
from xmodule.modulestore import Location
|
||||
|
||||
location = partial(Location, 'i4x', 'edX', 'test_course', 'problem')
|
||||
|
||||
|
||||
class UserProfileFactory(factory.Factory):
|
||||
FACTORY_FOR = UserProfile
|
||||
|
||||
user = None
|
||||
class UserProfileFactory(StudentUserProfileFactory):
|
||||
name = 'Robot Studio'
|
||||
courseware = 'course.xml'
|
||||
|
||||
|
||||
class RegistrationFactory(factory.Factory):
|
||||
FACTORY_FOR = Registration
|
||||
|
||||
user = None
|
||||
activation_key = uuid.uuid4().hex
|
||||
class RegistrationFactory(StudentRegistrationFactory):
|
||||
pass
|
||||
|
||||
|
||||
class UserFactory(factory.Factory):
|
||||
FACTORY_FOR = User
|
||||
|
||||
username = 'robot'
|
||||
class UserFactory(StudentUserFactory):
|
||||
email = 'robot@edx.org'
|
||||
password = 'test'
|
||||
first_name = 'Robot'
|
||||
last_name = 'Tester'
|
||||
is_staff = False
|
||||
is_active = True
|
||||
is_superuser = False
|
||||
last_login = datetime.now()
|
||||
date_joined = datetime.now()
|
||||
|
||||
|
||||
class GroupFactory(factory.Factory):
|
||||
FACTORY_FOR = Group
|
||||
|
||||
class GroupFactory(StudentGroupFactory):
|
||||
name = 'test_group'
|
||||
|
||||
|
||||
class CourseEnrollmentAllowedFactory(factory.Factory):
|
||||
FACTORY_FOR = CourseEnrollmentAllowed
|
||||
|
||||
email = 'test@edx.org'
|
||||
course_id = 'edX/test/2012_Fall'
|
||||
class CourseEnrollmentAllowedFactory(StudentCourseEnrollmentAllowedFactory):
|
||||
pass
|
||||
|
||||
|
||||
class StudentModuleFactory(factory.Factory):
|
||||
class StudentModuleFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = StudentModule
|
||||
|
||||
module_type = "problem"
|
||||
student = factory.SubFactory(UserFactory)
|
||||
student = SubFactory(UserFactory)
|
||||
course_id = "MITx/999/Robot_Super_Course"
|
||||
state = None
|
||||
grade = None
|
||||
max_grade = None
|
||||
done = 'na'
|
||||
|
||||
|
||||
class ContentFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = XModuleContentField
|
||||
|
||||
field_name = 'existing_field'
|
||||
value = json.dumps('old_value')
|
||||
definition_id = location('def_id').url()
|
||||
|
||||
|
||||
class SettingsFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = XModuleSettingsField
|
||||
|
||||
field_name = 'existing_field'
|
||||
value = json.dumps('old_value')
|
||||
usage_id = '%s-%s' % ('edX/test_course/test', location('def_id').url())
|
||||
|
||||
|
||||
class StudentPrefsFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = XModuleStudentPrefsField
|
||||
|
||||
field_name = 'existing_field'
|
||||
value = json.dumps('old_value')
|
||||
student = SubFactory(UserFactory)
|
||||
module_type = 'problem'
|
||||
|
||||
|
||||
class StudentInfoFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = XModuleStudentInfoField
|
||||
|
||||
field_name = 'existing_field'
|
||||
value = json.dumps('old_value')
|
||||
student = SubFactory(UserFactory)
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import factory
|
||||
import json
|
||||
from mock import Mock
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from functools import partial
|
||||
|
||||
from courseware.model_data import LmsKeyValueStore, InvalidWriteError, InvalidScopeError, ModelDataCache
|
||||
from courseware.models import StudentModule, XModuleContentField, XModuleSettingsField, XModuleStudentInfoField, XModuleStudentPrefsField
|
||||
from courseware.model_data import LmsKeyValueStore, InvalidWriteError
|
||||
from courseware.model_data import InvalidScopeError, ModelDataCache
|
||||
from courseware.models import StudentModule, XModuleContentField, XModuleSettingsField
|
||||
from courseware.models import XModuleStudentInfoField, XModuleStudentPrefsField
|
||||
|
||||
from student.tests.factories import UserFactory
|
||||
from courseware.tests.factories import StudentModuleFactory as cmfStudentModuleFactory
|
||||
from courseware.tests.factories import ContentFactory, SettingsFactory
|
||||
from courseware.tests.factories import StudentPrefsFactory, StudentInfoFactory
|
||||
|
||||
from xblock.core import Scope, BlockScope
|
||||
from xmodule.modulestore import Location
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
||||
@@ -19,6 +23,7 @@ def mock_field(scope, name):
|
||||
field.name = name
|
||||
return field
|
||||
|
||||
|
||||
def mock_descriptor(fields=[], lms_fields=[]):
|
||||
descriptor = Mock()
|
||||
descriptor.stores_state = True
|
||||
@@ -37,53 +42,9 @@ prefs_key = partial(LmsKeyValueStore.Key, Scope.preferences, 'user', 'problem')
|
||||
user_info_key = partial(LmsKeyValueStore.Key, Scope.user_info, 'user', None)
|
||||
|
||||
|
||||
class UserFactory(factory.Factory):
|
||||
FACTORY_FOR = User
|
||||
|
||||
username = 'user'
|
||||
|
||||
|
||||
class StudentModuleFactory(factory.Factory):
|
||||
FACTORY_FOR = StudentModule
|
||||
|
||||
module_type = 'problem'
|
||||
class StudentModuleFactory(cmfStudentModuleFactory):
|
||||
module_state_key = location('def_id').url()
|
||||
student = factory.SubFactory(UserFactory)
|
||||
course_id = course_id
|
||||
state = None
|
||||
|
||||
|
||||
class ContentFactory(factory.Factory):
|
||||
FACTORY_FOR = XModuleContentField
|
||||
|
||||
field_name = 'existing_field'
|
||||
value = json.dumps('old_value')
|
||||
definition_id = location('def_id').url()
|
||||
|
||||
|
||||
class SettingsFactory(factory.Factory):
|
||||
FACTORY_FOR = XModuleSettingsField
|
||||
|
||||
field_name = 'existing_field'
|
||||
value = json.dumps('old_value')
|
||||
usage_id = '%s-%s' % (course_id, location('def_id').url())
|
||||
|
||||
|
||||
class StudentPrefsFactory(factory.Factory):
|
||||
FACTORY_FOR = XModuleStudentPrefsField
|
||||
|
||||
field_name = 'existing_field'
|
||||
value = json.dumps('old_value')
|
||||
student = factory.SubFactory(UserFactory)
|
||||
module_type = 'problem'
|
||||
|
||||
|
||||
class StudentInfoFactory(factory.Factory):
|
||||
FACTORY_FOR = XModuleStudentInfoField
|
||||
|
||||
field_name = 'existing_field'
|
||||
value = json.dumps('old_value')
|
||||
student = factory.SubFactory(UserFactory)
|
||||
|
||||
|
||||
class TestDescriptorFallback(TestCase):
|
||||
@@ -114,7 +75,7 @@ class TestDescriptorFallback(TestCase):
|
||||
class TestInvalidScopes(TestCase):
|
||||
def setUp(self):
|
||||
self.desc_md = {}
|
||||
self.user = UserFactory.create()
|
||||
self.user = UserFactory.create(username='user')
|
||||
self.mdc = ModelDataCache([mock_descriptor([mock_field(Scope.user_state, 'a_field')])], course_id, self.user)
|
||||
self.kvs = LmsKeyValueStore(self.desc_md, self.mdc)
|
||||
|
||||
@@ -180,7 +141,7 @@ class TestStudentModuleStorage(TestCase):
|
||||
|
||||
class TestMissingStudentModule(TestCase):
|
||||
def setUp(self):
|
||||
self.user = UserFactory.create()
|
||||
self.user = UserFactory.create(username='user')
|
||||
self.desc_md = {}
|
||||
self.mdc = ModelDataCache([mock_descriptor()], course_id, self.user)
|
||||
self.kvs = LmsKeyValueStore(self.desc_md, self.mdc)
|
||||
|
||||
@@ -1,42 +1,18 @@
|
||||
import string
|
||||
import random
|
||||
import collections
|
||||
|
||||
from django.test import TestCase
|
||||
from factory import DjangoModelFactory
|
||||
from student.tests.factories import UserFactory, CourseEnrollmentFactory
|
||||
|
||||
import factory
|
||||
from django.contrib.auth.models import User
|
||||
from student.models import UserProfile, CourseEnrollment
|
||||
from django_comment_client.models import Role, Permission
|
||||
|
||||
import django_comment_client.models as models
|
||||
import django_comment_client.utils as utils
|
||||
|
||||
import xmodule.modulestore.django as django
|
||||
|
||||
|
||||
class UserFactory(factory.Factory):
|
||||
FACTORY_FOR = User
|
||||
username = 'robot'
|
||||
password = '123456'
|
||||
email = 'robot@edx.org'
|
||||
is_active = True
|
||||
is_staff = False
|
||||
|
||||
|
||||
class CourseEnrollmentFactory(factory.Factory):
|
||||
FACTORY_FOR = CourseEnrollment
|
||||
user = factory.SubFactory(UserFactory)
|
||||
course_id = 'edX/toy/2012_Fall'
|
||||
|
||||
|
||||
class RoleFactory(factory.Factory):
|
||||
class RoleFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = Role
|
||||
name = 'Student'
|
||||
course_id = 'edX/toy/2012_Fall'
|
||||
|
||||
|
||||
class PermissionFactory(factory.Factory):
|
||||
class PermissionFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = Permission
|
||||
name = 'create_comment'
|
||||
|
||||
|
||||
@@ -5,15 +5,19 @@ import json
|
||||
from uuid import uuid4
|
||||
from random import shuffle
|
||||
from tempfile import NamedTemporaryFile
|
||||
from factory import Factory, SubFactory
|
||||
from factory import DjangoModelFactory, SubFactory
|
||||
|
||||
from django.test import TestCase
|
||||
from django.test.client import Client
|
||||
from django.test.utils import override_settings
|
||||
from django.core.management import call_command
|
||||
from django.core.urlresolvers import reverse
|
||||
from nose.tools import assert_true
|
||||
|
||||
from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE
|
||||
from licenses.models import CourseSoftware, UserLicense
|
||||
from courseware.tests.tests import LoginEnrollmentTestCase, get_user
|
||||
|
||||
from student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
|
||||
@@ -27,7 +31,7 @@ SERIAL_1 = '123456abcde'
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CourseSoftwareFactory(Factory):
|
||||
class CourseSoftwareFactory(DjangoModelFactory):
|
||||
'''Factory for generating CourseSoftware objects in database'''
|
||||
FACTORY_FOR = CourseSoftware
|
||||
|
||||
@@ -37,7 +41,7 @@ class CourseSoftwareFactory(Factory):
|
||||
course_id = COURSE_1
|
||||
|
||||
|
||||
class UserLicenseFactory(Factory):
|
||||
class UserLicenseFactory(DjangoModelFactory):
|
||||
'''
|
||||
Factory for generating UserLicense objects in database
|
||||
|
||||
@@ -46,19 +50,24 @@ class UserLicenseFactory(Factory):
|
||||
'''
|
||||
FACTORY_FOR = UserLicense
|
||||
|
||||
user = None
|
||||
software = SubFactory(CourseSoftwareFactory)
|
||||
serial = SERIAL_1
|
||||
|
||||
|
||||
class LicenseTestCase(LoginEnrollmentTestCase):
|
||||
class LicenseTestCase(TestCase):
|
||||
'''Tests for licenses.views'''
|
||||
def setUp(self):
|
||||
'''creates a user and logs in'''
|
||||
self.setup_viewtest_user()
|
||||
# self.setup_viewtest_user()
|
||||
self.user = UserFactory(username='test',
|
||||
email='test@edx.org', password='test_password')
|
||||
self.client = Client()
|
||||
assert_true(self.client.login(username='test', password='test_password'))
|
||||
self.software = CourseSoftwareFactory()
|
||||
|
||||
def test_get_license(self):
|
||||
UserLicenseFactory(user=get_user(self.viewtest_email), software=self.software)
|
||||
UserLicenseFactory(user=self.user, software=self.software)
|
||||
response = self.client.post(reverse('user_software_license'),
|
||||
{'software': SOFTWARE_1, 'generate': 'false'},
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
@@ -125,7 +134,7 @@ class LicenseTestCase(LoginEnrollmentTestCase):
|
||||
self.assertEqual(404, response.status_code)
|
||||
|
||||
def test_get_license_without_login(self):
|
||||
self.logout()
|
||||
self.client.logout()
|
||||
response = self.client.post(reverse('user_software_license'),
|
||||
{'software': SOFTWARE_1, 'generate': 'false'},
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
|
||||
@@ -67,3 +67,4 @@ MITX_FEATURES['STUB_VIDEO_FOR_TESTING'] = True
|
||||
# Include the lettuce app for acceptance testing, including the 'harvest' django-admin command
|
||||
INSTALLED_APPS += ('lettuce.django',)
|
||||
LETTUCE_APPS = ('courseware',)
|
||||
LETTUCE_BROWSER = 'chrome'
|
||||
|
||||
@@ -61,8 +61,8 @@ sphinx==1.1.3
|
||||
|
||||
# Used for testing
|
||||
coverage==3.6
|
||||
factory_boy==1.3.0
|
||||
lettuce==0.2.15
|
||||
factory_boy==2.0.2
|
||||
lettuce==0.2.16
|
||||
mock==0.8.0
|
||||
nosexcover==1.0.7
|
||||
pep8==1.4.5
|
||||
|
||||
Reference in New Issue
Block a user