diff --git a/apps/course/tests/test_views.py b/apps/course/tests/test_views.py index 29a48fb9..c1305ad2 100644 --- a/apps/course/tests/test_views.py +++ b/apps/course/tests/test_views.py @@ -2,14 +2,19 @@ from datetime import timedelta from random import randint from selenium import webdriver +from factory.faker import Faker from django.utils import timezone from django.test import TestCase from django.shortcuts import reverse +from django.conf import settings +from django.utils.text import slugify +from unidecode import unidecode from project.tests.factories import * +from project.tests import SeleniumTestCase from project.utils.selenium_utils import SeleniumExtensions as SE - +''' class CoursesTestCase(TestCase): @classmethod @@ -18,6 +23,11 @@ class CoursesTestCase(TestCase): create_batch_unique(CourseFactory, status=Course.STATUS_CHOICES[:3], price=[0, 1000], age=Course.AGE_CHOICES[:2], deferred_start_at=[None, timezone.now() + timedelta(days=randint(5, 15))]) + @classmethod + def tearDownClass(cls): + print('teardown CoursesTestCase') + super().tearDownClass() + def test_courses_url_accessible(self): print('get ', reverse('courses')) resp = self.client.get(reverse('courses')) @@ -35,16 +45,79 @@ class CoursesTestCase(TestCase): print('get ', reverse('course_edit', args=[course.id])) resp = self.client.get(reverse('course_edit', args=[course.id])) self.assertEqual(resp.status_code, 200) +''' -class CourseEditTestCase(TestCase): +class CourseEditTestCase(SeleniumTestCase): @classmethod def setUpTestData(cls): - cls.driver = webdriver.Chrome() create_admin() - create_batch_unique(CourseFactory, status=Course.STATUS_CHOICES[:3], price=[0, 1000], - age=Course.AGE_CHOICES[:2], deferred_start_at=[None, timezone.now() + timedelta(days=randint(5, 15))]) + UserFactory.create_batch(5, role=User.AUTHOR_ROLE) + # create_batch_unique(CourseFactory, status=Course.STATUS_CHOICES[:3], price=[0, 1000], + # age=Course.AGE_CHOICES[:2], deferred_start_at=[None, timezone.now() + timedelta(days=randint(5, 15))]) + + @classmethod + def tearDownClass(cls): + print('teardown CourseEditTestCase') + super().tearDownClass() def test_course_edit(self): - print('Course.objects.all().count()', Course.objects.all().count()) + print('go to google') + self.driver.get('http://www.google.com') + return + + user = User.objects.filter(role=User.AUTHOR_ROLE).first() + self.client.force_login(user) + url = self.get_url(reverse('course_create')) + print('url', url) + self.driver.get(url) + # visible always elements + title_el = self.wait_elem_name('course-title') + slug_el = self.wait_elem_name('course-slug') + category_el = self.wait_elem_name('course-category') + is_paid_no_el = self.wait_elem_name('course-is-paid-no') + is_paid_yes_el = self.wait_elem_name('course-is-paid-yes') + is_paid_input_el = self.wait_elem_name('course-is-paid-input') + age_el = self.wait_elem_name('course-age') + is_featured_el = self.wait_elem_name('course-is-featured') + is_deferred_no_el = self.wait_elem_name('course-is-deferred-no') + is_deferred_yes_el = self.wait_elem_name('course-is-deferred-yes') + is_deferred_input_el = self.wait_elem_name('course-is-deferred-input') + content_btn_el = self.wait_elem_name('course-content-btn') + lessons_btn_el = self.wait_elem_name('course-lessons-btn') + content_el = self.wait_elem_name('course-content') + + title = Faker('sentence', nb_words=6) + title_el.send_keys(title) + slug = slugify(unidecode(title[:90])) + print('title', title, 'slug', slug) + self.assertEqual(slug_el.text, slug) + + print("is_paid_input_el.get_attribute('checked')", is_paid_input_el.get_attribute('checked')) + self.assertFalse(is_paid_input_el.get_attribute('checked')) + self.assertRaises(callable=lambda: self.driver.find_element_by_name('course-price')) + self.assertRaises(callable=lambda: self.driver.find_element_by_name('course-old-price')) + is_paid_yes_el.click() + try: + price_el = self.wait_elem_name('course-price') + old_price_el = self.wait_elem_name('course-old-price') + except: + self.fail('Price and old price elements not shown') + + self.assertFalse(is_deferred_input_el.get_attribute('checked')) + self.assertRaises(callable=lambda: self.driver.find_element_by_name('course-date')) + self.assertRaises(callable=lambda: self.driver.find_element_by_name('course-time')) + is_deferred_yes_el.click() + try: + date_el = self.wait_elem_name('course-date') + time_el = self.wait_elem_name('course-time') + except: + self.fail('Date and time elements not shown') + + # lessons_el = self.wait_elem_name('course-lessons') + # add_lesson_el = self.wait_elem_name('course-add-lesson') + # lesson_edit_el = self.wait_elem_name('course-lesson-edit') + # stream_el = self.wait_elem_name('course-stream') + + diff --git a/project/tests/__init__.py b/project/tests/__init__.py index e69de29b..b2548d50 100644 --- a/project/tests/__init__.py +++ b/project/tests/__init__.py @@ -0,0 +1,44 @@ +from django.test import TestCase +from selenium import webdriver +from selenium.webdriver.common.by import By +from pyvirtualdisplay import Display + +from project.utils.selenium_utils import SeleniumExtensions as SE +from django.conf import settings + + +class SeleniumTestCase(TestCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.display = Display(visible=0, size=(1280, 1024)) + cls.display.start() + cls.driver = webdriver.Chrome() + + @classmethod + def tearDownClass(cls): + cls.driver.close() + cls.display.stop() + super().tearDownClass() + + def get_url(self, url): + return 'http://%s%s' % (settings.MAIN_HOST, url) + + def wait_elem_xpath(self, xpath, inside_el=None, wait_time=10): + return SE.wait_elem(self.driver, (By.XPATH, xpath), inside_el, wait_time) + + def wait_elems_xpath(self, xpath, inside_el=None, wait_time=10): + return SE.wait_elems(self.driver, (By.XPATH, xpath), inside_el, wait_time) + + def wait_elem_css(self, selector, inside_el=None, wait_time=10): + return SE.wait_elem(self.driver, (By.CSS_SELECTOR, selector), inside_el, wait_time) + + def wait_elems_css(self, selector, inside_el=None, wait_time=10): + return SE.wait_elems(self.driver, (By.CSS_SELECTOR, selector), inside_el, wait_time) + + def wait_elem_name(self, name, inside_el=None, wait_time=10): + return SE.wait_elem(self.driver, (By.NAME, name), inside_el, wait_time) + + def wait_elems_name(self, name, inside_el=None, wait_time=10): + return SE.wait_elems(self.driver, (By.NAME, name), inside_el, wait_time) diff --git a/project/utils/selenium_utils.py b/project/utils/selenium_utils.py index 0b7f47cf..5bf62c6b 100644 --- a/project/utils/selenium_utils.py +++ b/project/utils/selenium_utils.py @@ -1,50 +1,46 @@ -# -*- coding: utf-8 -*- - -from selenium import webdriver -from selenium.webdriver.common.by import By -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as EC - - -class elem_in(object): - default_find_fn = 'find_element_by_xpath' - def __init__(self, element, xpath, find_fn=None): - self.element = element - self.xpath = xpath - self.find_fn = self.default_find_fn if find_fn is None else find_fn - - def __call__(self, driver): - try: - return getattr(self.element, self.find_fn)(self.xpath) - except: - return False - -class elems_in(elem_in): - default_find_fn = 'find_elements_by_xpath' - - -class SeleniumExtensions(object): - - @classmethod - def wait_elem(cls, driver, xpath, inside_el=None, wait_time=10): - if inside_el: - return WebDriverWait(driver, wait_time).until(elem_in(inside_el, xpath)) - if xpath[:2] != '//': - raise Exception('XPath in wait_elem must start with //') - return WebDriverWait(driver, wait_time).until( - EC.presence_of_element_located( - (By.XPATH, xpath) - ) - ) - - @classmethod - def wait_elems(cls, driver, xpath, inside_el=None, wait_time=10): - if inside_el: - return WebDriverWait(driver, wait_time).until(elems_in(inside_el, xpath)) - if xpath[:2] != '//': - raise Exception('XPath in wait_elems must start with //') - return WebDriverWait(driver, wait_time).until( - EC.presence_of_all_elements_located( - (By.XPATH, xpath) - ) - ) \ No newline at end of file +# -*- coding: utf-8 -*- + +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + + +class ElementIn(object): + + default_find_fn = 'find_element' + + def __init__(self, element, locator, find_fn=None): + self.element = element + self.locator = locator + self.find_fn = self.default_find_fn if find_fn is None else find_fn + + def __call__(self, driver): + try: + return getattr(self.element, self.find_fn)(self.locator) + except: + return False + + +class ElementsIn(ElementIn): + + default_find_fn = 'find_elements' + + +class SeleniumExtensions(object): + + @classmethod + def wait_elem(cls, driver, locator, inside_el=None, wait_time=10): + if inside_el: + return WebDriverWait(driver, wait_time).until(ElementIn(inside_el, locator)) + return WebDriverWait(driver, wait_time).until( + EC.presence_of_element_located(locator) + ) + + @classmethod + def wait_elems(cls, driver, locator, inside_el=None, wait_time=10): + if inside_el: + return WebDriverWait(driver, wait_time).until(ElementsIn(inside_el, locator)) + return WebDriverWait(driver, wait_time).until( + EC.presence_of_all_elements_located(locator) + ) diff --git a/requirements.txt b/requirements.txt index b0841a51..4dac0884 100644 --- a/requirements.txt +++ b/requirements.txt @@ -38,3 +38,5 @@ drf_dynamic_fields flower==0.9.2 unidecode factory-boy==2.11.1 +pyvirtualdisplay==0.2.1 # + sudo apt-get install xvfb + sudo apt-get install chromium-chromedriver +# + sudo ln -s /usr/lib/chromium-browser/chromedriver /usr/bin/chromedriver diff --git a/web/src/components/CourseRedactor.vue b/web/src/components/CourseRedactor.vue index 073e9f49..79a1ed67 100644 --- a/web/src/components/CourseRedactor.vue +++ b/web/src/components/CourseRedactor.vue @@ -6,12 +6,13 @@
@@ -71,8 +72,8 @@ v-bind:class="{ error: ($v.course.duration.$dirty || showErrors) && $v.course.duration.$invalid }">
ПРОДОЛЖИТЕЛЬНОСТЬ
- +
@@ -81,12 +82,14 @@
ДОСТУП
@@ -94,27 +97,29 @@
СТОИМОСТЬ
- +
СТОИМОСТЬ БЕЗ СКИДКИ
- +
ВОЗРАСТ
-
@@ -122,12 +127,14 @@
ЗАПУСК
@@ -135,13 +142,15 @@
ДАТА
- +
ВРЕМЯ
- +
@@ -153,12 +162,12 @@
- -
- +