Skip to content

Commit

Permalink
Add unit tests and fix a couple bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
cpsievert committed Apr 26, 2022
1 parent 083573b commit ecbe0af
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 11 deletions.
26 changes: 15 additions & 11 deletions shiny/ui/_navs.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,34 +45,34 @@ def render(
Add appropriate tag attributes to nav/content tags when linking to internal content.
"""

x = copy.copy(self)

# Nothing to do for nav_item()/nav_spacer()
if x.content is None:
return x.nav, None
if self.content is None:
return self

# At least currently, in the case where both nav and content are tags
# (i.e., nav()), the nav always has a child <a> tag...I'm not sure if
# there's a way to statically type this
a_tag = cast(Tag, x.nav.children[0])
nav = copy.deepcopy(self.nav)
a_tag = cast(Tag, nav.children[0])
if is_menu:
a_tag.add_class("dropdown-item")
else:
a_tag.add_class("nav-link")
x.nav.add_class("nav-item")
nav.add_class("nav-item")

# Hyperlink the nav to the content
x.content.attrs["id"] = id
content = copy.copy(self.content)
content.attrs["id"] = id
a_tag.attrs["href"] = f"#{id}"

# Mark the nav/content as active if it should be
if isinstance(selected, str) and selected == self.get_value():
x.content.add_class("active")
content.add_class("active")
a_tag.add_class("active")

x.nav.children[0] = a_tag
nav.children[0] = a_tag

return x.nav, x.content
return nav, content

def get_value(self) -> Optional[str]:
if self.content is None:
Expand Down Expand Up @@ -264,6 +264,10 @@ def render(self, selected: Optional[str], **kwargs: Any) -> Tuple[Tag, TagList]:
)

def get_value(self) -> Optional[str]:
for x in self.nav_items:
val = x.get_value()
if val:
return val
return None


Expand Down Expand Up @@ -748,7 +752,7 @@ def navs_bar(
nav = div(nav, id=collapse_id, class_="collapse navbar-collapse")

nav_container.append(nav)
nav_final = tags.nav({"class": "navbar"}, nav_container)
nav_final = tags.nav({"class": "navbar navbar-expand-md"}, nav_container)

if position != "static-top":
nav_final.add_class(position)
Expand Down
175 changes: 175 additions & 0 deletions tests/test_navs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import pytest

import random
import textwrap
from typing import Callable, Any, Union

from shiny import ui
from shiny._utils import private_seed
from htmltools import Tag, TagList


# Fix the randomness of these functions to make the tests deterministic
def with_private_seed(
func: Callable[[], Union[Tag, TagList]], *args: Any, **kwargs: Any
):
with private_seed():
random.seed(0)
return func(*args, **kwargs)


def test_nav_markup():
a = ui.nav("a", "a")
b = ui.nav("b", "b")
c = ui.nav("c", "c")
menu = ui.nav_menu(
"Menu",
c,
"----",
"Plain text",
"----",
ui.nav_item("Other item"),
)

x = with_private_seed(ui.navs_tab, a, b, ui.nav_item("Some item"), menu)

assert x.render()["html"] == textwrap.dedent(
"""\
<ul class="nav nav-tabs" data-tabsetid="7311">
<li class="nav-item">
<a data-bs-toggle="tab" data-value="a" role="tab" class="nav-link active" href="#tab-7311-0">a</a>
</li>
<li class="nav-item">
<a data-bs-toggle="tab" data-value="b" role="tab" class="nav-link" href="#tab-7311-1">b</a>
</li>
<li>Some item</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle " data-bs-toggle="dropdown" href="#" role="button">Menu</a>
<ul class="dropdown-menu " data-tabsetid="7890">
<li>
<a data-bs-toggle="tab" data-value="c" role="tab" class="dropdown-item" href="#tab-7890-0">c</a>
</li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">Plain text</li>
<li class="dropdown-divider"></li>
<li>Other item</li>
</ul>
</li>
</ul>
<div class="tab-content" data-tabsetid="7311">
<div class="tab-pane active" role="tabpanel" data-value="a" id="tab-7311-0">a</div>
<div class="tab-pane" role="tabpanel" data-value="b" id="tab-7311-1">b</div>
<div class="tab-pane" role="tabpanel" data-value="c" id="tab-7890-0">c</div>
</div>"""
)

x = with_private_seed(
ui.navs_pill,
menu,
a,
id="navs_pill_id",
)

assert x.render()["html"] == textwrap.dedent(
"""\
<ul class="nav nav-pills shiny-tab-input" id="navs_pill_id" data-tabsetid="7311">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle active" data-bs-toggle="dropdown" href="#" role="button">Menu</a>
<ul class="dropdown-menu " data-tabsetid="7890">
<li>
<a data-bs-toggle="tab" data-value="c" role="tab" class="dropdown-item active" href="#tab-7890-0">c</a>
</li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">Plain text</li>
<li class="dropdown-divider"></li>
<li>Other item</li>
</ul>
</li>
<li class="nav-item">
<a data-bs-toggle="tab" data-value="a" role="tab" class="nav-link" href="#tab-7311-1">a</a>
</li>
</ul>
<div class="tab-content" data-tabsetid="7311">
<div class="tab-pane active" role="tabpanel" data-value="c" id="tab-7890-0">c</div>
<div class="tab-pane" role="tabpanel" data-value="a" id="tab-7311-1">a</div>
</div>"""
)

x = with_private_seed(
ui.navs_pill_card,
a,
ui.nav_menu("Menu", c),
b,
selected="c",
)

assert x.render()["html"] == textwrap.dedent(
"""\
<div class="card">
<div class="card-header">
<ul class="nav nav-pills card-header-pills" data-tabsetid="7311">
<li class="nav-item">
<a data-bs-toggle="tab" data-value="a" role="tab" class="nav-link" href="#tab-7311-0">a</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle active" data-bs-toggle="dropdown" href="#" role="button">Menu</a>
<ul class="dropdown-menu " data-tabsetid="7890">
<li>
<a data-bs-toggle="tab" data-value="c" role="tab" class="dropdown-item active" href="#tab-7890-0">c</a>
</li>
</ul>
</li>
<li class="nav-item">
<a data-bs-toggle="tab" data-value="b" role="tab" class="nav-link" href="#tab-7311-2">b</a>
</li>
</ul>
</div>
<div class="card-body">
<div class="tab-content" data-tabsetid="7311">
<div class="tab-pane" role="tabpanel" data-value="a" id="tab-7311-0">a</div>
<div class="tab-pane active" role="tabpanel" data-value="c" id="tab-7890-0">c</div>
<div class="tab-pane" role="tabpanel" data-value="b" id="tab-7311-2">b</div>
</div>
</div>
</div>"""
)

x = with_private_seed(
ui.navs_bar, # type: ignore
ui.nav_menu("Menu", "Plain text", c),
title="Page title",
footer="Page footer",
header="Page header",
)

assert x.render()["html"] == textwrap.dedent(
"""\
<nav class="navbar navbar-expand-md">
<div class="container-fluid">
<a class="navbar-brand" href="#">Page title</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar-collapse-1663" aria-controls="navbar-collapse-1663" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div id="navbar-collapse-1663" class="collapse navbar-collapse">
<ul class="nav navbar-nav" data-tabsetid="7311">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle active" data-bs-toggle="dropdown" href="#" role="button">Menu</a>
<ul class="dropdown-menu " data-tabsetid="7890">
<li class="dropdown-header">Plain text</li>
<li>
<a data-bs-toggle="tab" data-value="c" role="tab" class="dropdown-item active" href="#tab-7890-1">c</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="row">Page header</div>
<div class="tab-content" data-tabsetid="7311">
<div class="tab-pane active" role="tabpanel" data-value="c" id="tab-7890-1">c</div>
</div>
<div class="row">Page footer</div>
</div>"""
)

0 comments on commit ecbe0af

Please sign in to comment.