diff --git a/apps/content/tests.py b/apps/content/tests.py
deleted file mode 100644
index 7ce503c2..00000000
--- a/apps/content/tests.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from django.test import TestCase
-
-# Create your tests here.
diff --git a/apps/content/tests/__init__.py b/apps/content/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/apps/content/tests/mixins.py b/apps/content/tests/mixins.py
new file mode 100644
index 00000000..71ff7e6e
--- /dev/null
+++ b/apps/content/tests/mixins.py
@@ -0,0 +1,129 @@
+import time
+
+from factory.faker import Faker
+from selenium.common.exceptions import TimeoutException
+from selenium.webdriver.common.by import By
+
+
+class TestContentMixin:
+ content_data = []
+ autosave = True
+
+ def check_auto_saving(self):
+ if not self.autosave:
+ return
+ raise NotImplementedError()
+
+ def check_content_auto_saving(self, object):
+ if not self.autosave:
+ return
+ print('Check content autosaving',)
+ self.assertEqual(object.content.all().count(), len(self.content_data))
+ for i, item in enumerate(object.content.all().order_by('position', '-created_at',)):
+ item_data = self.content_data[i].get('data')
+ for key, value in item_data.items():
+ print('real obj field value:', getattr(item, key, None))
+ print('expected value:', value)
+ self.assertEqual(getattr(item, key), value)
+ print('OK')
+
+ def check_content(self, inside_el=None):
+ print('Check content block')
+ self.object_data['content'] = self.content_data
+ block_add_el = self.wait_elem_name('block-add', inside_el)
+ open_el = self.wait_elem_name('block-add-open', block_add_el)
+ self.assertRaises(TimeoutException, lambda: self.wait_elem_name('block-add-close', block_add_el))
+ open_el.click()
+ time.sleep(1)
+ close_el = self.wait_elem_name('block-add-close', block_add_el)
+
+ block_text_el = self.wait_elem_name('block-add-block-text', block_add_el)
+ block_text_el.click()
+ time.sleep(0.5)
+ self.check_block_text(inside_el)
+
+ block_image_el = self.wait_elem_name('block-add-block-image', block_add_el)
+ block_image_el.click()
+ time.sleep(0.5)
+ self.check_block_image(inside_el)
+
+ block_image_text_el = self.wait_elem_name('block-add-block-image-text', block_add_el)
+ block_image_text_el.click()
+ time.sleep(0.5)
+ self.check_block_image_text(inside_el)
+
+ block_images_el = self.wait_elem_name('block-add-block-images', block_add_el)
+ block_images_el.click()
+ time.sleep(0.5)
+ self.check_block_images(inside_el)
+
+ block_video_el = self.wait_elem_name('block-add-block-video', block_add_el)
+ block_video_el.click()
+ time.sleep(0.5)
+ self.check_block_video(inside_el)
+
+ def check_block_text(self, inside_el=None):
+ print('Check block text')
+ time.sleep(1)
+ block_obj = {'type': 'text', 'data': {}}
+ block_el = self.wait_elem_name('block-text', inside_el)
+ title_el = self.wait_elem_name('block-text-title', block_el)
+ text_el = self.wait_elem_name('block-text-text-wrap', block_el)
+ text_el.find_element(
+ By.XPATH, './/div[contains(@class, "redactor-layer")][@contenteditable]')
+ self.content_data.append(block_obj)
+
+ title = Faker('sentence', nb_words=6).generate({})
+ title_el.send_keys(title)
+ block_obj['data']['title'] = title
+ text = Faker('sentence', nb_words=50).generate({})
+ self.driver.execute_script("arguments[0].click();", text_el)
+ self.driver.execute_script("arguments[0].innerHtml = arguments[1];", text_el, text)
+ self.driver.execute_script("arguments[0].dispatchEvent(new Event('change'));", text_el)
+ # text_el.send_keys(text)
+ block_obj['data']['text'] = '
%s
' % text
+ self.check_auto_saving()
+
+ def check_block_image(self, inside_el=None):
+ print('Check block image')
+ time.sleep(1)
+ block_obj = {'type': 'image', 'data': {}}
+ block_el = self.wait_elem_name('block-image', inside_el)
+ title_el = self.wait_elem_name('block-image-title', block_el)
+ image_el = self.wait_elem_name('block-image-image', block_el)
+ self.content_data.append(block_obj)
+
+ title = Faker('sentence', nb_words=6).generate({})
+ title_el.send_keys(title)
+ block_obj['data']['title'] = title
+ # TODO: check image upload
+ self.check_auto_saving()
+
+ def check_block_image_text(self, inside_el=None):
+ print('Check block image-text')
+ time.sleep(1)
+ block_obj = {'type': 'image-text', 'data': {}}
+ block_el = self.wait_elem_name('block-image-text', inside_el)
+ title_el = self.wait_elem_name('block-image-text-title', block_el)
+ text_el = self.wait_elem_name('block-image-text-text-wrap', block_el).find_element(
+ By.XPATH, './/div[contains(@class, "redactor-layer")][@contenteditable]')
+ image_el = self.wait_elem_name('block-image-text-image', block_el)
+ self.content_data.append(block_obj)
+
+ title = Faker('sentence', nb_words=6).generate({})
+ title_el.send_keys(title)
+ block_obj['data']['title'] = title
+ text = Faker('sentence', nb_words=50).generate({})
+ self.driver.execute_script("arguments[0].click();", text_el)
+ self.driver.execute_script("arguments[0].innerHtml = arguments[1];", text_el, text)
+ self.driver.execute_script("arguments[0].dispatchEvent(new Event('change'));", text_el)
+ # text_el.send_keys(text)
+ block_obj['data']['text'] = '%s
' % text
+ # TODO: check image upload
+ self.check_auto_saving()
+
+ def check_block_images(self, inside_el=None):
+ print('Check block images')
+
+ def check_block_video(self, inside_el=None):
+ print('Check block images')
diff --git a/apps/course/templates/course/course_edit.html b/apps/course/templates/course/course_edit.html
index 83990c00..5fc6666a 100644
--- a/apps/course/templates/course/course_edit.html
+++ b/apps/course/templates/course/course_edit.html
@@ -17,7 +17,8 @@
{% endblock header_buttons %}
{% block content %}
-
diff --git a/apps/course/tests/test_views.py b/apps/course/tests/test_views.py
index 5d791de9..9ddcc30c 100644
--- a/apps/course/tests/test_views.py
+++ b/apps/course/tests/test_views.py
@@ -14,6 +14,7 @@ from unidecode import unidecode
from project.tests.factories import create_admin, create_batch_unique, User, UserFactory, Course, CourseFactory
from project.tests import SeleniumTestCase
+from apps.content.tests.mixins import TestContentMixin
from project.utils.selenium_utils import SeleniumExtensions as SE
'''
@@ -50,7 +51,10 @@ class CoursesTestCase(TestCase):
'''
-class CourseEditTestCase(SeleniumTestCase):
+class CourseEditTestCase(TestContentMixin, SeleniumTestCase):
+ model = Course
+ object_id = None
+ object_data = {}
@classmethod
def setUpClass(cls):
@@ -65,13 +69,23 @@ class CourseEditTestCase(SeleniumTestCase):
print('teardown CourseEditTestCase')
super().tearDownClass()
+ def check_auto_saving(self):
+ # TODO
+ time.sleep(5)
+ obj = self.model.objects.get(id=self.object_id)
+ for key, value in self.object_data.items():
+ if key != 'content':
+ self.assertEqual(getattr(obj, key), value)
+ self.check_content_auto_saving(obj)
+
def test_course_edit(self):
user = User.objects.filter(role=User.AUTHOR_ROLE).first()
self.login(user)
url = self.get_url(reverse('course_create'))
- print('url', url)
+ print('url is', url)
self.driver.get(url)
print('page opened', self.driver.current_url)
+ course_redactor = self.wait_elem_name('course-redactor')
# visible always elements
title_el = self.wait_elem_name('course-title')
slug_el = self.wait_elem_name('course-slug')
@@ -92,17 +106,25 @@ class CourseEditTestCase(SeleniumTestCase):
title = Faker('sentence', nb_words=6).generate({})
title_el.send_keys(title)
slug = slugify(unidecode(title[:90]))
- print('title', title, 'slug', slug)
- time.sleep(1)
+ self.object_data['title'] = title
+ self.object_data['slug'] = slug
+ # print('title:', title)
+ # print('slug:', slug)
+ time.sleep(2)
self.assertEqual(slug_el.get_attribute('value'), slug)
+ # check save
+ obj = self.model.objects.get(title=title, slug=slug)
+ self.assertEqual(bool(obj), True)
+ self.object_id = obj.id
+
print("is_paid_input_el.get_attribute('checked')", is_paid_input_el.get_attribute('checked'))
self.assertEqual(is_paid_input_el.get_attribute('value'), 'false')
self.assertRaises(TimeoutException, callable=lambda: self.driver.find_element_by_name('course-price'))
self.assertRaises(TimeoutException, callable=lambda: self.driver.find_element_by_name('course-old-price'))
self.assertRaises(TimeoutException, callable=lambda: self.driver.find_element_by_name('course-access-duration'))
is_paid_yes_el.click()
- time.sleep(0.5)
+ time.sleep(1)
is_paid_input_el = self.wait_elem_css('[name=course-is-paid-input]:checked')
self.assertEqual(is_paid_input_el.get_attribute('value'), 'true')
try:
@@ -112,7 +134,7 @@ class CourseEditTestCase(SeleniumTestCase):
except:
self.fail('Price, old price and access_duration elements not shown')
- self.assertFalse(is_deferred_input_el.get_attribute('checked'))
+ self.assertEqual(is_deferred_input_el.get_attribute('checked'), 'true')
self.assertRaises(TimeoutException, callable=lambda: self.driver.find_element_by_name('course-date'))
self.assertRaises(TimeoutException, callable=lambda: self.driver.find_element_by_name('course-time'))
is_deferred_yes_el.click()
@@ -121,6 +143,8 @@ class CourseEditTestCase(SeleniumTestCase):
time_el = self.wait_elem_name('course-time')
except:
self.fail('Date and time elements not shown')
+
+ self.check_content(content_el)
# lessons_el = self.wait_elem_name('course-lessons')
# add_lesson_el = self.wait_elem_name('course-add-lesson')
diff --git a/project/utils/selenium_utils.py b/project/utils/selenium_utils.py
index 5bf62c6b..4f523d1b 100644
--- a/project/utils/selenium_utils.py
+++ b/project/utils/selenium_utils.py
@@ -17,7 +17,7 @@ class ElementIn(object):
def __call__(self, driver):
try:
- return getattr(self.element, self.find_fn)(self.locator)
+ return getattr(self.element, self.find_fn)(*self.locator)
except:
return False
diff --git a/web/src/components/CourseRedactor.vue b/web/src/components/CourseRedactor.vue
index 5dd557c8..709bea46 100644
--- a/web/src/components/CourseRedactor.vue
+++ b/web/src/components/CourseRedactor.vue
@@ -99,14 +99,16 @@
diff --git a/web/src/components/blocks/BlockAdd.vue b/web/src/components/blocks/BlockAdd.vue
index 0090a8df..0a3c9bd1 100644
--- a/web/src/components/blocks/BlockAdd.vue
+++ b/web/src/components/blocks/BlockAdd.vue
@@ -1,7 +1,7 @@
-
+
-
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/web/src/components/blocks/BlockContent.vue b/web/src/components/blocks/BlockContent.vue
index 3a3b223b..2fe1b0d9 100644
--- a/web/src/components/blocks/BlockContent.vue
+++ b/web/src/components/blocks/BlockContent.vue
@@ -1,14 +1,15 @@
-
+
-
+
-
+
@@ -18,7 +19,7 @@
-
+
diff --git a/web/src/components/blocks/BlockImage.vue b/web/src/components/blocks/BlockImage.vue
index 2d1f9695..ab6ab083 100644
--- a/web/src/components/blocks/BlockImage.vue
+++ b/web/src/components/blocks/BlockImage.vue
@@ -1,8 +1,8 @@
-
+
diff --git a/web/src/components/blocks/BlockImageText.vue b/web/src/components/blocks/BlockImageText.vue
index f4bab250..a2d7f0a5 100644
--- a/web/src/components/blocks/BlockImageText.vue
+++ b/web/src/components/blocks/BlockImageText.vue
@@ -1,12 +1,12 @@
-
+
+ v-on:update:imageId="onUpdateImageId" :access-token="accessToken" name="block-image-text-image"/>
-
-
diff --git a/web/src/components/blocks/BlockImages.vue b/web/src/components/blocks/BlockImages.vue
index ab607522..f48836ac 100644
--- a/web/src/components/blocks/BlockImages.vue
+++ b/web/src/components/blocks/BlockImages.vue
@@ -1,8 +1,8 @@
-
+
-
-
-
![]()
-
+
+
![]()
+