Skip to content

Commit

Permalink
NEW: Selenium helper to access window.localStorage
Browse files Browse the repository at this point in the history
  • Loading branch information
jedie committed Dec 11, 2018
1 parent 3fc0598 commit feda06d
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.creole
Expand Up @@ -709,6 +709,7 @@ Using the old place {{{django_tools.unittest_utils.selenium_utils}}} still works
* *dev* - [[https://github.com/jedie/django-tools/compare/v0.42.4...master|compare v0.42.4...master]]
** Refactor selenium helpers
** Split selenium test cases: with and without Django StaticLiveServerTestCase
** NEW: Selenium helper to access {{{ window.localStorage }}}
* v0.42.4 - 12.10.2018 - [[https://github.com/jedie/django-tools/compare/v0.42.3...v0.42.4|compare v0.42.3...v0.42.4]]
** Add {{{request}}} object to {{{TestUserMixin.login()}}} (needed for e.g.: django-axes auth backend)
* v0.42.3 - 10.10.2018 - [[https://github.com/jedie/django-tools/compare/v0.42.2...v0.42.3|compare v0.42.2...v0.42.3]]
Expand Down
69 changes: 69 additions & 0 deletions django_tools/selenium/base.py
Expand Up @@ -4,6 +4,7 @@
:license: GNU GPL v3 or above, see LICENSE for more details.
"""
import logging
import pprint
import sys
import traceback
import unittest
Expand All @@ -19,7 +20,70 @@
log = logging.getLogger(__name__)


class LocalStorage:
"""
https://developer.mozilla.org/de/docs/Web/API/Window/localStorage
Note:
* Access "window.localStorage" works only *after* a request.
* There's no type conversion!
Otherwise it ends in:
selenium.common.exceptions.WebDriverException:
Message: move target out of bounds:
Failed to read the 'localStorage' property from 'Window': Storage is disabled inside 'data:' URLs.
"""

def __init__(self, driver):
self.driver = driver

def items(self):
return self.driver.execute_script(
"var ls = window.localStorage, items = {}; "
"for (var i = 0, k; i < ls.length; ++i) "
" items[k = ls.key(i)] = ls.getItem(k); "
"return items; "
)

def keys(self):
return self.driver.execute_script(
"var ls = window.localStorage, keys = []; "
"for (var i = 0; i < ls.length; ++i) "
" keys[i] = ls.key(i); "
"return keys; "
)

def clear(self):
self.driver.execute_script("window.localStorage.clear();")

def __len__(self):
return self.driver.execute_script("return window.localStorage.length;")

def __getitem__(self, key):
value = self.driver.execute_script("return window.localStorage.getItem(arguments[0]);", key)
if value is None:
raise KeyError(key)
return value

def __setitem__(self, key, value):
self.driver.execute_script("window.localStorage.setItem(arguments[0], arguments[1]);", key, value)

def __contains__(self, key):
return key in self.keys()

def __repr__(self):
return self.items().__str__()


class SeleniumBaseTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()

if cls.driver is not None:
cls.local_storage = LocalStorage(cls.driver)

@classmethod
def tearDownClass(cls):
if cls.driver is not None:
Expand Down Expand Up @@ -152,3 +216,8 @@ def assert_clickable_by_xpath(self, xpath, timeout=10):
timeout=timeout,
msg="Wait for '%s' to be clickable. (timeout: %i)" % (xpath, timeout),
)

def assert_local_storage_key_value(self, *, key, value):
print("local_storage:", pprint.pformat(self.local_storage))
is_value = self.local_storage[key]
self.assertEqual(value, is_value)
3 changes: 2 additions & 1 deletion django_tools/selenium/chromedriver.py
Expand Up @@ -50,7 +50,6 @@ def test_admin_login_page(self):

@classmethod
def setUpClass(cls):
super().setUpClass()

chrome_options = webdriver.ChromeOptions()
for argument in cls.options:
Expand All @@ -72,6 +71,8 @@ def setUpClass(cls):
)
cls.driver.implicitly_wait(10)

super().setUpClass()

def get_browser_log(self):
assert "browser" in self.driver.log_types
browser_log = self.driver.get_log("browser")
Expand Down
4 changes: 2 additions & 2 deletions django_tools/selenium/geckodriver.py
Expand Up @@ -50,8 +50,6 @@ def test_admin_login_page(self):

@classmethod
def setUpClass(cls):
super().setUpClass()

options = webdriver.FirefoxOptions()
for argument in cls.options:
options.add_argument(argument)
Expand All @@ -72,6 +70,8 @@ def setUpClass(cls):
)
cls.driver.implicitly_wait(10)

super().setUpClass()


def firefox_available(filename=None):
"""
Expand Down
28 changes: 28 additions & 0 deletions django_tools_tests/test_unittest_selenium.py
Expand Up @@ -15,6 +15,7 @@
from selenium.common.exceptions import NoSuchElementException

# https://github.com/jedie/django-tools
from django_tools.selenium.base import SeleniumBaseTestCase
from django_tools.selenium.chromedriver import SeleniumChromiumTestCase, chromium_available
from django_tools.selenium.django import (
SeleniumChromiumStaticLiveServerTestCase, SeleniumFirefoxStaticLiveServerTestCase
Expand Down Expand Up @@ -126,6 +127,33 @@ def test_admin_static_files(self):
self.assert_in_page_source("margin: 0;")
self.assert_in_page_source("padding: 0;")

def test_local_storage_access(self):
self.driver.get(self.live_server_url + "/")

self.assertEqual(len(self.local_storage), 0)

with self.assertRaises(KeyError) as cm:
self.assert_local_storage_key_value(key="foo", value="bar")
self.assertEqual(cm.exception.args[0], "foo")

self.local_storage["bar"] = "foo"
self.assertEqual(len(self.local_storage), 1)
self.assert_local_storage_key_value(key="bar", value="foo")

self.assertIn("bar", self.local_storage)

self.assertEqual(repr(self.local_storage), "{'bar': 'foo'}")

# There's no type conversion!
self.local_storage["one"] = 1
self.local_storage["t"] = True
self.local_storage["f"] = False

self.assertEqual(self.local_storage.items(), {"bar": "foo", "f": "false", "t": "true", "one": "1"})
self.local_storage.clear()

self.assertEqual(self.local_storage.items(), {})


@override_settings(DEBUG=True)
@unittest.skipUnless(chromium_available(), "Skip because Chromium is not available!")
Expand Down

0 comments on commit feda06d

Please sign in to comment.