remotes/origin/feature/signed-user-cert-20-03-19
commit
ceffa402a2
24 changed files with 745 additions and 79 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.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: |
||||
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