Write clean Selenium tests in Django
Project description
django-selenium-test
Write Selenium tests on Django 3.2, Django 4.0, Django 3.1 and Python 3.8+. Based on django-selenium-clean.
This documentation is currently a work-in-progress.
Tutorial
Installation
In your virtualenv:
pip install django-selenium-test
Setting up
- Create a new django project and app:
django-admin startproject foo
cd foo
python manage.py startapp bar
-
In
foo/settings.py, add'bar'toINSTALLED_APPS -
In
foo/urls.py, addfrom bar.views import SimpleViewto the top, and addurl(r'^$', SimpleView.as_view())tourlpatterns. -
Add the SimpleView to
bar/views.py:
import textwrap
from django.http import HttpResponse
from django.views.generic.base import View
class SimpleView(View):
def dispatch(request, *args, **kwargs):
response_text = textwrap.dedent('''\
<html>
<head>
<title>Greetings to the world</title>
</head>
<body>
<h1 id="earth">Greetings to earth</h1>
<h1 id="world" style="display: none;">Hello, world!</h1>
<p>We have some javascript here so that when you click the button
the heading above toggles between "Greetings to earth" and
"Hello, world!".</p>
<button onclick="toggle()">Toggle</button>
<script type="text/javascript">
toggle = function () {
var heading_earth = document.getElementById("earth");
var heading_world = document.getElementById("world");
if (heading_earth.style.display == 'none') {
heading_world.style.display = 'none';
heading_earth.style.display = 'block';
} else {
heading_earth.style.display = 'none';
heading_world.style.display = 'block';
}
}
</script>
</body>
</html>
''')
return HttpResponse(response_text)
We're done setting up. If you now run python manage.py runserver
in your browser and visit http://localhost:8000/ in your browser, you
should see the simple page. Let's now proceed to write a test for it.
Writing the test
Modify bar/tests.py so that it has the following contents:
from unittest import skipUnless
from django.conf import settings
from django_selenium_test import selenium, SeleniumTestCase, PageElement
from selenium.webdriver.common.by import By
@skipUnless(getattr(settings, 'SELENIUM_WEBDRIVERS', False),
"Selenium is unconfigured")
class HelloTestCase(SeleniumTestCase):
heading_earth = PageElement(By.ID, 'earth')
heading_world = PageElement(By.ID, 'world')
button = PageElement(By.CSS_SELECTOR, 'button')
def test_toggle(self):
# Visit the page
self.selenium.get(self.live_server_url)
# Check that the earth heading is visible
self.assertTrue(self.heading_earth.is_displayed())
self.assertFalse(self.heading_world.is_displayed())
# Toggle and check the new condition
self.button.click()
self.heading_world.wait_until_is_displayed()
self.assertFalse(self.heading_earth.is_displayed())
self.assertTrue(self.heading_world.is_displayed())
# Toggle again and re-check
self.button.click()
self.heading_earth.wait_until_is_displayed()
self.assertTrue(self.heading_earth.is_displayed())
self.assertFalse(self.heading_world.is_displayed())
Executing the test
Try python manage.py test and it will skip the test because
selenium is unconfigured. You need to configure it by specifying
SELENIUM_WEBDRIVERS in foo/settings.py:
from django_selenium_test.settings import make_chrome_driver
SELENIUM_WEBDRIVERS = {
'default': make_chrome_driver([], {}),
}
Now try again, and it should execute the test.
Advanced test running tricks
Executing a test in many widths
Add this to your foo/settings.py:
SELENIUM_WIDTHS = [1024, 800, 350]
This will result in executing all SeleniumTestCase's three times,
one for each specified browser width. Useful for responsive designs.
The default is to run them on only one width, 1024.
Using many selenium drivers
You can have many SELENIUM_WEBDRIVERS:
from django_selenium_test.settings import make_chrome_driver, make_firefox_driver
SELENIUM_WEBDRIVERS = {
'default': make_chrome_driver([], {})
'firefox': make_firefox_driver([], {})
}
By default, the default one is used. You can specify another using
the SELENIUM_WEBDRIVER environment variable:
SELENIUM_WEBDRIVER=firefox python manage.py test
Running a headless browser
It can be very useful to run the selenium tests with a headless browser, that is, in an invisible browser window. For one thing, it is much faster.
To achieve this, pass headless=True to the make_BRAND_driver() function:
from django_selenium_test.settings import make_chrome_driver, make_firefox_driver
SELENIUM_WEBDRIVERS = {
'default': make_chrome_driver([], {}, headless=True)
'firefox': make_firefox_driver([], {}, headless=True)
}
Using advanced integration tests
(Currently undocumented)
Reference
SeleniumTestCase objects
.. code:: python
from django_selenium_test import SeleniumTestCase
SeleniumTestCase is the same as Django's
StaticLiveServerTestCase but it adds a little bit of Selenium
functionality. Derive your Selenium tests from this class instead of
StaticLiveServerTestCase.
The most important feature of SeleniumTestCase is the selenium
attribute. Technically it is a wrapper around the selenium driver. In
practice, you can think about it as the browser, or as the equivalent
of Django's test client. It has all selenium driver attributes and methods_, but you will mostly use get(). It also has the
following additional methods:
-
self.selenium.login(**credentials),self.selenium.force_login(user, base_url),self.selenium.logout()Similar to the Django test client
login(),force_login()andlogout()methods.login()returnsTrueif login is possible;Falseif the provided credentials are incorrect, or the user is inactive, or if the sessions framework is not available.The
force_login()code was adapted from django-selenium-login, which is licensed under the MIT License. -
self.selenium.wait_until_n_windows(n, timeout=2)Useful when a Javascript action has caused the browser to open another window. The typical usage is this:
button_that_will_open_a_second_window.click()
self.selenium.wait_until_n_windows(n=2, timeout=10)
windows = self.selenium.window_handles
self.selenium.switch_to.window(windows[1])
# continue testing
If the timeout (in seconds) elapses and the number of browser
windows never becomes n, an AssertionError is raised.
PageElement objects
from django_selenium_test import PageElement
PageElement is a lazy wrapper around WebElement_; it has all its
properties and methods. It is initialized with a locator_, but the
element is not actually located until needed. In addition to
WebElement_ properties and methods, it has these:
-
PageElement.exists(): Returns True if the element can be located. -
PageElement.wait_until_exists(timeout=10)PageElement.wait_until_not_exists(timeout=10)PageElement.wait_until_is_displayed(timeout=10)PageElement.wait_until_not_displayed(timeout=10)PageElement.wait_until_contains(text, timeout=10)PageElement.wait_until_not_contains(text, timeout=10)What these methods do should be self-explanatory from their name. The ones ending in
containsrefer to whether the element contains the specified text. The methods raise an exception if there is a timeout.
IntegrationTest objects
(Currently undocumented)
Running django-selenium-test's own unit tests
By default the unit tests will use Chrome::
./setup.py test
Use the SELENIUM_BROWSER environment variable to use another browser:
SELENIUM_BROWSER=firefox ./setup.py test
License
Licensed under the BSD 3-clause license; see LICENSE.txt for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django-selenium-test-2.0.0.tar.gz.
File metadata
- Download URL: django-selenium-test-2.0.0.tar.gz
- Upload date:
- Size: 21.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55ea1fdfe969017ef914d4651184898cc2eafd3e75f02ea596267683c0df1de9
|
|
| MD5 |
28c13e1547e781dec37043270d643cf2
|
|
| BLAKE2b-256 |
c38ad0ff05b6b6a2c3db989efb282a321690697c66998687607743406bea022c
|
File details
Details for the file django_selenium_test-2.0.0-py3-none-any.whl.
File metadata
- Download URL: django_selenium_test-2.0.0-py3-none-any.whl
- Upload date:
- Size: 21.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
866fda0b0868dc54df76d2842f86a42397ee9baed3ca6524818b1be6dc66aad4
|
|
| MD5 |
1c81da708e545c057cffeea57d2e0583
|
|
| BLAKE2b-256 |
17ac6f551cde4a2d9bdcf4c119a2cad2b8a3d3f2102d49b5a31f2cd61fe219a4
|