112 lines
3.6 KiB
Python
112 lines
3.6 KiB
Python
import pytest
|
|
from fasthtml.components import Div
|
|
|
|
from components.undo_redo.components.UndoRedo import UndoRedo, CommandHistory
|
|
from core.settings_management import SettingsManager, MemoryDbEngine
|
|
from helpers import matches, div_icon, Contains, DoesNotContain
|
|
from my_mocks import tabs_manager
|
|
|
|
|
|
class UndoableCommand(CommandHistory):
|
|
def __init__(self, old_value=0, new_value=0):
|
|
super().__init__("Set new value", lambda value: f"Setting new value to {value}", None)
|
|
self.old_value = old_value
|
|
self.new_value = new_value
|
|
|
|
def undo(self):
|
|
return Div(self.old_value, hx_swap_oob="true")
|
|
|
|
def redo(self):
|
|
return Div(self.new_value, hx_swap_oob="true")
|
|
|
|
|
|
@pytest.fixture
|
|
def undo_redo(session, tabs_manager):
|
|
return UndoRedo(session,
|
|
UndoRedo.create_component_id(session),
|
|
settings_manager=SettingsManager(engine=MemoryDbEngine()),
|
|
tabs_manager=tabs_manager)
|
|
|
|
|
|
def test_i_can_render(undo_redo):
|
|
actual = undo_redo.__ft__()
|
|
expected = Div(
|
|
Div(div_icon("undo", cls=Contains("mmt-btn-disabled")), data_tooltip="Nothing to undo."),
|
|
Div(div_icon("redo", cls=Contains("mmt-btn-disabled")), data_tooltip="Nothing to redo."),
|
|
id=undo_redo.get_id(),
|
|
)
|
|
|
|
assert matches(actual, expected)
|
|
|
|
|
|
def test_i_can_render_when_undoing_and_redoing(undo_redo):
|
|
undo_redo.push(UndoableCommand(0, 1))
|
|
undo_redo.push(UndoableCommand(1, 2))
|
|
|
|
actual = undo_redo.__ft__()
|
|
expected = Div(
|
|
Div(div_icon("undo", cls=DoesNotContain("mmt-btn-disabled")), data_tooltip="Undo 'Set new value'."),
|
|
Div(div_icon("redo", cls=Contains("mmt-btn-disabled")), data_tooltip="Nothing to redo."),
|
|
id=undo_redo.get_id(),
|
|
)
|
|
assert matches(actual, expected)
|
|
|
|
undo_redo.undo() # The command is now undone. We can redo it and undo the first command.
|
|
actual = undo_redo.__ft__()
|
|
expected = Div(
|
|
Div(div_icon("undo", cls=DoesNotContain("mmt-btn-disabled")), data_tooltip="Undo 'Set new value'."),
|
|
Div(div_icon("redo", cls=DoesNotContain("mmt-btn-disabled")), data_tooltip="Redo 'Set new value'."),
|
|
id=undo_redo.get_id(),
|
|
)
|
|
assert matches(actual, expected)
|
|
|
|
undo_redo.undo() # Undo again, I cannot undo anymore.
|
|
actual = undo_redo.__ft__()
|
|
expected = Div(
|
|
Div(div_icon("undo", cls=Contains("mmt-btn-disabled"))),
|
|
Div(div_icon("redo", cls=DoesNotContain("mmt-btn-disabled"))),
|
|
id=undo_redo.get_id(),
|
|
)
|
|
assert matches(actual, expected)
|
|
|
|
undo_redo.redo() # Redo once.
|
|
actual = undo_redo.__ft__()
|
|
expected = Div(
|
|
Div(div_icon("undo", cls=DoesNotContain("mmt-btn-disabled"))),
|
|
Div(div_icon("redo", cls=DoesNotContain("mmt-btn-disabled"))),
|
|
id=undo_redo.get_id(),
|
|
)
|
|
assert matches(actual, expected)
|
|
|
|
undo_redo.redo() # Redo a second time.
|
|
actual = undo_redo.__ft__()
|
|
expected = Div(
|
|
Div(div_icon("undo", cls=DoesNotContain("mmt-btn-disabled"))),
|
|
Div(div_icon("redo", cls=Contains("mmt-btn-disabled"))),
|
|
id=undo_redo.get_id(),
|
|
)
|
|
assert matches(actual, expected)
|
|
|
|
|
|
def test_i_can_undo_and_redo(undo_redo):
|
|
undo_redo.push(UndoableCommand(0, 1))
|
|
undo_redo.push(UndoableCommand(1, 2))
|
|
|
|
self, res = undo_redo.undo()
|
|
expected = Div(1, hx_swap_oob="true")
|
|
assert matches(res, expected)
|
|
|
|
self, res = undo_redo.redo()
|
|
expected = Div(2, hx_swap_oob="true")
|
|
assert matches(res, expected)
|
|
|
|
def test_history_is_rewritten_when_pushing_a_command(undo_redo):
|
|
undo_redo.push(UndoableCommand(0, 1))
|
|
undo_redo.push(UndoableCommand(1, 2))
|
|
undo_redo.push(UndoableCommand(2, 3))
|
|
|
|
undo_redo.undo()
|
|
undo_redo.undo()
|
|
undo_redo.push(UndoableCommand(1, 5))
|
|
|
|
assert len(undo_redo.history) == 2 |