Skip to content

Commit 5d648f3

Browse files
committed
docs(pytest-plugin): Expand examples with advanced testing techniques
- Add comprehensive examples for testing with multiple panes - Add section on testing complex tmux configurations with custom settings - Add examples for working with temporary files and directories in tests - Add advanced polling techniques for more robust command execution tests - Improve debugging section with more detailed diagnostics
1 parent 2606be4 commit 5d648f3

File tree

1 file changed

+263
-4
lines changed

1 file changed

+263
-4
lines changed

docs/pytest-plugin/examples.md

Lines changed: 263 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ The libtmux pytest plugin provides powerful fixtures for testing tmux-related fu
99
Testing a simple server connection:
1010

1111
```python
12+
import libtmux
13+
1214
def test_server_connection(server):
1315
"""Test that we can connect to a tmux server."""
1416
assert server is not None
@@ -20,6 +22,8 @@ def test_server_connection(server):
2022
Testing session creation and properties:
2123

2224
```python
25+
import libtmux
26+
2327
def test_new_session(session):
2428
"""Test that the session fixture provides a working session."""
2529
assert session is not None
@@ -38,6 +42,9 @@ def test_new_session(session):
3842
Testing window creation and manipulation:
3943

4044
```python
45+
import libtmux
46+
from libtmux.constants import PaneDirection
47+
4148
def test_window_operations(session):
4249
"""Test window creation and properties."""
4350
# Create a new window
@@ -49,7 +56,7 @@ def test_window_operations(session):
4956
assert window.window_name == "renamed_window"
5057

5158
# Split the window
52-
pane = window.split_window()
59+
pane = window.split(direction=PaneDirection.Right)
5360
assert len(window.panes) == 2
5461

5562
# Send keys to pane
@@ -67,6 +74,9 @@ def test_window_operations(session):
6774
Testing pane creation and interaction:
6875

6976
```python
77+
import libtmux
78+
from libtmux.constants import PaneDirection
79+
7080
def test_pane_operations(pane):
7181
"""Test operations on a pane fixture."""
7282
# Send a command
@@ -81,7 +91,7 @@ def test_pane_operations(pane):
8191
assert any("Testing pane operations" in line for line in output)
8292

8393
# Split the pane
84-
new_pane = pane.split_window()
94+
new_pane = pane.split(direction=PaneDirection.Below)
8595
assert new_pane is not None
8696

8797
# Verify we have two panes now
@@ -94,6 +104,8 @@ def test_pane_operations(pane):
94104
Setting up a specific environment for tests:
95105

96106
```python
107+
import libtmux
108+
97109
def test_with_custom_environment(server):
98110
"""Test with a customized environment setup."""
99111
# Create a session with specific options
@@ -116,7 +128,7 @@ def test_with_custom_environment(server):
116128

117129
# Test window switching
118130
custom_session.switch_window(1)
119-
current = custom_session.attached_window
131+
current = custom_session.active_window
120132
assert current.window_name == "window2"
121133

122134
# Clean up
@@ -132,6 +144,8 @@ def test_with_custom_environment(server):
132144
Handling commands that take time to execute:
133145

134146
```python
147+
import libtmux
148+
135149
def test_long_running_command(pane):
136150
"""Test interaction with long-running commands."""
137151
# Start a command that will run for a few seconds
@@ -158,6 +172,8 @@ def test_long_running_command(pane):
158172
Testing integration with other terminal programs:
159173

160174
```python
175+
import libtmux
176+
161177
def test_program_integration(pane):
162178
"""Test interaction with another terminal program."""
163179
# Start a text editor (nano is simple and widely available)
@@ -195,6 +211,8 @@ def test_program_integration(pane):
195211
Testing error handling:
196212

197213
```python
214+
import libtmux
215+
198216
def test_error_handling(pane):
199217
"""Test handling of command errors."""
200218
# Send a command that will fail
@@ -217,6 +235,7 @@ Using pytest parametrization with tmux fixtures:
217235

218236
```python
219237
import pytest
238+
import libtmux
220239

221240
@pytest.mark.parametrize("window_name", ["test1", "test2", "test3"])
222241
def test_multiple_windows(session, window_name):
@@ -225,7 +244,7 @@ def test_multiple_windows(session, window_name):
225244
assert window.window_name == window_name
226245

227246
# Do something with each window
228-
pane = window.attached_pane
247+
pane = window.active_pane
229248
pane.send_keys(f"echo 'Testing window {window_name}'", enter=True)
230249

231250
# Verify output
@@ -248,6 +267,8 @@ def test_multiple_windows(session, window_name):
248267
If you're having trouble with your tmux tests, try these techniques:
249268

250269
```python
270+
import libtmux
271+
251272
def test_with_debugging(pane):
252273
"""Example showing debugging techniques."""
253274
# Capture initial state
@@ -279,3 +300,241 @@ def test_with_debugging(pane):
279300
print(f"Failed to find '{expected_text}' in output: {output}")
280301
assert any(expected_text in line for line in output)
281302
```
303+
304+
## Testing with Multiple Panes
305+
306+
Testing applications that require multiple panes and interaction between them:
307+
308+
```python
309+
import pytest
310+
import libtmux
311+
from libtmux.constants import PaneDirection
312+
import time
313+
314+
def test_multi_pane_interaction(server, session):
315+
"""Test interaction between multiple panes."""
316+
# Create a window with multiple panes for testing
317+
window = session.new_window(window_name="multi-pane-test")
318+
319+
# First pane (already exists as the active pane)
320+
main_pane = window.active_pane
321+
322+
# Create a second pane for output
323+
output_pane = window.split(direction=PaneDirection.Right)
324+
325+
# Create a third pane for monitoring
326+
monitor_pane = main_pane.split(direction=PaneDirection.Below)
327+
328+
# Wait for panes to be ready
329+
time.sleep(0.5)
330+
331+
# Set up the panes with specific content
332+
main_pane.send_keys("echo 'This is the main pane'", enter=True)
333+
output_pane.send_keys("echo 'This is the output pane'", enter=True)
334+
monitor_pane.send_keys("echo 'This is the monitor pane'", enter=True)
335+
336+
# Create a temporary file in one pane
337+
main_pane.send_keys("echo 'Shared data' > shared_file.txt", enter=True)
338+
time.sleep(0.5)
339+
340+
# Read it from another pane
341+
output_pane.send_keys("cat shared_file.txt", enter=True)
342+
time.sleep(0.5)
343+
344+
# Verify the content was shared
345+
output_content = output_pane.capture_pane()
346+
assert any("Shared data" in line for line in output_content)
347+
348+
# Use the monitor pane to check the file exists
349+
monitor_pane.send_keys("ls -la shared_file.txt", enter=True)
350+
time.sleep(0.5)
351+
352+
monitor_content = monitor_pane.capture_pane()
353+
assert any("shared_file.txt" in line for line in monitor_content)
354+
355+
# Clean up
356+
main_pane.send_keys("rm shared_file.txt", enter=True)
357+
```
358+
359+
## Testing Complex Tmux Configurations
360+
361+
Testing with a custom tmux configuration:
362+
363+
```python
364+
import pytest
365+
import libtmux
366+
import pathlib
367+
import tempfile
368+
369+
@pytest.fixture
370+
def custom_config():
371+
"""Create a temporary tmux configuration file."""
372+
with tempfile.NamedTemporaryFile(mode='w+', suffix='.conf') as f:
373+
# Write custom tmux configuration
374+
f.write("# Custom tmux configuration for testing\n")
375+
f.write("set -g base-index 1\n")
376+
f.write("set -g pane-base-index 1\n")
377+
f.write("set -g status-left '[#S] '\n")
378+
f.write("set -g status-style bg=green,fg=black\n")
379+
f.write("set -g history-limit 5000\n")
380+
f.flush()
381+
yield pathlib.Path(f.name)
382+
383+
@pytest.fixture
384+
def custom_server(custom_config, TestServer):
385+
"""Create a server with custom configuration."""
386+
Server = TestServer()
387+
server = Server(config_file=str(custom_config))
388+
yield server
389+
server.kill_server()
390+
391+
def test_with_custom_config(custom_server):
392+
"""Test tmux with a custom configuration."""
393+
session = custom_server.new_session(session_name="custom-config-test")
394+
395+
# Verify custom configuration was applied
396+
options = custom_server.show_options("g")
397+
398+
# Check that history limit was set correctly
399+
history_limit = options.get("history-limit", "")
400+
assert history_limit == "5000"
401+
402+
# Create a window to test base-index
403+
window = session.new_window(window_name="test-window")
404+
405+
# In our custom config, the first window should be index 1
406+
window_index = window.get("window_index")
407+
assert int(window_index) > 0, "Custom base-index wasn't applied"
408+
```
409+
410+
## Testing with Temporary Files and Directories
411+
412+
Managing temporary files in tests:
413+
414+
```python
415+
import pytest
416+
import libtmux
417+
import pathlib
418+
import tempfile
419+
import time
420+
421+
@pytest.fixture
422+
def temp_project_dir():
423+
"""Create a temporary project directory for testing."""
424+
with tempfile.TemporaryDirectory() as tmpdirname:
425+
project_dir = pathlib.Path(tmpdirname)
426+
427+
# Create some sample files
428+
(project_dir / "main.py").write_text("print('Hello, world!')")
429+
(project_dir / "README.md").write_text("# Test Project\n\nThis is a test project.")
430+
(project_dir / "config.ini").write_text("[settings]\nverbose = true")
431+
432+
yield project_dir
433+
434+
def test_project_file_manipulation(session, temp_project_dir):
435+
"""Test working with files in a temporary project directory."""
436+
window = session.new_window(window_name="file-test")
437+
pane = window.active_pane
438+
439+
# Navigate to the project directory
440+
pane.send_keys(f"cd {temp_project_dir}", enter=True)
441+
time.sleep(0.5)
442+
443+
# List files
444+
pane.send_keys("ls -la", enter=True)
445+
time.sleep(0.5)
446+
447+
# Verify files are visible
448+
output = pane.capture_pane()
449+
assert any("main.py" in line for line in output)
450+
assert any("README.md" in line for line in output)
451+
452+
# Run a Python file
453+
pane.send_keys("python main.py", enter=True)
454+
time.sleep(0.5)
455+
456+
# Verify output
457+
output = pane.capture_pane()
458+
assert any("Hello, world!" in line for line in output)
459+
460+
# Create a new file through tmux
461+
pane.send_keys("echo 'print(\"Testing is fun\")' > test.py", enter=True)
462+
time.sleep(0.5)
463+
464+
# Run the new file
465+
pane.send_keys("python test.py", enter=True)
466+
time.sleep(0.5)
467+
468+
# Verify output from new file
469+
output = pane.capture_pane()
470+
assert any("Testing is fun" in line for line in output)
471+
```
472+
473+
## Advanced Polling for Command Completion
474+
475+
More robust way to wait for command completion:
476+
477+
```python
478+
import pytest
479+
import libtmux
480+
import time
481+
import re
482+
483+
def wait_for_output(pane, expected_pattern, timeout=5, interval=0.1):
484+
"""
485+
Wait for a specific pattern to appear in the pane output.
486+
487+
Args:
488+
pane: The tmux pane to check
489+
expected_pattern: Regex pattern to look for
490+
timeout: Maximum time to wait in seconds
491+
interval: Time between checks in seconds
492+
493+
Returns:
494+
The matching line if found, None if timeout occurs
495+
"""
496+
pattern = re.compile(expected_pattern)
497+
start_time = time.time()
498+
499+
while time.time() - start_time < timeout:
500+
output = pane.capture_pane()
501+
502+
for line in output:
503+
if pattern.search(line):
504+
return line
505+
506+
time.sleep(interval)
507+
508+
return None # Timeout occurred
509+
510+
def test_command_with_polling(session):
511+
"""Test robust command polling."""
512+
window = session.new_window(window_name="polling-test")
513+
pane = window.active_pane
514+
515+
# Start a command that takes time
516+
pane.send_keys("echo 'Starting'; sleep 2; echo 'Finished!'", enter=True)
517+
518+
# Wait for command to complete
519+
result = wait_for_output(pane, r"Finished!")
520+
521+
# Verify command completed successfully
522+
assert result is not None, "Command did not finish within timeout"
523+
524+
# Run a sequence of commands
525+
pane.send_keys("echo 'Processing step 1'", enter=True)
526+
assert wait_for_output(pane, r"Processing step 1")
527+
528+
pane.send_keys("echo 'Processing step 2'", enter=True)
529+
assert wait_for_output(pane, r"Processing step 2")
530+
531+
pane.send_keys("echo 'Processing step 3'", enter=True)
532+
assert wait_for_output(pane, r"Processing step 3")
533+
534+
# Verify order of operations
535+
output = pane.capture_pane()
536+
step1_line = next((i for i, line in enumerate(output) if "Processing step 1" in line), -1)
537+
step2_line = next((i for i, line in enumerate(output) if "Processing step 2" in line), -1)
538+
step3_line = next((i for i, line in enumerate(output) if "Processing step 3" in line), -1)
539+
540+
assert step1_line < step2_line < step3_line, "Commands did not execute in the correct order"

0 commit comments

Comments
 (0)