|
| 1 | +--- |
| 2 | +myst: |
| 3 | + html_meta: |
| 4 | + description: "Advanced techniques for testing with the libtmux pytest plugin" |
| 5 | + keywords: "tmux, pytest, advanced testing, polling, temporary files" |
| 6 | +--- |
| 7 | + |
| 8 | +(advanced-techniques)= |
| 9 | + |
| 10 | +# Advanced Techniques |
| 11 | + |
| 12 | +This page covers advanced testing techniques using the libtmux pytest plugin for more sophisticated testing scenarios. |
| 13 | + |
| 14 | +## Testing with Temporary Files |
| 15 | + |
| 16 | +### Creating Temporary Project Directories |
| 17 | + |
| 18 | +```{literalinclude} ../../tests/pytest_examples/test_temp_files.py |
| 19 | +:language: python |
| 20 | +:pyobject: temp_project_dir |
| 21 | +``` |
| 22 | + |
| 23 | +### Working with Files in Temporary Directories |
| 24 | + |
| 25 | +```{literalinclude} ../../tests/pytest_examples/test_temp_files.py |
| 26 | +:language: python |
| 27 | +:pyobject: test_project_file_manipulation |
| 28 | +``` |
| 29 | + |
| 30 | +## Command Polling |
| 31 | + |
| 32 | +### Implementing Robust Wait Functions |
| 33 | + |
| 34 | +```{literalinclude} ../../tests/pytest_examples/test_command_polling.py |
| 35 | +:language: python |
| 36 | +:pyobject: wait_for_output |
| 37 | +``` |
| 38 | + |
| 39 | +### Testing with Command Polling |
| 40 | + |
| 41 | +```{literalinclude} ../../tests/pytest_examples/test_command_polling.py |
| 42 | +:language: python |
| 43 | +:pyobject: test_command_with_polling |
| 44 | +``` |
| 45 | + |
| 46 | +### Error Handling with Polling |
| 47 | + |
| 48 | +```{literalinclude} ../../tests/pytest_examples/test_command_polling.py |
| 49 | +:language: python |
| 50 | +:pyobject: test_error_handling |
| 51 | +``` |
| 52 | + |
| 53 | +## Setting Custom Home Directory |
| 54 | + |
| 55 | +### Temporary Home Directory Setup |
| 56 | + |
| 57 | +```{literalinclude} ../../tests/pytest_examples/test_home_directory.py |
| 58 | +:language: python |
| 59 | +:pyobject: set_home |
| 60 | +``` |
| 61 | + |
| 62 | +## Testing Across tmux Server Restarts |
| 63 | + |
| 64 | +For testing functionality that needs to persist across server restarts: |
| 65 | + |
| 66 | +```python |
| 67 | +def test_persist_across_restart(session): |
| 68 | + """Test functionality across server restarts.""" |
| 69 | + # Set up initial state |
| 70 | + window = session.new_window(window_name="persist-test") |
| 71 | + pane = window.active_pane |
| 72 | + pane.send_keys("echo 'Data to persist' > /tmp/test-data.txt", enter=True) |
| 73 | + time.sleep(0.5) |
| 74 | + |
| 75 | + # Get server info for reconnecting |
| 76 | + socket_path = session.server.socket_path |
| 77 | + session_id = session.id |
| 78 | + |
| 79 | + # Kill the server |
| 80 | + session.server.kill_server() |
| 81 | + |
| 82 | + # Create a new server with the same socket |
| 83 | + new_server = libtmux.Server(socket_path=socket_path) |
| 84 | + new_server.new_session(session_name="restart-test") |
| 85 | + |
| 86 | + # Verify data persisted |
| 87 | + new_session = new_server.get_by_id(session_id) |
| 88 | + assert new_session is None # Old session should not exist |
| 89 | + |
| 90 | + # But our file should still exist |
| 91 | + new_pane = new_server.sessions[0].attached_window.active_pane |
| 92 | + new_pane.send_keys("cat /tmp/test-data.txt", enter=True) |
| 93 | + time.sleep(0.5) |
| 94 | + |
| 95 | + output = new_pane.capture_pane() |
| 96 | + assert any("Data to persist" in line for line in output) |
| 97 | + |
| 98 | + # Clean up |
| 99 | + new_pane.send_keys("rm /tmp/test-data.txt", enter=True) |
| 100 | +``` |
| 101 | + |
| 102 | +## Testing with Complex Layouts |
| 103 | + |
| 104 | +Creating and testing more complex window layouts: |
| 105 | + |
| 106 | +```python |
| 107 | +def test_complex_layouts(session): |
| 108 | + """Test creating and interacting with complex window layouts.""" |
| 109 | + # Create a window with multiple panes in a specific layout |
| 110 | + window = session.new_window(window_name="complex-layout") |
| 111 | + |
| 112 | + # Start with a simple pane |
| 113 | + main_pane = window.active_pane |
| 114 | + |
| 115 | + # Split into a left pane and right column |
| 116 | + left_pane = main_pane |
| 117 | + right_top = window.split(direction="right", percent=50) |
| 118 | + |
| 119 | + # Split the right column into top and bottom |
| 120 | + right_bottom = right_top.split(direction="below", percent=50) |
| 121 | + |
| 122 | + # Apply a layout |
| 123 | + window.select_layout("main-vertical") |
| 124 | + |
| 125 | + # Verify the layout was applied |
| 126 | + assert window.get("window_layout") != None |
| 127 | + |
| 128 | + # Send unique commands to each pane for identification |
| 129 | + left_pane.send_keys("echo 'Left Pane'", enter=True) |
| 130 | + right_top.send_keys("echo 'Right Top'", enter=True) |
| 131 | + right_bottom.send_keys("echo 'Right Bottom'", enter=True) |
| 132 | + |
| 133 | + time.sleep(0.5) |
| 134 | + |
| 135 | + # Verify each pane has the correct content |
| 136 | + assert any("Left Pane" in line for line in left_pane.capture_pane()) |
| 137 | + assert any("Right Top" in line for line in right_top.capture_pane()) |
| 138 | + assert any("Right Bottom" in line for line in right_bottom.capture_pane()) |
| 139 | +``` |
| 140 | + |
| 141 | +## Best Practices |
| 142 | + |
| 143 | +### Test Structure |
| 144 | + |
| 145 | +1. **Arrange** - Set up your tmux environment and test data |
| 146 | +2. **Act** - Perform the actions you want to test |
| 147 | +3. **Assert** - Verify the expected outcome |
| 148 | +4. **Clean up** - Reset any state changes (usually handled by fixtures) |
| 149 | + |
| 150 | +### Tips for Reliable Tests |
| 151 | + |
| 152 | +1. **Use appropriate waits**: Terminal operations aren't instantaneous. Add sufficient wait times or use polling techniques. |
| 153 | + |
| 154 | +2. **Capture full pane contents**: Use `pane.capture_pane()` to get all output content for verification. |
| 155 | + |
| 156 | +3. **Isolate tests**: Don't rely on state from other tests. Each test should set up its own environment. |
| 157 | + |
| 158 | +4. **Use descriptive assertions**: When tests fail, the assertion message should clarify what went wrong. |
| 159 | + |
| 160 | +5. **Test error conditions**: Include tests for error handling to ensure your code behaves correctly in failure scenarios. |
| 161 | + |
| 162 | +6. **Keep tests fast**: Minimize wait times while keeping tests reliable. |
| 163 | + |
| 164 | +7. **Use parametrized tests**: For similar tests with different inputs, use pytest's parametrize feature. |
| 165 | + |
| 166 | +8. **Document test requirements**: If tests require specific tmux features, document this in comments. |
| 167 | + |
| 168 | +9. **Mind CI environments**: Tests should work consistently in both local and CI environments, which may have different tmux versions and capabilities. |
0 commit comments