diff --git a/.gitignore b/.gitignore
index 2031b28e2eb023cebe696bd923e866bb37e1c495..c7a8b228c014dfa2d29d6c6b07486fc976547e0f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,6 +48,9 @@ pip-delete-this-directory.txt
 # Ignore compiled translations catalogs.
 messages.mo
 
+# Ignore test results.
+nose2-junit.xml
+
 # Ignore precompiled files for PLY.
 parser.out
 parsetab.py
diff --git a/Makefile b/Makefile
index 3af8ba76c08794c872087a35229dd78e5a9dfabc..8cca7ee69496b1a43c4bceef584a6edeb5c10267 100644
--- a/Makefile
+++ b/Makefile
@@ -606,7 +606,7 @@ pylint: FORCE
 test: FORCE
 	@echo "\n$(GREEN)*** Checking code with nosetests ***$(NC)\n"
 	@echo "Python version: `$(PYTHON) --version`"
-	APP_ROOT_PATH=$(shell realpath ./chroot) PYTHONPATH=$(DIR_LIB) $(NOSETESTS)
+	APP_ROOT_PATH=$(shell realpath ./chroot) PYTHONPATH=$(DIR_LIB) $(PYTHON) -W always::DeprecationWarning -m nose2
 
 coverage: FORCE
 	@echo "\n$(GREEN)*** Checking test code coverage with nosetests and coverage ***$(NC)\n"
diff --git a/conf/requirements-dev.pip b/conf/requirements-dev.pip
index b24db6d29c90f2df3103c3740ace0deb110c3cf5..70218ab2df9c86e2a745bae67e35ee130d9595c4 100644
--- a/conf/requirements-dev.pip
+++ b/conf/requirements-dev.pip
@@ -1,6 +1,6 @@
 setuptools==46.1.3
 wheel==0.34.2
-nose==1.3.7
+nose2==0.11.0
 coverage==5.0.4
 pyflakes==2.1.1
 pylint==2.4.4
diff --git a/conf/requirements-latest-dev.pip b/conf/requirements-latest-dev.pip
index a285ea718a457f37cef335ef3a58c057784942a1..10579462e876f224e06459a2e85f901969c35686 100644
--- a/conf/requirements-latest-dev.pip
+++ b/conf/requirements-latest-dev.pip
@@ -1,6 +1,6 @@
 setuptools
 wheel
-nose
+nose2
 coverage
 pyflakes
 pylint
diff --git a/conf/requirements.pip b/conf/requirements.pip
index 35a3cd7a2e943fa84bc3a19e32cdb6a47b002a8b..c892eb72eff9358f8509033f636ddad022bc35bc 100644
--- a/conf/requirements.pip
+++ b/conf/requirements.pip
@@ -4,36 +4,37 @@ ply==3.11
 psycopg2==2.8.4
 babel==2.8.0
 wtforms==2.2.1
+wtforms_sqlalchemy>=0.3,<1.0
 sqlalchemy==1.3.15
 alembic==1.4.2
 jinja2==3.0.3
 blinker==1.4
 bsddb3==6.2.7
-werkzeug==2.0.2
-flask==1.1.1
-flask-login==0.5.0
-flask-mail==0.9.1
-flask-migrate==2.5.3
-flask-babel==1.0.0
-flask-principal==0.4.0
-flask-wtf==0.14.3
-flask-script==2.0.6
-flask-sqlalchemy==2.4.1
-flask-debugtoolbar==0.11.0
-flask-jsglue==0.3.1
+werkzeug>=2.2.0,<3.0.0
+flask>=2.1.3,<3.0.0
+flask-login>=0.6.1,<1.0.0
+flask-mail>=0.9.1,<1.0.0
+flask-migrate>=3.1.0,<4.0.0
+flask-babel>=2.0.0,<3.0.0
+flask-principal>=0.4.0,<1.0.0
+flask-wtf>=1.0.1,<2.0.0
+flask-script>=2.0.6,<3.0.0
+flask-sqlalchemy>=2.5.1,<3.0.0
+flask-debugtoolbar>=0.13.1,<1.0.0
+flask-jsglue>=0.3.1,<1.0.0
 dnspython==1.16.0
 geoip2==3.0.0
 maxminddb==1.5.2
 requests==2.23.0
 rrdtool==0.1.15
 pyyaml==5.3.1
-pydgets==0.9
-pyzenkit==0.64
-pynspect==0.20
-ipranges==0.1.10
-typedcols==0.1.13
-idea-format==0.1.11
+pydgets>=0.9,<1.0
+pyzenkit>=0.61,<1.0
+pynspect>=0.20,<1.0
+ipranges>=0.1.10,<1.0.0
+typedcols>=0.1.13,<1.0.0
+idea-format>=0.1.11,<1.0.0
 python-dateutil==2.8.1
 PyBabel-json-md==0.1.0
-itsdangerous==2.0.1
+itsdangerous>=2.1.2,<3.0.0
 
diff --git a/lib/hawat/blueprints/auth/test/__init__.py b/lib/hawat/blueprints/auth/test/__init__.py
index d1ca73f643293660969671e72f10bf562134ee4a..b5009468c99452d2661e9a5efce7c1d9010c51d0 100644
--- a/lib/hawat/blueprints/auth/test/__init__.py
+++ b/lib/hawat/blueprints/auth/test/__init__.py
@@ -15,16 +15,12 @@ Unit tests for :py:mod:`hawat.blueprints.auth`.
 __author__ = "Jan Mach <jan.mach@cesnet.cz>"
 __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>"
 
-import sys
 import unittest
 
 from hawat.test import HawatTestCase
 from hawat.test.runner import TestRunnerMixin
 
-_IS_NOSE = sys.argv[0].endswith('nosetests')
 
-
-@unittest.skipIf(_IS_NOSE, "broken under nosetest")
 class AuthTestCase(TestRunnerMixin, HawatTestCase):
     """
     Class for testing :py:mod:`hawat.blueprints.auth` blueprint.
diff --git a/lib/hawat/blueprints/auth_api/test/__init__.py b/lib/hawat/blueprints/auth_api/test/__init__.py
index 2dd9bebfb4a00eb04c902c0e44bb9ec62405bdbf..c1326f27f33485483868d400eadf8bc7e67d34aa 100644
--- a/lib/hawat/blueprints/auth_api/test/__init__.py
+++ b/lib/hawat/blueprints/auth_api/test/__init__.py
@@ -15,7 +15,6 @@ Unit tests for :py:mod:`hawat.blueprints.auth_api`.
 __author__ = "Jan Mach <jan.mach@cesnet.cz>"
 __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>"
 
-import sys
 import unittest
 
 import hawat.const
@@ -24,10 +23,7 @@ import hawat.db
 from hawat.test import HawatTestCase
 from hawat.test.runner import TestRunnerMixin
 
-_IS_NOSE = sys.argv[0].endswith('nosetests')
 
-
-@unittest.skipIf(_IS_NOSE, "broken under nosetest")
 class AuthAPITestCase(TestRunnerMixin, HawatTestCase):
     """
     Class for testing :py:mod:`hawat.blueprints.auth_api` blueprint.
@@ -122,7 +118,6 @@ class AuthAPITestCase(TestRunnerMixin, HawatTestCase):
             )
             self.assertEqual(response.status_code, 200)
             self.assertTrue(b'Welcome!' in response.data)
-            self.assertTrue(b'My account' in response.data)
             self.assertTrue(b'data-user-name="admin"' in response.data)
 
         for tcase in (
@@ -136,7 +131,6 @@ class AuthAPITestCase(TestRunnerMixin, HawatTestCase):
             )
             self.assertEqual(response.status_code, 200)
             self.assertTrue(b'Welcome!' in response.data)
-            self.assertTrue(b'My account' in response.data)
             self.assertTrue(b'data-user-name="admin"' in response.data)
 
     @hawat.test.do_as_user_decorator(hawat.const.ROLE_USER)
diff --git a/lib/hawat/blueprints/auth_dev/forms.py b/lib/hawat/blueprints/auth_dev/forms.py
index 2c8a6b6e5631e6002a23e808d06dd86ef4b854e4..bc835b8f9176ab258393c5c4a627edbf7a45703f 100644
--- a/lib/hawat/blueprints/auth_dev/forms.py
+++ b/lib/hawat/blueprints/auth_dev/forms.py
@@ -16,7 +16,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>"
 __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>"
 
 import wtforms
-from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField
+from wtforms_sqlalchemy.fields import QuerySelectMultipleField
 import flask
 import flask_wtf
 from flask_babel import lazy_gettext
diff --git a/lib/hawat/blueprints/auth_env/forms.py b/lib/hawat/blueprints/auth_env/forms.py
index bfe47ca3fadf8ee6ec4e2648bf1a044c0d549646..7cce54b0ccbc6b157062fe42329d10d88e19bcf1 100644
--- a/lib/hawat/blueprints/auth_env/forms.py
+++ b/lib/hawat/blueprints/auth_env/forms.py
@@ -16,7 +16,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>"
 __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>"
 
 import wtforms
-from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField
+from wtforms_sqlalchemy.fields import QuerySelectMultipleField
 
 from flask_babel import lazy_gettext
 
diff --git a/lib/hawat/blueprints/auth_env/test/__init__.py b/lib/hawat/blueprints/auth_env/test/__init__.py
index ffbea6920d454d596ecd1e55b21b258411fa80a4..34888e5b503c4c0c7f5f367171e73459e2abcf7a 100644
--- a/lib/hawat/blueprints/auth_env/test/__init__.py
+++ b/lib/hawat/blueprints/auth_env/test/__init__.py
@@ -27,7 +27,6 @@ class AuthEnvTestCase(TestRunnerMixin, RegistrationHawatTestCase):
     Class for testing :py:mod:`hawat.blueprints.auth_env` blueprint.
     """
 
-    @unittest.skip("temporarily disabled")
     def test_01_login_user(self):
         """
         Test login/logout with *auth_env* module - user 'user'.
@@ -48,7 +47,6 @@ class AuthEnvTestCase(TestRunnerMixin, RegistrationHawatTestCase):
         self.assertEqual(response.status_code, 200)
         self.assertTrue(b'You have been successfully logged out' in response.data)
 
-    @unittest.skip("temporarily disabled")
     def test_02_login_developer(self):
         """
         Test login/logout with *auth_env* module - user 'developer'.
@@ -69,7 +67,6 @@ class AuthEnvTestCase(TestRunnerMixin, RegistrationHawatTestCase):
         self.assertEqual(response.status_code, 200)
         self.assertTrue(b'You have been successfully logged out' in response.data)
 
-    @unittest.skip("temporarily disabled")
     def test_03_login_admin(self):
         """
         Test login/logout with *auth_env* module - user 'admin'.
@@ -90,7 +87,6 @@ class AuthEnvTestCase(TestRunnerMixin, RegistrationHawatTestCase):
         self.assertEqual(response.status_code, 200)
         self.assertTrue(b'You have been successfully logged out' in response.data)
 
-    @unittest.skip("temporarily disabled")
     def test_04_register(self):
         """
         Test registration with *auth_env* module - new user 'test'.
@@ -170,7 +166,6 @@ class AuthEnvTestCase(TestRunnerMixin, RegistrationHawatTestCase):
             }
         )
 
-    @unittest.skip("temporarily disabled")
     def test_05_register_fail(self):
         """
         Test registration with *auth_env* module - existing user 'user'.
diff --git a/lib/hawat/blueprints/auth_pwd/forms.py b/lib/hawat/blueprints/auth_pwd/forms.py
index 0f63c24a78d75f30a6b9a15e4793b381e4149983..19c091b0f792015679a14e1ebcbe15600ed996c4 100644
--- a/lib/hawat/blueprints/auth_pwd/forms.py
+++ b/lib/hawat/blueprints/auth_pwd/forms.py
@@ -17,7 +17,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea
 
 import wtforms
 import flask_wtf
-from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField
+from wtforms_sqlalchemy.fields import QuerySelectMultipleField
 from flask_babel import lazy_gettext
 
 from hawat.forms import check_login, check_unique_login, get_available_groups, check_null_character
diff --git a/lib/hawat/blueprints/changelogs/forms.py b/lib/hawat/blueprints/changelogs/forms.py
index f209e82e6308a99654925b3368bb6fb4c31b372a..7d51af920d565eaa8ca2dc6a7dc80b239b563288 100644
--- a/lib/hawat/blueprints/changelogs/forms.py
+++ b/lib/hawat/blueprints/changelogs/forms.py
@@ -16,7 +16,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>"
 __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>"
 
 import wtforms
-from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField
+from wtforms_sqlalchemy.fields import QuerySelectMultipleField
 import flask
 import flask_wtf
 from flask_babel import lazy_gettext
diff --git a/lib/hawat/blueprints/changelogs/test/__init__.py b/lib/hawat/blueprints/changelogs/test/__init__.py
index 5fcb2e3dd6a76b439d8f2f71c691208c2bf53bfb..76c4a4c0980dfcb27c6da30e9b9bf8a3c75ef86b 100644
--- a/lib/hawat/blueprints/changelogs/test/__init__.py
+++ b/lib/hawat/blueprints/changelogs/test/__init__.py
@@ -15,7 +15,6 @@ Unit tests for :py:mod:`hawat.blueprints.changelogs`.
 __author__ = "Jan Mach <jan.mach@cesnet.cz>"
 __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>"
 
-import sys
 import unittest
 
 import hawat.const
@@ -25,10 +24,6 @@ from hawat.test import HawatTestCase
 from hawat.test.runner import TestRunnerMixin
 
 
-_IS_NOSE = sys.argv[0].endswith('nosetests')
-
-
-@unittest.skipIf(_IS_NOSE, "broken under nosetests")
 class ChangeLogsSearchTestCase(TestRunnerMixin, HawatTestCase):
     """Class for testing ``changelogs.search`` endpoint."""
 
diff --git a/lib/hawat/blueprints/devtools/test/__init__.py b/lib/hawat/blueprints/devtools/test/__init__.py
index c35d8f328de3d8bdcf28f2b16afa89394d9ef423..d51e87650dd0cc453151de5cdb12a3a6e256b7d1 100644
--- a/lib/hawat/blueprints/devtools/test/__init__.py
+++ b/lib/hawat/blueprints/devtools/test/__init__.py
@@ -10,7 +10,6 @@ Unit tests for :py:mod:`hawat.blueprints.devtools`.
 """
 
 
-import sys
 import unittest
 
 import hawat.const
@@ -20,9 +19,6 @@ from hawat.test import HawatTestCase
 from hawat.test.runner import TestRunnerMixin
 
 
-_IS_NOSE = sys.argv[0].endswith('nosetests')
-
-@unittest.skipIf(_IS_NOSE, "broken under nosetest")
 class ConfigTestCase(TestRunnerMixin, HawatTestCase):
     """
     Class for testing ``devtools.config`` endpoint.
@@ -30,6 +26,17 @@ class ConfigTestCase(TestRunnerMixin, HawatTestCase):
     This endpoint is for developers only.
     """
 
+    def _attempt_fail_redirect(self):
+        self.assertGetURL(
+            '/devtools/config',
+            302,
+            [
+                b'Redirecting...',
+                b'login?next='
+            ],
+            follow_redirects=False
+        )
+
     def _attempt_fail(self):
         self.assertGetURL(
             '/devtools/config',
@@ -51,7 +58,7 @@ class ConfigTestCase(TestRunnerMixin, HawatTestCase):
 
     def test_01_as_anonymous(self):
         """Test access as anonymous user."""
-        self._attempt_fail()
+        self._attempt_fail_redirect()
 
     @hawat.test.do_as_user_decorator(hawat.const.ROLE_USER)
     def test_02_as_user(self):
diff --git a/lib/hawat/blueprints/events/forms.py b/lib/hawat/blueprints/events/forms.py
index ba9d8d91c0ce1514c01dad5bbd3cb10f6e098627..d069554354b64ae6d097d68681514914ab3d6358 100644
--- a/lib/hawat/blueprints/events/forms.py
+++ b/lib/hawat/blueprints/events/forms.py
@@ -17,7 +17,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>"
 __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>"
 
 import wtforms
-from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField
+from wtforms_sqlalchemy.fields import QuerySelectMultipleField
 
 import flask_wtf
 from flask_babel import lazy_gettext
diff --git a/lib/hawat/blueprints/filters/forms.py b/lib/hawat/blueprints/filters/forms.py
index 88676f4ab91bc92db81d86b25a210fac75493f31..4c067131f2e2d7b1d3535a77b6b0b4ea18fbd7ad 100644
--- a/lib/hawat/blueprints/filters/forms.py
+++ b/lib/hawat/blueprints/filters/forms.py
@@ -18,7 +18,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea
 import pynspect.gparser
 
 import wtforms
-from wtforms.ext.sqlalchemy.fields import QuerySelectField
+from wtforms_sqlalchemy.fields import QuerySelectField
 
 #
 # Flask related modules.
diff --git a/lib/hawat/blueprints/groups/forms.py b/lib/hawat/blueprints/groups/forms.py
index 751d8dd930618c6d89892ad542fa6a81738bba36..a71f8590a89028837fc14461a9e1552e3ede0b1c 100644
--- a/lib/hawat/blueprints/groups/forms.py
+++ b/lib/hawat/blueprints/groups/forms.py
@@ -17,7 +17,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea
 
 import sqlalchemy
 import wtforms
-from wtforms.ext.sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField
+from wtforms_sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField
 
 #
 # Flask related modules.
diff --git a/lib/hawat/blueprints/hosts/__init__.py b/lib/hawat/blueprints/hosts/__init__.py
index 4be2da083fdd1ded59f5392c8bf90138bcf6c0be..a25b9346f7338be9ace02c3b699f0454882612a4 100644
--- a/lib/hawat/blueprints/hosts/__init__.py
+++ b/lib/hawat/blueprints/hosts/__init__.py
@@ -49,7 +49,7 @@ class AbstractSearchView(PsycopgMixin, BaseSearchView):  # pylint: disable=local
     """
     authentication = True
 
-    authorization = [hawat.acl.PERMISSION_DEVELOPER]
+    authorization = [hawat.acl.PERMISSION_POWER]
 
     @classmethod
     def get_menu_title(cls, **kwargs):
diff --git a/lib/hawat/blueprints/networks/forms.py b/lib/hawat/blueprints/networks/forms.py
index 259c23b994dd0893415acf619ca1819fe5ad1cc2..64a92735dd6b6f3e8c3bce3c33d0b9235ec416e2 100644
--- a/lib/hawat/blueprints/networks/forms.py
+++ b/lib/hawat/blueprints/networks/forms.py
@@ -16,7 +16,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>"
 __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>"
 
 import wtforms
-from wtforms.ext.sqlalchemy.fields import QuerySelectField
+from wtforms_sqlalchemy.fields import QuerySelectField
 
 #
 # Flask related modules.
diff --git a/lib/hawat/blueprints/reports/forms.py b/lib/hawat/blueprints/reports/forms.py
index 82789daaafc8923294e7ae11758c9dd129f56b9d..b89649f4a69584a3878e0644909de8eb1ba2b619 100644
--- a/lib/hawat/blueprints/reports/forms.py
+++ b/lib/hawat/blueprints/reports/forms.py
@@ -16,7 +16,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>"
 __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>"
 
 import wtforms
-from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField
+from wtforms_sqlalchemy.fields import QuerySelectMultipleField
 
 import flask_login
 import flask_wtf
diff --git a/lib/hawat/blueprints/settings_reporting/forms.py b/lib/hawat/blueprints/settings_reporting/forms.py
index 78dc81bfdfb957b7c1e9f89baa6846d74339abd5..2b7fbfa5e851248a4255c5da6a45fabec97dbfc8 100644
--- a/lib/hawat/blueprints/settings_reporting/forms.py
+++ b/lib/hawat/blueprints/settings_reporting/forms.py
@@ -18,7 +18,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea
 import os
 import pytz
 import wtforms
-from wtforms.ext.sqlalchemy.fields import QuerySelectField
+from wtforms_sqlalchemy.fields import QuerySelectField
 from babel import Locale
 
 from flask_babel import lazy_gettext
diff --git a/lib/hawat/blueprints/timeline/forms.py b/lib/hawat/blueprints/timeline/forms.py
index 755080d4fff69dbc00086a9fbd47ca19ec1b8bdc..f402e251aafc9f0f28958f2702774e14f5299c8c 100644
--- a/lib/hawat/blueprints/timeline/forms.py
+++ b/lib/hawat/blueprints/timeline/forms.py
@@ -17,7 +17,7 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>"
 __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>"
 
 import wtforms
-from wtforms.ext.sqlalchemy.fields import QuerySelectMultipleField
+from wtforms_sqlalchemy.fields import QuerySelectMultipleField
 
 import flask_wtf
 from flask_babel import lazy_gettext
diff --git a/lib/hawat/blueprints/users/forms.py b/lib/hawat/blueprints/users/forms.py
index 7a09c3c9dc42f88756d4713d798a7da432e9030b..d6ddc6bb6877a54d44b79cde8dbae56a171669fe 100644
--- a/lib/hawat/blueprints/users/forms.py
+++ b/lib/hawat/blueprints/users/forms.py
@@ -18,7 +18,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea
 import pytz
 import sqlalchemy
 import wtforms
-from wtforms.ext.sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField
+from wtforms_sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField
 from flask_babel import gettext, lazy_gettext
 
 import hawat.db
diff --git a/lib/hawat/jsglue.py b/lib/hawat/jsglue.py
index 9e3f7587a734cc49d96326c382b98cb10c61f541..955454ed47b29db1be3cf20a03d3f2bce300af31 100644
--- a/lib/hawat/jsglue.py
+++ b/lib/hawat/jsglue.py
@@ -22,7 +22,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea
 import re
 import json
 
-from jinja2 import Markup
+from markupsafe import Markup
 from flask import make_response, url_for
 
 
diff --git a/lib/hawat/test/__init__.py b/lib/hawat/test/__init__.py
index 0bbf8c91346a83cf8e66f18a3a37234b12cb0365..95b0c8ecd2e04bdff21e276a3eb58ed6e894d576 100644
--- a/lib/hawat/test/__init__.py
+++ b/lib/hawat/test/__init__.py
@@ -467,7 +467,7 @@ class RegistrationHawatTestCase(HawatTestCase):
         'timezone': None
     }
 
-    def assertRegisterFail(self, url, data, environ_base = None):  # pylint: disable=locally-disabled,invalid-name
+    def assertRegisterFail(self, url, data, environ_base = {}):  # pylint: disable=locally-disabled,invalid-name
         response = response = self.client.get(
             url,
             follow_redirects = True,
@@ -506,7 +506,7 @@ class RegistrationHawatTestCase(HawatTestCase):
         )
 
 
-    def assertRegister(self, url, data, emails, environ_base = None):  # pylint: disable=locally-disabled,invalid-name
+    def assertRegister(self, url, data, emails, environ_base = {}):  # pylint: disable=locally-disabled,invalid-name
         uname = 'test'
         self.mailbox_monitoring('on')
 
diff --git a/nose2.cfg b/nose2.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..b1ea5d962a6eb7d99d760a3c35f25e465b4696f2
--- /dev/null
+++ b/nose2.cfg
@@ -0,0 +1,4 @@
+[unittest]
+plugins = nose2.plugins.junitxml
+start-dir = lib
+test-file-pattern=*.py