Fixed unit tests
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from fastcore.xml import FT
|
||||||
from fasthtml.components import *
|
from fasthtml.components import *
|
||||||
|
|
||||||
from components.BaseComponent import BaseComponentSingleton
|
from components.BaseComponent import BaseComponentSingleton
|
||||||
@@ -8,6 +9,7 @@ from components.undo_redo.assets.icons import icon_redo, icon_undo
|
|||||||
from components.undo_redo.commands import UndoRedoCommandManager
|
from components.undo_redo.commands import UndoRedoCommandManager
|
||||||
from components.undo_redo.constants import UNDO_REDO_INSTANCE_ID, UndoRedoAttrs
|
from components.undo_redo.constants import UNDO_REDO_INSTANCE_ID, UndoRedoAttrs
|
||||||
from components_helpers import mk_icon, mk_tooltip
|
from components_helpers import mk_icon, mk_tooltip
|
||||||
|
from core.settings_management import NoDefault
|
||||||
|
|
||||||
logger = logging.getLogger("UndoRedoApp")
|
logger = logging.getLogger("UndoRedoApp")
|
||||||
|
|
||||||
@@ -64,13 +66,19 @@ class UndoRedo(BaseComponentSingleton):
|
|||||||
previous_state = self._settings_manager.load(self._session, None, digest=previous.digest)
|
previous_state = self._settings_manager.load(self._session, None, digest=previous.digest)
|
||||||
|
|
||||||
# reapply the state
|
# reapply the state
|
||||||
current_state[current.key] = previous_state[current.key]
|
if previous_state is not NoDefault:
|
||||||
|
current_state[current.key] = previous_state[current.key]
|
||||||
|
else:
|
||||||
|
del current_state[current.key]
|
||||||
self._settings_manager.save(self._session, current.entry, current_state)
|
self._settings_manager.save(self._session, current.entry, current_state)
|
||||||
|
|
||||||
self.index -= 1
|
self.index -= 1
|
||||||
|
|
||||||
if current.attrs.on_undo is not None:
|
if current.attrs.on_undo is not None:
|
||||||
return self, current.attrs.on_undo()
|
ret = current.attrs.on_undo()
|
||||||
|
if isinstance(ret, FT) and 'id' in ret.attrs:
|
||||||
|
ret.attrs["hx-swap-oob"] = "true"
|
||||||
|
return self, ret
|
||||||
else:
|
else:
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@@ -87,13 +95,19 @@ class UndoRedo(BaseComponentSingleton):
|
|||||||
next_state = self._settings_manager.load(self._session, None, digest=next_.digest)
|
next_state = self._settings_manager.load(self._session, None, digest=next_.digest)
|
||||||
|
|
||||||
# reapply the state
|
# reapply the state
|
||||||
current_state[current.key] = next_state[current.key]
|
if current_state is not NoDefault:
|
||||||
|
current_state[current.key] = next_state[current.key]
|
||||||
|
else:
|
||||||
|
current_state = {current.key : next_state[current.key]}
|
||||||
self._settings_manager.save(self._session, current.entry, current_state)
|
self._settings_manager.save(self._session, current.entry, current_state)
|
||||||
|
|
||||||
self.index += 1
|
self.index += 1
|
||||||
|
|
||||||
if current.attrs.on_undo is not None:
|
if current.attrs.on_redo is not None:
|
||||||
return self, current.attrs.on_redo()
|
ret = current.attrs.on_undo()
|
||||||
|
if isinstance(ret, FT) and 'id' in ret.attrs:
|
||||||
|
ret.attrs["hx-swap-oob"] = "true"
|
||||||
|
return self, ret
|
||||||
else:
|
else:
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@@ -125,7 +139,7 @@ class UndoRedo(BaseComponentSingleton):
|
|||||||
|
|
||||||
def _mk_redo(self):
|
def _mk_redo(self):
|
||||||
if self._can_redo():
|
if self._can_redo():
|
||||||
command = self.history[self.index]
|
command = self.history[self.index + 1]
|
||||||
return mk_tooltip(mk_icon(icon_redo,
|
return mk_tooltip(mk_icon(icon_redo,
|
||||||
size=24,
|
size=24,
|
||||||
**self._commands.redo()),
|
**self._commands.redo()),
|
||||||
|
|||||||
@@ -1,20 +1,66 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from fasthtml.components import Div
|
from fasthtml.components import Div
|
||||||
|
|
||||||
from components.undo_redo.components.UndoRedo import UndoRedo
|
from components.undo_redo.components.UndoRedo import UndoRedo
|
||||||
|
from components.undo_redo.constants import UndoRedoAttrs
|
||||||
|
from core.dbengine import DbEngine
|
||||||
from core.settings_management import SettingsManager, MemoryDbEngine
|
from core.settings_management import SettingsManager, MemoryDbEngine
|
||||||
from helpers import matches, div_icon, Contains, DoesNotContain
|
from helpers import matches, div_icon, Contains, DoesNotContain
|
||||||
from my_mocks import tabs_manager
|
from my_mocks import tabs_manager
|
||||||
|
|
||||||
|
DB_ENGINE_ROOT = "undo_redo_test_db"
|
||||||
|
TEST_DB_ENTRY = "TestDbEntry"
|
||||||
|
TEST_DB_KEY = "TestDbKey"
|
||||||
|
|
||||||
|
|
||||||
|
class TestCommand:
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if not isinstance(other, TestCommand):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return self.value == other.value
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.value)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def engine(session):
|
||||||
|
if os.path.exists(DB_ENGINE_ROOT):
|
||||||
|
shutil.rmtree(DB_ENGINE_ROOT)
|
||||||
|
|
||||||
|
engine = DbEngine(DB_ENGINE_ROOT)
|
||||||
|
engine.init(session["user_id"])
|
||||||
|
|
||||||
|
yield engine
|
||||||
|
|
||||||
|
shutil.rmtree(DB_ENGINE_ROOT)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def settings_manager(engine):
|
||||||
|
return SettingsManager(engine=engine)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def undo_redo(session, tabs_manager):
|
def undo_redo(session, tabs_manager, settings_manager):
|
||||||
return UndoRedo(session,
|
return UndoRedo(session,
|
||||||
UndoRedo.create_component_id(session),
|
UndoRedo.create_component_id(session),
|
||||||
settings_manager=SettingsManager(engine=MemoryDbEngine()),
|
settings_manager=settings_manager,
|
||||||
tabs_manager=tabs_manager)
|
tabs_manager=tabs_manager)
|
||||||
|
|
||||||
|
|
||||||
|
def init_command(session, settings_manager, undo_redo, value, on_undo=None):
|
||||||
|
settings_manager.save(session, TEST_DB_ENTRY, {TEST_DB_KEY: TestCommand(value)})
|
||||||
|
undo_redo.snapshot(UndoRedoAttrs(f"Set value to {value}", on_undo=on_undo), TEST_DB_ENTRY, TEST_DB_KEY)
|
||||||
|
|
||||||
|
|
||||||
def test_i_can_render(undo_redo):
|
def test_i_can_render(undo_redo):
|
||||||
actual = undo_redo.__ft__()
|
actual = undo_redo.__ft__()
|
||||||
expected = Div(
|
expected = Div(
|
||||||
@@ -26,13 +72,13 @@ def test_i_can_render(undo_redo):
|
|||||||
assert matches(actual, expected)
|
assert matches(actual, expected)
|
||||||
|
|
||||||
|
|
||||||
def test_i_can_render_when_undoing_and_redoing(undo_redo):
|
def test_i_can_render_when_undoing_and_redoing(session, settings_manager, undo_redo):
|
||||||
undo_redo.push(UndoableCommand(0, 1))
|
init_command(session, settings_manager, undo_redo, "1")
|
||||||
undo_redo.push(UndoableCommand(1, 2))
|
init_command(session, settings_manager, undo_redo, "2")
|
||||||
|
|
||||||
actual = undo_redo.__ft__()
|
actual = undo_redo.__ft__()
|
||||||
expected = Div(
|
expected = Div(
|
||||||
Div(div_icon("undo", cls=DoesNotContain("mmt-btn-disabled")), data_tooltip="Undo 'Set new value'."),
|
Div(div_icon("undo", cls=DoesNotContain("mmt-btn-disabled")), data_tooltip="Undo 'Set value to 2'."),
|
||||||
Div(div_icon("redo", cls=Contains("mmt-btn-disabled")), data_tooltip="Nothing to redo."),
|
Div(div_icon("redo", cls=Contains("mmt-btn-disabled")), data_tooltip="Nothing to redo."),
|
||||||
id=undo_redo.get_id(),
|
id=undo_redo.get_id(),
|
||||||
)
|
)
|
||||||
@@ -41,8 +87,8 @@ def test_i_can_render_when_undoing_and_redoing(undo_redo):
|
|||||||
undo_redo.undo() # The command is now undone. We can redo it and undo the first command.
|
undo_redo.undo() # The command is now undone. We can redo it and undo the first command.
|
||||||
actual = undo_redo.__ft__()
|
actual = undo_redo.__ft__()
|
||||||
expected = Div(
|
expected = Div(
|
||||||
Div(div_icon("undo", cls=DoesNotContain("mmt-btn-disabled")), data_tooltip="Undo 'Set new value'."),
|
Div(div_icon("undo", cls=DoesNotContain("mmt-btn-disabled")), data_tooltip="Undo 'Set value to 1'."),
|
||||||
Div(div_icon("redo", cls=DoesNotContain("mmt-btn-disabled")), data_tooltip="Redo 'Set new value'."),
|
Div(div_icon("redo", cls=DoesNotContain("mmt-btn-disabled")), data_tooltip="Redo 'Set value to 2'."),
|
||||||
id=undo_redo.get_id(),
|
id=undo_redo.get_id(),
|
||||||
)
|
)
|
||||||
assert matches(actual, expected)
|
assert matches(actual, expected)
|
||||||
@@ -75,26 +121,48 @@ def test_i_can_render_when_undoing_and_redoing(undo_redo):
|
|||||||
assert matches(actual, expected)
|
assert matches(actual, expected)
|
||||||
|
|
||||||
|
|
||||||
def test_i_can_undo_and_redo(undo_redo):
|
def test_values_are_correctly_reset(session, settings_manager, undo_redo):
|
||||||
undo_redo.push(UndoableCommand(0, 1))
|
# checks that the values are correctly returned
|
||||||
undo_redo.push(UndoableCommand(1, 2))
|
# Only checks that hx_swap_oob="true" is automatically put when id is present in the return
|
||||||
|
|
||||||
|
def on_undo():
|
||||||
|
current = settings_manager.get(session, TEST_DB_ENTRY, TEST_DB_KEY)
|
||||||
|
return Div(current.value, id='an_id')
|
||||||
|
|
||||||
|
init_command(session, settings_manager, undo_redo, "1", on_undo=on_undo)
|
||||||
|
init_command(session, settings_manager, undo_redo, "2", on_undo=on_undo)
|
||||||
|
|
||||||
self, res = undo_redo.undo()
|
self, res = undo_redo.undo()
|
||||||
expected = Div(1, hx_swap_oob="true")
|
expected = Div("1", id='an_id', hx_swap_oob="true")
|
||||||
assert matches(res, expected)
|
assert matches(res, expected)
|
||||||
|
|
||||||
self, res = undo_redo.redo()
|
self, res = undo_redo.redo()
|
||||||
expected = Div(2, hx_swap_oob="true")
|
expected = Div("2", id='an_id', hx_swap_oob="true")
|
||||||
assert matches(res, expected)
|
assert matches(res, expected)
|
||||||
|
|
||||||
|
|
||||||
def test_history_is_rewritten_when_pushing_a_command(undo_redo):
|
def test_i_can_manage_when_the_entry_was_not_present(session, settings_manager, undo_redo):
|
||||||
undo_redo.push(UndoableCommand(0, 1))
|
def on_undo():
|
||||||
undo_redo.push(UndoableCommand(1, 2))
|
snapshot = settings_manager.load(session, TEST_DB_ENTRY)
|
||||||
undo_redo.push(UndoableCommand(2, 3))
|
if TEST_DB_KEY in snapshot:
|
||||||
|
return Div(snapshot[TEST_DB_KEY].value, id='an_id')
|
||||||
|
else:
|
||||||
|
return Div("**Not Found**", id='an_id')
|
||||||
|
|
||||||
|
init_command(session, settings_manager, undo_redo, "1", on_undo=on_undo)
|
||||||
|
|
||||||
|
self, res = undo_redo.undo()
|
||||||
|
expected = Div("**Not Found**", id='an_id', hx_swap_oob="true")
|
||||||
|
assert matches(res, expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_history_is_rewritten_when_pushing_a_command_after_undo(session, settings_manager, undo_redo):
|
||||||
|
init_command(session, settings_manager, undo_redo, "1")
|
||||||
|
init_command(session, settings_manager, undo_redo, "2")
|
||||||
|
init_command(session, settings_manager, undo_redo, "3")
|
||||||
|
|
||||||
undo_redo.undo()
|
undo_redo.undo()
|
||||||
undo_redo.undo()
|
undo_redo.undo()
|
||||||
undo_redo.push(UndoableCommand(1, 5))
|
init_command(session, settings_manager, undo_redo, "5")
|
||||||
|
|
||||||
assert len(undo_redo.history) == 2
|
assert len(undo_redo.history) == 3 # do not forget that history always has a default command with digest = None
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from fastcore.basics import NotStr
|
from fastcore.basics import NotStr
|
||||||
from fasthtml.components import *
|
from fasthtml.components import *
|
||||||
from fasthtml.xtend import Script
|
from fasthtml.xtend import Script
|
||||||
|
|
||||||
|
from components.undo_redo.components.UndoRedo import UndoRedo
|
||||||
from components.workflows.components.WorkflowDesigner import WorkflowDesigner, COMPONENT_TYPES
|
from components.workflows.components.WorkflowDesigner import WorkflowDesigner, COMPONENT_TYPES
|
||||||
from components.workflows.constants import ProcessorTypes
|
from components.workflows.constants import ProcessorTypes
|
||||||
from components.workflows.db_management import WorkflowsDesignerSettings, WorkflowComponent, Connection
|
from components.workflows.db_management import WorkflowsDesignerSettings, WorkflowComponent, Connection
|
||||||
|
from core.instance_manager import InstanceManager
|
||||||
from core.settings_management import SettingsManager, MemoryDbEngine
|
from core.settings_management import SettingsManager, MemoryDbEngine
|
||||||
from helpers import matches, Contains
|
from helpers import matches, Contains
|
||||||
from my_mocks import tabs_manager
|
from my_mocks import tabs_manager
|
||||||
@@ -13,6 +17,27 @@ from my_mocks import tabs_manager
|
|||||||
TEST_WORKFLOW_DESIGNER_ID = "workflow_designer_id"
|
TEST_WORKFLOW_DESIGNER_ID = "workflow_designer_id"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def mock_undo_redo(session):
|
||||||
|
# Create a mock UndoRedo instance
|
||||||
|
undo_redo = MagicMock(spec=UndoRedo)
|
||||||
|
|
||||||
|
# Store original get method
|
||||||
|
original_get = InstanceManager.get
|
||||||
|
|
||||||
|
def mock_get(sess, instance_id, *args, **kwargs):
|
||||||
|
if instance_id == UndoRedo.create_component_id(sess):
|
||||||
|
return undo_redo
|
||||||
|
return original_get(sess, instance_id, *args, **kwargs)
|
||||||
|
|
||||||
|
# Replace get method with our mock
|
||||||
|
InstanceManager.get = mock_get
|
||||||
|
|
||||||
|
yield undo_redo
|
||||||
|
|
||||||
|
# Restore original get method after test
|
||||||
|
InstanceManager.get = original_get
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def designer(session, tabs_manager):
|
def designer(session, tabs_manager):
|
||||||
return WorkflowDesigner(session=session, _id=TEST_WORKFLOW_DESIGNER_ID,
|
return WorkflowDesigner(session=session, _id=TEST_WORKFLOW_DESIGNER_ID,
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ import pandas as pd
|
|||||||
import pytest
|
import pytest
|
||||||
from pandas.testing import assert_frame_equal
|
from pandas.testing import assert_frame_equal
|
||||||
|
|
||||||
|
from components.undo_redo.components.UndoRedo import UndoRedo
|
||||||
from components.workflows.components.WorkflowDesigner import COMPONENT_TYPES, WorkflowDesigner
|
from components.workflows.components.WorkflowDesigner import COMPONENT_TYPES, WorkflowDesigner
|
||||||
from components.workflows.components.WorkflowPlayer import WorkflowPlayer, WorkflowsPlayerError
|
from components.workflows.components.WorkflowPlayer import WorkflowPlayer, WorkflowsPlayerError
|
||||||
from components.workflows.constants import ProcessorTypes
|
from components.workflows.constants import ProcessorTypes
|
||||||
from components.workflows.db_management import WorkflowComponent, Connection, ComponentState, WorkflowsDesignerSettings
|
from components.workflows.db_management import WorkflowComponent, Connection, ComponentState, WorkflowsDesignerSettings
|
||||||
|
from core.instance_manager import InstanceManager
|
||||||
from core.settings_management import SettingsManager, MemoryDbEngine
|
from core.settings_management import SettingsManager, MemoryDbEngine
|
||||||
from my_mocks import tabs_manager
|
from my_mocks import tabs_manager
|
||||||
from workflow.engine import DataProcessorError
|
from workflow.engine import DataProcessorError
|
||||||
@@ -16,6 +18,27 @@ TEST_WORKFLOW_DESIGNER_ID = "workflow_designer_id"
|
|||||||
TEST_WORKFLOW_PLAYER_ID = "workflow_player_id"
|
TEST_WORKFLOW_PLAYER_ID = "workflow_player_id"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def mock_undo_redo(session):
|
||||||
|
# Create a mock UndoRedo instance
|
||||||
|
undo_redo = MagicMock(spec=UndoRedo)
|
||||||
|
|
||||||
|
# Store original get method
|
||||||
|
original_get = InstanceManager.get
|
||||||
|
|
||||||
|
def mock_get(sess, instance_id, *args, **kwargs):
|
||||||
|
if instance_id == UndoRedo.create_component_id(sess):
|
||||||
|
return undo_redo
|
||||||
|
return original_get(sess, instance_id, *args, **kwargs)
|
||||||
|
|
||||||
|
# Replace get method with our mock
|
||||||
|
InstanceManager.get = mock_get
|
||||||
|
|
||||||
|
yield undo_redo
|
||||||
|
|
||||||
|
# Restore original get method after test
|
||||||
|
InstanceManager.get = original_get
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def settings_manager():
|
def settings_manager():
|
||||||
return SettingsManager(MemoryDbEngine())
|
return SettingsManager(MemoryDbEngine())
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from fasthtml.components import *
|
from fasthtml.components import *
|
||||||
|
|
||||||
from components.form.components.MyForm import FormField, MyForm
|
from components.form.components.MyForm import FormField, MyForm
|
||||||
|
from components.undo_redo.components.UndoRedo import UndoRedo
|
||||||
from components.workflows.components.Workflows import Workflows
|
from components.workflows.components.Workflows import Workflows
|
||||||
|
from core.instance_manager import InstanceManager
|
||||||
from core.settings_management import SettingsManager, MemoryDbEngine
|
from core.settings_management import SettingsManager, MemoryDbEngine
|
||||||
from helpers import matches, div_icon, search_elements_by_name, Contains
|
from helpers import matches, div_icon, search_elements_by_name, Contains
|
||||||
from my_mocks import tabs_manager
|
from my_mocks import tabs_manager
|
||||||
@@ -18,6 +22,28 @@ def workflows(session, tabs_manager):
|
|||||||
tabs_manager=tabs_manager)
|
tabs_manager=tabs_manager)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def mock_undo_redo(session):
|
||||||
|
# Create a mock UndoRedo instance
|
||||||
|
undo_redo = MagicMock(spec=UndoRedo)
|
||||||
|
|
||||||
|
# Store original get method
|
||||||
|
original_get = InstanceManager.get
|
||||||
|
|
||||||
|
def mock_get(sess, instance_id, *args, **kwargs):
|
||||||
|
if instance_id == UndoRedo.create_component_id(sess):
|
||||||
|
return undo_redo
|
||||||
|
return original_get(sess, instance_id, *args, **kwargs)
|
||||||
|
|
||||||
|
# Replace get method with our mock
|
||||||
|
InstanceManager.get = mock_get
|
||||||
|
|
||||||
|
yield undo_redo
|
||||||
|
|
||||||
|
# Restore original get method after test
|
||||||
|
InstanceManager.get = original_get
|
||||||
|
|
||||||
|
|
||||||
def test_render_no_workflow(workflows):
|
def test_render_no_workflow(workflows):
|
||||||
actual = workflows.__ft__()
|
actual = workflows.__ft__()
|
||||||
expected = Div(
|
expected = Div(
|
||||||
|
|||||||
Reference in New Issue
Block a user