Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions nicegui/testing/user_interaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from nicegui.element import Element
from nicegui.elements.mixins.disableable_element import DisableableElement
from nicegui.elements.mixins.value_element import ValueElement
from nicegui.elements.sub_pages import SubPages

if TYPE_CHECKING:
from .user import User
Expand Down Expand Up @@ -72,6 +73,21 @@ def click(self) -> Self:
for element in self.elements:
if isinstance(element, ui.link):
href = element.props.get('href', '#')
target = element.props.get('target', '_self')
if target == '_blank':
background_tasks.create(self.user.open(href), name=f'open {href}')
return self
if href.startswith('/'):
sub_pages_elements = [el for el in self.user.client.layout.descendants()
if isinstance(el, SubPages)]
if sub_pages_elements:
async def navigate_with_history(path: str = href):
with self.user.client:
await self.user.client.sub_pages_router._handle_navigate(path) # pylint: disable=protected-access
self.user.back_history.append(path)
self.user.forward_history.clear()
background_tasks.create(navigate_with_history(), name=f'navigate to {href}')
return self
background_tasks.create(self.user.open(href), name=f'open {href}')
return self

Expand Down
18 changes: 16 additions & 2 deletions nicegui/testing/user_navigate.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from nicegui import Client, background_tasks
from nicegui.element import Element
from nicegui.elements.sub_pages import SubPages
from nicegui.functions.navigate import Navigate

if TYPE_CHECKING:
Expand All @@ -27,16 +28,29 @@ def back(self) -> None:
current = self.user.back_history.pop()
self.user.forward_history.append(current)
target = self.user.back_history.pop()
background_tasks.create(self.user.open(target, clear_forward_history=False), name=f'navigate back to {target}')
background_tasks.create(self._navigate_to(target, clear_forward_history=False),
name=f'navigate back to {target}')

def forward(self) -> None:
if not self.user.forward_history:
return
target = self.user.forward_history[0]
del self.user.forward_history[0]
background_tasks.create(self.user.open(target, clear_forward_history=False),
background_tasks.create(self._navigate_to(target, clear_forward_history=False),
name=f'navigate forward to {target}')

async def _navigate_to(self, path: str, clear_forward_history: bool = True) -> None:
if self.user.client:
sub_pages_elements = [el for el in self.user.client.layout.descendants() if isinstance(el, SubPages)]
if sub_pages_elements:
with self.user.client:
await self.user.client.sub_pages_router._handle_open(path) # pylint: disable=protected-access
if clear_forward_history:
self.user.forward_history.clear()
self.user.back_history.append(path)
return
await self.user.open(path, clear_forward_history=clear_forward_history)

def reload(self) -> None:
target = self.user.back_history.pop()
background_tasks.create(self.user.open(target, clear_forward_history=False),
Expand Down
96 changes: 96 additions & 0 deletions tests/test_user_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,3 +661,99 @@ def page():
await user.should_not_see('A1')
await user.should_not_see('A21')
await user.should_not_see('A22')


async def test_switching_between_sub_pages(user: User) -> None:
calls = {'index': 0, 'a': 0, 'b': 0}

@ui.page('/')
@ui.page('/b')
def index():
calls['index'] += 1
ui.label('Index')
ui.button('back', on_click=ui.navigate.back)
ui.button('forward', on_click=ui.navigate.forward)
ui.sub_pages({
'/': sub_page_a,
'/b': sub_page_b,
})

def sub_page_a():
calls['a'] += 1
ui.label('Page A')
ui.link('Go to B', '/b')
ui.link('Go to B with slash', '/b/')

def sub_page_b():
calls['b'] += 1
ui.label('Page B')
ui.link('Go to A', '/')
ui.link('Go to B with slash', '/b/')

await user.open('/')
await user.should_see('Index')
await user.should_see('Page A')
await user.should_not_see('Page B')
assert calls == {'index': 1, 'a': 1, 'b': 0}

user.find('Go to B').click()
await user.should_see('Index')
await user.should_see('Page B')
await user.should_not_see('Page A')
assert calls == {'index': 1, 'a': 1, 'b': 1}

user.find('back').click()
await user.should_see('Index')
await user.should_see('Page A')
await user.should_not_see('Page B')
assert calls == {'index': 1, 'a': 2, 'b': 1}

user.find('forward').click()
await user.should_see('Index')
await user.should_see('Page B')
await user.should_not_see('Page A')
assert calls == {'index': 1, 'a': 2, 'b': 2}

user.find('Go to A').click()
await user.should_see('Page A')
assert calls == {'index': 1, 'a': 3, 'b': 2}
user.find('Go to B with slash').click()
await user.should_see('Page B')
assert calls == {'index': 1, 'a': 3, 'b': 3}

user.find('Go to B with slash').click()
await user.should_see('Page B')
assert calls == {'index': 1, 'a': 3, 'b': 3}, 'no rebuilding if path stays the same'


async def test_sub_pages_with_fragments(user: User) -> None:
calls = {'index': 0, 'page': 0}

@ui.page('/')
@ui.page('/{_:path}')
def index():
calls['index'] += 1
ui.sub_pages({
'/': main_page,
'/page': content_page,
})

def main_page():
ui.label('Main')

def content_page():
calls['page'] += 1
ui.link_target('top')
ui.label('Top content')
ui.link('Go to bottom', '/page#bottom')
ui.link_target('bottom')
ui.label('Bottom content')
ui.link('Go to top', '/page#top')

await user.open('/page#bottom')
await user.should_see('Bottom content')
assert calls == {'index': 1, 'page': 1}

user.find('Go to top').click()
await user.should_see('Top content')
assert calls == {'index': 1, 'page': 1}, 'same-page fragment navigation should not rebuild'
Loading