Added initial tests

This commit is contained in:
Johannes Hoppe 2015-03-03 10:01:51 +01:00
parent 91dad724fb
commit 18fa453ac0
18 changed files with 3473 additions and 109 deletions

3
.gitignore vendored
View File

@ -14,3 +14,6 @@ docs/_build
.idea/
*.iml
*.iws
env/
venv/
.cache/

48
.travis.yml Normal file
View File

@ -0,0 +1,48 @@
language: python
sudo: false
python:
- "2.6"
- "2.7"
- "3.2"
- "3.3"
- "3.4"
- "pypy"
- "pypy3"
env:
global:
- DISPLAY=:99.0
matrix:
- DJANGO="<1.5,>=1.4"
- DJANGO="<1.7,>=1.6"
- DJANGO="<1.8,>=1.7"
- DJANGO="==1.8rc1"
matrix:
exclude:
- python: "3.2"
env: DJANGO="<1.5,>=1.4"
- python: "3.3"
env: DJANGO="<1.5,>=1.4"
- python: "3.4"
env: DJANGO="<1.5,>=1.4"
- python: "pypy3"
env: DJANGO="<1.5,>=1.4"
- python: "2.6"
env: DJANGO="<1.8,>=1.7"
allow_failures:
- env: DJANGO="==1.8rc1"
- python: "3.2"
- python: "3.3"
- python: "3.4"
- python: "pypy"
- python: "pypy3"
install:
- pip install --upgrade pip
- pip install .
- pip install -r requirements_dev.txt
- pip install Django$DJANGO
- pip install coveralls
- sh -e /etc/init.d/xvfb start
script:
coverage run --source=django_select2 runtests.py
after_success:
coveralls

5
pytest.ini Normal file
View File

@ -0,0 +1,5 @@
[pytest]
norecursedirs=env testapp django_select2 docs
addopts = --tb=short --pep8 --flakes -rxs
pep8ignore=
flakes-ignore=

6
requirements_dev.txt Normal file
View File

@ -0,0 +1,6 @@
pytest
pytest-pep8
pytest-flakes
pytest-django
selenium
model_mommy

3085
runtests.py Executable file

File diff suppressed because it is too large Load Diff

153
setup.py Normal file → Executable file
View File

@ -1,107 +1,19 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import codecs
import os
import sys
from distutils.util import convert_path
from fnmatch import fnmatchcase
from setuptools import setup, find_packages
from setuptools import setup, find_packages, Command
def read(fname):
return codecs.open(os.path.join(os.path.dirname(__file__), fname)).read()
f = codecs.open(os.path.join(os.path.dirname(__file__), fname), 'rb')
return f.read()
# Provided as an attribute, so you can append to these instead
# of replicating them:
standard_exclude = ["*.py", "*.pyc", "*$py.class", "*~", ".*", "*.bak"]
standard_exclude_directories = [
".*", "CVS", "_darcs", "./build", "./dist", "EGG-INFO", "*.egg-info"
]
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
# Note: you may want to copy this into your setup.py file verbatim, as
# you can't import this from another package, when you don't know if
# that package is installed yet.
def find_package_data(
where=".",
package="",
exclude=standard_exclude,
exclude_directories=standard_exclude_directories,
only_in_packages=True,
show_ignored=False):
"""
Return a dictionary suitable for use in ``package_data``
in a distutils ``setup.py`` file.
The dictionary looks like::
{"package": [files]}
Where ``files`` is a list of all the files in that package that
don"t match anything in ``exclude``.
If ``only_in_packages`` is true, then top-level directories that
are not packages won"t be included (but directories under packages
will).
Directories matching any pattern in ``exclude_directories`` will
be ignored; by default directories with leading ``.``, ``CVS``,
and ``_darcs`` will be ignored.
If ``show_ignored`` is true, then all the files that aren"t
included in package data are shown on stderr (for debugging
purposes).
Note patterns use wildcards, or can be exact paths (including
leading ``./``), and all searching is case-insensitive.
"""
out = {}
stack = [(convert_path(where), "", package, only_in_packages)]
while stack:
where, prefix, package, only_in_packages = stack.pop(0)
for name in os.listdir(where):
fn = os.path.join(where, name)
if os.path.isdir(fn):
bad_name = False
for pattern in exclude_directories:
if (fnmatchcase(name, pattern)
or fn.lower() == pattern.lower()):
bad_name = True
if show_ignored:
print >> sys.stderr, (
"Directory %s ignored by pattern %s"
% (fn, pattern))
break
if bad_name:
continue
if (os.path.isfile(os.path.join(fn, "__init__.py"))
and not prefix):
if not package:
new_package = name
else:
new_package = package + "." + name
stack.append((fn, "", new_package, False))
else:
stack.append((fn, prefix + name + "/", package, only_in_packages))
elif package or not only_in_packages:
# is a file
bad_name = False
for pattern in exclude:
if (fnmatchcase(name, pattern)
or fn.lower() == pattern.lower()):
bad_name = True
if show_ignored:
print >> sys.stderr, (
"File %s ignored by pattern %s"
% (fn, pattern))
break
if bad_name:
continue
out.setdefault(package, []).append(prefix+name)
return out
PACKAGE = "django_select2"
NAME = "Django-Select2"
DESCRIPTION = "Select2 option fields for Django"
@ -110,11 +22,14 @@ AUTHOR_EMAIL = "admin@applegrew.com"
URL = "https://github.com/applegrew/django-select2"
VERSION = __import__(PACKAGE).__version__
def getPkgPath():
return __import__(PACKAGE).__path__[0] + '/'
def minify(files, outfile, ftype):
import urllib, json
import urllib
import json
content = u''
for filename in files:
@ -127,7 +42,7 @@ def minify(files, outfile, ftype):
data = urllib.urlencode([
('code', content.encode('utf-8')),
('type', ftype),
])
])
f = urllib.urlopen('http://api.applegrew.com/minify', data)
data = u''
@ -142,11 +57,6 @@ def minify(files, outfile, ftype):
f.close()
data = json.loads(data)
for key in data:
value = data[key]
if isinstance(value, str):
value = value.decode('utf-8')
if data['success']:
with open(getPkgPath() + outfile, 'w') as f:
f.write(data['compiled_code'].encode('utf8'))
@ -155,13 +65,39 @@ def minify(files, outfile, ftype):
print data['error']
raise Exception('Could not minify.')
if len(sys.argv) > 1 and 'sdist' == sys.argv[1]:
minify(['static/js/select2.js'], 'static/js/select2.min.js', 'js')
minify(['static/js/heavy_data.js'], 'static/js/heavy_data.min.js', 'js')
minify(['static/css/select2.css'], 'static/css/select2.min.css', 'css')
minify(['static/css/select2.css', 'static/css/extra.css'], 'static/css/all.min.css', 'css')
minify(['static/css/select2.css', 'static/css/select2-bootstrap.css'], 'static/css/select2-bootstrapped.min.css', 'css')
minify(['static/css/select2.css', 'static/css/extra.css', 'static/css/select2-bootstrap.css'], 'static/css/all-bootstrapped.min.css', 'css')
minify(['static/css/select2.css', 'static/css/extra.css'],
'static/css/all.min.css', 'css')
minify(['static/css/select2.css', 'static/css/select2-bootstrap.css'],
'static/css/select2-bootstrapped.min.css', 'css')
minify(
[
'static/css/select2.css',
'static/css/extra.css',
'static/css/select2-bootstrap.css'
], 'static/css/all-bootstrapped.min.css', 'css')
class PyTest(Command):
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
import sys
import subprocess
errno = subprocess.call([sys.executable, 'runtests.py'])
raise SystemExit(errno)
setup(
name=NAME,
@ -172,9 +108,7 @@ setup(
author_email=AUTHOR_EMAIL,
license="LICENSE.txt",
url=URL,
packages=[PACKAGE, PACKAGE + '.templatetags'],
package_data=find_package_data(),
exclude_package_data={ '': standard_exclude },
packages=find_packages(exclude=['tests']),
include_package_data=True,
classifiers=[
"Development Status :: 5 - Production/Stable",
@ -186,7 +120,8 @@ setup(
"Framework :: Django",
],
install_requires=[
"Django>=1.3",
"Django>=1.4",
],
zip_safe=False,
cmdclass={'test': PyTest},
)

1
tests/__init__.py Normal file
View File

@ -0,0 +1 @@
__author__ = 'johannes'

50
tests/conftest.py Normal file
View File

@ -0,0 +1,50 @@
# -*- coding:utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals
import os
import pytest
from django import conf
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
def pytest_configure():
os.environ[conf.ENVIRONMENT_VARIABLE] = "tests.testapp.settings"
try:
import django
django.setup()
except AttributeError:
pass
from django.test.utils import setup_test_environment
setup_test_environment()
from django.db import connection
connection.creation.create_test_db()
browsers = {
'firefox': webdriver.Firefox,
'chrome': webdriver.Chrome,
}
@pytest.fixture(scope='session',
params=browsers.keys())
def driver(request):
if 'DISPLAY' not in os.environ:
pytest.skip('Test requires display server (export DISPLAY)')
try:
b = browsers[request.param]()
except WebDriverException as e:
pytest.skip(e)
else:
b.set_window_size(1200, 800)
request.addfinalizer(lambda *args: b.quit())
return b

30
tests/test_fields.py Normal file
View File

@ -0,0 +1,30 @@
# -*- coding:utf-8 -*-
from __future__ import print_function, unicode_literals
import pytest
from django.core.urlresolvers import reverse
from model_mommy import mommy
from selenium.common.exceptions import NoSuchElementException
class ViewTestMixin(object):
url = ''
def test_get(self, client):
response = client.get(self.url)
assert response.status_code == 200
@pytest.fixture
def genres(db):
mommy.make('testapp.Genre', _quantity=100)
class TestAutoModelSelect2TagField(object):
url = reverse('single_value_model_field')
def test_no_js_error(self, db, client, live_server, driver, genres):
driver.get(live_server + self.url)
with pytest.raises(NoSuchElementException):
error = driver.find_element_by_xpath('//body[@JSError]')
pytest.fail(error.get_attribute('JSError'))

View File

View File

@ -0,0 +1,53 @@
# -*- coding:utf-8 -*-
from __future__ import absolute_import, unicode_literals
from django import forms
from django_select2.fields import Select2MultipleWidget
from tests.testapp import models
from . import fields
class GenreModelForm(forms.ModelForm):
class Meta:
model = models.Genre
fields = (
'title',
)
class GenreForm(forms.Form):
title = forms.CharField(max_length=50)
class ArtistModelForm(forms.ModelForm):
test = forms.BooleanField('asdf')
class Meta:
model = models.Artist
fields = (
'title',
'genres',
)
widgets = {
'genres': Select2MultipleWidget
}
class ArtistForm(forms.Form):
title = forms.CharField(max_length=50)
genres = fields.GenreTagField()
class AlbumModelForm(forms.ModelForm):
class Meta:
model = models.Album
fields = (
'title',
'artist',
)
class AlbumForm(forms.Form):
title = forms.CharField(max_length=255)
artist = fields.ArtistField()

View File

@ -0,0 +1,15 @@
# -*- coding:utf-8 -*-
from __future__ import absolute_import, unicode_literals
from django_select2.fields import (AutoModelSelect2Field,
AutoModelSelect2TagField)
from tests.testapp import models
class GenreTagField(AutoModelSelect2TagField):
queryset = models.Genre
class ArtistField(AutoModelSelect2Field):
queryset = models.Artist

42
tests/testapp/models.py Normal file
View File

@ -0,0 +1,42 @@
# -*- coding:utf-8 -*-
from __future__ import absolute_import, unicode_literals
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class Genre(models.Model):
title = models.CharField(max_length=50)
def __str__(self):
return self.title
@python_2_unicode_compatible
class Artist(models.Model):
title = models.CharField(max_length=50)
genres = models.ManyToManyField(Genre)
def __str__(self):
return self.title
@python_2_unicode_compatible
class Album(models.Model):
title = models.CharField(max_length=255)
artist = models.ForeignKey(Artist)
def __str__(self):
return self.title
@python_2_unicode_compatible
class Song(models.Model):
title = models.CharField(max_length=255)
album = models.ForeignKey(Album, blank=True, null=True)
artist = models.ForeignKey(Artist)
genres = models.ManyToManyField(Genre, blank=True, null=True)
def __str__(self):
return self.title

43
tests/testapp/settings.py Normal file
View File

@ -0,0 +1,43 @@
import os.path
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
}
}
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.staticfiles',
'django_select2',
'tests.testapp',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
SITE_ID = 1
ROOT_URLCONF = 'tests.testapp.urls'
TEMPLATE_DIRS = (
os.path.join(BASE_DIR, "templates"),
)
SECRET_KEY = '123456'
USE_L10N = True
AUTO_RENDER_SELECT2_STATICS = False

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,21 @@
{% load staticfiles %}
{% load django_select2_tags %}
<!DOCTYPE html>
<html>
<head>
<script src="{% static 'jquery-1.7.2.min.js' %}"></script>
<script type="text/javascript">
window.onerror = function (msg) {
$("body").attr("JSError", msg);
}
</script>
{% import_django_select2_js %}
{% import_django_select2_css %}
</head>
<body>
<form method="post" action="">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit Form"/>
</form>
</body>

15
tests/testapp/urls.py Normal file
View File

@ -0,0 +1,15 @@
# -*- conding:utf-8 -*-
from __future__ import absolute_import, unicode_literals
from django.conf.urls import include, patterns, url
from .forms import ArtistForm
from .views import TemplateFormView
urlpatterns = patterns(
'',
url(r'single_value_model_field',
TemplateFormView.as_view(form_class=ArtistForm), name='single_value_model_field'),
url(r'^select2/', include('django_select2.urls')),
)

8
tests/testapp/views.py Normal file
View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.views.generic import FormView
class TemplateFormView(FormView):
template_name = 'form.html'