Merge pull request #14462 from edx/renzo/programs-from-catalog
Load all programs from the catalog
This commit is contained in:
@@ -19,8 +19,5 @@ COMMENTS_STUB_URL = os.environ.get('comments_url', 'http://localhost:4567')
|
||||
# Get the URL of the EdxNotes service stub used in the test
|
||||
EDXNOTES_STUB_URL = os.environ.get('edxnotes_url', 'http://localhost:8042')
|
||||
|
||||
# Get the URL of the Programs service stub used in the test
|
||||
PROGRAMS_STUB_URL = os.environ.get('programs_url', 'http://localhost:8090')
|
||||
|
||||
# Get the URL of the Catalog service stub used in the test
|
||||
CATALOG_STUB_URL = os.environ.get('catalog_url', 'http://localhost:8091')
|
||||
|
||||
@@ -13,31 +13,31 @@ class CatalogFixture(object):
|
||||
"""
|
||||
Interface to set up mock responses from the Catalog stub server.
|
||||
"""
|
||||
def install_programs(self, programs):
|
||||
def install_programs(self, data):
|
||||
"""Set response data for the catalog's course run API."""
|
||||
key = 'catalog.programs'
|
||||
|
||||
requests.put(
|
||||
'{}/set_config'.format(CATALOG_STUB_URL),
|
||||
data={key: json.dumps(programs)},
|
||||
)
|
||||
if isinstance(data, dict):
|
||||
key += '.' + data['uuid']
|
||||
|
||||
def install_course_run(self, course_run):
|
||||
"""Set response data for the catalog's course run API."""
|
||||
key = 'catalog.{}'.format(course_run['key'])
|
||||
|
||||
requests.put(
|
||||
'{}/set_config'.format(CATALOG_STUB_URL),
|
||||
data={key: json.dumps(course_run)},
|
||||
)
|
||||
requests.put(
|
||||
'{}/set_config'.format(CATALOG_STUB_URL),
|
||||
data={key: json.dumps(data)},
|
||||
)
|
||||
else:
|
||||
requests.put(
|
||||
'{}/set_config'.format(CATALOG_STUB_URL),
|
||||
data={key: json.dumps({'results': data})},
|
||||
)
|
||||
|
||||
|
||||
class CatalogConfigMixin(object):
|
||||
class CatalogIntegrationMixin(object):
|
||||
"""Mixin providing a method used to configure the catalog integration."""
|
||||
def set_catalog_configuration(self, is_enabled=False, service_url=CATALOG_STUB_URL):
|
||||
"""Dynamically adjusts the catalog config model during tests."""
|
||||
def set_catalog_integration(self, is_enabled=False, service_username=None):
|
||||
"""Use this to change the catalog integration config model during tests."""
|
||||
ConfigModelFixture('/config/catalog', {
|
||||
'enabled': is_enabled,
|
||||
'internal_api_url': '{}/api/v1/'.format(service_url),
|
||||
'internal_api_url': '{}/api/v1/'.format(CATALOG_STUB_URL),
|
||||
'cache_ttl': 0,
|
||||
'service_username': service_username,
|
||||
}).install()
|
||||
|
||||
@@ -1,46 +1,19 @@
|
||||
"""
|
||||
Tools to create programs-related data for use in bok choy tests.
|
||||
"""
|
||||
import json
|
||||
|
||||
import requests
|
||||
|
||||
from common.test.acceptance.fixtures import PROGRAMS_STUB_URL
|
||||
from common.test.acceptance.fixtures.config import ConfigModelFixture
|
||||
|
||||
|
||||
class ProgramsFixture(object):
|
||||
"""
|
||||
Interface to set up mock responses from the Programs stub server.
|
||||
"""
|
||||
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={key: json.dumps(api_result)},
|
||||
)
|
||||
|
||||
|
||||
class ProgramsConfigMixin(object):
|
||||
"""Mixin providing a method used to configure the programs feature."""
|
||||
def set_programs_api_configuration(self, is_enabled=False, api_version=1, api_url=PROGRAMS_STUB_URL):
|
||||
def set_programs_api_configuration(self, is_enabled=False, api_version=1):
|
||||
"""Dynamically adjusts the Programs config model during tests."""
|
||||
ConfigModelFixture('/config/programs', {
|
||||
'enabled': is_enabled,
|
||||
'api_version_number': api_version,
|
||||
'internal_service_url': api_url,
|
||||
'public_service_url': api_url,
|
||||
'cache_ttl': 0,
|
||||
'marketing_path': '/foo',
|
||||
'enable_student_dashboard': is_enabled,
|
||||
'enable_studio_tab': is_enabled,
|
||||
'enable_certification': is_enabled,
|
||||
'program_listing_enabled': is_enabled,
|
||||
'program_details_enabled': is_enabled,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
"""LMS-hosted Programs pages"""
|
||||
from uuid import uuid4
|
||||
|
||||
from bok_choy.page_object import PageObject
|
||||
|
||||
from common.test.acceptance.pages.lms import BASE_URL
|
||||
@@ -24,8 +26,8 @@ class ProgramListingPage(PageObject):
|
||||
|
||||
class ProgramDetailsPage(PageObject):
|
||||
"""Program details page."""
|
||||
program_id = 123
|
||||
url = BASE_URL + '/dashboard/programs/{}/program-name/'.format(program_id)
|
||||
program_uuid = str(uuid4())
|
||||
url = '{base}/dashboard/programs/{program_uuid}/'.format(base=BASE_URL, program_uuid=program_uuid)
|
||||
|
||||
def is_browser_on_page(self):
|
||||
return self.q(css='.js-program-details-wrapper').present
|
||||
|
||||
@@ -1,67 +1,48 @@
|
||||
"""Acceptance tests for LMS-hosted Programs pages"""
|
||||
from nose.plugins.attrib import attr
|
||||
|
||||
from common.test.acceptance.fixtures.catalog import CatalogFixture, CatalogConfigMixin
|
||||
from common.test.acceptance.fixtures.programs import ProgramsFixture, ProgramsConfigMixin
|
||||
from common.test.acceptance.fixtures.catalog import CatalogFixture, CatalogIntegrationMixin
|
||||
from common.test.acceptance.fixtures.programs import ProgramsConfigMixin
|
||||
from common.test.acceptance.fixtures.course import CourseFixture
|
||||
from common.test.acceptance.tests.helpers import UniqueCourseTest
|
||||
from common.test.acceptance.pages.lms.auto_auth import AutoAuthPage
|
||||
from common.test.acceptance.pages.lms.programs import ProgramListingPage, ProgramDetailsPage
|
||||
from openedx.core.djangoapps.catalog.tests import factories as catalog_factories
|
||||
from openedx.core.djangoapps.programs.tests import factories as program_factories
|
||||
from openedx.core.djangoapps.catalog.tests.factories import (
|
||||
ProgramFactory, CourseFactory, CourseRunFactory
|
||||
)
|
||||
|
||||
|
||||
class ProgramPageBase(ProgramsConfigMixin, CatalogConfigMixin, UniqueCourseTest):
|
||||
class ProgramPageBase(ProgramsConfigMixin, CatalogIntegrationMixin, UniqueCourseTest):
|
||||
"""Base class used for program listing page tests."""
|
||||
def setUp(self):
|
||||
super(ProgramPageBase, self).setUp()
|
||||
|
||||
self.set_programs_api_configuration(is_enabled=True)
|
||||
|
||||
self.programs = [catalog_factories.Program() for __ in range(3)]
|
||||
self.course_run = catalog_factories.CourseRun(key=self.course_id)
|
||||
self.stub_catalog_api()
|
||||
|
||||
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
|
||||
|
||||
run_mode = program_factories.RunMode(course_key=course_id)
|
||||
course_code = program_factories.CourseCode(run_modes=[run_mode])
|
||||
org = program_factories.Organization(key=self.course_info['org'])
|
||||
|
||||
if program_id:
|
||||
program = program_factories.Program(
|
||||
id=program_id,
|
||||
status='active',
|
||||
organizations=[org],
|
||||
course_codes=[course_code]
|
||||
)
|
||||
else:
|
||||
program = program_factories.Program(
|
||||
status='active',
|
||||
organizations=[org],
|
||||
course_codes=[course_code]
|
||||
)
|
||||
|
||||
return program
|
||||
|
||||
def stub_programs_api(self, programs, is_list=True):
|
||||
"""Stub out the programs API with fake data."""
|
||||
ProgramsFixture().install_programs(programs, is_list=is_list)
|
||||
|
||||
def stub_catalog_api(self):
|
||||
"""Stub out the catalog API's program and course run endpoints."""
|
||||
self.set_catalog_configuration(is_enabled=True)
|
||||
CatalogFixture().install_programs(self.programs)
|
||||
CatalogFixture().install_course_run(self.course_run)
|
||||
self.programs = ProgramFactory.create_batch(3)
|
||||
self.username = None
|
||||
|
||||
def auth(self, enroll=True):
|
||||
"""Authenticate, enrolling the user in the configured course if requested."""
|
||||
CourseFixture(**self.course_info).install()
|
||||
|
||||
course_id = self.course_id if enroll else None
|
||||
AutoAuthPage(self.browser, course_id=course_id).visit()
|
||||
auth_page = AutoAuthPage(self.browser, course_id=course_id)
|
||||
auth_page.visit()
|
||||
|
||||
self.username = auth_page.user_info['username']
|
||||
|
||||
def create_program(self):
|
||||
"""DRY helper for creating test program data."""
|
||||
course_run = CourseRunFactory(key=self.course_id)
|
||||
course = CourseFactory(course_runs=[course_run])
|
||||
|
||||
return ProgramFactory(courses=[course])
|
||||
|
||||
def stub_catalog_api(self, data=None):
|
||||
"""Stub out the catalog API's program and course run endpoints."""
|
||||
self.set_catalog_integration(is_enabled=True, service_username=self.username)
|
||||
CatalogFixture().install_programs(data or self.programs)
|
||||
|
||||
|
||||
class ProgramListingPageTest(ProgramPageBase):
|
||||
@@ -73,9 +54,8 @@ class ProgramListingPageTest(ProgramPageBase):
|
||||
|
||||
def test_no_enrollments(self):
|
||||
"""Verify that no cards appear when the user has no enrollments."""
|
||||
program = self.create_program()
|
||||
self.stub_programs_api([program])
|
||||
self.auth(enroll=False)
|
||||
self.stub_catalog_api()
|
||||
|
||||
self.listing_page.visit()
|
||||
|
||||
@@ -87,14 +67,8 @@ class ProgramListingPageTest(ProgramPageBase):
|
||||
Verify that no cards appear when the user has enrollments
|
||||
but none are included in an active program.
|
||||
"""
|
||||
course_id = self.course_id.replace(
|
||||
self.course_info['run'],
|
||||
'other_run'
|
||||
)
|
||||
|
||||
program = self.create_program(course_id=course_id)
|
||||
self.stub_programs_api([program])
|
||||
self.auth()
|
||||
self.stub_catalog_api()
|
||||
|
||||
self.listing_page.visit()
|
||||
|
||||
@@ -106,10 +80,11 @@ class ProgramListingPageTest(ProgramPageBase):
|
||||
Verify that cards appear when the user has enrollments
|
||||
which are included in at least one active program.
|
||||
"""
|
||||
program = self.create_program()
|
||||
self.stub_programs_api([program])
|
||||
self.auth()
|
||||
|
||||
program = self.create_program()
|
||||
self.stub_catalog_api(data=[program])
|
||||
|
||||
self.listing_page.visit()
|
||||
|
||||
self.assertTrue(self.listing_page.is_sidebar_present)
|
||||
@@ -124,12 +99,13 @@ class ProgramListingPageA11yTest(ProgramPageBase):
|
||||
|
||||
self.listing_page = ProgramListingPage(self.browser)
|
||||
|
||||
program = self.create_program()
|
||||
self.stub_programs_api([program])
|
||||
self.program = self.create_program()
|
||||
|
||||
def test_empty_a11y(self):
|
||||
"""Test a11y of the page's empty state."""
|
||||
self.auth(enroll=False)
|
||||
self.stub_catalog_api(data=[self.program])
|
||||
|
||||
self.listing_page.visit()
|
||||
|
||||
self.assertTrue(self.listing_page.is_sidebar_present)
|
||||
@@ -139,6 +115,8 @@ class ProgramListingPageA11yTest(ProgramPageBase):
|
||||
def test_cards_a11y(self):
|
||||
"""Test a11y when program cards are present."""
|
||||
self.auth()
|
||||
self.stub_catalog_api(data=[self.program])
|
||||
|
||||
self.listing_page.visit()
|
||||
|
||||
self.assertTrue(self.listing_page.is_sidebar_present)
|
||||
@@ -154,11 +132,14 @@ class ProgramDetailsPageA11yTest(ProgramPageBase):
|
||||
|
||||
self.details_page = ProgramDetailsPage(self.browser)
|
||||
|
||||
program = self.create_program(program_id=self.details_page.program_id)
|
||||
self.stub_programs_api([program], is_list=False)
|
||||
self.program = self.create_program()
|
||||
self.program['uuid'] = self.details_page.program_uuid
|
||||
|
||||
def test_a11y(self):
|
||||
"""Test the page's a11y compliance."""
|
||||
self.auth()
|
||||
self.stub_catalog_api(data=self.program)
|
||||
|
||||
self.details_page.visit()
|
||||
|
||||
self.details_page.a11y_audit.check_for_accessibility_errors()
|
||||
|
||||
Reference in New Issue
Block a user