Skip to content

Commit c79db31

Browse files
committed
Add selenium test for admin list page
Part of #30
1 parent 063e78d commit c79db31

16 files changed

+224
-1
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ help:
99
test:
1010
@coverage run orderable/tests/run.py
1111
@coverage report -m
12+
@bdd/manage.py behave
1213
@flake8
1314

1415
release:

bdd/bdd/__init__.py

Whitespace-only changes.

bdd/bdd/admin.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from django.contrib import admin
2+
3+
from orderable.admin import OrderableAdmin
4+
from .models import Item
5+
6+
7+
admin.site.register(Item, OrderableAdmin)

bdd/bdd/migrations/0001_initial.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Generated by Django 2.1.2 on 2018-10-26 21:17
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
initial = True
9+
10+
dependencies = [
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name='Item',
16+
fields=[
17+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18+
('sort_order', models.IntegerField(blank=True, db_index=True)),
19+
],
20+
options={
21+
'ordering': ['sort_order'],
22+
'abstract': False,
23+
},
24+
),
25+
]

bdd/bdd/migrations/__init__.py

Whitespace-only changes.

bdd/bdd/models.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from orderable.models import Orderable
2+
3+
4+
class Item(Orderable):
5+
pass

bdd/bdd/settings.py

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import os
2+
3+
4+
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
5+
6+
SECRET_KEY = 'r+n-oywnjf7&b*#(!@zx-wa4j=4_yy7a%j-lep&q8nx6^=lwf5'
7+
ROOT_URLCONF = 'bdd.urls'
8+
STATIC_URL = '/static/'
9+
DATABASES = {'default': {
10+
'ENGINE': 'django.db.backends.postgresql_psycopg2',
11+
'NAME': 'orderable',
12+
'HOST': 'localhost'
13+
}}
14+
15+
INSTALLED_APPS = [
16+
# Project.
17+
'bdd',
18+
19+
# 3rd party.
20+
'behave_django',
21+
'orderable',
22+
23+
# Django.
24+
'django.contrib.admin',
25+
'django.contrib.auth',
26+
'django.contrib.contenttypes',
27+
'django.contrib.sessions',
28+
'django.contrib.messages',
29+
'django.contrib.staticfiles',
30+
]
31+
32+
MIDDLEWARE = [
33+
'django.middleware.security.SecurityMiddleware',
34+
'django.contrib.sessions.middleware.SessionMiddleware',
35+
'django.middleware.common.CommonMiddleware',
36+
'django.middleware.csrf.CsrfViewMiddleware',
37+
'django.contrib.auth.middleware.AuthenticationMiddleware',
38+
'django.contrib.messages.middleware.MessageMiddleware',
39+
'django.middleware.clickjacking.XFrameOptionsMiddleware',
40+
]
41+
42+
43+
TEMPLATES = [
44+
{
45+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
46+
'DIRS': [],
47+
'APP_DIRS': True,
48+
'OPTIONS': {
49+
'context_processors': [
50+
'django.template.context_processors.debug',
51+
'django.template.context_processors.request',
52+
'django.contrib.auth.context_processors.auth',
53+
'django.contrib.messages.context_processors.messages',
54+
],
55+
},
56+
},
57+
]

bdd/bdd/urls.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from django.conf.urls import url
2+
from django.contrib import admin
3+
4+
5+
urlpatterns = [
6+
url('^admin/', admin.site.urls),
7+
]

bdd/manage.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env python
2+
import os
3+
import sys
4+
5+
if __name__ == '__main__':
6+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'bdd.settings')
7+
try:
8+
from django.core.management import execute_from_command_line
9+
except ImportError:
10+
raise ImportError(
11+
"Couldn't import Django. Are you sure it's installed and "
12+
"available on your PYTHONPATH environment variable? Did you "
13+
"forget to activate a virtual environment?"
14+
)
15+
execute_from_command_line(sys.argv)

features/browser.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from selenium import webdriver
2+
3+
4+
class Browser(object):
5+
driver = webdriver.Chrome()
6+
driver.implicitly_wait(5)
7+
8+
def close(context):
9+
context.driver.close()

features/environment.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from .browser import Browser
2+
from .pages import ItemListPage
3+
4+
5+
def before_all(context):
6+
context.browser = Browser()
7+
context.item_list_page = ItemListPage()
8+
9+
10+
def after_all(context):
11+
context.browser.close()

features/order-list.feature

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Feature: Ordering on the list page
2+
3+
Scenario: Move an item to the end of the list
4+
Given the following items:
5+
| pk |
6+
| 1 |
7+
| 2 |
8+
| 3 |
9+
And we are on the item list page
10+
When item 1 is moved to position 3
11+
Then the items should be ordered thus:
12+
| pk |
13+
| 2 |
14+
| 3 |
15+
| 1 |

features/pages.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from browser import Browser
2+
from selenium.webdriver.common.action_chains import ActionChains
3+
4+
5+
class ItemListPage(Browser):
6+
def move_item(self, source, destination):
7+
8+
template = '#neworder-{} .ui-sortable-handle'
9+
find = self.driver.find_element_by_css_selector
10+
offset = 2 if destination > source else -2
11+
(
12+
ActionChains(self.driver)
13+
.click_and_hold(find(template.format(source)))
14+
.move_to_element(find(template.format(destination)))
15+
.move_by_offset(0, offset)
16+
.release()
17+
.perform()
18+
)
19+
20+
def open(self, context):
21+
url = context.get_url('admin:bdd_item_changelist')
22+
self.driver.get(url)

features/steps/steps.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import time
2+
3+
from behave import given, then, when
4+
from django.contrib.auth.models import User
5+
from seleniumlogin import force_login
6+
7+
from bdd.models import Item
8+
9+
10+
@given(u'the following items')
11+
def set_up_items(context):
12+
Item.objects.bulk_create([
13+
Item(pk=row['pk'], sort_order=i)
14+
for i, row
15+
in enumerate(context.table)
16+
])
17+
18+
19+
@given(u'we are on the item list page')
20+
def go_to_admin_page(context):
21+
user = User.objects.create_superuser(
22+
23+
password='password',
24+
username='myuser',
25+
)
26+
force_login(user, context.browser.driver, context.test.live_server_url)
27+
context.item_list_page.open(context)
28+
29+
30+
@when(u'item {initial_position:d} is moved to position {new_position:d}')
31+
def move_items(context, initial_position, new_position):
32+
context.item_list_page.move_item(initial_position, new_position)
33+
time.sleep(.1)
34+
35+
36+
@then(u'the items should be ordered thus')
37+
def check_item_order(context):
38+
items = list(Item.objects.values_list('pk', flat=True))
39+
expected = []
40+
for row in context.table:
41+
expected.append(int(row['pk']))
42+
43+
assert items == expected, (items, expected)

requirements.txt

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
behave==1.2.6
2+
behave_django==1.1.0
13
coverage==3.7.1
4+
django-selenium-login==1.0.2
25
flake8==3.6.0
36
flake8-import-order==0.18
47
hypothesis==2.0.0
58
psycopg2==2.7.4
9+
selenium==3.14.1

setup.cfg

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
[wheel]
22
universal = 1
33
[flake8]
4-
application-import-names = orderable
4+
application-import-names = orderable, bdd
5+
exclude =
6+
bdd/bdd/migrations
57
import-order-style = google
68
max-complexity = 10
79
max-line-length = 90

0 commit comments

Comments
 (0)