Commit 21f75ff2 by JonahStanley

Various stylistic and pylint fixes / changes

Version numbers have very different ranges for different browsers so not having a dictionary of those.

Fixed a whitespace issue

Fixed pylint/pep8 violations

Don't need django_url

Spacing issues

Changed how commenting works

Forgot one

Used wrong name

Changed around importing

Remove django_url

Fixed function orderingn

Made logic nicer for getting a new browser

Modifying tests to run in opera

Needed to increase time to account for slow sauce loading

Now safari LMS works

Forgot an assert statement

Skipping a few tests for opera
parent bb7cbf4d
...@@ -2,7 +2,6 @@ Feature: Advanced (manual) course policy ...@@ -2,7 +2,6 @@ Feature: Advanced (manual) course policy
In order to specify course policy settings for which no custom user interface exists In order to specify course policy settings for which no custom user interface exists
I want to be able to manually enter JSON key /value pairs I want to be able to manually enter JSON key /value pairs
#Sauce labs does not play nicely with CodeMirror
Scenario: A course author sees default advanced settings Scenario: A course author sees default advanced settings
Given I have opened a new course in Studio Given I have opened a new course in Studio
...@@ -13,6 +12,7 @@ Feature: Advanced (manual) course policy ...@@ -13,6 +12,7 @@ Feature: Advanced (manual) course policy
Given I am on the Advanced Course Settings page in Studio Given I am on the Advanced Course Settings page in Studio
Then the settings are alphabetized Then the settings are alphabetized
# Sauce labs does not play nicely with CodeMirror
@skip_sauce @skip_sauce
Scenario: Test cancel editing key value Scenario: Test cancel editing key value
Given I am on the Advanced Course Settings page in Studio Given I am on the Advanced Course Settings page in Studio
...@@ -22,6 +22,7 @@ Feature: Advanced (manual) course policy ...@@ -22,6 +22,7 @@ Feature: Advanced (manual) course policy
And I reload the page And I reload the page
Then the policy key value is unchanged Then the policy key value is unchanged
# Sauce labs does not play nicely with CodeMirror
@skip_sauce @skip_sauce
Scenario: Test editing key value Scenario: Test editing key value
Given I am on the Advanced Course Settings page in Studio Given I am on the Advanced Course Settings page in Studio
...@@ -30,6 +31,7 @@ Feature: Advanced (manual) course policy ...@@ -30,6 +31,7 @@ Feature: Advanced (manual) course policy
And I reload the page And I reload the page
Then the policy key value is changed Then the policy key value is changed
# Sauce labs does not play nicely with CodeMirror
@skip_sauce @skip_sauce
Scenario: Test how multi-line input appears Scenario: Test how multi-line input appears
Given I am on the Advanced Course Settings page in Studio Given I am on the Advanced Course Settings page in Studio
...@@ -38,6 +40,7 @@ Feature: Advanced (manual) course policy ...@@ -38,6 +40,7 @@ Feature: Advanced (manual) course policy
And I reload the page And I reload the page
Then it is displayed as formatted Then it is displayed as formatted
# Sauce labs does not play nicely with CodeMirror
@skip_sauce @skip_sauce
Scenario: Test error if value supplied is of the wrong type Scenario: Test error if value supplied is of the wrong type
Given I am on the Advanced Course Settings page in Studio Given I am on the Advanced Course Settings page in Studio
...@@ -47,6 +50,7 @@ Feature: Advanced (manual) course policy ...@@ -47,6 +50,7 @@ Feature: Advanced (manual) course policy
Then the policy key value is unchanged Then the policy key value is unchanged
# This feature will work in Firefox only when Firefox is the active window # This feature will work in Firefox only when Firefox is the active window
# Sauce labs does not play nicely with CodeMirror
@skip_sauce @skip_sauce
Scenario: Test automatic quoting of non-JSON values Scenario: Test automatic quoting of non-JSON values
Given I am on the Advanced Course Settings page in Studio Given I am on the Advanced Course Settings page in Studio
...@@ -55,6 +59,7 @@ Feature: Advanced (manual) course policy ...@@ -55,6 +59,7 @@ Feature: Advanced (manual) course policy
And I reload the page And I reload the page
Then it is displayed as a string Then it is displayed as a string
# Sauce labs does not play nicely with CodeMirror
@skip_sauce @skip_sauce
Scenario: Confirmation is shown on save Scenario: Confirmation is shown on save
Given I am on the Advanced Course Settings page in Studio Given I am on the Advanced Course Settings page in Studio
......
...@@ -10,8 +10,9 @@ Feature: Course checklists ...@@ -10,8 +10,9 @@ Feature: Course checklists
Then I can check and uncheck tasks in a checklist Then I can check and uncheck tasks in a checklist
And They are correctly selected after reloading the page And They are correctly selected after reloading the page
# CHROME ONLY, due to issues getting link to be active in firefox # There are issues getting link to be active in browsers other than chrome
@skip_firefox @skip_firefox
@skip_opera
Scenario: A task can link to a location within Studio Scenario: A task can link to a location within Studio
Given I have opened Checklists Given I have opened Checklists
When I select a link to the course outline When I select a link to the course outline
...@@ -19,8 +20,9 @@ Feature: Course checklists ...@@ -19,8 +20,9 @@ Feature: Course checklists
And I press the browser back button And I press the browser back button
Then I am brought back to the course outline in the correct state Then I am brought back to the course outline in the correct state
# CHROME ONLY, due to issues getting link to be active in firefox # There are issues getting link to be active in browsers other than chrome
@skip_firefox @skip_firefox
@skip_opera
Scenario: A task can link to a location outside Studio Scenario: A task can link to a location outside Studio
Given I have opened Checklists Given I have opened Checklists
When I select a link to help page When I select a link to help page
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#pylint: disable=W0621 #pylint: disable=W0621
from lettuce import world, step from lettuce import world, step
from lettuce.django import django_url
from common import create_studio_user from common import create_studio_user
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from auth.authz import get_course_groupname_for_role, get_user_by_email from auth.authz import get_course_groupname_for_role, get_user_by_email
...@@ -92,7 +91,7 @@ def remove_course_team_admin(_step, outer_capture, name): ...@@ -92,7 +91,7 @@ def remove_course_team_admin(_step, outer_capture, name):
@step(u'"([^"]*)" logs in$') @step(u'"([^"]*)" logs in$')
def other_user_login(_step, name): def other_user_login(_step, name):
world.visit(django_url('logout')) world.visit('logout')
world.visit('/') world.visit('/')
signin_css = 'a.action-signin' signin_css = 'a.action-signin'
......
...@@ -112,10 +112,10 @@ def changes_not_persisted(step): ...@@ -112,10 +112,10 @@ def changes_not_persisted(step):
@step(u'I see the assignment type "(.*)"$') @step(u'I see the assignment type "(.*)"$')
def i_see_the_assignment_type(_step, name): def i_see_the_assignment_type(_step, name):
assignment_css = '#course-grading-assignment-name' assignment_css = '#course-grading-assignment-name'
assignments = world.css_find(assignment_css) assignments = world.css_find(assignment_css)
types = [ele['value'] for ele in assignments] types = [ele['value'] for ele in assignments]
assert name in types assert name in types
@step(u'I change the highest grade range to "(.*)"$') @step(u'I change the highest grade range to "(.*)"$')
...@@ -144,6 +144,7 @@ def cannot_edit_fail(_step): ...@@ -144,6 +144,7 @@ def cannot_edit_fail(_step):
pass # We should get this exception on failing to edit the element pass # We should get this exception on failing to edit the element
@step(u'I change the grace period to "(.*)"$') @step(u'I change the grace period to "(.*)"$')
def i_change_grace_period(_step, grace_period): def i_change_grace_period(_step, grace_period):
grace_period_css = '#course-grading-graceperiod' grace_period_css = '#course-grading-graceperiod'
......
Feature: Video Component Editor Feature: Video Component Editor
As a course author, I want to be able to create video components. As a course author, I want to be able to create video components.
#Sauce Labs cannot delete cookies
Scenario: User can view Video metadata Scenario: User can view Video metadata
Given I have created a Video component Given I have created a Video component
And I edit the component And I edit the component
...@@ -14,12 +12,14 @@ Feature: Video Component Editor ...@@ -14,12 +12,14 @@ Feature: Video Component Editor
Then I can modify the display name Then I can modify the display name
And my video display name change is persisted on save And my video display name change is persisted on save
# Sauce Labs cannot delete cookies
@skip_sauce @skip_sauce
Scenario: Captions are hidden when "show captions" is false Scenario: Captions are hidden when "show captions" is false
Given I have created a Video component Given I have created a Video component
And I have set "show captions" to False And I have set "show captions" to False
Then when I view the video it does not show the captions Then when I view the video it does not show the captions
# Sauce Labs cannot delete cookies
@skip_sauce @skip_sauce
Scenario: Captions are shown when "show captions" is true Scenario: Captions are shown when "show captions" is true
Given I have created a Video component Given I have created a Video component
......
...@@ -12,6 +12,9 @@ from django.core.management import call_command ...@@ -12,6 +12,9 @@ from django.core.management import call_command
from django.conf import settings from django.conf import settings
from selenium.common.exceptions import WebDriverException from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from requests import put
from base64 import encodestring
from json import dumps
# Let the LMS and CMS do their one-time setup # Let the LMS and CMS do their one-time setup
# For example, setting up mongo caches # For example, setting up mongo caches
...@@ -42,27 +45,32 @@ LOGGER.info("Loading the lettuce acceptance testing terrain file...") ...@@ -42,27 +45,32 @@ LOGGER.info("Loading the lettuce acceptance testing terrain file...")
MAX_VALID_BROWSER_ATTEMPTS = 20 MAX_VALID_BROWSER_ATTEMPTS = 20
# https://gist.github.com/santiycr/1644439
import requests def get_username_and_key():
import base64 """
try: Returns the Sauce Labs username and access ID as set by environment variables
import json """
except ImportError: return {"username": settings.SAUCE.get('USERNAME'), "access-key": settings.SAUCE.get('ACCESS_ID')}
import simplejson as json
def set_job_status(jobid, passed=True): def set_job_status(jobid, passed=True):
body_content = json.dumps({"passed": passed}) """
Sets the job status on sauce labs
"""
body_content = dumps({"passed": passed})
config = get_username_and_key() config = get_username_and_key()
base64string = base64.encodestring('{}:{}'.format(config['username'], config['access-key']))[:-1] base64string = encodestring('{}:{}'.format(config['username'], config['access-key']))[:-1]
result = requests.put('http://saucelabs.com/rest/v1/{}/jobs/{}'.format(config['username'], world.jobid), result = put('http://saucelabs.com/rest/v1/{}/jobs/{}'.format(config['username'], world.jobid),
data=body_content, data=body_content,
headers={"Authorization": "Basic {}".format(base64string)}) headers={"Authorization": "Basic {}".format(base64string)})
return result.status_code == 200 return result.status_code == 200
def make_desired_capabilities(): def make_desired_capabilities():
desired_capabilities = settings.SAUCE.get('BROWSER', DesiredCapabilities.CHROME) """
Returns a DesiredCapabilities object corresponding to the environment sauce parameters
"""
desired_capabilities = settings.SAUCE.get('BROWSER', DesiredCapabilities.CHROME)
desired_capabilities['platform'] = settings.SAUCE.get('PLATFORM') desired_capabilities['platform'] = settings.SAUCE.get('PLATFORM')
desired_capabilities['version'] = settings.SAUCE.get('VERSION') desired_capabilities['version'] = settings.SAUCE.get('VERSION')
desired_capabilities['device-type'] = settings.SAUCE.get('DEVICE') desired_capabilities['device-type'] = settings.SAUCE.get('DEVICE')
...@@ -77,61 +85,55 @@ def make_desired_capabilities(): ...@@ -77,61 +85,55 @@ def make_desired_capabilities():
return desired_capabilities return desired_capabilities
def get_username_and_key():
return {"username": settings.SAUCE.get('USERNAME'), "access-key": settings.SAUCE.get('ACCESS_ID')}
@before.harvest @before.harvest
def initial_setup(server): def initial_setup(server):
""" """
Launch the browser once before executing the tests. Launch the browser once before executing the tests.
""" """
world.absorb(settings.SAUCE.get('SAUCE_ENABLED'),'SAUCE_ENABLED') world.absorb(settings.SAUCE.get('SAUCE_ENABLED'), 'SAUCE_ENABLED')
browser_driver = getattr(settings, 'LETTUCE_BROWSER', 'chrome')
# There is an issue with ChromeDriver2 r195627 on Ubuntu
# in which we sometimes get an invalid browser session.
# This is a work-around to ensure that we get a valid session.
success = False
num_attempts = 0
while (not success) and num_attempts < MAX_VALID_BROWSER_ATTEMPTS:
# Get a browser session
if world.SAUCE_ENABLED:
config = get_username_and_key()
world.browser = Browser(
'remote',
url="http://{}:{}@ondemand.saucelabs.com:80/wd/hub".format(config['username'], config['access-key']),
**make_desired_capabilities()
)
world.absorb(world.browser.driver.session_id, 'jobid')
else:
world.browser = Browser(browser_driver)
world.browser.driver.implicitly_wait(30) if not world.SAUCE_ENABLED:
browser_driver = getattr(settings, 'LETTUCE_BROWSER', 'chrome')
# There is an issue with ChromeDriver2 r195627 on Ubuntu
# in which we sometimes get an invalid browser session.
# This is a work-around to ensure that we get a valid session.
success = False
num_attempts = 0
while (not success) and num_attempts < MAX_VALID_BROWSER_ATTEMPTS:
world.browser = Browser(browser_driver)
# Try to visit the main page # Try to visit the main page
# If the browser session is invalid, this will # If the browser session is invalid, this will
# raise a WebDriverException # raise a WebDriverException
try: try:
world.visit('/') world.visit('/')
except WebDriverException: except WebDriverException:
world.browser.quit() world.browser.quit()
num_attempts += 1 num_attempts += 1
else: else:
success = True success = True
# If we were unable to get a valid session within the limit of attempts, # If we were unable to get a valid session within the limit of attempts,
# then we cannot run the tests. # then we cannot run the tests.
if not success: if not success:
raise IOError("Could not acquire valid {driver} browser session.".format(driver='remote')) raise IOError("Could not acquire valid {driver} browser session.".format(driver='remote'))
# Set the browser size to 1280x1024
if not world.SAUCE_ENABLED:
world.browser.driver.set_window_size(1280, 1024) world.browser.driver.set_window_size(1280, 1024)
else:
config = get_username_and_key()
world.browser = Browser(
'remote',
url="http://{}:{}@ondemand.saucelabs.com:80/wd/hub".format(config['username'], config['access-key']),
**make_desired_capabilities()
)
world.browser.driver.implicitly_wait(30)
world.absorb(world.browser.driver.session_id, 'jobid')
@before.each_scenario @before.each_scenario
def reset_data(scenario): def reset_data(scenario):
......
...@@ -99,7 +99,7 @@ def i_am_logged_in_user(step): ...@@ -99,7 +99,7 @@ def i_am_logged_in_user(step):
@step('I am not logged in$') @step('I am not logged in$')
def i_am_not_logged_in(step): def i_am_not_logged_in(step):
world.visit(django_url('logout')) world.visit('logout')
@step('I am staff for course "([^"]*)"$') @step('I am staff for course "([^"]*)"$')
...@@ -138,10 +138,13 @@ def should_have_link_with_path_and_text(step, path, text): ...@@ -138,10 +138,13 @@ def should_have_link_with_path_and_text(step, path, text):
@step(r'should( not)? see "(.*)" (?:somewhere|anywhere) (?:in|on) (?:the|this) page') @step(r'should( not)? see "(.*)" (?:somewhere|anywhere) (?:in|on) (?:the|this) page')
def should_see_in_the_page(step, doesnt_appear, text): def should_see_in_the_page(step, doesnt_appear, text):
multiplier = 1
if world.SAUCE_ENABLED:
multiplier = 2
if doesnt_appear: if doesnt_appear:
assert world.browser.is_text_not_present(text, wait_time=5) assert world.browser.is_text_not_present(text, wait_time=5*multiplier)
else: else:
assert world.browser.is_text_present(text, wait_time=5) assert world.browser.is_text_present(text, wait_time=5*multiplier)
@step('I am logged in$') @step('I am logged in$')
...@@ -150,7 +153,7 @@ def i_am_logged_in(step): ...@@ -150,7 +153,7 @@ def i_am_logged_in(step):
world.log_in(username='robot', password='test') world.log_in(username='robot', password='test')
world.browser.visit(django_url('/')) world.browser.visit(django_url('/'))
# You should not see the login link # You should not see the login link
world.is_css_not_present('a#login') assert world.is_css_not_present('a#login')
@step(u'I am an edX user$') @step(u'I am an edX user$')
......
...@@ -11,7 +11,7 @@ Feature: Login in as a registered user ...@@ -11,7 +11,7 @@ Feature: Login in as a registered user
And I submit my credentials on the login form And I submit my credentials on the login form
Then I should see the login error message "This account has not been activated" Then I should see the login error message "This account has not been activated"
# CHROME ONLY, firefox will not redirect properly # firefox will not redirect properly when the whole suite is run
@skip_firefox @skip_firefox
Scenario: Login to an activated account Scenario: Login to an activated account
Given I am an edX user Given I am an edX user
......
...@@ -13,6 +13,8 @@ Feature: Navigate Course ...@@ -13,6 +13,8 @@ Feature: Navigate Course
When I click on subsection "2" When I click on subsection "2"
Then I should see the content of subsection "2" Then I should see the content of subsection "2"
# Clicking on the sequence link doesn't work on opera through sauce
@skip_opera
Scenario: I can navigate to sequences Scenario: I can navigate to sequences
Given I am viewing a section with multiple sequences Given I am viewing a section with multiple sequences
When I click on sequence "2" When I click on sequence "2"
......
...@@ -3,7 +3,7 @@ Feature: Sign in ...@@ -3,7 +3,7 @@ Feature: Sign in
As a new user As a new user
I want to signup for a student account I want to signup for a student account
# CHROME ONLY, firefox will not redirect properly # firefox will not redirect properly
@skip_firefox @skip_firefox
Scenario: Sign up from the homepage Scenario: Sign up from the homepage
Given I visit the homepage Given I visit the homepage
......
...@@ -11,7 +11,7 @@ Feature: Video component ...@@ -11,7 +11,7 @@ Feature: Video component
Given the course has a Video component in Youtube mode Given the course has a Video component in Youtube mode
Then when I view the video it has rendered in Youtube mode Then when I view the video it has rendered in Youtube mode
#Firefox doesn't have HTML5 # Firefox doesn't have HTML5
@skip_firefox @skip_firefox
Scenario: Autoplay is enabled in LMS for a Video component Scenario: Autoplay is enabled in LMS for a Video component
Given the course has a Video component in HTML5 mode Given the course has a Video component in HTML5 mode
......
...@@ -27,25 +27,26 @@ DESIRED_CAPABILITIES = { ...@@ -27,25 +27,26 @@ DESIRED_CAPABILITIES = {
'android': DesiredCapabilities.ANDROID 'android': DesiredCapabilities.ANDROID
} }
PLATFORMS = ['Linux', 'OS X 10.8', 'OS X 10.6', 'Windows 8', 'Windows 7', 'Windows XP']
#HACK #HACK
#This needs to be done because Jenkins needs to satisfy URLs, JSON, BASH, SAUCE, and PYTHON #This needs to be done because Jenkins needs to satisfy URLs, JSON, BASH, SAUCE, and PYTHON
#This is the simplest way to adhere to all of these requirements and still be readible #This is the simplest way to adhere to all of these requirements and still be readable
DEFAULT_CONFIG = 'Linux-chrome--' DEFAULT_CONFIG = 'Linux-chrome--'
SAUCE_INFO = os.environ.get('SAUCE_INFO', DEFAULT_CONFIG).split('-') SAUCE_INFO = os.environ.get('SAUCE_INFO', DEFAULT_CONFIG).split('-')
if len(SAUCE_INFO) !=4: if len(SAUCE_INFO) != 4:
SAUCE_INFO = DEFAULT_CONFIG.split('-') SAUCE_INFO = DEFAULT_CONFIG.split('-')
# Information needed to utilize Sauce Labs. # Information needed to utilize Sauce Labs.
SAUCE = { SAUCE = {
'SAUCE_ENABLED': os.environ.get('SAUCE_ENABLED'), 'SAUCE_ENABLED': os.environ.get('SAUCE_ENABLED'),
'USERNAME': os.environ.get('SAUCE_USER_NAME'), 'USERNAME': os.environ.get('SAUCE_USER_NAME'),
'ACCESS_ID': os.environ.get('SAUCE_API_KEY'), 'ACCESS_ID': os.environ.get('SAUCE_API_KEY'),
'BROWSER': DESIRED_CAPABILITIES.get(SAUCE_INFO[0].lower(), DesiredCapabilities.CHROME), 'PLATFORM': SAUCE_INFO[0] if SAUCE_INFO[0] in PLATFORMS else 'Linux',
'PLATFORM': SAUCE_INFO[0], 'BROWSER': DESIRED_CAPABILITIES.get(SAUCE_INFO[1].lower(), DesiredCapabilities.CHROME),
'VERSION': SAUCE_INFO[2], 'VERSION': SAUCE_INFO[2],
'DEVICE': SAUCE_INFO[3], 'DEVICE': SAUCE_INFO[3],
'SESSION': 'Jenkins Acceptance Tests', 'SESSION': 'Jenkins Acceptance Tests',
'BUILD': os.environ.get('JOB_NAME', 'LETTUCE TESTS'), 'BUILD': os.environ.get('BUILD_DISPLAY_NAME', 'LETTUCE TESTS'),
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment