Skip to content

Commit

Permalink
Adds selenium and qunit integration into Django test suite.
Browse files Browse the repository at this point in the history
Implements blueprint frontend-testing.
Implements blueprint javascript-unit-tests.

Adds selenium to buildout script and uses django-nose-selenium to integrate with Django's unit test machinery. Includes proof-of-implementation tests with both selenium and qunit.

Change-Id: Ic7db4994be398c633a78dca7369359602c7d8f57
  • Loading branch information
gabrielhurley committed Nov 9, 2011
1 parent 67a979a commit 2532d25
Show file tree
Hide file tree
Showing 15 changed files with 1,936 additions and 8 deletions.
3 changes: 2 additions & 1 deletion .gitignore
@@ -1,5 +1,6 @@
*.pyc
*.swp
.selenium_log
.coverage
coverage.xml
pep8.txt
Expand All @@ -20,5 +21,5 @@ django-nova-syspanel/src/django_nova_syspanel.egg-info
openstack-dashboard/.dashboard-venv
openstack-dashboard/local/dashboard_openstack.sqlite3
openstack-dashboard/local/local_settings.py
build/
docs/build/
docs/source/sourcecode
10 changes: 8 additions & 2 deletions docs/source/ref/run_tests.rst
Expand Up @@ -28,12 +28,18 @@ environments will be necessary but not necessarily as time consuming.
I just want to run the tests!
=============================

Running both sets of unit tests quickly and easily is the main goal of this
Running the full set of unit tests quickly and easily is the main goal of this
script. All you need to do is::

./run_tests.sh

Yep, that's it. Everything else the script can do is optional.
Yep, that's it. However, for a quicker test run you can skip the Selenium
tests by using the ``--skip-selenium`` flag::

./run_tests.sh --skip-selenium

This isn't recommended, but can be a timesaver when you only need to run
the code tests and not the frontend tests during development.

Give me metrics!
================
Expand Down
7 changes: 7 additions & 0 deletions horizon/buildout.cfg
Expand Up @@ -6,6 +6,7 @@ parts =
openstackx
python-novaclient
python-keystoneclient
seleniumrc
develop = .
versions = versions

Expand Down Expand Up @@ -33,6 +34,8 @@ eggs =
coverage
glance
quantum
django-nose-selenium
CherryPy
interpreter = python


Expand Down Expand Up @@ -124,3 +127,7 @@ urls =
#recipe = bazaarrecipe
#urls =
# https://launchpad.net/~hudson-openstack/glance/trunk/ glance


[seleniumrc]
recipe=collective.recipe.seleniumrc
3 changes: 2 additions & 1 deletion horizon/horizon/templatetags/horizon.py
Expand Up @@ -43,6 +43,7 @@ def horizon_main_nav(context):
""" Generates top-level dashboard navigation entries. """
if 'request' not in context:
return {}
current_dashboard = context['request'].horizon.get('dashboard', None)
dashboards = []
for dash in Horizon.get_dashboards():
if callable(dash.nav) and dash.nav(context):
Expand All @@ -51,7 +52,7 @@ def horizon_main_nav(context):
dashboards.append(dash)
return {'components': dashboards,
'user': context['request'].user,
'current': context['request'].horizon['dashboard'].slug}
'current': getattr(current_dashboard, 'slug', None)}


@register.inclusion_tag('horizon/_subnav_list.html', takes_context=True)
Expand Down
6 changes: 5 additions & 1 deletion horizon/horizon/tests/testsettings.py
Expand Up @@ -26,11 +26,13 @@
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': '/tmp/horizon.db'}}
'NAME': '/tmp/horizon.db',
'TEST_NAME': '/tmp/test_horizon.db',}}

INSTALLED_APPS = (
'django.contrib.sessions',
'django.contrib.messages',
'django_nose',
'horizon',
'horizon.tests',
'horizon.dashboards.nova',
Expand Down Expand Up @@ -80,6 +82,8 @@
NOSE_ARGS = ['--nocapture',
'--cover-package=horizon',
'--cover-inclusive']
# For nose-selenium integration
LIVE_SERVER_PORT = 8000

# django-mailer uses a different config attribute
# even though it just wraps django.core.mail
Expand Down
4 changes: 3 additions & 1 deletion openstack-dashboard/dashboard/settings.py
Expand Up @@ -86,6 +86,7 @@
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_nose',
'horizon',
'horizon.dashboards.nova',
'horizon.dashboards.syspanel',
Expand Down Expand Up @@ -137,4 +138,5 @@
MIDDLEWARE_CLASSES += (
'debug_toolbar.middleware.DebugToolbarMiddleware',)
except ImportError:
logging.info('Running in debug mode without debug_toolbar.')
_logger = logging.getLogger(__name__)
_logger.debug('Running in debug mode without debug_toolbar.')
226 changes: 226 additions & 0 deletions openstack-dashboard/dashboard/static/qunit/qunit.css
@@ -0,0 +1,226 @@
/**
* QUnit 1.2.0pre - A JavaScript Unit Testing Framework
*
* http://docs.jquery.com/QUnit
*
* Copyright (c) 2011 John Resig, Jörn Zaefferer
* Dual licensed under the MIT (MIT-LICENSE.txt)
* or GPL (GPL-LICENSE.txt) licenses.
*/

/** Font Family and Sizes */

#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}

#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }


/** Resets */

#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
margin: 0;
padding: 0;
}


/** Header */

#qunit-header {
padding: 0.5em 0 0.5em 1em;

color: #8699a4;
background-color: #0d3349;

font-size: 1.5em;
line-height: 1em;
font-weight: normal;

border-radius: 15px 15px 0 0;
-moz-border-radius: 15px 15px 0 0;
-webkit-border-top-right-radius: 15px;
-webkit-border-top-left-radius: 15px;
}

#qunit-header a {
text-decoration: none;
color: #c2ccd1;
}

#qunit-header a:hover,
#qunit-header a:focus {
color: #fff;
}

#qunit-banner {
height: 5px;
}

#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
background-color: #eee;
}

#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
background-color: #2b81af;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}


/** Tests: Pass/Fail */

#qunit-tests {
list-style-position: inside;
}

#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
border-bottom: 1px solid #fff;
list-style-position: inside;
}

#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}

#qunit-tests li strong {
cursor: pointer;
}

#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}

#qunit-tests ol {
margin-top: 0.5em;
padding: 0.5em;

background-color: #fff;

border-radius: 15px;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;

box-shadow: inset 0px 2px 13px #999;
-moz-box-shadow: inset 0px 2px 13px #999;
-webkit-box-shadow: inset 0px 2px 13px #999;
}

#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
}

#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 .5em 0 0;
}

#qunit-tests td {
vertical-align: top;
}

#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}

#qunit-tests del {
background-color: #e0f2be;
color: #374e0c;
text-decoration: none;
}

#qunit-tests ins {
background-color: #ffcaca;
color: #500;
text-decoration: none;
}

/*** Test Counts */

#qunit-tests b.counts { color: black; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }

#qunit-tests li li {
margin: 0.5em;
padding: 0.4em 0.5em 0.4em 0.5em;
background-color: #fff;
border-bottom: none;
list-style-position: inside;
}

/*** Passing Styles */

#qunit-tests li li.pass {
color: #5E740B;
background-color: #fff;
border-left: 26px solid #C6E746;
}

#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }

#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }

#qunit-banner.qunit-pass { background-color: #C6E746; }

/*** Failing Styles */

#qunit-tests li li.fail {
color: #710909;
background-color: #fff;
border-left: 26px solid #EE5757;
white-space: pre;
}

#qunit-tests > li:last-child {
border-radius: 0 0 15px 15px;
-moz-border-radius: 0 0 15px 15px;
-webkit-border-bottom-right-radius: 15px;
-webkit-border-bottom-left-radius: 15px;
}

#qunit-tests .fail { color: #000000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000000; }

#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: green; }

#qunit-banner.qunit-fail { background-color: #EE5757; }


/** Result */

#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;

color: #2b81af;
background-color: #D2E0E6;

border-bottom: 1px solid white;
}

/** Fixture */

#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
}

1 comment on commit 2532d25

@neiljohnston
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great that Selenium is being included for testing. The documentation needs to be updated to provide instructions for the usage of Selenium within the horizon dev environment and maybe by ./run_tests.sh. Currently ./run_tests.sh is simply hanging with the message: horizon/bin/seleniumrc: No such file or directory
......................

Being a newcomer to all this, some guidance to meeting this dependency is needed.

Please sign in to comment.