diff --git a/.travis.yml b/.travis.yml index 409c1041a..52c076101 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ services: env: # Make sure to update this string on every Insights or Data API release - DATA_API_VERSION: "0.20.1-rc.3" + DATA_API_VERSION: "0.21.0" DOCKER_COMPOSE_VERSION: "1.9.0" before_install: diff --git a/.travis/docker-compose-travis.yml b/.travis/docker-compose-travis.yml index af6825510..e6e56d469 100644 --- a/.travis/docker-compose-travis.yml +++ b/.travis/docker-compose-travis.yml @@ -32,6 +32,7 @@ services: ENABLE_OAUTH_TESTS: "False" ENABLE_ERROR_PAGE_TESTS: "False" DISPLAY_LEARNER_ANALYTICS: "True" + ENABLE_COURSE_LIST_FILTERS: "True" depends_on: - "es" - "analyticsapi" diff --git a/Makefile b/Makefile index 511696a67..e84e8d832 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,9 @@ test_python: test_compress test_python_no_compress accept: ifeq ("${DISPLAY_LEARNER_ANALYTICS}", "True") ./manage.py waffle_flag enable_learner_analytics on --create --everyone +endif +ifeq ("${ENABLE_COURSE_LIST_FILTERS}", "True") + ./manage.py waffle_switch enable_course_filters on --create endif nosetests -v acceptance_tests -e NUM_PROCESSES=1 --exclude-dir=acceptance_tests/course_validation diff --git a/README.md b/README.md index 33b13230b..4a251253f 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ The following switches are available: | enable_performance_learning_outcome | Enable performance section with learning outcome breakdown (functionality based on tagging questions in Studio) | | enable_learner_download | Display Download CSV button on Learner List page. | | enable_problem_response_download | Enable downloadable CSV of problem responses | +| enable_course_filters | Enable filters (e.g. pacing type) on courses page. | [Waffle](http://waffle.readthedocs.org/en/latest/) flags are used to disable/enable functionality on request (e.g. turning on beta functionality for superusers). Create a diff --git a/acceptance_tests/__init__.py b/acceptance_tests/__init__.py index bedea8618..feed3ccf8 100644 --- a/acceptance_tests/__init__.py +++ b/acceptance_tests/__init__.py @@ -78,3 +78,6 @@ def str2bool(s): # Learner analytics DISPLAY_LEARNER_ANALYTICS = str2bool(os.environ.get('DISPLAY_LEARNER_ANALYTICS', False)) + +# Learner analytics +ENABLE_COURSE_LIST_FILTERS = str2bool(os.environ.get('ENABLE_COURSE_LIST_FILTERS', False)) diff --git a/acceptance_tests/test_course_index.py b/acceptance_tests/test_course_index.py index 39960ba10..cf0a01458 100644 --- a/acceptance_tests/test_course_index.py +++ b/acceptance_tests/test_course_index.py @@ -2,7 +2,10 @@ from bok_choy.web_app_test import WebAppTest from selenium.webdriver.common.keys import Keys -from acceptance_tests import TEST_COURSE_ID +from acceptance_tests import ( + ENABLE_COURSE_LIST_FILTERS, + TEST_COURSE_ID, +) from acceptance_tests.mixins import AnalyticsDashboardWebAppTestMixin from acceptance_tests.pages import CourseIndexPage @@ -25,6 +28,8 @@ def test_page(self): self._test_clear_input() self._test_clear_active_filter() self._test_clear_all_filters() + if ENABLE_COURSE_LIST_FILTERS: + self._test_filters() def _test_course_list(self): """ @@ -161,3 +166,57 @@ def _test_clear_all_filters(self): clear_all_filters.first.click() self.check_cleared() + + def _test_individual_filters(self): + """ + Tests checking each option under each filter set. + + The test course will only be displayed under "Upcoming" or "self_paced" filters. + """ + # maps id of filter in DOM to display name shown in active filters + filters = { + "Archived": "Archived", + "Current": "Current", + "Upcoming": "Upcoming", + "unknown": "Unknown", + "instructor_paced": "Instructor-Paced", + "self_paced": "Self-Paced", + } + course_in_filters = ['Upcoming', 'self_paced'] + for filter_id, display_name in filters.items(): + self._test_filter(filter_id, display_name, + course_in_filter=(True if filter_id in course_in_filters else False)) + + def _test_multiple_filters(self, filter_sequence): + """ + Tests checking multiple filter options together and whether the course is shown after each filter application. + + filter_sequence should be a list of tuples where each element, by index, is: + 0. the filter id to apply + 1. the filter display name + 2. boolean for whether the test course is shown in the list after the filter is applied. + """ + for index, filter in enumerate(filter_sequence): + id = filter[0] + name = filter[1] + course_shown = filter[2] + first_filter = index == 0 + self._test_filter(id, name, course_in_filter=course_shown, clear_existing_filters=first_filter) + + def _test_filters(self): + self._test_individual_filters() + + # Filters ORed within a set + self._test_multiple_filters([ + ('Archived', 'Archived', False), + ('Upcoming', 'Upcoming', True), + ('Current', 'Current', True), + ('unknown', 'Unknown', True), + ]) + + # Filters ANDed between sets + self._test_multiple_filters([ + ('Upcoming', 'Upcoming', True), + ('self_paced', 'Self-Paced', False), + ('instructor_paced', 'Instructor-Paced', False), + ]) diff --git a/analytics_dashboard/core/templates/core/landing.html b/analytics_dashboard/core/templates/core/landing.html index 4b93bc708..98901af85 100644 --- a/analytics_dashboard/core/templates/core/landing.html +++ b/analytics_dashboard/core/templates/core/landing.html @@ -12,7 +12,7 @@ {% block body %}