Produce at startup the map of route names to paths, for template use
authorKarl O. Pinc <kop@karlpinc.com>
Tue, 8 Dec 2020 03:57:40 +0000 (21:57 -0600)
committerKarl O. Pinc <kop@karlpinc.com>
Tue, 8 Dec 2020 03:57:40 +0000 (21:57 -0600)
src/pgwui_common/urls.py [new file with mode: 0644]
src/pgwui_common/view.py
tests/test_pgwui_common.py
tests/test_urls.py [new file with mode: 0644]
tests/test_view.py

diff --git a/src/pgwui_common/urls.py b/src/pgwui_common/urls.py
new file mode 100644 (file)
index 0000000..c87f88c
--- /dev/null
@@ -0,0 +1,115 @@
+# Copyright (C) 2018, 2020 The Meme Factory, Inc.  http://www.karlpinc.com/
+
+# This file is part of PGWUI_Common.
+#
+# This program is free software: you can redistribute it and/or
+# modify it under the terms of the GNU Affero General Public License
+# as published by the Free Software Foundation, either version 3 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with this program.  If not, see
+# <http://www.gnu.org/licenses/>.
+#
+
+# Karl O. Pinc <kop@karlpinc.com>
+
+'''Expose useful response "variables" to templates
+'''
+
+import pyramid.request
+
+from .plugin import find_pgwui_components
+from . import exceptions as ex
+
+
+def route_path(request, page_name, source):
+    '''Return the route path of the page's "source"
+    '''
+    try:
+        return request.route_path(source)
+    except KeyError as old_ex:
+        raise ex.BadRouteError(page_name, old_ex)
+
+
+def asset_path(request, page_name, source):
+    '''Return the static path to the asset's "source"
+    '''
+    try:
+        return request.static_path(source)
+    except ValueError as old_ex:
+        raise ex.BadAssetError(page_name, old_ex)
+
+
+def url_of_page(request, page_name):
+    '''Return a url to the page.  This may or may not be fully
+    qualified, depending on what the user specifies in the settings.
+    '''
+    page_conf = request.registry.settings['pgwui'][page_name]
+    type = page_conf['type']
+    source = page_conf['source']
+    if type == 'URL':
+        return source
+    if type == 'file':
+        return request.route_path(f'pgwui_common.{page_name}')
+    if type == 'route':
+        return route_path(request, page_name, source)
+    if type == 'asset':
+        return asset_path(request, page_name, source)
+
+
+def set_menu_url(request, urls):
+    '''Add urls for pgwui_menu, return non-menu components
+    '''
+    try:
+        menu_url = url_of_page(request, 'menu_page')
+    except KeyError:
+        try:
+            menu_url = request.route_path('pgwui_menu')
+        except KeyError:
+            return
+    if menu_url != urls['pgwui_home']:
+        urls['pgwui_menu'] = menu_url
+
+
+def set_component_urls(request, urls):
+    '''Add urls for each pgwui component to the 'urls' dict
+    '''
+    set_menu_url(request, urls)
+    components = find_pgwui_components()
+    if 'pgwui_menu' in components:
+        components.remove('pgwui_menu')
+
+    for component in components:
+        try:
+            url = request.route_path(component)
+        except KeyError:
+            pass         # In case a component has no route
+        else:
+            urls.setdefault(component, url)
+
+
+def set_urls(request, urls):
+    '''Build 'urls' dict with all the urls
+    '''
+    home_url = url_of_page(request, 'home_page')
+    urls.setdefault('pgwui_home', home_url)
+    set_component_urls(request, urls)
+
+
+def add_urls_setting(config, settings):
+    '''Add the 'urls' dict to settings, from the existing settings and
+    route configuration
+    '''
+    urls = dict()
+    # We could use introspection, but that would require pyramid_testing
+    # be installed in a production enviornment.  And some RAM.
+    request = pyramid.request.Request.blank('/')
+    request.registry = config.registry
+    set_urls(request, urls)
+    settings['pgwui']['urls'] = urls
index 59fb6495f4540d02199f362573cada0284b0f7c7..d74560a608b69cd23efcfcd555fbef21d739f98d 100644 (file)
 '''View decorators to expose useful response "variables" to templates
 '''
 
-from .plugin import find_pgwui_components
-from . import exceptions as ex
 
-
-def route_path(request, page_name, source):
-    '''Return the route path of the page's "source"
-    '''
-    try:
-        return request.route_path(source)
-    except KeyError as old_ex:
-        raise ex.BadRouteError(page_name, old_ex)
-
-
-def asset_path(request, page_name, source):
-    '''Return the static path to the asset's "source"
-    '''
-    try:
-        return request.static_path(source)
-    except ValueError as old_ex:
-        raise ex.BadAssetError(page_name, old_ex)
-
-
-def url_of_page(request, page_name):
-    '''Return a url to the page.  This may or may not be fully
-    qualified, depending on what the user specifies in the settings.
-    '''
-    page_conf = request.registry.settings['pgwui'][page_name]
-    type = page_conf['type']
-    source = page_conf['source']
-    if type == 'URL':
-        return source
-    if type == 'file':
-        return request.route_path(f'pgwui_common.{page_name}')
-    if type == 'route':
-        return route_path(request, page_name, source)
-    if type == 'asset':
-        return asset_path(request, page_name, source)
-
-
-def set_menu_url(request, urls):
-    '''Add urls for pgwui_menu, return non-menu components
-    '''
-    try:
-        menu_url = url_of_page(request, 'menu_page')
-    except KeyError:
-        try:
-            menu_url = request.route_path('pgwui_menu')
-        except KeyError:
-            return
-    if menu_url != urls['pgwui_home']:
-        urls['pgwui_menu'] = menu_url
-
-
-def set_component_urls(request, urls):
-    '''Add urls for each pgwui component to the 'urls' dict
-    '''
-    set_menu_url(request, urls)
-    components = find_pgwui_components()
-    if 'pgwui_menu' in components:
-        components.remove('pgwui_menu')
-
-    for component in components:
-        try:
-            url = request.route_path(component)
-        except KeyError:
-            pass         # In case a component has no route
-        else:
-            urls.setdefault(component, url)
-
-
-def set_urls(request, urls):
-    '''Build 'urls' dict with all the urls
+def merge_urls(request, pgwui):
+    '''Merge the urls in the settings with the urls put into the
+    the pgwui portion of the response by the view
     '''
-    home_url = url_of_page(request, 'home_page')
-    urls.setdefault('pgwui_home', home_url)
-    set_component_urls(request, urls)
+    urls = request.registry.settings['pgwui']['urls'].copy()
+    pgwui.setdefault('urls', dict())
+    urls.update(pgwui['urls'])
+    pgwui['urls'] = urls
 
 
 def base_view(wrapped):
@@ -108,8 +41,7 @@ def base_view(wrapped):
         '''
         response = wrapped(request)
         pgwui = response.get('pgwui', {})
-        urls = pgwui.setdefault('urls', dict())
-        set_urls(request, urls)
+        merge_urls(request, pgwui)
         response['pgwui'] = pgwui
         return response
     return wrapper
index dbd14cf4f1fbf632190c308b122f560a58939962..b380dfb94c03f0d9d0be9386421b3d97943ab353 100644 (file)
@@ -24,12 +24,13 @@ import pyramid.config
 import pyramid.testing
 from pyramid.threadlocal import get_current_request
 
+import pgwui_common.urls as urls
 import pgwui_common.view as view
 import pgwui_common.pgwui_common as pgwui_common
 
 from pgwui_testing import testing
 
-# Activiate our pytest plugin
+# Activiate the PGWUI pytest plugin
 pytest_plugins = ("pgwui",)
 
 
@@ -38,7 +39,7 @@ pytest_plugins = ("pgwui",)
 FOO_URL = 'foo://bar/'
 
 mock_find_pgwui_components = testing.make_mock_fixture(
-    view, 'find_pgwui_components')
+    urls, 'find_pgwui_components')
 
 mock_method_route_path = testing.instance_method_mock_fixture('route_path')
 mock_route_url = testing.instance_method_mock_fixture('route_url')
@@ -142,13 +143,14 @@ def test_auth_base_view_integration(
         pyramid_request_config, mock_find_pgwui_components):
     '''There are urls for every component
     '''
-    test_pgwui = {'home_page': {'type': 'URL', 'source': '/'}}
-
     test_urls = {
         'pgwui_menu': '/menu',
         'pgwui_logout': '/logout',
         'pgwui_foo': '/foo'}
 
+    test_pgwui = {'home_page': {'type': 'URL', 'source': '/'},
+                  'urls': test_urls.copy()}
+
     mock_find_pgwui_components.return_value = list(test_urls)
 
     pyramid_request_config.add_settings(pgwui=test_pgwui)
@@ -160,7 +162,9 @@ def test_auth_base_view_integration(
     request = get_current_request()
     result = wrapper(request)
 
-    assert result['pgwui']['urls'] == dict(test_urls, pgwui_home='/')
+    # The 'home_page' route is not added because it is (normally) added
+    # to the pgwui settings by pgwui_server.py.
+    assert result['pgwui']['urls'] == test_urls
 
 
 # includeme()
diff --git a/tests/test_urls.py b/tests/test_urls.py
new file mode 100644 (file)
index 0000000..9a3c467
--- /dev/null
@@ -0,0 +1,309 @@
+# Copyright (C) 2018, 2020 The Meme Factory, Inc.  http://www.karlpinc.com/
+
+# This file is part of PGWUI_Common.
+#
+# This program is free software: you can redistribute it and/or
+# modify it under the terms of the GNU Affero General Public License
+# as published by the Free Software Foundation, either version 3 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with this program.  If not, see
+# <http://www.gnu.org/licenses/>.
+#
+
+# Karl O. Pinc <kop@karlpinc.com>
+
+import pytest
+import pyramid.request
+from pyramid.threadlocal import get_current_request
+
+import pgwui_common.urls as urls
+import pgwui_common.exceptions as common_ex
+
+from pgwui_testing import testing
+
+# Activiate the PGWUI pytest plugin
+pytest_plugins = ("pgwui",)
+
+# Mark all tests with "unittest"
+pytestmark = pytest.mark.unittest
+
+
+# Helper functions and constants
+
+FOO_URL = 'foo://bar/'
+
+mock_find_pgwui_components = testing.make_mock_fixture(
+    urls, 'find_pgwui_components')
+
+mock_method_route_path = testing.instance_method_mock_fixture('route_path')
+mock_route_url = testing.instance_method_mock_fixture('route_url')
+mock_include = testing.instance_method_mock_fixture('include')
+mock_add_static_view = testing.instance_method_mock_fixture('add_static_view')
+mock_add_route = testing.instance_method_mock_fixture('add_route')
+mock_add_view = testing.instance_method_mock_fixture('add_view')
+mock_static_path = testing.instance_method_mock_fixture('static_path')
+
+mock_request_blank = testing.make_magicmock_fixture(
+    pyramid.request, 'Request')
+
+
+def mock_view(request):
+    if (hasattr(request, 'registry')
+            and 'pgwui' in request.registry.settings):
+        return request.registry.settings
+    return {'pgwui': {'foo': FOO_URL}}
+
+
+def check_base_view_results(request, pgwui):
+    assert pgwui['foo'] == FOO_URL
+
+
+# Unit tests
+
+# route_path()
+
+def test_route_path_with_path(pyramid_request_config, mock_method_route_path):
+    '''static_path() result is returned
+    '''
+    expected = 'route'
+
+    request = get_current_request()
+    mocked_route_path = mock_method_route_path(request)
+    mocked_route_path.return_value = expected
+
+    result = urls.route_path(request, None, None)
+
+    assert result == expected
+
+
+def test_route_path_no_path(pyramid_request_config, mock_method_route_path):
+    '''BadRouteError() raised when there's no path
+    '''
+    request = get_current_request()
+    mocked_route_path = mock_method_route_path(request)
+    mocked_route_path.side_effect = KeyError
+
+    with pytest.raises(common_ex.BadRouteError):
+        urls.route_path(request, None, None)
+
+    assert True
+
+
+mock_route_path = testing.make_mock_fixture(
+    urls, 'route_path')
+
+
+# asset_path()
+
+def test_asset_path_with_path(pyramid_request_config, mock_static_path):
+    '''static_path() result is returned
+    '''
+    expected = 'static'
+
+    request = get_current_request()
+    mocked_static_path = mock_static_path(request)
+    mocked_static_path.return_value = expected
+
+    result = urls.asset_path(request, None, None)
+
+    assert result == expected
+
+
+def test_asset_path_no_path(pyramid_request_config, mock_static_path):
+    '''BadAssetError() raised when there's no path
+    '''
+    request = get_current_request()
+    mocked_static_path = mock_static_path(request)
+    mocked_static_path.side_effect = ValueError
+
+    with pytest.raises(common_ex.BadAssetError):
+        urls.asset_path(request, None, None)
+
+    assert True
+
+
+mock_asset_path = testing.make_mock_fixture(
+    urls, 'asset_path')
+
+
+# url_of_page()
+
+@pytest.mark.parametrize(
+    ('pgwui', 'page_name', 'expected'), [
+        ({'test_page': {'type': 'URL',
+                        'source': 'somesource'}},
+         'test_page',
+         'somesource'),
+        ({'test_page': {'type': 'file',
+                        'source': 'somesource'}},
+         'test_page',
+         'pgwui_common.test_page'),
+        ({'test_page': {'type': 'route',
+                        'source': 'somesource'}},
+         'test_page',
+         'routepath'),
+        ({'test_page': {'type': 'asset',
+                        'source': 'somesource'}},
+         'test_page',
+         'static'),
+        ({'test_page': {'type': 'impossible',
+                        'source': 'somesource'}},
+         'test_page',
+         None)])
+def test_url_of_page(
+        pyramid_request_config, mock_method_route_path,
+        mock_route_path, mock_asset_path, pgwui, page_name, expected):
+    '''The right results and calls are made
+    '''
+    mock_asset_path.return_value = 'static'
+    mock_route_path.return_value = 'routepath'
+
+    request = get_current_request()
+    mocked_route_path = mock_method_route_path(request)
+    mocked_route_path.side_effect = lambda x: x
+
+    request.registry.settings['pgwui'] = pgwui
+    result = urls.url_of_page(request, page_name)
+
+    assert result == expected
+
+
+mock_url_of_page = testing.make_mock_fixture(
+    urls, 'url_of_page')
+
+
+# set_menu_url()
+
+@pytest.mark.parametrize(
+    "test_urls,expected",
+    [
+        # menu and home have identical urls, no url is added for menu
+        ({'pgwui_menu': '/', 'pgwui_home': '/'},
+         {}),
+        # No menu url, no url is added for menu
+        ({'pgwui_home': '/'},
+         {}),
+        # menu and home have different urls, url is added for menu
+        ({'pgwui_menu': '/menu', 'pgwui_home': '/'},
+         {'pgwui_menu': '/menu'})])
+def test_set_menu_url(
+        pyramid_request_config, mock_method_route_path, mock_url_of_page,
+        test_urls, expected):
+    '''The expected urls are returned
+    '''
+    def path_func(name):
+        return test_urls[name]
+
+    mock_url_of_page.side_effect = lambda *args: test_urls['pgwui_menu']
+    request = get_current_request()
+    mocked_route_path = mock_method_route_path(request)
+    mocked_route_path.side_effect = path_func
+
+    urls_dict = {'pgwui_home': test_urls['pgwui_home']}
+    expected.update(urls_dict)
+    urls.set_menu_url(request, urls_dict)
+
+    assert urls_dict == expected
+
+
+mock_set_menu_url = testing.make_mock_fixture(
+    urls, 'set_menu_url')
+
+
+# set_component_urls()
+
+@pytest.mark.parametrize(
+    'test_urls', [
+        # With a pgwui_menu
+        {'pgwui_menu': '/menu',
+         'pgwui_logout': '/logout',
+         'pgwui_foo': '/foo',
+         'pgwui_home': '/'},
+        # Without a pgwui_menu
+        {'pgwui_logout': '/logout',
+         'pgwui_foo': '/foo',
+         'pgwui_home': '/'}])
+def test_set_component_urls(
+        pyramid_request_config, mock_method_route_path, mock_set_menu_url,
+        mock_find_pgwui_components, test_urls):
+    '''Urls are set for every component which has a route, except for
+    pgwui_menu
+    '''
+    test_components = list(test_urls) + ['pgwui_noroute']
+
+    def url_func(url):
+        return test_urls[url]
+
+    request = get_current_request()
+    mocked_route_path = mock_method_route_path(request)
+    mocked_route_path.side_effect = url_func
+    mock_find_pgwui_components.return_value = test_components
+
+    urls_dict = dict()
+    urls.set_component_urls(request, urls_dict)
+
+    expected_urls = test_urls.copy()
+    if 'pgwui_menu' in expected_urls:
+        del expected_urls['pgwui_menu']
+
+    mock_set_menu_url.assert_called_once()
+    assert urls_dict == expected_urls
+
+
+mock_set_component_urls = testing.make_mock_fixture(
+    urls, 'set_component_urls')
+
+
+# set_urls()
+
+def test_set_urls(
+        pyramid_request_config, mock_url_of_page, mock_set_component_urls):
+    '''The 'home' url is added and set_component_urls() called
+    '''
+    test_home_route = '/'
+    request = get_current_request()
+
+    mock_url_of_page.return_value = test_home_route
+
+    urls_dict = dict()
+    urls.set_urls(request, urls_dict)
+
+    assert urls_dict['pgwui_home'] == test_home_route
+    mock_set_component_urls.assert_called_once()
+
+
+mock_set_urls = testing.make_mock_fixture(
+    urls, 'set_urls')
+
+
+# add_urls_setting()
+
+def test_add_urls_setting(
+        pyramid_request_config, mock_request_blank, mock_set_urls):
+    '''Request.blank() and set_urls() are called, the urls set
+    are put in the pgwui dict in the settings
+    '''
+    expected_urls = {'key1': 'val1', 'key2': 'val2'}
+
+    def set_urls(request, urls):
+        urls.update(expected_urls)
+
+    mock_set_urls.side_effect = set_urls
+
+    request_settings = {'pgwui': {'urls': expected_urls}}
+    request = get_current_request()
+    request.registry.settings = request_settings
+
+    settings = {'pgwui': {}}
+    urls.add_urls_setting(pyramid_request_config, settings)
+
+    mock_request_blank.blank.assert_called_once()
+    mock_set_urls.assert_called_once()
+    assert settings['pgwui']['urls'] == expected_urls
index 42291dc1239bd239325a9fe41b5ce94e3cc67551..80032e3f0518c32d0f2d98988a2f88e4fe3bb2d4 100644 (file)
@@ -23,13 +23,15 @@ import pytest
 from pyramid.threadlocal import get_current_request
 
 import pgwui_common.view as view
-import pgwui_common.exceptions as common_ex
 
 from pgwui_testing import testing
 
-# Activiate our pytest plugin
+# Activiate the PGWUI pytest plugin
 pytest_plugins = ("pgwui",)
 
+# Mark all tests with "unittest"
+pytestmark = pytest.mark.unittest
+
 
 # Helper functions and constants
 
@@ -38,14 +40,6 @@ FOO_URL = 'foo://bar/'
 mock_find_pgwui_components = testing.make_mock_fixture(
     view, 'find_pgwui_components')
 
-mock_method_route_path = testing.instance_method_mock_fixture('route_path')
-mock_route_url = testing.instance_method_mock_fixture('route_url')
-mock_include = testing.instance_method_mock_fixture('include')
-mock_add_static_view = testing.instance_method_mock_fixture('add_static_view')
-mock_add_route = testing.instance_method_mock_fixture('add_route')
-mock_add_view = testing.instance_method_mock_fixture('add_view')
-mock_static_path = testing.instance_method_mock_fixture('static_path')
-
 
 def mock_view(request):
     if (hasattr(request, 'registry')
@@ -60,248 +54,51 @@ def check_base_view_results(request, pgwui):
 
 # Unit tests
 
-# route_path()
-
-@pytest.mark.unittest
-def test_route_path_with_path(pyramid_request_config, mock_method_route_path):
-    '''static_path() result is returned
-    '''
-    expected = 'route'
-
-    request = get_current_request()
-    mocked_route_path = mock_method_route_path(request)
-    mocked_route_path.return_value = expected
-
-    result = view.route_path(request, None, None)
-
-    assert result == expected
-
-
-@pytest.mark.unittest
-def test_route_path_no_path(pyramid_request_config, mock_method_route_path):
-    '''BadRouteError() raised when there's no path
-    '''
-    request = get_current_request()
-    mocked_route_path = mock_method_route_path(request)
-    mocked_route_path.side_effect = KeyError
-
-    with pytest.raises(common_ex.BadRouteError):
-        view.route_path(request, None, None)
-
-    assert True
-
-
-mock_route_path = testing.make_mock_fixture(
-    view, 'route_path')
-
-
-# asset_path()
-
-@pytest.mark.unittest
-def test_asset_path_with_path(pyramid_request_config, mock_static_path):
-    '''static_path() result is returned
-    '''
-    expected = 'static'
-
-    request = get_current_request()
-    mocked_static_path = mock_static_path(request)
-    mocked_static_path.return_value = expected
-
-    result = view.asset_path(request, None, None)
-
-    assert result == expected
+# merge_urls()
 
-
-@pytest.mark.unittest
-def test_asset_path_no_path(pyramid_request_config, mock_static_path):
-    '''BadAssetError() raised when there's no path
-    '''
-    request = get_current_request()
-    mocked_static_path = mock_static_path(request)
-    mocked_static_path.side_effect = ValueError
-
-    with pytest.raises(common_ex.BadAssetError):
-        view.asset_path(request, None, None)
-
-    assert True
-
-
-mock_asset_path = testing.make_mock_fixture(
-    view, 'asset_path')
-
-
-# url_of_page()
-
-@pytest.mark.parametrize(
-    ('pgwui', 'page_name', 'expected'), [
-        ({'test_page': {'type': 'URL',
-                        'source': 'somesource'}},
-         'test_page',
-         'somesource'),
-        ({'test_page': {'type': 'file',
-                        'source': 'somesource'}},
-         'test_page',
-         'pgwui_common.test_page'),
-        ({'test_page': {'type': 'route',
-                        'source': 'somesource'}},
-         'test_page',
-         'routepath'),
-        ({'test_page': {'type': 'asset',
-                        'source': 'somesource'}},
-         'test_page',
-         'static'),
-        ({'test_page': {'type': 'impossible',
-                        'source': 'somesource'}},
-         'test_page',
-         None)])
-@pytest.mark.unittest
-def test_url_of_page(
-        pyramid_request_config, mock_method_route_path,
-        mock_route_path, mock_asset_path, pgwui, page_name, expected):
-    '''The right results and calls are made
-    '''
-    mock_asset_path.return_value = 'static'
-    mock_route_path.return_value = 'routepath'
-
-    request = get_current_request()
-    mocked_route_path = mock_method_route_path(request)
-    mocked_route_path.side_effect = lambda x: x
-
-    request.registry.settings['pgwui'] = pgwui
-    result = view.url_of_page(request, page_name)
-
-    assert result == expected
-
-
-mock_url_of_page = testing.make_mock_fixture(
-    view, 'url_of_page')
-
-
-# set_menu_url()
-
-@pytest.mark.unittest
-@pytest.mark.parametrize(
-    "test_urls,expected",
-    [
-        # menu and home have identical urls, no url is added for menu
-        ({'pgwui_menu': '/', 'pgwui_home': '/'},
-         {}),
-        # No menu url, no url is added for menu
-        ({'pgwui_home': '/'},
-         {}),
-        # menu and home have different urls, url is added for menu
-        ({'pgwui_menu': '/menu', 'pgwui_home': '/'},
-         {'pgwui_menu': '/menu'})])
-def test_set_menu_url(
-        pyramid_request_config, mock_method_route_path, mock_url_of_page,
-        test_urls, expected):
-    '''The expected urls are returned
+def test_merge_urls(pyramid_request_config):
+    '''The urls in the pgwui response dict is updated with
+    the urls in the request's settings
     '''
-    def path_func(name):
-        return test_urls[name]
-
-    mock_url_of_page.side_effect = lambda *args: test_urls['pgwui_menu']
-    request = get_current_request()
-    mocked_route_path = mock_method_route_path(request)
-    mocked_route_path.side_effect = path_func
-
-    urls = {'pgwui_home': test_urls['pgwui_home']}
-    expected.update(urls)
-    view.set_menu_url(request, urls)
-
-    assert urls == expected
-
-
-mock_set_menu_url = testing.make_mock_fixture(
-    view, 'set_menu_url')
-
-
-# set_component_urls()
-
-@pytest.mark.parametrize(
-    'test_urls', [
-        # With a pgwui_menu
-        {'pgwui_menu': '/menu',
-         'pgwui_logout': '/logout',
-         'pgwui_foo': '/foo',
-         'pgwui_home': '/'},
-        # Without a pgwui_menu
-        {'pgwui_logout': '/logout',
-         'pgwui_foo': '/foo',
-         'pgwui_home': '/'}])
-@pytest.mark.unittest
-def test_set_component_urls(
-        pyramid_request_config, mock_method_route_path, mock_set_menu_url,
-        mock_find_pgwui_components, test_urls):
-    '''Urls are set for every component which has a route, except for
-    pgwui_menu
-    '''
-    test_components = list(test_urls) + ['pgwui_noroute']
-
-    def url_func(url):
-        return test_urls[url]
-
+    old_urls = {'key1': 'val1'}
+    new_urls = {'key2': 'val2', 'key3': 'val3'}
     request = get_current_request()
-    mocked_route_path = mock_method_route_path(request)
-    mocked_route_path.side_effect = url_func
-    mock_find_pgwui_components.return_value = test_components
-
-    urls = dict()
-    view.set_component_urls(request, urls)
+    request.registry.settings = {'pgwui': {'urls': new_urls}}
+    pgwui = {'urls': old_urls.copy()}
+    view.merge_urls(request, pgwui)
 
-    expected_urls = test_urls.copy()
-    if 'pgwui_menu' in expected_urls:
-        del expected_urls['pgwui_menu']
+    expected_urls = old_urls.copy()
+    expected_urls.update(new_urls)
+    assert pgwui['urls'] == expected_urls
 
-    mock_set_menu_url.assert_called_once()
-    assert urls == expected_urls
 
+mock_merge_urls = testing.make_mock_fixture(
+    view, 'merge_urls')
 
-mock_set_component_urls = testing.make_mock_fixture(
-    view, 'set_component_urls')
 
-
-# set_urls()
-
-@pytest.mark.unittest
-def test_set_urls(
-        pyramid_request_config, mock_url_of_page, mock_set_component_urls):
-    '''The 'home' url is added and set_component_urls() called
+# base_view()
+def test_base_view_urls(mock_merge_urls):
+    '''The response has the 'pgwui['urls']' dict added to it by merge_urls()
     '''
-    test_home_route = '/'
-    request = get_current_request()
-
-    mock_url_of_page.return_value = test_home_route
-
-    urls = dict()
-    view.set_urls(request, urls)
+    expected_urls = {'key1': 'val1', 'key2': 'val2'}
 
-    assert urls['pgwui_home'] == test_home_route
-    mock_set_component_urls.assert_called_once()
-
-
-mock_set_urls = testing.make_mock_fixture(
-    view, 'set_urls')
-
-
-# base_view()
-@pytest.mark.unittest
-def test_base_view_urls(mock_set_urls):
-    '''The response has the 'pgwui['urls']' dict added to it'''
     def mock_view(request):
         return {}
 
+    def fake_merge_urls(request, pgwui):
+        pgwui['urls'] = expected_urls
+
+    mock_merge_urls.side_effect = fake_merge_urls
     wrapper = view.base_view(mock_view)
     response = wrapper(get_current_request())
 
     assert 'pgwui' in response
     pgwui = response['pgwui']
     assert 'urls' in pgwui
-    assert isinstance(pgwui['urls'], dict)
+    assert pgwui['urls'] == expected_urls
 
 
-@pytest.mark.unittest
-def test_base_view_default(mock_set_urls):
+def test_base_view_default(mock_merge_urls):
     '''The response retains the mock view's variables'''
     wrapper = view.base_view(mock_view)
     request = get_current_request()
@@ -315,7 +112,6 @@ mock_base_view = testing.make_mock_fixture(view, 'base_view')
 
 # auth_base_view()
 
-@pytest.mark.unittest
 def test_auth_base_view(mock_base_view):
     '''Wrapper calls base_view()
     '''