Покрыть тестами - заполнение курсов.

remotes/origin/feature/testing_courses_30-01-19
gzbender 7 years ago
parent 45427829f8
commit 59797388ac
  1. 1
      apps/auth/__init__.py
  2. 25
      apps/auth/migrations/0001_initial.py
  3. 27
      apps/auth/models.py
  4. 41
      apps/course/tests/test_views.py
  5. 2
      project/settings.py
  6. 21
      project/tests/__init__.py
  7. 1
      project/tests/factories.py
  8. 15
      requirements.txt
  9. 3
      web/src/components/CourseRedactor.vue

@ -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,7 +1,9 @@
from datetime import timedelta from datetime import timedelta
from random import randint from random import randint
import time
from selenium import webdriver from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from factory.faker import Faker from factory.faker import Faker
from django.utils import timezone from django.utils import timezone
from django.test import TestCase from django.test import TestCase
@ -10,7 +12,7 @@ from django.conf import settings
from django.utils.text import slugify from django.utils.text import slugify
from unidecode import unidecode from unidecode import unidecode
from project.tests.factories import * from project.tests.factories import create_admin, create_batch_unique, User, UserFactory, Course, CourseFactory
from project.tests import SeleniumTestCase from project.tests import SeleniumTestCase
from project.utils.selenium_utils import SeleniumExtensions as SE from project.utils.selenium_utils import SeleniumExtensions as SE
@ -51,7 +53,8 @@ class CoursesTestCase(TestCase):
class CourseEditTestCase(SeleniumTestCase): class CourseEditTestCase(SeleniumTestCase):
@classmethod @classmethod
def setUpTestData(cls): def setUpClass(cls):
super().setUpClass()
create_admin() create_admin()
UserFactory.create_batch(5, role=User.AUTHOR_ROLE) UserFactory.create_batch(5, role=User.AUTHOR_ROLE)
# create_batch_unique(CourseFactory, status=Course.STATUS_CHOICES[:3], price=[0, 1000], # create_batch_unique(CourseFactory, status=Course.STATUS_CHOICES[:3], price=[0, 1000],
@ -63,24 +66,22 @@ class CourseEditTestCase(SeleniumTestCase):
super().tearDownClass() super().tearDownClass()
def test_course_edit(self): def test_course_edit(self):
print('go to google')
self.driver.get('http://www.google.com')
return
user = User.objects.filter(role=User.AUTHOR_ROLE).first() user = User.objects.filter(role=User.AUTHOR_ROLE).first()
self.client.force_login(user) self.login(user)
url = self.get_url(reverse('course_create')) url = self.get_url(reverse('course_create'))
print('url', url) print('url', url)
self.driver.get(url) self.driver.get(url)
print('page opened', self.driver.current_url)
# visible always elements # visible always elements
title_el = self.wait_elem_name('course-title') title_el = self.wait_elem_name('course-title')
slug_el = self.wait_elem_name('course-slug') slug_el = self.wait_elem_name('course-slug')
category_el = self.wait_elem_name('course-category') category_el = self.wait_elem_name('course-category')
is_paid_no_el = self.wait_elem_name('course-is-paid-no') 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_yes_el = self.wait_elem_name('course-is-paid-yes')
is_paid_input_el = self.wait_elem_name('course-is-paid-input') is_paid_input_el = self.wait_elem_css('[name=course-is-paid-input]:checked')
age_el = self.wait_elem_name('course-age') age_el = self.wait_elem_name('course-age')
is_featured_el = self.wait_elem_name('course-is-featured') # 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_no_el = self.wait_elem_name('course-is-deferred-no')
is_deferred_yes_el = self.wait_elem_name('course-is-deferred-yes') is_deferred_yes_el = self.wait_elem_name('course-is-deferred-yes')
is_deferred_input_el = self.wait_elem_name('course-is-deferred-input') is_deferred_input_el = self.wait_elem_name('course-is-deferred-input')
@ -88,26 +89,32 @@ class CourseEditTestCase(SeleniumTestCase):
lessons_btn_el = self.wait_elem_name('course-lessons-btn') lessons_btn_el = self.wait_elem_name('course-lessons-btn')
content_el = self.wait_elem_name('course-content') content_el = self.wait_elem_name('course-content')
title = Faker('sentence', nb_words=6) title = Faker('sentence', nb_words=6).generate({})
title_el.send_keys(title) title_el.send_keys(title)
slug = slugify(unidecode(title[:90])) slug = slugify(unidecode(title[:90]))
print('title', title, 'slug', slug) print('title', title, 'slug', slug)
self.assertEqual(slug_el.text, slug) time.sleep(1)
self.assertEqual(slug_el.get_attribute('value'), slug)
print("is_paid_input_el.get_attribute('checked')", is_paid_input_el.get_attribute('checked')) 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.assertEqual(is_paid_input_el.get_attribute('value'), 'false')
self.assertRaises(callable=lambda: self.driver.find_element_by_name('course-price')) self.assertRaises(TimeoutException, callable=lambda: self.driver.find_element_by_name('course-price'))
self.assertRaises(callable=lambda: self.driver.find_element_by_name('course-old-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() is_paid_yes_el.click()
time.sleep(0.5)
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: try:
price_el = self.wait_elem_name('course-price') price_el = self.wait_elem_name('course-price')
old_price_el = self.wait_elem_name('course-old-price') old_price_el = self.wait_elem_name('course-old-price')
access_duration_el = self.wait_elem_name('course-access-duration')
except: except:
self.fail('Price and old price elements not shown') self.fail('Price, old price and access_duration elements not shown')
self.assertFalse(is_deferred_input_el.get_attribute('checked')) self.assertFalse(is_deferred_input_el.get_attribute('checked'))
self.assertRaises(callable=lambda: self.driver.find_element_by_name('course-date')) self.assertRaises(TimeoutException, callable=lambda: self.driver.find_element_by_name('course-date'))
self.assertRaises(callable=lambda: self.driver.find_element_by_name('course-time')) self.assertRaises(TimeoutException, callable=lambda: self.driver.find_element_by_name('course-time'))
is_deferred_yes_el.click() is_deferred_yes_el.click()
try: try:
date_el = self.wait_elem_name('course-date') date_el = self.wait_elem_name('course-date')

@ -59,7 +59,7 @@ INSTALLED_APPS = [
'django_user_agents', 'django_user_agents',
'imagekit', 'imagekit',
] + [ ] + [
'apps.auth.apps', 'apps.auth',
'apps.user', 'apps.user',
'apps.notification', 'apps.notification',
'apps.payment', 'apps.payment',

@ -1,13 +1,14 @@
from django.test import TestCase from django.test import LiveServerTestCase
from selenium import webdriver from selenium import webdriver
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from pyvirtualdisplay import Display from pyvirtualdisplay import Display
from django.conf import settings
from project.utils.selenium_utils import SeleniumExtensions as SE from project.utils.selenium_utils import SeleniumExtensions as SE
from django.conf import settings from apps.auth.models import TempToken
class SeleniumTestCase(TestCase): class SeleniumTestCase(LiveServerTestCase ):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
@ -18,12 +19,12 @@ class SeleniumTestCase(TestCase):
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
cls.driver.close() cls.driver.quit()
cls.display.stop() cls.display.stop()
super().tearDownClass() super().tearDownClass()
def get_url(self, url): def get_url(self, url=''):
return 'http://%s%s' % (settings.MAIN_HOST, url) return '%s%s' % (self.live_server_url, url)
def wait_elem_xpath(self, xpath, inside_el=None, wait_time=10): 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) return SE.wait_elem(self.driver, (By.XPATH, xpath), inside_el, wait_time)
@ -40,5 +41,13 @@ class SeleniumTestCase(TestCase):
def wait_elem_name(self, name, inside_el=None, wait_time=10): 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) 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): 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) return SE.wait_elems(self.driver, (By.NAME, name), inside_el, wait_time)
def login(self, user):
tt = TempToken.objects.create(user=user)
self.driver.get('%s?temp-token=%s' % (self.get_url(), tt.key))

@ -75,6 +75,7 @@ class UserFactory(DjangoModelFactory):
gallery = None gallery = None
photo = None #factory.SubFactory(ImageObjectFactory) photo = None #factory.SubFactory(ImageObjectFactory)
is_active = True is_active = True
auth_token = None
class CategoryFactory(DjangoModelFactory): class CategoryFactory(DjangoModelFactory):

@ -38,5 +38,16 @@ drf_dynamic_fields
flower==0.9.2 flower==0.9.2
unidecode unidecode
factory-boy==2.11.1 factory-boy==2.11.1
pyvirtualdisplay==0.2.1 # + sudo apt-get install xvfb + sudo apt-get install chromium-chromedriver pyvirtualdisplay==0.2.1
# + sudo ln -s /usr/lib/chromium-browser/chromedriver /usr/bin/chromedriver selenium
# sudo apt-get install xvfb
# sudo apt-get install libappindicator3-1 fonts-liberation
# wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
# sudo apt-get install unzip
# wget -N https://chromedriver.storage.googleapis.com/73.0.3683.20/chromedriver_linux64.zip
# unzip chromedriver_linux64.zip
# chmod +x chromedriver
# sudo mv -f chromedriver /usr/local/share/chromedriver
# sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver
# sudo ln -s /usr/local/share/chromedriver /usr/bin/chromedriver

@ -90,7 +90,7 @@
<div class="field__label field__label_gray">ПРОДОЛЖИТЕЛЬНОСТЬ ДОСТУПА</div> <div class="field__label field__label_gray">ПРОДОЛЖИТЕЛЬНОСТЬ ДОСТУПА</div>
<div class="field__wrap field__wrap__appended"> <div class="field__wrap field__wrap__appended">
<input type="text" class="field__input field__input__appended" v-model.number="course.access_duration" <input type="text" class="field__input field__input__appended" v-model.number="course.access_duration"
@input="$v.course.access_duration.$touch()"> @input="$v.course.access_duration.$touch()" name="course-access-duration">
<button disabled class="field__append">{{pluralize(course.access_duration, ['день', 'дня', 'дней'])}}</button> <button disabled class="field__append">{{pluralize(course.access_duration, ['день', 'дня', 'дней'])}}</button>
</div> </div>
</div> </div>
@ -612,7 +612,6 @@
this.lessons = data.lessons.map((lessonJson) => { this.lessons = data.lessons.map((lessonJson) => {
return api.convertLessonJson(lessonJson); return api.convertLessonJson(lessonJson);
}); });
this.course.access_duration = this.course.access_duration || '';
}, },
loadCourseDraft() { loadCourseDraft() {
//console.log('loadCourseDraft'); //console.log('loadCourseDraft');

Loading…
Cancel
Save