diff --git a/.idea/django-separate-users.iml b/.idea/django-separate-users.iml new file mode 100644 index 0000000..ae71067 --- /dev/null +++ b/.idea/django-separate-users.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..dfb77dc --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..fa598c8 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..2af2edf --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,556 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + DEFINITION_ORDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1489851499607 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CHANGELOG.txt b/CHANGELOG.txt new file mode 100644 index 0000000..24def7e --- /dev/null +++ b/CHANGELOG.txt @@ -0,0 +1,11 @@ + +==== 0.xxx (not yet) === + +- fix for djangocms-admin-styles + + +==== 0.0.1 (not yet) === + +- support for django 1.9 +- refactored tests, to use default manage.py test command + diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..0a9b2a3 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,7 @@ +include LICENSES +include README.rst +global-exclude *.orig *.pyc *.log *.swp + +recursive-include separate_users/templates * +recursive-include separate_users/static * +recursive-include separate_users/locale * diff --git a/compilemessages.sh b/compilemessages.sh new file mode 100755 index 0000000..f519a5c --- /dev/null +++ b/compilemessages.sh @@ -0,0 +1,4 @@ + +cd separate_users +django-admin.py compilemessages +cd .. \ No newline at end of file diff --git a/makemessages.sh b/makemessages.sh new file mode 100755 index 0000000..d0185b4 --- /dev/null +++ b/makemessages.sh @@ -0,0 +1,5 @@ + + +cd separate_users +django-admin.py makemessages -l en +cd .. \ No newline at end of file diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..4e42ee0 --- /dev/null +++ b/manage.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault('DJANGO_SETTINGS_MODULE', + 'separate_users.tests.settings_runtestapp') + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/release.txt b/release.txt new file mode 100644 index 0000000..d0b25f3 --- /dev/null +++ b/release.txt @@ -0,0 +1,12 @@ + + +git flow release start 0.xxx +version bump in separate_users/__init__.py +git flow release finish 0.xxx +git push --all; git push --tags +python setup.py sdist +# no wheel for now?! python setup.py bdist_wheel --universal +python setup.py register -r pypitest +twine upload dist/* -r pypitest +python setup.py register -r pypi +twine upload dist/* diff --git a/separate_users/__init__.py b/separate_users/__init__.py new file mode 100644 index 0000000..25fda2c --- /dev/null +++ b/separate_users/__init__.py @@ -0,0 +1,2 @@ +__version__ = '0.1.2' +__author__ = 'benzkji' diff --git a/separate_users/admin.py b/separate_users/admin.py new file mode 100644 index 0000000..451f989 --- /dev/null +++ b/separate_users/admin.py @@ -0,0 +1,61 @@ +from django.conf.urls import url +from django.contrib import admin +from django.db import models +from django.http import JsonResponse + + +class DjangoLinkAdmin(admin.ModelAdmin): + + def get_model_perms(self, request): + """ + http://stackoverflow.com/questions/2431727/django-admin-hide-a-model + Return empty perms dict thus hiding the model from admin index. + """ + return {} + + def get_urls(self): + """ + add verify url. + """ + my_urls = [ + url( + r'^verify/$', + self.admin_site.admin_view(self.verify), + name=self._get_verify_url_name() + ), + ] + return my_urls + super(DjangoLinkAdmin, self).get_urls() + + def _get_verify_url_name(self): + return '{0}_{1}_verify'.format(self.model._meta.app_label, + self.model._meta.model_name) + + def verify(self, request): + """ + verify data with modelform, send through data. + :param request: + :return: + """ + form = self.get_form(request, )(request.POST) + if form.is_valid(): + verified_data = form.cleaned_data + obj = self.model(**verified_data) + link_value = '' + # prepopulate href + if (getattr(obj, 'get_link', None)): + link_value = obj.get_link() + # basic serialize only + for key, value in verified_data.items(): + if isinstance(value, models.Model): + verified_data[key] = value.id + return_data = {"valid": 'true', 'data': verified_data, 'link_value': link_value} + else: + errors = form.errors + return_data = {"valid": 'false', 'errors': errors} + return JsonResponse(return_data) + + def save_model(self, request, obj, form, change): + """ + no save! + """ + return False diff --git a/separate_users/models.py b/separate_users/models.py new file mode 100644 index 0000000..e69de29 diff --git a/separate_users/tests/__init__.py b/separate_users/tests/__init__.py new file mode 100644 index 0000000..b8c48bd --- /dev/null +++ b/separate_users/tests/__init__.py @@ -0,0 +1 @@ +__author__ = 'benzkji' diff --git a/separate_users/tests/settings_runtestapp.py b/separate_users/tests/settings_runtestapp.py new file mode 100644 index 0000000..8533e04 --- /dev/null +++ b/separate_users/tests/settings_runtestapp.py @@ -0,0 +1,13 @@ +""" +These settings are used by the ``manage.py`` command. +""" + +from .settings_test import * # NOQA + + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'db.sqlite', + } +} diff --git a/separate_users/tests/settings_test.py b/separate_users/tests/settings_test.py new file mode 100644 index 0000000..e756bf0 --- /dev/null +++ b/separate_users/tests/settings_test.py @@ -0,0 +1,151 @@ +"""Settings that need to be set in order to run the tests.""" +import os +import sys +import tempfile +import logging + +from django.core.urlresolvers import reverse_lazy + + +DEBUG = True + +logging.getLogger("factory").setLevel(logging.WARN) + +# from selenium.webdriver.firefox import webdriver +from selenium.webdriver.phantomjs import webdriver +SELENIUM_WEBDRIVER = webdriver + + +separate_users_MODEL = 'separate_users.tests.test_app.models.LinkModel' +separate_users_IFRAME_URL = reverse_lazy('admin:test_app_linkmodel_add') +separate_users_VERIFY_URL = reverse_lazy('admin:test_app_linkmodel_verify') + +CKEDITOR_CONFIGS = { + 'default': { + 'djangolinkIframeURL': separate_users_IFRAME_URL, + 'djangolinkVerifyURL': separate_users_VERIFY_URL, + 'linkShowAdvancedTab': False, + 'extraPlugins': ','.join( + [ + # your extra plugins here + 'djangolink', + 'autolink', + 'autoembed', + 'embedsemantic', + 'autogrow', + 'devtools', + 'widget', + 'lineutils', + 'clipboard', + 'dialog', + 'dialogui', + 'elementspath' + ]), + 'toolbar': 'Custom', + 'toolbar_Custom': [ + ['Bold', 'Underline'], + ['DjangoLink', 'Unlink'], + ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'], + ['Link', 'Unlink'], + ['RemoveFormat', 'Source'] + ] + } +} + +SITE_ID = 1 + +APP_ROOT = os.path.abspath( + os.path.join(os.path.dirname(__file__), "..")) + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': ':memory:', + } +} + +LANGUAGE_CODE = 'en' +LANGUAGES = ( + ('en', 'ENGLISHS' ), +) + +ROOT_URLCONF = 'separate_users.tests.urls' + +# media root is overridden when needed in tests +MEDIA_ROOT = tempfile.mkdtemp(suffix='ckeditor_media_root') +MEDIA_URL = "/media/" +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(APP_ROOT, '../test_app_static') +STATICFILES_DIRS = ( + os.path.join(APP_ROOT, 'static'), +) + +# TEMPLATE_DIRS = ( +# os.path.join(APP_ROOT, 'tests/test_app/templates'), +# ) + +COVERAGE_REPORT_HTML_OUTPUT_DIR = os.path.join( + os.path.join(APP_ROOT, 'tests/coverage')) +COVERAGE_MODULE_EXCLUDES = [ + 'tests$', 'settings$', 'urls$', 'locale$', + 'migrations', 'fixtures', 'admin$', 'django_extensions', +] + +EXTERNAL_APPS = ( + 'django.contrib.admin', + # 'django.contrib.admindocs', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.messages', + 'django.contrib.sessions', + 'django.contrib.staticfiles', + 'django.contrib.sitemaps', + 'django.contrib.sites', + 'ckeditor', + # 'djangocms_text_ckeditor', + # 'cms', + # 'treebeard', + # 'menus', +) + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'django.template.context_processors.i18n', + 'django.template.context_processors.request', + 'django.template.context_processors.media', + 'django.template.context_processors.static', + ], + 'loaders': [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + # 'django.template.loaders.eggs.Loader', + ], + } + }, +] + + +INTERNAL_APPS = ( + 'separate_users', + 'separate_users.tests.test_app', +) + +MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + # Uncomment the next line for simple clickjacking protection: + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'django.middleware.locale.LocaleMiddleware', +) + +INSTALLED_APPS = EXTERNAL_APPS + INTERNAL_APPS +COVERAGE_MODULE_EXCLUDES += EXTERNAL_APPS + +SECRET_KEY = 'foobarXXXxxsvXY' diff --git a/separate_users/tests/test_app/__init__.py b/separate_users/tests/test_app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/separate_users/tests/test_app/admin.py b/separate_users/tests/test_app/admin.py new file mode 100644 index 0000000..7058a7d --- /dev/null +++ b/separate_users/tests/test_app/admin.py @@ -0,0 +1,18 @@ +from django import forms +from django.contrib import admin +from django.forms.extras.widgets import SelectDateWidget + +from separate_users.admin import DjangoLinkAdmin + +from .models import TestModel, LinkModel + + +class LinkModelForm(forms.ModelForm): + when = forms.DateField(widget=SelectDateWidget, required=False) + + +class CKLinkModelAdmin(DjangoLinkAdmin): + form = LinkModelForm + +admin.site.register(TestModel) +admin.site.register(LinkModel, CKLinkModelAdmin) diff --git a/separate_users/tests/test_app/fixtures/test_app.json b/separate_users/tests/test_app/fixtures/test_app.json new file mode 100644 index 0000000..b071f53 --- /dev/null +++ b/separate_users/tests/test_app/fixtures/test_app.json @@ -0,0 +1 @@ +[{"model": "test_app.testmodel", "pk": 1, "fields": {"title": "Test 2", "richtext": "

None

", "richtext_second": ""}}, {"model": "test_app.testmodel", "pk": 2, "fields": {"title": "Testing different Link Form Widgets", "richtext": "

One Two Link One (Date Link, haha)

\r\n\r\n

Link Two (Foreign Key)

\r\n\r\n

what

", "richtext_second": "

sdvasdva link

"}}] \ No newline at end of file diff --git a/separate_users/tests/test_app/models.py b/separate_users/tests/test_app/models.py new file mode 100644 index 0000000..f0e2bb0 --- /dev/null +++ b/separate_users/tests/test_app/models.py @@ -0,0 +1,61 @@ +from __future__ import unicode_literals + +from django.core.urlresolvers import reverse +from django.utils.encoding import python_2_unicode_compatible +from django.db import models +from ckeditor.fields import RichTextField +# from djangocms_text_ckeditor.fields import HTMLField + + +@python_2_unicode_compatible +class TestModel(models.Model): + title = models.CharField(max_length=255, ) + richtext = RichTextField(default='') + richtext_second = RichTextField(default='') + + def __str__(self): + return "%s" % self.title + + def get_absolute_url(self): + return reverse('testmodel_detail', args=(self.id, )) + + +# @python_2_unicode_compatible +# class CMSTestModel(models.Model): +# title = models.CharField(max_length=255, ) +# richtext = HTMLField() +# +# def __str__(self): +# return "%s" % self.title + + +@python_2_unicode_compatible +class LinkModelBase(models.Model): + target = models.CharField(max_length=255, blank=True, default='', ) + external_url = models.CharField(max_length=255, blank=True, default='',) + email = models.EmailField(blank=True, default='',) + # http://stackoverflow.com/questions/12644142/prefill-a-datetimefield-from-url-in-django-admin + when = models.DateField(blank=True, null=True) + testmodel = models.ForeignKey(TestModel, null=True, default=None, blank=True) + + class Meta: + abstract = True + + def __str__(self): + return "LINK object: %s" % self.get_link() + + def get_link(self): + if self.external_url: + return self.external_url + else: + return "http://no-link-given.com/" + + def get_target(self): + return "_blank" + + def get_css_class(self): + return "no-css-class" + + +class LinkModel(LinkModelBase): + pass diff --git a/separate_users/tests/test_app/views.py b/separate_users/tests/test_app/views.py new file mode 100644 index 0000000..526428d --- /dev/null +++ b/separate_users/tests/test_app/views.py @@ -0,0 +1,7 @@ +from django.views.generic import DetailView + +from .models import TestModel + + +class TestModelDetailView(DetailView): + model = TestModel diff --git a/separate_users/tests/test_editor.py b/separate_users/tests/test_editor.py new file mode 100644 index 0000000..6b63656 --- /dev/null +++ b/separate_users/tests/test_editor.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +from time import sleep + +from django.contrib.auth.models import User +from django.core.urlresolvers import reverse +from selenium.common.exceptions import NoSuchElementException +from selenium.webdriver.support.expected_conditions import visibility_of +from selenium.webdriver.support.wait import WebDriverWait + +from separate_users.tests.utils.selenium_utils import SeleniumTestCase, CustomWebDriver +from separate_users.tests.test_app.models import TestModel, LinkModel + + +class separate_usersEditorTests(SeleniumTestCase): + fixtures = ['test_app.json', ] + username = 'admin' + password = 'admin' + + def setUp(self): + superuser = User.objects.create_superuser(self.username, 'admin@free.fr', self.password) + self.existing = TestModel.objects.get(pk=1) + # Instantiating the WebDriver will load your browser + self.wd = CustomWebDriver() + + def tearDown(self): + self.wd.quit() + + def test_app_index_get(self): + # if this fails, everything is probably broken. + self.login() + self.open(reverse('admin:index')) + self.wd.find_css(".app-test_app") + + def test_editor_has_button_dialog_opens_has_form(self): + self.login() + sleep(1) # must be a better solution! + self.open(reverse('admin:test_app_testmodel_change', args=[self.existing.id])) + sleep(1) # argh + button = self.wd.wait_for_css(".cke_button__djangolink") + button[0].click() + dialog_title = self.wd.wait_for_css(".cke_dialog_title") + sleep(1) # argh + iframe = self.wd.find_css(".cke_dialog_ui_html") + self.wd.switch_to.frame(iframe) + target = self.wd.wait_for_css("#id_target") + + def test_dialog_form_validation(self): + self.login() + sleep(1) # must be a better solution! + self.open(reverse('admin:test_app_testmodel_change', args=[self.existing.id])) + sleep(1) # argh + button = self.wd.wait_for_css(".cke_button__djangolink") + button[0].click() + self.wd.wait_for_css(".cke_dialog_title") + sleep(1) # argh + iframe = self.wd.find_css(".cke_dialog_ui_html") + self.wd.switch_to.frame(iframe) + email = self.wd.wait_for_css("#id_email") + email.send_keys('what-foo') + self.wd.switch_to.default_content() + ok = self.wd.wait_for_css(".cke_dialog_ui_button_ok") + ok.click() + self.wd.switch_to.frame(iframe) + self.wd.wait_for_css(".field-email .errorlist") + email.send_keys('root@example.com') + self.wd.switch_to.default_content() + ok = self.wd.wait_for_css(".cke_dialog_ui_button_ok") + ok.click() + sleep(1) # argh + try: + title = self.wd.find_css(".cke_dialog_title") + self.assertFalse(title.is_displayed()) + except NoSuchElementException: + # ok if removed from the DOM!! + pass + + def test_dialog_submit_and_link_attrs(self): + self.login() + self.open(reverse('admin:test_app_testmodel_change', args=[self.existing.id])) + + def test_remove_foreign_key_attrs(self): + self.login() + self.open(reverse('admin:test_app_testmodel_change', args=[self.existing.id])) \ No newline at end of file diff --git a/separate_users/tests/test_templatetag.py b/separate_users/tests/test_templatetag.py new file mode 100644 index 0000000..75d033b --- /dev/null +++ b/separate_users/tests/test_templatetag.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +from django.core.urlresolvers import reverse +from django.test import Client +from django.test import TestCase + +from separate_users.tests.test_app.models import TestModel, LinkModel + + +class separate_usersDialogTests(TestCase): + fixtures = ['test_app.json', ] + + def setUp(self): + self.test_object = TestModel.objects.get(pk=2) + + def tearDown(self): + pass + + def test_tag_link_target_class_value(self): + """ + does it transform everything as it should? + """ + client = Client() + url = reverse('testmodel_detail', args=[self.test_object.id]) + response = client.get(url) + content = response.content + # check it! + + def test_tag_no_destruction_of_existing_links(self): + """ + normal existing \d+)/$', TestModelDetailView.as_view(), name='testmodel_detail'), +] + +# if settings.DEBUG: +# urlpatterns += [ +# url(r'^media/(?P.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}), +# ] diff --git a/separate_users/tests/utils/__init__.py b/separate_users/tests/utils/__init__.py new file mode 100644 index 0000000..b8c48bd --- /dev/null +++ b/separate_users/tests/utils/__init__.py @@ -0,0 +1 @@ +__author__ = 'benzkji' diff --git a/separate_users/tests/utils/django_utils.py b/separate_users/tests/utils/django_utils.py new file mode 100644 index 0000000..f9a9f8c --- /dev/null +++ b/separate_users/tests/utils/django_utils.py @@ -0,0 +1,8 @@ +from django.contrib.auth.models import User + + +def create_superuser(): + superuser = User.objects.create_superuser('admin', + 'admin@free.fr', + 'secret') + return superuser diff --git a/separate_users/tests/utils/selenium_utils.py b/separate_users/tests/utils/selenium_utils.py new file mode 100644 index 0000000..3eca316 --- /dev/null +++ b/separate_users/tests/utils/selenium_utils.py @@ -0,0 +1,55 @@ +from django.conf import settings +from django.contrib.staticfiles.testing import StaticLiveServerTestCase +from django.core.urlresolvers import reverse +from selenium.common.exceptions import NoSuchElementException +from selenium.webdriver.support.wait import WebDriverWait + + +#determine the WebDriver module. default to Firefox +try: + web_driver_module = settings.SELENIUM_WEBDRIVER +except AttributeError: + from selenium.webdriver.firefox import webdriver as web_driver_module + + +class SeleniumTestCase(StaticLiveServerTestCase): + """ + A base test case for Selenium, providing hepler methods for generating + clients and logging in profiles. + """ + def open(self, url): + self.wd.get("%s%s" % (self.live_server_url, url)) + + def login(self): + self.open(reverse('admin:index')) + # SeleniFIXTURESum knows it has to wait for page loads (except for AJAX requests) + # so we don't need to do anything about that, and can just + # call find_css. Since we can chain methods, we can + # call the built-in send_keys method right away to change the + # value of the field + self.wd.find_css('#id_username').send_keys(self.username) + # for the password, we can now just call find_css since we know the page + # has been rendered + self.wd.find_css("#id_password").send_keys(self.password) + # You're not limited to CSS selectors only, check + # http://seleniumhq.org/docs/03_webdriver.html for + # a more compreehensive documentation. + self.wd.find_element_by_xpath('//input[@type="submit"]').click() + + +class CustomWebDriver(web_driver_module.WebDriver): + """Our own WebDriver with some helpers added""" + + def find_css(self, css_selector): + """Shortcut to find elements by CSS. Returns either a list or singleton""" + elems = self.find_elements_by_css_selector(css_selector) + found = len(elems) + if found == 1: + return elems[0] + elif not elems: + raise NoSuchElementException(css_selector) + return elems + + def wait_for_css(self, css_selector, timeout=7): + """ Shortcut for WebDriverWait""" + return WebDriverWait(self, timeout).until(lambda driver : driver.find_css(css_selector)) \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..e0e6708 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,3 @@ +[flake8] +ignore = F999,E501,E128,E124 +exclude = .git,*/migrations/*,*/static/CACHE/*,*/south_migrations/* diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..51a7c34 --- /dev/null +++ b/setup.py @@ -0,0 +1,39 @@ +# coding: utf-8 +from setuptools import setup, find_packages +import os + +# not so bad: http://joebergantine.com/blog/2015/jul/17/releasing-package-pypi/ +version = __import__('separate_users').__version__ + + +def read(fname): + # read the contents of a text file + return open(os.path.join(os.path.dirname(__file__), fname)).read() + +setup( + name="django-separate-users", + version=version, + url='http://github.com/bnzk/django-separate-users', + license='MIT', + platforms=['OS Independent'], + description="separate staff and non staff users with two proxy models", + long_description=read('README.rst'), + author=u'Ben Stähli', + author_email='bnzk@bnzk.ch', + packages=find_packages(), + install_requires=( + # 'Django>=1.3,<1.5', # no need to limit while in development + 'Django>=1.8', + ), + include_package_data=True, + zip_safe=False, + classifiers=[ + 'Development Status :: 4 - Beta', + 'Framework :: Django', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Internet :: WWW/HTTP', + ], +) diff --git a/test_coverage.sh b/test_coverage.sh new file mode 100755 index 0000000..58bcd3c --- /dev/null +++ b/test_coverage.sh @@ -0,0 +1,2 @@ +coverage run --source='separate_users' ./manage.py test +coverage report diff --git a/test_requirements.txt b/test_requirements.txt new file mode 100644 index 0000000..7602156 --- /dev/null +++ b/test_requirements.txt @@ -0,0 +1,14 @@ +# not required by setup.py.. +tox +coverage +django-coverage +flake8 +factory_boy +mock +selenium + +django==1.9 +django-ckeditor==5.1.1 + +lxml +cssselect \ No newline at end of file diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..70c99f8 --- /dev/null +++ b/tox.ini @@ -0,0 +1,36 @@ + +[tox] +envlist = django18, django19, django110 + +[testenv] +commands = python manage.py test +setenv = + DJANGO_SETTINGS_MODULE=separate_users.tests.settings_test + PYTHONPATH={toxinidir} + +[base] +deps = + coverage + django-coverage + factory_boy + mock + selenium + lxml + cssselect + django-ckeditor==5.1.1 + djangocms-text-ckeditor + +[testenv:django18] +deps = + django>=1.8, <1.9 + {[base]deps} + +[testenv:django19] +deps = + django>=1.9, <1.10 + {[base]deps} + +[testenv:django110] +deps = + django>=1.10, <1.11 + {[base]deps} \ No newline at end of file