Skip to content

Commit

Permalink
tests(sidebar): Add tests for sidebar (#1715)
Browse files Browse the repository at this point in the history
  • Loading branch information
karangattu authored Oct 4, 2024
1 parent ead102a commit fa9f8d4
Show file tree
Hide file tree
Showing 4 changed files with 300 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* Small improvements to the default pulse busy indicator to better blend with any background. It's also now slightly smaller by default.(#1707)

* Added `.expect_class()`, `.expect_gap()`, `.expect_bg_color()`, `.expect_desktop_state()`, `.expect_mobile_state()`, `.expect_mobile_max_height()`, `.expect_title()`, and `.expect_padding()` for `Sidebar` in `shiny.playwright.controllers` (#1715)

* Modified `.expect_text()` for `Sidebar` in `shiny.playwright.controllers` to use `.loc_content` instead of `loc` for text. Also modified `.expect_width()` to check the `.loc_container`'s style instead of the `.loc` element. (#1715)

* Modified `.expect_text()` and `.expect_width()` for `Sidebar` in `shiny.playwright.controllers` to use `loc_content` instead of `loc` for text. (#1715)

* Added `.expect_class()` and `.expect_multiple()` for `Accordion` in `shiny.playwright.controllers` (#1710)

* Added [narwhals](https://posit-dev.github.io/py-narwhals) support for `@render.table`. This allows for any eager data frame supported by narwhals to be returned from a `@render.table` output method. (#1570)
Expand Down
179 changes: 176 additions & 3 deletions shiny/playwright/controller/_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
from playwright.sync_api import expect as playwright_expect

from .._types import PatternOrStr, Timeout
from ..expect._internal import (
expect_attribute_to_have_value as _expect_attribute_to_have_value,
)
from ..expect._internal import expect_class_to_have_value as _expect_class_to_have_value
from ._base import UiWithContainer, WidthLocM
from ..expect._internal import expect_style_to_have_value as _expect_style_to_have_value
from ._base import UiWithContainer


class Sidebar(
WidthLocM,
UiWithContainer,
):
"""Controller for :func:`shiny.ui.sidebar`."""
Expand All @@ -32,6 +35,14 @@ class Sidebar(
"""
Playwright `Locator` for the position of the sidebar.
"""
loc_content: Locator
"""
Playwright `Locator` for the content of the sidebar.
"""
loc_title: Locator
"""
Playwright `Locator` for the title of the sidebar.
"""

def __init__(self, page: Page, id: str) -> None:
"""
Expand All @@ -52,6 +63,8 @@ def __init__(self, page: Page, id: str) -> None:
)
self.loc_handle = self.loc_container.locator("button.collapse-toggle")
self.loc_position = self.loc.locator("..")
self.loc_content = self.loc.locator("> div.sidebar-content")
self.loc_title = self.loc_content.locator("> header.sidebar-title")

def expect_text(self, value: PatternOrStr, *, timeout: Timeout = None) -> None:
"""
Expand All @@ -64,7 +77,167 @@ def expect_text(self, value: PatternOrStr, *, timeout: Timeout = None) -> None:
timeout
The maximum time to wait for the text to appear. Defaults to `None`.
"""
playwright_expect(self.loc).to_have_text(value, timeout=timeout)
playwright_expect(self.loc_content).to_have_text(value, timeout=timeout)

def expect_class(
self,
class_name: str,
*,
has_class: bool = True,
timeout: Timeout = None,
) -> None:
"""
Asserts that the sidebar has or does not have a CSS class.
Parameters
----------
class_name
The CSS class to check for.
has_class
`True` if the sidebar should have the CSS class, `False` otherwise.
timeout
The maximum time to wait for the sidebar to appear. Defaults to `None`.
"""
_expect_class_to_have_value(
self.loc,
class_name,
has_class=has_class,
timeout=timeout,
)

def expect_width(self, value: PatternOrStr, *, timeout: Timeout = None) -> None:
"""
Asserts that the sidebar has the expected width.
Parameters
----------
value
The expected width of the sidebar.
timeout
The maximum time to wait for the width to appear. Defaults to `None`.
"""
_expect_style_to_have_value(
self.loc_container, "--_sidebar-width", value, timeout=timeout
)

def expect_gap(self, value: PatternOrStr, *, timeout: Timeout = None) -> None:
"""
Asserts that the sidebar has the expected gap.
Parameters
----------
value
The expected gap of the sidebar.
timeout
The maximum time to wait for the gap to appear. Defaults to `None`.
"""
_expect_style_to_have_value(self.loc_content, "gap", value, timeout=timeout)

def expect_bg_color(self, value: PatternOrStr, *, timeout: Timeout = None) -> None:
"""
Asserts that the sidebar has the expected background color.
Parameters
----------
value
The expected background color of the sidebar.
timeout
The maximum time to wait for the background color to appear. Defaults to `None`.
"""
_expect_style_to_have_value(
self.loc_container, "--_sidebar-bg", value, timeout=timeout
)

def expect_desktop_state(
self, value: Literal["open", "closed", "always"], *, timeout: Timeout = None
) -> None:
"""
Asserts that the sidebar has the expected state on desktop.
Parameters
----------
value
The expected state of the sidebar on desktop.
timeout
The maximum time to wait for the state to appear. Defaults to `None`.
"""
_expect_attribute_to_have_value(
self.loc_container,
name="data-open-desktop",
value=value,
timeout=timeout,
)

def expect_mobile_state(
self, value: Literal["open", "closed", "always"], *, timeout: Timeout = None
) -> None:
"""
Asserts that the sidebar has the expected state on mobile.
Parameters
----------
value
The expected state of the sidebar on mobile.
timeout
The maximum time to wait for the state to appear. Defaults to `None`.
"""
_expect_attribute_to_have_value(
self.loc_container,
name="data-open-mobile",
value=value,
timeout=timeout,
)

def expect_mobile_max_height(
self, value: PatternOrStr, *, timeout: Timeout = None
) -> None:
"""
Asserts that the sidebar has the expected maximum height on mobile.
Parameters
----------
value
The expected maximum height of the sidebar on mobile.
timeout
The maximum time to wait for the maximum height to appear. Defaults to `None`.
"""
self.expect_mobile_state("always", timeout=timeout)
_expect_style_to_have_value(
self.loc_container, "--_mobile-max-height", value, timeout=timeout
)

def expect_title(self, value: PatternOrStr, *, timeout: Timeout = None) -> None:
"""
Asserts that the sidebar has the expected title.
Parameters
----------
value
The expected title of the sidebar.
timeout
The maximum time to wait for the title to appear. Defaults to `None`.
"""
playwright_expect(self.loc_title).to_have_text(value, timeout=timeout)

def expect_padding(
self, value: str | list[str], *, timeout: Timeout = None
) -> None:
"""
Asserts that the sidebar has the expected padding.
Parameters
----------
value
The expected padding of the sidebar.
timeout
The maximum time to wait for the padding to appear. Defaults to `None`.
"""
if not isinstance(value, list):
value = [value]
padding_val = " ".join(value)
_expect_style_to_have_value(
self.loc_content, "padding", padding_val, timeout=timeout
)

def expect_position(
self,
Expand Down
68 changes: 68 additions & 0 deletions tests/playwright/shiny/inputs/sidebar_kitchensink/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from shiny.express import input, render, ui

ui.page_opts(fillable=True)

with ui.card():
with ui.layout_sidebar():
with ui.sidebar(
id="sidebar_left",
open="desktop",
title="Left sidebar",
bg="dodgerBlue",
class_="text-white",
gap="20px",
padding="10px",
width="200px",
):
"Left sidebar content"

@render.code
def state_left():
return f"input.sidebar_left(): {input.sidebar_left()}"


with ui.card():
with ui.layout_sidebar():
with ui.sidebar(
id="sidebar_right",
position="right",
open={"desktop": "closed", "mobile": "open"},
padding=["10px", "20px"],
bg="SlateBlue",
):
"Right sidebar content"

@render.code
def state_right():
return f"input.sidebar_right(): {input.sidebar_right()}"


with ui.card():
with ui.layout_sidebar():
with ui.sidebar(
id="sidebar_closed",
open="closed",
bg="LightCoral",
padding=["10px", "20px", "30px"],
):
"Closed sidebar content"

@render.code
def state_closed():
return f"input.sidebar_closed(): {input.sidebar_closed()}"


with ui.card():
with ui.layout_sidebar():
with ui.sidebar(
id="sidebar_always",
open="always",
bg="PeachPuff",
padding=["10px", "20px", "30px", "40px"],
max_height_mobile="175px",
):
"Always sidebar content"

@render.code
def state_always():
return f"input.sidebar_always(): {input.sidebar_always()}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from playwright.sync_api import Page

from shiny.playwright import controller
from shiny.run import ShinyAppProc


def test_sidebar_kitchensink(page: Page, local_app: ShinyAppProc) -> None:
page.goto(local_app.url)

left_sidebar = controller.Sidebar(page, "sidebar_left")
output_txt_left = controller.OutputTextVerbatim(page, "state_left")
left_sidebar.set(True)
left_sidebar.expect_padding("10px")
left_sidebar.expect_padding(["10px"])
left_sidebar.expect_title("Left sidebar")
left_sidebar.expect_gap("20px")
left_sidebar.expect_class("text-white", has_class=True)
left_sidebar.expect_bg_color("dodgerBlue")
left_sidebar.expect_desktop_state("open")
left_sidebar.expect_mobile_state("closed")
left_sidebar.expect_width("200px")
output_txt_left.expect_value("input.sidebar_left(): True")
left_sidebar.expect_open(True)
left_sidebar.set(False)
output_txt_left.expect_value("input.sidebar_left(): False")
left_sidebar.expect_handle(True)
left_sidebar.expect_open(False)
left_sidebar.loc_handle.click()
left_sidebar.expect_open(True)
output_txt_left.expect_value("input.sidebar_left(): True")

right_sidebar = controller.Sidebar(page, "sidebar_right")
right_sidebar.expect_padding(["10px", "20px"])
right_sidebar.expect_bg_color("SlateBlue")
right_sidebar.expect_mobile_state("open")
right_sidebar.expect_desktop_state("closed")

closed_sidebar = controller.Sidebar(page, "sidebar_closed")
closed_sidebar.expect_padding(["10px", "20px", "30px"])
closed_sidebar.expect_bg_color("LightCoral")
closed_sidebar.expect_mobile_state("closed")
closed_sidebar.expect_desktop_state("closed")

always_sidebar = controller.Sidebar(page, "sidebar_always")
always_sidebar.expect_padding(["10px", "20px", "30px", "40px"])
always_sidebar.expect_bg_color("PeachPuff")
always_sidebar.expect_open(True)
always_sidebar.expect_desktop_state("always")
always_sidebar.expect_mobile_state("always")
always_sidebar.expect_mobile_max_height("175px")

0 comments on commit fa9f8d4

Please sign in to comment.