Merge pull request #12599 from edx/renzo/supplement-program-data

Supplement program data with course and enrollment data
This commit is contained in:
Renzo Lucioni
2016-06-02 12:04:51 -04:00
9 changed files with 234 additions and 66 deletions

View File

@@ -1,9 +1,9 @@
"""
Stub implementation of programs service for acceptance tests
"""
import re
import urlparse
from .http import StubHttpRequestHandler, StubHttpService
@@ -11,10 +11,13 @@ class StubProgramsServiceHandler(StubHttpRequestHandler): # pylint: disable=mis
def do_GET(self): # pylint: disable=invalid-name, missing-docstring
pattern_handlers = {
"/api/v1/programs/$": self.get_programs_list,
r'/api/v1/programs/$': self.get_programs_list,
r'/api/v1/programs/(\d+)/$': self.get_program_details,
}
if self.match_pattern(pattern_handlers):
return
self.send_response(404, content="404 Not Found")
def match_pattern(self, pattern_handlers):
@@ -25,7 +28,7 @@ class StubProgramsServiceHandler(StubHttpRequestHandler): # pylint: disable=mis
for pattern in pattern_handlers:
match = re.match(pattern, path)
if match:
pattern_handlers[pattern](**match.groupdict())
pattern_handlers[pattern](*match.groups())
return True
return None
@@ -36,6 +39,13 @@ class StubProgramsServiceHandler(StubHttpRequestHandler): # pylint: disable=mis
programs = self.server.config.get('programs', [])
self.send_json_response(programs)
def get_program_details(self, program_id):
"""
Stubs a program details endpoint.
"""
program = self.server.config.get('programs.{}'.format(program_id), [])
self.send_json_response(program)
class StubProgramsService(StubHttpService): # pylint: disable=missing-docstring
HANDLER_CLASS = StubProgramsServiceHandler

View File

@@ -1,49 +1,31 @@
"""
Tools to create programs-related data for use in bok choy tests.
"""
from collections import namedtuple
import json
import requests
from . import PROGRAMS_STUB_URL
from .config import ConfigModelFixture
from openedx.core.djangoapps.programs.tests import factories
FakeProgram = namedtuple('FakeProgram', ['name', 'status', 'org_key', 'course_id'])
class ProgramsFixture(object):
"""
Interface to set up mock responses from the Programs stub server.
"""
def install_programs(self, fake_programs):
"""
Sets the response data for the programs list endpoint.
At present, `fake_programs` must be a iterable of FakeProgram named tuples.
"""
programs = []
for program in fake_programs:
run_mode = factories.RunMode(course_key=program.course_id)
course_code = factories.CourseCode(run_modes=[run_mode])
org = factories.Organization(key=program.org_key)
program = factories.Program(
name=program.name,
status=program.status,
organizations=[org],
course_codes=[course_code]
)
programs.append(program)
api_result = {'results': programs}
def install_programs(self, programs, is_list=True):
"""Sets the response data for Programs API endpoints."""
if is_list:
key = 'programs'
api_result = {'results': programs}
else:
program = programs[0]
key = 'programs.{}'.format(program['id'])
api_result = program
requests.put(
'{}/set_config'.format(PROGRAMS_STUB_URL),
data={'programs': json.dumps(api_result)},
data={key: json.dumps(api_result)},
)

View File

@@ -24,7 +24,8 @@ class ProgramListingPage(PageObject):
class ProgramDetailsPage(PageObject):
"""Program details page."""
url = BASE_URL + '/dashboard/programs/123/program-name/'
program_id = 123
url = BASE_URL + '/dashboard/programs/{}/program-name/'.format(program_id)
def is_browser_on_page(self):
return self.q(css='.js-program-details-wrapper').present

View File

@@ -1,11 +1,12 @@
"""Acceptance tests for LMS-hosted Programs pages"""
from nose.plugins.attrib import attr
from ...fixtures.programs import FakeProgram, ProgramsFixture, ProgramsConfigMixin
from ...fixtures.programs import ProgramsFixture, ProgramsConfigMixin
from ...fixtures.course import CourseFixture
from ..helpers import UniqueCourseTest
from ...pages.lms.auto_auth import AutoAuthPage
from ...pages.lms.programs import ProgramListingPage, ProgramDetailsPage
from openedx.core.djangoapps.programs.tests import factories
class ProgramPageBase(ProgramsConfigMixin, UniqueCourseTest):
@@ -15,16 +16,33 @@ class ProgramPageBase(ProgramsConfigMixin, UniqueCourseTest):
self.set_programs_api_configuration(is_enabled=True)
def stub_api(self, course_id=None):
"""Stub out the programs API with fake data."""
name = 'Fake Program'
status = 'active'
org_key = self.course_info['org']
def create_program(self, program_id=None, course_id=None):
"""DRY helper for creating test program data."""
course_id = course_id if course_id else self.course_id
ProgramsFixture().install_programs([
FakeProgram(name=name, status=status, org_key=org_key, course_id=course_id),
])
run_mode = factories.RunMode(course_key=course_id)
course_code = factories.CourseCode(run_modes=[run_mode])
org = factories.Organization(key=self.course_info['org'])
if program_id:
program = factories.Program(
id=program_id,
status='active',
organizations=[org],
course_codes=[course_code]
)
else:
program = factories.Program(
status='active',
organizations=[org],
course_codes=[course_code]
)
return program
def stub_api(self, programs, is_list=True):
"""Stub out the programs API with fake data."""
ProgramsFixture().install_programs(programs, is_list=is_list)
def auth(self, enroll=True):
"""Authenticate, enrolling the user in the configured course if requested."""
@@ -43,8 +61,10 @@ class ProgramListingPageTest(ProgramPageBase):
def test_no_enrollments(self):
"""Verify that no cards appear when the user has no enrollments."""
self.stub_api()
program = self.create_program()
self.stub_api([program])
self.auth(enroll=False)
self.listing_page.visit()
self.assertTrue(self.listing_page.is_sidebar_present)
@@ -59,8 +79,11 @@ class ProgramListingPageTest(ProgramPageBase):
self.course_info['run'],
'other_run'
)
self.stub_api(course_id=course_id)
program = self.create_program(course_id=course_id)
self.stub_api([program])
self.auth()
self.listing_page.visit()
self.assertTrue(self.listing_page.is_sidebar_present)
@@ -71,8 +94,10 @@ class ProgramListingPageTest(ProgramPageBase):
Verify that cards appear when the user has enrollments
which are included in at least one active program.
"""
self.stub_api()
program = self.create_program()
self.stub_api([program])
self.auth()
self.listing_page.visit()
self.assertTrue(self.listing_page.is_sidebar_present)
@@ -87,9 +112,11 @@ class ProgramListingPageA11yTest(ProgramPageBase):
self.listing_page = ProgramListingPage(self.browser)
program = self.create_program()
self.stub_api([program])
def test_empty_a11y(self):
"""Test a11y of the page's empty state."""
self.stub_api()
self.auth(enroll=False)
self.listing_page.visit()
@@ -100,7 +127,6 @@ class ProgramListingPageA11yTest(ProgramPageBase):
def test_cards_a11y(self):
"""Test a11y when program cards are present."""
self.stub_api()
self.auth()
self.listing_page.visit()
@@ -118,9 +144,12 @@ class ProgramDetailsPageA11yTest(ProgramPageBase):
self.details_page = ProgramDetailsPage(self.browser)
program = self.create_program(program_id=self.details_page.program_id)
self.stub_api([program], is_list=False)
def test_a11y(self):
"""Test a11y of the page's state."""
self.auth(enroll=False)
"""Test the page's a11y compliance."""
self.auth()
self.details_page.visit()
self.details_page.a11y_audit.check_for_accessibility_errors()

View File

@@ -8,7 +8,7 @@ from uuid import uuid4
from ...fixtures import PROGRAMS_STUB_URL
from ...fixtures.config import ConfigModelFixture
from ...fixtures.programs import FakeProgram, ProgramsFixture, ProgramsConfigMixin
from ...fixtures.programs import ProgramsFixture, ProgramsConfigMixin
from ...pages.studio.auto_auth import AutoAuthPage
from ...pages.studio.library import LibraryEditPage
from ...pages.studio.index import DashboardPage, DashboardPageWithPrograms
@@ -17,6 +17,7 @@ from ..helpers import (
select_option_by_text,
get_selected_option_text
)
from openedx.core.djangoapps.programs.tests import factories
class CreateLibraryTest(WebAppTest):
@@ -111,11 +112,24 @@ class DashboardProgramsTabTest(ProgramsConfigMixin, WebAppTest):
via config, and the results of the program list should display when
the list is nonempty.
"""
test_program_values = [
FakeProgram(name='first program', status='unpublished', org_key='org1', course_id='foo/bar/baz'),
FakeProgram(name='second program', status='unpublished', org_key='org2', course_id='qux/quux/corge'),
test_program_values = [('first program', 'org1'), ('second program', 'org2')]
programs = [
factories.Program(
name=name,
organizations=[
factories.Organization(key=org),
],
course_codes=[
factories.CourseCode(run_modes=[
factories.RunMode(),
]),
]
)
for name, org in test_program_values
]
ProgramsFixture().install_programs(test_program_values)
ProgramsFixture().install_programs(programs)
self.set_programs_api_configuration(True)
@@ -126,8 +140,7 @@ class DashboardProgramsTabTest(ProgramsConfigMixin, WebAppTest):
self.assertFalse(self.dashboard_page.is_empty_list_create_button_present())
results = self.dashboard_page.get_program_list()
expected = [(p.name, p.org_key) for p in test_program_values]
self.assertEqual(results, expected)
self.assertEqual(results, test_program_values)
def test_tab_requires_staff(self):
"""