Skip to content

Commit

Permalink
test: add a JS unit test to verify filterSubVerticals
Browse files Browse the repository at this point in the history
  • Loading branch information
Ali-D-Akbar committed Feb 4, 2025
1 parent 2884cc5 commit 71d27e9
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 2 deletions.
3 changes: 2 additions & 1 deletion conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
# List of test classes that are backed by TransactionTestCase
TTC = ['course_discovery/apps/course_metadata/management/commands/tests/test_refresh_course_metadata.py::'
'RefreshCourseMetadataCommandTests',
'course_discovery/apps/course_metadata/tests/test_admin.py::ProgramAdminFunctionalTests']
'course_discovery/apps/course_metadata/tests/test_admin.py::ProgramAdminFunctionalTests',
'course_discovery/apps/tagging/tests/test_views.py::CourseTaggingDetailViewJSTests']


class LoadScopeSchedulingDjangoOrdered(LoadScopeScheduling):
Expand Down
115 changes: 114 additions & 1 deletion course_discovery/apps/tagging/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from ddt import data, ddt
from django.conf import settings
from django.contrib.auth.models import Group
from django.test import TestCase
from django.test import LiveServerTestCase, TestCase
from django.urls import reverse
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.ui import Select, WebDriverWait

from course_discovery.apps.core.tests.factories import UserFactory
from course_discovery.apps.course_metadata.tests.factories import CourseFactory
Expand Down Expand Up @@ -68,6 +72,115 @@ def test_post_invalid_sub_vertical(self):
self.assertContains(response, 'Sub-vertical does not belong to the selected vertical.')


class CourseTaggingDetailViewJSTests(LiveServerTestCase):
"""
Functional tests using Selenium to verify the JS script filterSubVerticals behavior in the CourseTaggingDetailView.
"""

@classmethod
def setUpClass(cls):
super().setUpClass()
firefox_options = Options()
firefox_options.headless = True
cls.driver = webdriver.Firefox(options=firefox_options)
cls.driver.implicitly_wait(10)

@classmethod
def tearDownClass(cls):
cls.driver.quit()
super().tearDownClass()

def setUp(self):
"""
Create a superuser, a course, verticals and sub-verticals used for testing.
"""
self.user = UserFactory(username='superuser_func', is_superuser=True, is_staff=True)
self.user.set_password('password')
self.user.save()

self.course = CourseFactory(title='Advanced Python')

self.vertical = VerticalFactory(name='AI')
self.sub_vertical = SubVerticalFactory(name='Machine Learning', vertical=self.vertical)

self.other_vertical = VerticalFactory(name='Business')
self.other_sub_vertical = SubVerticalFactory(name='Innovation', vertical=self.other_vertical)

self.multi_vertical = VerticalFactory(name='Data')
self.multi_sub_vertical1 = SubVerticalFactory(name='Analytics', vertical=self.multi_vertical)
self.multi_sub_vertical2 = SubVerticalFactory(name='Visualization', vertical=self.multi_vertical)

self.url = self.live_server_url + reverse('tagging:course_tagging_detail', kwargs={'uuid': self.course.uuid})
self.login_url = self.live_server_url + reverse('admin:login')

# Login via the admin login page as it does not share cookies with Django's test client.
self.driver.get(self.login_url)
self.driver.find_element(By.NAME, 'username').send_keys(self.user.username)
self.driver.find_element(By.NAME, 'password').send_keys('password')
self.driver.find_element(By.XPATH, "//input[@type='submit']").click()

self.driver.get(self.url)

def get_visible_options(self, select_id):
"""
Returns a list of visible <option> elements for the given select element.
Visible options are defined as those with a 'data-vertical' attribute and no inline 'display: none' style.
"""
select_element = self.driver.find_element(By.ID, select_id)
options = select_element.find_elements(By.TAG_NAME, 'option')
visible_options = [
option for option in options
if option.get_attribute('data-vertical') is not None and
'display: none' not in (option.get_attribute('style') or '')
]
return visible_options

def filter_sub_verticals(self, vertical_slug, expected_slugs):
"""
Selects the vertical with the given slug, triggers the JavaScript change event, and waits
until the expected sub-vertical options (by their slug values) are visible in the sub_vertical select.
Returns the list of visible option elements.
"""
vertical_select = Select(self.driver.find_element(By.ID, 'vertical'))
vertical_select.select_by_value(vertical_slug)
self.driver.execute_script(
"document.getElementById('vertical').dispatchEvent(new Event('change'));"
)
# Wait until the visible sub-vertical options match the expected set.
WebDriverWait(self.driver, 5).until(
lambda d: set(
option.get_attribute('value')
for option in self.get_visible_options('sub_vertical')
) == set(expected_slugs)
)
return self.get_visible_options('sub_vertical')

def test_filter_sub_verticals_javascript(self):
"""
Verify that selecting a vertical with one sub-vertical (AI and Business) shows the expected single sub-vertical
and a vertical with two sub-verticals ('Data') shows both sub-verticals.
"""
# Test for vertical 'AI' with one sub-vertical 'Machine Learning'
visible_options = self.filter_sub_verticals(self.vertical.slug, [self.sub_vertical.slug])
self.assertEqual(len(visible_options), 1)
self.assertEqual(visible_options[0].get_attribute('value'), self.sub_vertical.slug)

# Test for vertical 'Business' with one sub-vertical 'Innovation'
visible_options = self.filter_sub_verticals(self.other_vertical.slug, [self.other_sub_vertical.slug])
self.assertEqual(len(visible_options), 1)
self.assertEqual(visible_options[0].get_attribute('value'), self.other_sub_vertical.slug)

# Test for vertical 'Data' with two sub-verticals: 'Analytics' and 'Visualization'
visible_options = self.filter_sub_verticals(
self.multi_vertical.slug,
[self.multi_sub_vertical1.slug, self.multi_sub_vertical2.slug]
)
option_values = sorted([option.get_attribute('value') for option in visible_options])
expected_values = sorted([self.multi_sub_vertical1.slug, self.multi_sub_vertical2.slug])
self.assertEqual(len(visible_options), 2)
self.assertEqual(option_values, expected_values)


@ddt
class CourseListViewTests(BaseViewsTestCase):
"""Tests for the CourseListView."""
Expand Down

0 comments on commit 71d27e9

Please sign in to comment.