Skip to content

Commit

Permalink
Introduce snapshot-based tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
xavierog committed Nov 22, 2024
1 parent 2fe919b commit fe93698
Show file tree
Hide file tree
Showing 117 changed files with 15,063 additions and 0 deletions.
3 changes: 3 additions & 0 deletions examples/moulti-python-checks.bash
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ moulti step add versions --title='Versions' --bottom-text=' '
mypy --version
echo --
pylint --version
echo --
pytest --version
} 2>&1 | moulti pass versions

moulti_exec ruff check setup.py src
moulti_exec mypy src
moulti_exec pylint src
moulti_exec pytest
11 changes: 11 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,14 @@ disable = [
"too-many-public-methods",
"too-many-statements",
]

[tool.pytest.ini_options]
# Recommended in https://textual.textualize.io/guide/testing/#testing-frameworks-for-textual
asyncio_mode = "auto"
# Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope.
asyncio_default_fixture_loop_scope = "function"
addopts = ["-n", "auto", "--forked"]
testpaths = ["tests"]
filterwarnings = [
"ignore:.*may lead to deadlocks in the child.*:DeprecationWarning"
]
5 changes: 5 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ build
mypy
pylint
pyperclip
pytest
pytest-asyncio
pytest-forked
pytest-textual-snapshot
pytest-xdist
ruff
textual-dev
textual==0.83.0
Expand Down
7 changes: 7 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from os import environ as environment_variables

# Remove MOULTI_* environment variables so as not to disrupt tests.
# For instance, MOULTI_CUSTOM_CSS can dramatically alter the resulting snapshots.
for variable_name in environment_variables:
if variable_name.startswith('MOULTI_'):
environment_variables.pop(variable_name)
220 changes: 220 additions & 0 deletions tests/__snapshots__/test_buttonquestion/test_buttonquestion.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
212 changes: 212 additions & 0 deletions tests/__snapshots__/test_diff/test_diff_no_delta.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
217 changes: 217 additions & 0 deletions tests/__snapshots__/test_diff/test_diff_with_delta.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
204 changes: 204 additions & 0 deletions tests/__snapshots__/test_display_steps/test_display_steps_top_down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
204 changes: 204 additions & 0 deletions tests/__snapshots__/test_display_steps/test_display_steps_top_up.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
205 changes: 205 additions & 0 deletions tests/__snapshots__/test_divider/test_divider.1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
201 changes: 201 additions & 0 deletions tests/__snapshots__/test_divider/test_divider.2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
205 changes: 205 additions & 0 deletions tests/__snapshots__/test_divider/test_divider.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
204 changes: 204 additions & 0 deletions tests/__snapshots__/test_fill_step/test_fill_step.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
204 changes: 204 additions & 0 deletions tests/__snapshots__/test_first_steps/test_first_steps.1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
219 changes: 219 additions & 0 deletions tests/__snapshots__/test_first_steps/test_first_steps.10.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
218 changes: 218 additions & 0 deletions tests/__snapshots__/test_first_steps/test_first_steps.11.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
210 changes: 210 additions & 0 deletions tests/__snapshots__/test_first_steps/test_first_steps.2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
210 changes: 210 additions & 0 deletions tests/__snapshots__/test_first_steps/test_first_steps.3.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
210 changes: 210 additions & 0 deletions tests/__snapshots__/test_first_steps/test_first_steps.4.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
215 changes: 215 additions & 0 deletions tests/__snapshots__/test_first_steps/test_first_steps.5.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
216 changes: 216 additions & 0 deletions tests/__snapshots__/test_first_steps/test_first_steps.6.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
217 changes: 217 additions & 0 deletions tests/__snapshots__/test_first_steps/test_first_steps.7.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
218 changes: 218 additions & 0 deletions tests/__snapshots__/test_first_steps/test_first_steps.8.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
219 changes: 219 additions & 0 deletions tests/__snapshots__/test_first_steps/test_first_steps.9.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
201 changes: 201 additions & 0 deletions tests/__snapshots__/test_first_steps/test_first_steps.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
208 changes: 208 additions & 0 deletions tests/__snapshots__/test_help_dialog/test_help_dialog.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
208 changes: 208 additions & 0 deletions tests/__snapshots__/test_inputquestion/test_inputquestion.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
222 changes: 222 additions & 0 deletions tests/__snapshots__/test_load/test_load.svg

Large diffs are not rendered by default.

204 changes: 204 additions & 0 deletions tests/__snapshots__/test_maximize/test_maximize_large_step.svg

Large diffs are not rendered by default.

203 changes: 203 additions & 0 deletions tests/__snapshots__/test_maximize/test_maximize_small_step.svg

Large diffs are not rendered by default.

209 changes: 209 additions & 0 deletions tests/__snapshots__/test_maximize/test_search_maximize.svg

Large diffs are not rendered by default.

209 changes: 209 additions & 0 deletions tests/__snapshots__/test_maximize/test_search_unmaximize.svg

Large diffs are not rendered by default.

205 changes: 205 additions & 0 deletions tests/__snapshots__/test_maximize/test_unmaximize_large_step.svg

Large diffs are not rendered by default.

209 changes: 209 additions & 0 deletions tests/__snapshots__/test_maximize/test_unmaximize_small_step.svg

Large diffs are not rendered by default.

203 changes: 203 additions & 0 deletions tests/__snapshots__/test_progressbar/test_progressbar.1.svg

Large diffs are not rendered by default.

202 changes: 202 additions & 0 deletions tests/__snapshots__/test_progressbar/test_progressbar.2.svg

Large diffs are not rendered by default.

203 changes: 203 additions & 0 deletions tests/__snapshots__/test_progressbar/test_progressbar.3.svg

Large diffs are not rendered by default.

203 changes: 203 additions & 0 deletions tests/__snapshots__/test_progressbar/test_progressbar.svg

Large diffs are not rendered by default.

214 changes: 214 additions & 0 deletions tests/__snapshots__/test_question/test_question.svg

Large diffs are not rendered by default.

209 changes: 209 additions & 0 deletions tests/__snapshots__/test_quit/test_quit_default_ask.svg

Large diffs are not rendered by default.

201 changes: 201 additions & 0 deletions tests/__snapshots__/test_quit/test_quit_default_quit.svg

Large diffs are not rendered by default.

212 changes: 212 additions & 0 deletions tests/__snapshots__/test_quit/test_quit_running_ask.svg

Large diffs are not rendered by default.

201 changes: 201 additions & 0 deletions tests/__snapshots__/test_quit/test_quit_running_leave.svg

Large diffs are not rendered by default.

201 changes: 201 additions & 0 deletions tests/__snapshots__/test_quit/test_quit_running_terminate.svg

Large diffs are not rendered by default.

204 changes: 204 additions & 0 deletions tests/__snapshots__/test_run_output/test_custom_step.svg

Large diffs are not rendered by default.

201 changes: 201 additions & 0 deletions tests/__snapshots__/test_run_output/test_discard_output.svg

Large diffs are not rendered by default.

204 changes: 204 additions & 0 deletions tests/__snapshots__/test_run_output/test_harvest_output.svg

Large diffs are not rendered by default.

208 changes: 208 additions & 0 deletions tests/__snapshots__/test_scrolling/test_auto_scrolling.svg

Large diffs are not rendered by default.

206 changes: 206 additions & 0 deletions tests/__snapshots__/test_scrolling/test_lock_scroll.1.svg

Large diffs are not rendered by default.

206 changes: 206 additions & 0 deletions tests/__snapshots__/test_scrolling/test_lock_scroll.svg

Large diffs are not rendered by default.

206 changes: 206 additions & 0 deletions tests/__snapshots__/test_scrolling/test_programmatic_scrolling.1.svg

Large diffs are not rendered by default.

207 changes: 207 additions & 0 deletions tests/__snapshots__/test_scrolling/test_programmatic_scrolling.2.svg

Large diffs are not rendered by default.

206 changes: 206 additions & 0 deletions tests/__snapshots__/test_scrolling/test_programmatic_scrolling.3.svg

Large diffs are not rendered by default.

206 changes: 206 additions & 0 deletions tests/__snapshots__/test_scrolling/test_programmatic_scrolling.4.svg

Large diffs are not rendered by default.

206 changes: 206 additions & 0 deletions tests/__snapshots__/test_scrolling/test_programmatic_scrolling.5.svg

Large diffs are not rendered by default.

206 changes: 206 additions & 0 deletions tests/__snapshots__/test_scrolling/test_programmatic_scrolling.6.svg

Large diffs are not rendered by default.

206 changes: 206 additions & 0 deletions tests/__snapshots__/test_scrolling/test_programmatic_scrolling.svg

Large diffs are not rendered by default.

201 changes: 201 additions & 0 deletions tests/__snapshots__/test_simple_start/test_start.svg

Large diffs are not rendered by default.

208 changes: 208 additions & 0 deletions tests/__snapshots__/test_step_classes/test_step_classes.svg

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

204 changes: 204 additions & 0 deletions tests/__snapshots__/test_textsearch/test_search_bar.1.svg

Large diffs are not rendered by default.

204 changes: 204 additions & 0 deletions tests/__snapshots__/test_textsearch/test_search_bar.2.svg

Large diffs are not rendered by default.

204 changes: 204 additions & 0 deletions tests/__snapshots__/test_textsearch/test_search_bar.3.svg

Large diffs are not rendered by default.

204 changes: 204 additions & 0 deletions tests/__snapshots__/test_textsearch/test_search_bar.svg

Large diffs are not rendered by default.

78 changes: 78 additions & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import os
from typing import Awaitable, Callable, Iterable
import pytest
from _pytest.fixtures import FixtureRequest
from textual.pilot import Pilot
from moulti.app import Moulti

TERMINAL_SIZE = (128, 36)
COMMAND_PREFIX = 'tests/scripts/'

async def wait_script_start(pilot):
"""Wait until the script starts."""
while pilot.app.init_command_running is None:
await pilot.pause(0.1)

async def wait_script_end(pilot):
"""Wait until the script finishes, assuming it has started already."""
while pilot.app.init_command_running:
await pilot.pause(0.1)

async def wait_script(pilot):
"""Wait until the script finishes."""
await wait_script_start(pilot)
await wait_script_end(pilot)

@pytest.fixture
def moulti_test(request: FixtureRequest, snap_compare):
"""
Helper fixture that wraps around Textual's snap_compare. It takes care of:
- setting THE terminal size;
- picking a non-conflicting Moulti instance name, with optional suffix;
- creating a Moulti instance;
- passing an optional command;
- taking a snapshot through snap_compare;
- exiting the Moulti instance so it stops listening;
- returning snap_compare's result.
press, run_before and terminal_size are the same as snap_compare's.
If a command is passed, run_before defaults to wait_script, so that the snapshot is not taken prematurely.
"""
def compare(
command: list[str]|None = None,
press: Iterable[str] = (),
run_before: Callable[[Pilot], Awaitable[None]|None]|None = None,
run_after: Callable|None = None,
terminal_size: tuple[int, int] = TERMINAL_SIZE,
suffix: str|None = None,
):
name = request.node.reportinfo()[2].replace('_', '-')
if suffix is not None:
name += suffix
if command:
if command[0] != 'moulti' and not command[0].startswith(COMMAND_PREFIX):
command[0] = COMMAND_PREFIX + command[0]
if not run_before:
run_before = wait_script
moulti_app = Moulti(command=command, instance_name=f'{os.getpid()}-{name}')
result = snap_compare(moulti_app, press, terminal_size, run_before)
if run_after:
run_after(moulti_app)
else:
moulti_app.exit()
return result
return compare

def steps(max_step):
"""
Helper that iterates from 1 to max_step (inclusive) and yields
integer-string-suffix tuples, e.g. (2, '2', '-02').
"""
for index in range(1, max_step+1):
yield (index, str(index), f'-{index:02d}')

def moulti_test_steps(moulti_test, script_path, max_step):
"""
Helper that runs a script through moulti_test max_step times in a row.
"""
for _, i, suffix in steps(max_step):
assert moulti_test(command=[script_path, i], suffix=suffix)
Loading

0 comments on commit fe93698

Please sign in to comment.