Source code for horizon.test.tests.tabs

# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2012 Nebula, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import copy

from django import http

from horizon import exceptions
from horizon import tabs as horizon_tabs
from horizon.test import helpers as test

from horizon.test.tests.tables import MyTable  # noqa
from horizon.test.tests.tables import TEST_DATA  # noqa


[docs]class BaseTestTab(horizon_tabs.Tab):
[docs] def get_context_data(self, request): return {"tab": self}
[docs]class TabOne(BaseTestTab): slug = "tab_one" name = "Tab One" template_name = "_tab.html"
[docs]class TabDelayed(BaseTestTab): slug = "tab_delayed" name = "Delayed Tab" template_name = "_tab.html" preload = False
[docs]class TabDisabled(BaseTestTab): slug = "tab_disabled" name = "Disabled Tab" template_name = "_tab.html"
[docs] def enabled(self, request): return False
[docs]class TabDisallowed(BaseTestTab): slug = "tab_disallowed" name = "Disallowed Tab" template_name = "_tab.html"
[docs] def allowed(self, request): return False
[docs]class Group(horizon_tabs.TabGroup): slug = "tab_group" tabs = (TabOne, TabDelayed, TabDisabled, TabDisallowed) sticky = True
[docs] def tabs_not_available(self): self._assert_tabs_not_available = True
[docs]class TabWithTable(horizon_tabs.TableTab): table_classes = (MyTable,) name = "Tab With My Table" slug = "tab_with_table" template_name = "horizon/common/_detail_table.html"
[docs] def get_my_table_data(self): return TEST_DATA
[docs]class RecoverableErrorTab(horizon_tabs.Tab): name = "Recoverable Error Tab" slug = "recoverable_error_tab" template_name = "_tab.html"
[docs] def get_context_data(self, request): # Raise a known recoverable error. exc = exceptions.AlreadyExists("Recoverable!", horizon_tabs.Tab) exc.silence_logging = True raise exc
[docs]class TableTabGroup(horizon_tabs.TabGroup): slug = "tab_group" tabs = [TabWithTable]
[docs]class TabWithTableView(horizon_tabs.TabbedTableView): tab_group_class = TableTabGroup template_name = "tab_group.html"
[docs]class TabTests(test.TestCase):
[docs] def test_tab_group_basics(self): tg = Group(self.request) # Test tab instantiation/attachement to tab group, and get_tabs method tabs = tg.get_tabs() # "tab_disallowed" should NOT be in this list. self.assertQuerysetEqual(tabs, ['<TabOne: tab_one>', '<TabDelayed: tab_delayed>', '<TabDisabled: tab_disabled>']) # Test get_id self.assertEqual(tg.get_id(), "tab_group") # get_default_classes self.assertEqual(tg.get_default_classes(), horizon_tabs.base.CSS_TAB_GROUP_CLASSES) # Test get_tab self.assertEqual(tg.get_tab("tab_one").slug, "tab_one") # Test selected is None w/o GET input self.assertIsNone(tg.selected) # Test get_selected_tab is None w/o GET input self.assertIsNone(tg.get_selected_tab())
[docs] def test_tab_group_active_tab(self): tg = Group(self.request) # active tab w/o selected self.assertEqual(tg.active, tg.get_tabs()[0]) # active tab w/ selected self.request.GET['tab'] = "tab_group__tab_delayed" tg = Group(self.request) self.assertEqual(tg.active, tg.get_tab('tab_delayed')) # active tab w/ invalid selected self.request.GET['tab'] = "tab_group__tab_invalid" tg = Group(self.request) self.assertEqual(tg.active, tg.get_tabs()[0]) # active tab w/ disallowed selected self.request.GET['tab'] = "tab_group__tab_disallowed" tg = Group(self.request) self.assertEqual(tg.active, tg.get_tabs()[0]) # active tab w/ disabled selected self.request.GET['tab'] = "tab_group__tab_disabled" tg = Group(self.request) self.assertEqual(tg.active, tg.get_tabs()[0])
[docs] def test_tab_basics(self): tg = Group(self.request) tab_one = tg.get_tab("tab_one") tab_delayed = tg.get_tab("tab_delayed") tab_disabled = tg.get_tab("tab_disabled", allow_disabled=True) # Disallowed tab isn't even returned tab_disallowed = tg.get_tab("tab_disallowed") self.assertIsNone(tab_disallowed) # get_id self.assertEqual(tab_one.get_id(), "tab_group__tab_one") # get_default_classes self.assertEqual(tab_one.get_default_classes(), horizon_tabs.base.CSS_ACTIVE_TAB_CLASSES) self.assertEqual(tab_disabled.get_default_classes(), horizon_tabs.base.CSS_DISABLED_TAB_CLASSES) # load, allowed, enabled self.assertTrue(tab_one.load) self.assertFalse(tab_delayed.load) self.assertFalse(tab_disabled.load) self.request.GET['tab'] = tab_delayed.get_id() tg = Group(self.request) tab_delayed = tg.get_tab("tab_delayed") self.assertTrue(tab_delayed.load) # is_active self.request.GET['tab'] = "" tg = Group(self.request) tab_one = tg.get_tab("tab_one") tab_delayed = tg.get_tab("tab_delayed") self.assertTrue(tab_one.is_active()) self.assertFalse(tab_delayed.is_active()) self.request.GET['tab'] = tab_delayed.get_id() tg = Group(self.request) tab_one = tg.get_tab("tab_one") tab_delayed = tg.get_tab("tab_delayed") self.assertFalse(tab_one.is_active()) self.assertTrue(tab_delayed.is_active())
[docs] def test_rendering(self): tg = Group(self.request) tab_one = tg.get_tab("tab_one") tab_delayed = tg.get_tab("tab_delayed") tab_disabled = tg.get_tab("tab_disabled", allow_disabled=True) # tab group output = tg.render() res = http.HttpResponse(output.strip()) self.assertContains(res, "<li", 3) # stickiness self.assertContains(res, 'data-sticky-tabs="sticky"', 1) # tab output = tab_one.render() self.assertEqual(output.strip(), tab_one.name) # disabled tab output = tab_disabled.render() self.assertEqual(output.strip(), "") # preload false output = tab_delayed.render() self.assertEqual(output.strip(), "") # preload false w/ active self.request.GET['tab'] = tab_delayed.get_id() tg = Group(self.request) tab_delayed = tg.get_tab("tab_delayed") output = tab_delayed.render() self.assertEqual(output.strip(), tab_delayed.name)
[docs] def test_table_tabs(self): tab_group = TableTabGroup(self.request) tabs = tab_group.get_tabs() # Only one tab, as expected. self.assertEqual(len(tabs), 1) tab = tabs[0] # Make sure it's the tab we think it is. self.assertIsInstance(tab, horizon_tabs.TableTab) # Data should not be loaded yet. self.assertFalse(tab._table_data_loaded) table = tab._tables[MyTable.Meta.name] self.assertIsInstance(table, MyTable) # Let's make sure the data *really* isn't loaded yet. self.assertIsNone(table.data) # Okay, load the data. tab.load_table_data() self.assertTrue(tab._table_data_loaded) self.assertQuerysetEqual(table.data, ['<FakeObject: object_1>', '<FakeObject: object_2>', '<FakeObject: object_3>']) context = tab.get_context_data(self.request) # Make sure our table is loaded into the context correctly self.assertEqual(context['my_table_table'], table) # Since we only had one table we should get the shortcut name too. self.assertEqual(context['table'], table)
[docs] def test_tabbed_table_view(self): view = TabWithTableView.as_view() # Be sure we get back a rendered table containing data for a GET req = self.factory.get("/") res = view(req) self.assertContains(res, "<table", 1) self.assertContains(res, "Displaying 3 items", 1) # AJAX response to GET for row update params = {"table": "my_table", "action": "row_update", "obj_id": "1"} req = self.factory.get('/', params, HTTP_X_REQUESTED_WITH='XMLHttpRequest') res = view(req) self.assertEqual(res.status_code, 200) # Make sure we got back a row but not a table or body self.assertContains(res, "<tr", 1) self.assertContains(res, "<table", 0) self.assertContains(res, "<body", 0) # Response to POST for table action action_string = "my_table__toggle__2" req = self.factory.post('/', {'action': action_string}) res = view(req) self.assertEqual(res.status_code, 302) self.assertEqual(res["location"], "/") # Ensure that lookup errors are raised as such instead of converted # to TemplateSyntaxErrors. action_string = "my_table__toggle__2000000000" req = self.factory.post('/', {'action': action_string}) self.assertRaises(exceptions.Http302, view, req)
[docs]class TabExceptionTests(test.TestCase):
[docs] def setUp(self): super(TabExceptionTests, self).setUp() self._original_tabs = copy.copy(TabWithTableView.tab_group_class.tabs) TabWithTableView.tab_group_class.tabs.append(RecoverableErrorTab)
[docs] def tearDown(self): super(TabExceptionTests, self).tearDown() TabWithTableView.tab_group_class.tabs = self._original_tabs
[docs] def test_tab_view_exception(self): view = TabWithTableView.as_view() req = self.factory.get("/") res = view(req) self.assertMessageCount(res, error=1)