remotes/origin/feature/cloudpayments
commit
cc87a10677
24 changed files with 744 additions and 78 deletions
@ -0,0 +1 @@ |
|||||||
|
default_app_config = 'apps.auth.apps.AuthConfig' |
||||||
@ -0,0 +1,25 @@ |
|||||||
|
# Generated by Django 2.0.7 on 2019-02-19 18:31 |
||||||
|
|
||||||
|
from django.conf import settings |
||||||
|
from django.db import migrations, models |
||||||
|
import django.db.models.deletion |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
initial = True |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.CreateModel( |
||||||
|
name='TempToken', |
||||||
|
fields=[ |
||||||
|
('key', models.CharField(max_length=40, primary_key=True, serialize=False, verbose_name='Key')), |
||||||
|
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')), |
||||||
|
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='auth_temp_token', to=settings.AUTH_USER_MODEL, verbose_name='User')), |
||||||
|
], |
||||||
|
), |
||||||
|
] |
||||||
@ -1,8 +1,29 @@ |
|||||||
|
import binascii |
||||||
|
import os |
||||||
|
|
||||||
from django.db import models |
from django.db import models |
||||||
|
from django.conf import settings |
||||||
|
from django.utils.translation import ugettext_lazy as _ |
||||||
|
|
||||||
from rest_framework.authtoken.models import Token |
|
||||||
|
|
||||||
|
class TempToken(models.Model): |
||||||
|
key = models.CharField(_("Key"), max_length=40, primary_key=True) |
||||||
|
user = models.OneToOneField( |
||||||
|
settings.AUTH_USER_MODEL, related_name='auth_temp_token', |
||||||
|
on_delete=models.CASCADE, verbose_name=_("User") |
||||||
|
) |
||||||
|
created = models.DateTimeField(_("Created"), auto_now_add=True) |
||||||
|
|
||||||
class TempToken(Token): |
|
||||||
class Meta: |
class Meta: |
||||||
app_label = 'auth' |
app_label = 'lilcity_auth' |
||||||
|
|
||||||
|
def save(self, *args, **kwargs): |
||||||
|
if not self.key: |
||||||
|
self.key = self.generate_key() |
||||||
|
return super().save(*args, **kwargs) |
||||||
|
|
||||||
|
def generate_key(self): |
||||||
|
return binascii.hexlify(os.urandom(20)).decode() |
||||||
|
|
||||||
|
def __str__(self): |
||||||
|
return self.key |
||||||
|
|||||||
@ -1,3 +0,0 @@ |
|||||||
from django.test import TestCase |
|
||||||
|
|
||||||
# Create your tests here. |
|
||||||
@ -0,0 +1,144 @@ |
|||||||
|
import time |
||||||
|
|
||||||
|
from factory.faker import Faker |
||||||
|
from selenium.common.exceptions import TimeoutException |
||||||
|
from selenium.webdriver.common.by import By |
||||||
|
from django.utils.html import strip_tags |
||||||
|
|
||||||
|
|
||||||
|
class TestContentMixin: |
||||||
|
content_data = [] |
||||||
|
|
||||||
|
def check_saving(self): |
||||||
|
if not self.autosave: |
||||||
|
return |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
def check_content_saving(self, obj): |
||||||
|
print('Check content saving',) |
||||||
|
self.assertEqual(obj.content.all().count(), len(self.content_data)) |
||||||
|
for i, item in enumerate(obj.content.all().order_by('position', '-created_at',)): |
||||||
|
item_data = self.content_data[i].get('data') |
||||||
|
for key, value in item_data.items(): |
||||||
|
if key == 'txt': |
||||||
|
self.assertEqual(strip_tags(getattr(item, key)), value) |
||||||
|
else: |
||||||
|
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(0.5) |
||||||
|
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) |
||||||
|
|
||||||
|
open_el.click() |
||||||
|
time.sleep(0.5) |
||||||
|
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) |
||||||
|
|
||||||
|
open_el.click() |
||||||
|
time.sleep(0.5) |
||||||
|
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) |
||||||
|
|
||||||
|
open_el.click() |
||||||
|
time.sleep(0.5) |
||||||
|
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) |
||||||
|
|
||||||
|
open_el.click() |
||||||
|
time.sleep(0.5) |
||||||
|
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).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({}) |
||||||
|
text_el.click() |
||||||
|
text_el.send_keys(text) |
||||||
|
block_obj['data']['txt'] = text |
||||||
|
self.check_saving() |
||||||
|
|
||||||
|
def check_block_image(self, inside_el=None): |
||||||
|
return |
||||||
|
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_saving() |
||||||
|
|
||||||
|
def check_block_image_text(self, inside_el=None): |
||||||
|
return |
||||||
|
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({}) |
||||||
|
text_el.click() |
||||||
|
text_el.send_keys(text) |
||||||
|
block_obj['data']['txt'] = text |
||||||
|
# TODO: check image upload |
||||||
|
self.check_saving() |
||||||
|
|
||||||
|
def check_block_images(self, inside_el=None): |
||||||
|
print('Check block images') |
||||||
|
time.sleep(1) |
||||||
|
block_obj = {'type': 'images', 'data': {}} |
||||||
|
self.content_data.append(block_obj) |
||||||
|
# block_el = self.wait_elem_name('block-images', inside_el) |
||||||
|
# title_el = self.wait_elem_name('block-images-title', block_el) |
||||||
|
# title = Faker('sentence', nb_words=6).generate({}) |
||||||
|
# title_el.send_keys(title) |
||||||
|
# block_obj['data']['title'] = title |
||||||
|
|
||||||
|
self.check_saving() |
||||||
|
|
||||||
|
def check_block_video(self, inside_el=None): |
||||||
|
return |
||||||
|
print('Check block images') |
||||||
@ -1,3 +0,0 @@ |
|||||||
from django.test import TestCase |
|
||||||
|
|
||||||
# Create your tests here. |
|
||||||
@ -0,0 +1,196 @@ |
|||||||
|
from datetime import timedelta |
||||||
|
from random import randint |
||||||
|
import time |
||||||
|
import re |
||||||
|
|
||||||
|
from selenium.common.exceptions import TimeoutException |
||||||
|
from factory.faker import Faker |
||||||
|
from django.utils import timezone |
||||||
|
from django.test import TestCase |
||||||
|
from django.shortcuts import reverse |
||||||
|
from django.utils.text import slugify |
||||||
|
from unidecode import unidecode |
||||||
|
from selenium.webdriver.common.by import By |
||||||
|
from django.utils.html import strip_tags |
||||||
|
|
||||||
|
from project.tests.factories import create_admin, create_batch_unique, User, UserFactory, Course, CourseFactory, login_admin |
||||||
|
from project.tests import SeleniumTestCase |
||||||
|
from apps.content.tests.mixins import TestContentMixin |
||||||
|
|
||||||
|
|
||||||
|
class CoursesTestCase(TestCase): |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def setUpTestData(cls): |
||||||
|
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))]) |
||||||
|
|
||||||
|
def test_courses_url_accessible(self): |
||||||
|
print('test_courses_url_accessible') |
||||||
|
print('get ', reverse('courses')) |
||||||
|
resp = self.client.get(reverse('courses')) |
||||||
|
self.assertEqual(resp.status_code, 200) |
||||||
|
|
||||||
|
def test_course_url_accessible(self): |
||||||
|
print('test_course_url_accessible') |
||||||
|
for course in Course.objects.filter(status=Course.PUBLISHED): |
||||||
|
print('get ', course.url) |
||||||
|
resp = self.client.get(course.url) |
||||||
|
self.assertEqual(resp.status_code, 200) |
||||||
|
|
||||||
|
@login_admin |
||||||
|
def test_course_edit_url_accessible(self): |
||||||
|
print('test_course_edit_url_accessible') |
||||||
|
for course in Course.objects.all(): |
||||||
|
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(TestContentMixin, SeleniumTestCase): |
||||||
|
model = Course |
||||||
|
object_id = None |
||||||
|
object_data = {} |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def setUpClass(cls): |
||||||
|
super().setUpClass() |
||||||
|
create_admin() |
||||||
|
UserFactory.create_batch(5, role=User.AUTHOR_ROLE) |
||||||
|
|
||||||
|
def check_saving(self, url=None, response_code=200): |
||||||
|
print('Check saving') |
||||||
|
time.sleep(1) |
||||||
|
request = self.wait_for_request(url or f'/api/v1/courses/{self.object_id}/') |
||||||
|
self.assertEqual(request[2].get('status'), response_code) |
||||||
|
self.assertNotEqual(request[2].get('response'), None) |
||||||
|
obj = self.model.objects.get(id=self.object_id) |
||||||
|
for key, value in self.object_data.items(): |
||||||
|
if key not in ['content', 'lessons']: |
||||||
|
self.assertEqual(getattr(obj, key), value) |
||||||
|
self.check_content_saving(obj) |
||||||
|
self.check_lessons_saving(obj) |
||||||
|
|
||||||
|
def check_lessons_saving(self, obj): |
||||||
|
print('Check lessons saving', ) |
||||||
|
lessons = self.object_data.get('lessons', []) |
||||||
|
self.assertEqual(obj.lessons.all().count(), len(lessons)) |
||||||
|
for i, lesson in enumerate(obj.lessons.all().order_by('title',)): |
||||||
|
self.assertEqual(strip_tags(lesson.short_description), lessons[i]['short_description']) |
||||||
|
self.assertEqual(lesson.title, lessons[i]['title']) |
||||||
|
print('OK') |
||||||
|
|
||||||
|
def test_course_edit(self): |
||||||
|
print('test_course_edit') |
||||||
|
user = User.objects.filter(role=User.AUTHOR_ROLE).first() |
||||||
|
self.login(user) |
||||||
|
url = self.get_url(reverse('course_create')) |
||||||
|
print('url is', url) |
||||||
|
self.driver.get(url) |
||||||
|
print('page opened', self.driver.current_url) |
||||||
|
self.add_requests_log() |
||||||
|
|
||||||
|
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') |
||||||
|
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_css('[name=course-is-paid-input]:checked') |
||||||
|
age_el = self.wait_elem_name('course-age') |
||||||
|
# Only for ADMIN |
||||||
|
# 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).generate({}) |
||||||
|
title_el.send_keys(title) |
||||||
|
slug = slugify(unidecode(title[:90])) |
||||||
|
slug = re.sub(r'[^-\w]+$', '', slug) |
||||||
|
slug = re.sub(r'[^-\w]', '-', slug) |
||||||
|
self.object_data['title'] = title |
||||||
|
self.object_data['slug'] = slug |
||||||
|
time.sleep(1) |
||||||
|
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 |
||||||
|
|
||||||
|
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(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: |
||||||
|
price_el = self.wait_elem_name('course-price') |
||||||
|
old_price_el = self.wait_elem_name('course-old-price') |
||||||
|
access_duration_el = self.wait_elem_name('course-access-duration') |
||||||
|
except: |
||||||
|
self.fail('Price, old price and access_duration elements not shown') |
||||||
|
|
||||||
|
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() |
||||||
|
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') |
||||||
|
|
||||||
|
price_el.send_keys(1000) |
||||||
|
self.object_data['price'] = 1000 |
||||||
|
old_price_el.send_keys(1500) |
||||||
|
self.object_data['old_price'] = 1500 |
||||||
|
access_duration_el.send_keys(15) |
||||||
|
self.object_data['access_duration'] = 15 |
||||||
|
self.check_saving() |
||||||
|
|
||||||
|
self.check_content(content_el) |
||||||
|
|
||||||
|
lessons_btn_el.click() |
||||||
|
time.sleep(0.5) |
||||||
|
# lessons_el = self.wait_elem_name('course-lessons') |
||||||
|
# lesson_edit_el = self.wait_elem_name('course-lesson-edit') |
||||||
|
# stream_el = self.wait_elem_name('course-stream') |
||||||
|
add_lesson_el = self.wait_elem_name('course-add-lesson') |
||||||
|
|
||||||
|
add_lesson_el.click() |
||||||
|
time.sleep(0.5) |
||||||
|
|
||||||
|
lesson_title_el = self.wait_elem_name('course-lesson-title') |
||||||
|
lesson_text_el = self.wait_elem_name('course-lesson-text-wrap').find_element( |
||||||
|
By.XPATH, './/div[contains(@class, "redactor-layer")][@contenteditable]') |
||||||
|
lesson_save_btn_el = self.wait_elem_name('course-lesson-save') |
||||||
|
|
||||||
|
lesson = {} |
||||||
|
title = Faker('sentence', nb_words=6).generate({}) |
||||||
|
lesson_title_el.send_keys(title) |
||||||
|
lesson['title'] = title |
||||||
|
|
||||||
|
text = Faker('sentence', nb_words=50).generate({}) |
||||||
|
lesson_text_el.click() |
||||||
|
lesson_text_el.send_keys(text) |
||||||
|
time.sleep(0.5) |
||||||
|
|
||||||
|
lesson_save_btn_el.click() |
||||||
|
self.object_data['lessons'] = [{ |
||||||
|
'title': title, |
||||||
|
'short_description': text |
||||||
|
}] |
||||||
|
self.check_saving('/api/v1/lessons/', 201) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,65 @@ |
|||||||
|
from django.test import LiveServerTestCase |
||||||
|
from selenium import webdriver |
||||||
|
from selenium.webdriver.common.by import By |
||||||
|
from pyvirtualdisplay import Display |
||||||
|
from django.conf import settings |
||||||
|
from selenium.webdriver.support.ui import WebDriverWait |
||||||
|
from selenium.webdriver.support import expected_conditions as EC |
||||||
|
|
||||||
|
from project.utils.selenium_utils import SeleniumExtensions as SE |
||||||
|
from apps.auth.models import TempToken |
||||||
|
|
||||||
|
|
||||||
|
class SeleniumTestCase(LiveServerTestCase): |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def setUpClass(cls): |
||||||
|
super().setUpClass() |
||||||
|
cls.display = Display(visible=0, size=(1280, 1024)) |
||||||
|
cls.display.start() |
||||||
|
cls.driver = webdriver.Firefox() |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def tearDownClass(cls): |
||||||
|
cls.driver.quit() |
||||||
|
cls.display.stop() |
||||||
|
super().tearDownClass() |
||||||
|
|
||||||
|
def get_url(self, url=''): |
||||||
|
return '%s%s' % (self.live_server_url, 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_elem_id(self, id, inside_el=None, wait_time=10): |
||||||
|
return SE.wait_elem(self.driver, (By.ID, id), 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) |
||||||
|
|
||||||
|
def login(self, user): |
||||||
|
TempToken.objects.all().delete() |
||||||
|
tt = TempToken.objects.create(user=user) |
||||||
|
self.driver.get('%s?temp-token=%s' % (self.get_url(), tt.key)) |
||||||
|
|
||||||
|
def add_requests_log(self): |
||||||
|
SE.add_requests_log(self.driver) |
||||||
|
|
||||||
|
def get_requests(self): |
||||||
|
return SE.get_requests(self.driver) |
||||||
|
|
||||||
|
def wait_for_request(self, path, wait_time=10): |
||||||
|
return SE.wait_for_request(self.driver, path, wait_time) |
||||||
|
|
||||||
@ -0,0 +1,96 @@ |
|||||||
|
from itertools import combinations |
||||||
|
|
||||||
|
from factory.django import DjangoModelFactory, ImageField |
||||||
|
import factory |
||||||
|
import factory.fuzzy |
||||||
|
from unidecode import unidecode |
||||||
|
from django.utils.text import slugify |
||||||
|
|
||||||
|
|
||||||
|
from apps.course.models import * |
||||||
|
from apps.content.models import * |
||||||
|
from apps.user.models import * |
||||||
|
|
||||||
|
|
||||||
|
ADMIN_EMAIL = 'admin@mail.com' |
||||||
|
|
||||||
|
|
||||||
|
def create_admin(): |
||||||
|
admin = UserFactory(username=ADMIN_EMAIL, email=ADMIN_EMAIL, role=User.ADMIN_ROLE, |
||||||
|
is_staff=True, is_superuser=True) |
||||||
|
admin.set_password('admin') |
||||||
|
admin.save() |
||||||
|
return admin |
||||||
|
|
||||||
|
|
||||||
|
def create_users(count_multiplier=1): |
||||||
|
create_admin() |
||||||
|
UserFactory.create_batch(10 * count_multiplier, role=User.USER_ROLE) |
||||||
|
UserFactory.create_batch(5 * count_multiplier, role=User.AUTHOR_ROLE) |
||||||
|
UserFactory.create_batch(5 * count_multiplier, role=User.TEACHER_ROLE) |
||||||
|
UserFactory.create_batch(5, role=User.ADMIN_ROLE, is_staff=True) |
||||||
|
|
||||||
|
|
||||||
|
def login_admin(fn): |
||||||
|
def wrap(self, *args, **kwargs): |
||||||
|
admin = User.objects.get(username=ADMIN_EMAIL) |
||||||
|
self.client.force_login(admin) |
||||||
|
try: |
||||||
|
fn(self, *args, **kwargs) |
||||||
|
finally: |
||||||
|
self.client.logout() |
||||||
|
return wrap |
||||||
|
|
||||||
|
|
||||||
|
def create_batch_unique(factory_class, **kwargs): |
||||||
|
model = factory_class._meta.model |
||||||
|
values = [] |
||||||
|
for k, v in kwargs.items(): |
||||||
|
try: |
||||||
|
f = model._meta.get_field(k) |
||||||
|
except: |
||||||
|
del kwargs[k] |
||||||
|
if getattr(f, 'choices', None): |
||||||
|
v = [c[0] for c in v] |
||||||
|
values += ((k, val) for val in v) |
||||||
|
for params in combinations(values, len(kwargs)): |
||||||
|
data = dict(params) |
||||||
|
if len(data) == len(kwargs): |
||||||
|
factory_class(**data) |
||||||
|
|
||||||
|
|
||||||
|
class ImageObjectFactory(DjangoModelFactory): |
||||||
|
image = ImageField() |
||||||
|
image_thumbnail = ImageField() |
||||||
|
|
||||||
|
|
||||||
|
class UserFactory(DjangoModelFactory): |
||||||
|
class Meta: |
||||||
|
model = User |
||||||
|
|
||||||
|
first_name = factory.Faker('first_name') |
||||||
|
last_name = factory.Faker('last_name') |
||||||
|
email = factory.Sequence(lambda n: "test_user%d@mail.com" % n) |
||||||
|
username = factory.LazyAttribute(lambda o: o.email) |
||||||
|
gallery = None |
||||||
|
photo = None #factory.SubFactory(ImageObjectFactory) |
||||||
|
is_active = True |
||||||
|
auth_token = None |
||||||
|
|
||||||
|
|
||||||
|
class CategoryFactory(DjangoModelFactory): |
||||||
|
class Meta: |
||||||
|
model = Category |
||||||
|
|
||||||
|
|
||||||
|
class CourseFactory(DjangoModelFactory): |
||||||
|
class Meta: |
||||||
|
model = Course |
||||||
|
|
||||||
|
author = factory.SubFactory(UserFactory, role=User.AUTHOR_ROLE) |
||||||
|
title = factory.Faker('sentence', nb_words=6) |
||||||
|
slug = factory.LazyAttribute(lambda o: slugify(unidecode(o.title[:90]))) |
||||||
|
category = factory.SubFactory(CategoryFactory) |
||||||
|
cover = None #factory.SubFactory(ImageObjectFactory) |
||||||
|
gallery = None |
||||||
|
status = factory.Iterator([s[0] for s in Course.STATUS_CHOICES]) |
||||||
@ -0,0 +1,93 @@ |
|||||||
|
# -*- coding: utf-8 -*- |
||||||
|
|
||||||
|
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) |
||||||
|
) |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def wait_for_js_load(cls, driver, wait_time=10): |
||||||
|
WebDriverWait(driver, wait_time).until( |
||||||
|
lambda driver: driver.execute_script('return document.readyState') == 'complete') |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def add_requests_log(cls, driver): |
||||||
|
js = ''' |
||||||
|
(function() { |
||||||
|
var open = XMLHttpRequest.prototype.open; |
||||||
|
var send = XMLHttpRequest.prototype.send; |
||||||
|
window._requestsLog = []; |
||||||
|
window._findRequest = function(pathOrXHR){ |
||||||
|
for(var i=window._requestsLog.length - 1; i >= 0; i--){ |
||||||
|
var request = window._requestsLog[i]; |
||||||
|
if(typeof(pathOrXHR) == 'string' && request[1].indexOf(pathOrXHR) > -1 |
||||||
|
|| request[2] === pathOrXHR){ |
||||||
|
return request; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
XMLHttpRequest.prototype.open = function(method, url){ |
||||||
|
window._requestsLog.push([method, url, this]); |
||||||
|
return open.apply(this, arguments); |
||||||
|
} |
||||||
|
XMLHttpRequest.prototype.send = function(body){ |
||||||
|
var r = window._findRequest(this); |
||||||
|
if(r){ |
||||||
|
r.push(body); |
||||||
|
} |
||||||
|
return send.apply(this, arguments); |
||||||
|
} |
||||||
|
})(); |
||||||
|
''' |
||||||
|
return driver.execute_script(js) |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def get_requests(cls, driver): |
||||||
|
return driver.execute_script('return window._requestsLog;') |
||||||
|
|
||||||
|
@classmethod |
||||||
|
def wait_for_request(cls, driver, path, wait_time=10): |
||||||
|
WebDriverWait(driver, wait_time).until( |
||||||
|
lambda driver: driver.execute_script(''' |
||||||
|
var r = window._findRequest(arguments[0]); |
||||||
|
return !!r && r[2].readyState == 4; |
||||||
|
''', path) is True) |
||||||
|
return driver.execute_script('return window._findRequest(arguments[0]);', path) |
||||||
Loading…
Reference in new issue