Files
edx-platform/lms/djangoapps/courseware/tests/test_navigation.py
Michael Terry cb1bb7fa64 test: switch default test store to the split store
It's long past time that the default test modulestore was Split,
instead of Old Mongo. This commit switches the default store and
fixes some tests that now fail:
- Tests that didn't expect MFE to be enabled (because we don't
  enable MFE for Old Mongo) - opt out of MFE for those
- Tests that hardcoded old key string formats
- Lots of other random little differences

In many places, I didn't spend much time trying to figure out how to
properly fix the test, and instead just set the modulestore to Old
Mongo.

For those tests that I didn't spend time investigating, I've set
the modulestore to TEST_DATA_MONGO_AMNESTY_MODULESTORE - search for
that string to find further work.
2022-02-04 14:32:50 -05:00

322 lines
12 KiB
Python

"""
This test file will run through some LMS test scenarios regarding access and navigation of the LMS
"""
import time
from unittest.mock import patch
from django.conf import settings
from django.test.utils import override_settings
from django.urls import reverse
from edx_toggles.toggles.testutils import override_waffle_flag
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from common.djangoapps.student.tests.factories import GlobalStaffFactory
from lms.djangoapps.courseware.tests.helpers import LoginEnrollmentTestCase
from lms.djangoapps.courseware.toggles import COURSEWARE_USE_LEGACY_FRONTEND
from openedx.features.course_experience import DISABLE_COURSE_OUTLINE_PAGE_FLAG
from common.djangoapps.student.tests.factories import UserFactory
@override_waffle_flag(COURSEWARE_USE_LEGACY_FRONTEND, active=True)
class TestNavigation(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
"""
Check that navigation state is saved properly.
"""
STUDENT_INFO = [('view@test.com', 'foo'), ('view2@test.com', 'foo')]
@classmethod
def setUpClass(cls):
# pylint: disable=super-method-not-called
with super().setUpClassAndTestData():
cls.test_course = CourseFactory.create()
cls.test_course_proctored = CourseFactory.create()
cls.course = CourseFactory.create()
@classmethod
def setUpTestData(cls): # lint-amnesty, pylint: disable=super-method-not-called
cls.chapter0 = ItemFactory.create(parent=cls.course,
display_name='Overview')
cls.chapter9 = ItemFactory.create(parent=cls.course,
display_name='factory_chapter')
cls.section0 = ItemFactory.create(parent=cls.chapter0,
display_name='Welcome')
cls.section9 = ItemFactory.create(parent=cls.chapter9,
display_name='factory_section')
cls.unit0 = ItemFactory.create(parent=cls.section0,
display_name='New Unit 0')
cls.chapterchrome = ItemFactory.create(parent=cls.course,
display_name='Chrome')
cls.chromelesssection = ItemFactory.create(parent=cls.chapterchrome,
display_name='chromeless',
chrome='none')
cls.accordionsection = ItemFactory.create(parent=cls.chapterchrome,
display_name='accordion',
chrome='accordion')
cls.tabssection = ItemFactory.create(parent=cls.chapterchrome,
display_name='tabs',
chrome='tabs')
cls.defaultchromesection = ItemFactory.create(
parent=cls.chapterchrome,
display_name='defaultchrome',
)
cls.fullchromesection = ItemFactory.create(parent=cls.chapterchrome,
display_name='fullchrome',
chrome='accordion,tabs')
cls.tabtest = ItemFactory.create(parent=cls.chapterchrome,
display_name='pdf_textbooks_tab',
default_tab='progress')
cls.staff_user = GlobalStaffFactory()
cls.user = UserFactory()
def setUp(self):
super().setUp()
# Create student accounts and activate them.
for i in range(len(self.STUDENT_INFO)):
email, password = self.STUDENT_INFO[i]
username = f'u{i}'
self.create_account(username, email, password)
self.activate_user(email)
def assertTabActive(self, tabname, response):
''' Check if the progress tab is active in the tab set '''
for line in response.content.decode('utf-8').split('\n'):
if tabname in line and 'active' in line:
return
raise AssertionError(f"assertTabActive failed: {tabname} not active")
def assertTabInactive(self, tabname, response): # lint-amnesty, pylint: disable=useless-return
''' Check if the progress tab is active in the tab set '''
for line in response.content.decode('utf-8').split('\n'):
if tabname in line and 'active' in line:
raise AssertionError("assertTabInactive failed: " + tabname + " active")
return
# TODO: LEARNER-71: Do we need to adjust or remove this test?
@override_waffle_flag(DISABLE_COURSE_OUTLINE_PAGE_FLAG, active=True)
def test_chrome_settings(self):
'''
Test settings for disabling and modifying navigation chrome in the courseware:
- Accordion enabled, or disabled
- Navigation tabs enabled, disabled, or redirected
'''
email, password = self.STUDENT_INFO[0]
self.login(email, password)
self.enroll(self.course, True)
test_data = (
('tabs', False, True),
('none', False, False),
('accordion', True, False),
('fullchrome', True, True),
)
for (displayname, accordion, tabs) in test_data:
response = self.client.get(reverse('courseware_section', kwargs={
'course_id': str(self.course.id),
'chapter': 'Chrome',
'section': displayname,
}))
assert ('course-tabs' in response.content.decode('utf-8')) == tabs
assert ('course-navigation' in response.content.decode('utf-8')) == accordion
self.assertTabInactive('progress', response)
self.assertTabActive('home', response)
response = self.client.get(reverse('courseware_section', kwargs={
'course_id': str(self.course.id),
'chapter': 'Chrome',
'section': 'pdf_textbooks_tab',
}))
self.assertTabActive('progress', response)
self.assertTabInactive('home', response)
@override_settings(SESSION_INACTIVITY_TIMEOUT_IN_SECONDS=1)
def test_inactive_session_timeout(self):
"""
Verify that an inactive session times out and redirects to the
login page
"""
email, password = self.STUDENT_INFO[0]
self.login(email, password)
# make sure we can access courseware immediately
resp = self.client.get(reverse('dashboard'))
assert resp.status_code == 200
# then wait a bit and see if we get timed out
time.sleep(2)
resp = self.client.get(reverse('dashboard'))
# re-request, and we should get a redirect to login page
self.assertRedirects(resp, settings.LOGIN_REDIRECT_URL + '?next=' + reverse('dashboard'))
def test_redirects_first_time(self):
"""
Verify that the first time we click on the courseware tab we are
redirected to the 'Welcome' section.
"""
email, password = self.STUDENT_INFO[0]
self.login(email, password)
self.enroll(self.course, True)
self.enroll(self.test_course, True)
resp = self.client.get(reverse('courseware',
kwargs={'course_id': str(self.course.id)}))
self.assertRedirects(resp, reverse(
'courseware_section', kwargs={'course_id': str(self.course.id),
'chapter': 'Overview',
'section': 'Welcome'}))
def test_redirects_second_time(self):
"""
Verify the accordion remembers we've already visited the Welcome section
and redirects correspondingly.
"""
email, password = self.STUDENT_INFO[0]
self.login(email, password)
self.enroll(self.course, True)
self.enroll(self.test_course, True)
section_url = reverse(
'courseware_section',
kwargs={
'course_id': str(self.course.id),
'chapter': 'Overview',
'section': 'Welcome',
},
)
self.client.get(section_url)
resp = self.client.get(
reverse('courseware', kwargs={'course_id': str(self.course.id)}),
)
self.assertRedirects(resp, section_url)
def test_accordion_state(self):
"""
Verify the accordion remembers which chapter you were last viewing.
"""
email, password = self.STUDENT_INFO[0]
self.login(email, password)
self.enroll(self.course, True)
self.enroll(self.test_course, True)
# Now we directly navigate to a section in a chapter other than 'Overview'.
section_url = reverse(
'courseware_section',
kwargs={
'course_id': str(self.course.id),
'chapter': 'factory_chapter',
'section': 'factory_section',
}
)
self.assert_request_status_code(200, section_url)
# And now hitting the courseware tab should redirect to 'factory_chapter'
url = reverse(
'courseware',
kwargs={'course_id': str(self.course.id)}
)
resp = self.client.get(url)
self.assertRedirects(resp, section_url)
# TODO: LEARNER-71: Do we need to adjust or remove this test?
@override_waffle_flag(DISABLE_COURSE_OUTLINE_PAGE_FLAG, active=True)
def test_incomplete_course(self):
email = self.staff_user.email
password = "test"
self.login(email, password)
self.enroll(self.test_course, True)
test_course_id = str(self.test_course.id)
url = reverse(
'courseware',
kwargs={'course_id': test_course_id}
)
response = self.assert_request_status_code(200, url)
self.assertContains(response, "No content has been added to this course")
section = ItemFactory.create(
parent_location=self.test_course.location,
display_name='New Section'
)
url = reverse(
'courseware',
kwargs={'course_id': test_course_id}
)
response = self.assert_request_status_code(200, url)
self.assertNotContains(response, "No content has been added to this course")
self.assertContains(response, "New Section")
subsection = ItemFactory.create(
parent_location=section.location,
display_name='New Subsection',
)
url = reverse(
'courseware',
kwargs={'course_id': test_course_id}
)
response = self.assert_request_status_code(200, url)
self.assertContains(response, "New Subsection")
self.assertNotContains(response, "sequence-nav")
ItemFactory.create(
parent_location=subsection.location,
display_name='New Unit',
)
url = reverse(
'courseware',
kwargs={'course_id': test_course_id}
)
self.assert_request_status_code(302, url)
def test_proctoring_js_includes(self):
"""
Make sure that proctoring JS does not get included on
courseware pages if either the FEATURE flag is turned off
or the course is not proctored enabled
"""
email, password = self.STUDENT_INFO[0]
self.login(email, password)
self.enroll(self.test_course_proctored, True)
test_course_id = str(self.test_course_proctored.id)
with patch.dict(settings.FEATURES, {'ENABLE_SPECIAL_EXAMS': False}):
url = reverse(
'courseware',
kwargs={'course_id': test_course_id}
)
resp = self.client.get(url)
self.assertNotContains(resp, '/static/js/lms-proctoring.js')
with patch.dict(settings.FEATURES, {'ENABLE_SPECIAL_EXAMS': True}):
url = reverse(
'courseware',
kwargs={'course_id': test_course_id}
)
resp = self.client.get(url)
self.assertNotContains(resp, '/static/js/lms-proctoring.js')
# now set up a course which is proctored enabled
self.test_course_proctored.enable_proctored_exams = True
self.test_course_proctored.save()
modulestore().update_item(self.test_course_proctored, self.user.id)
resp = self.client.get(url)
self.assertContains(resp, '/static/js/lms-proctoring.js')