|
10 | 10 |
|
11 | 11 | **Single test**: Use busted directly: `busted --verbose --filter='"<FULL TEST NAME HERE>"'` |
12 | 12 |
|
| 13 | +## Test Environment Notes |
| 14 | + |
| 15 | +### TextChanged Autocmds in Headless Mode |
| 16 | + |
| 17 | +**Key Understanding**: `TextChanged` autocmds don't fire in headless neovim due to typeahead/operator pending behavior: |
| 18 | + |
| 19 | +- **`TextChanged`/`TextChangedI`/`TextChangedP` autocmds**: Do NOT fire in headless mode, regardless of whether changes are programmatic (`nvim_buf_set_lines`) or simulated user input (`feedkeys`, `vim.cmd.normal`). According to `:help TextChanged`: *"Not triggered when there is typeahead or when an operator is pending."* |
| 20 | +- **`nvim_buf_attach` with `on_bytes` callback**: DOES fire reliably in all scenarios (headless, interactive, programmatic, user input). |
| 21 | +- **`changedtick`**: Does increment for all buffer changes, providing a way to detect that changes occurred. |
| 22 | + |
| 23 | +This is why tests require manual `r.buf_watcher.fire()` calls - the current implementation uses `TextChanged` autocmd to batch `on_bytes` events, but this autocmd never fires in headless test environments. |
| 24 | + |
| 25 | +**Current workaround in tests**: Call `r.buf_watcher.fire()` manually after programmatic buffer changes to simulate the autocmd that would fire with real user input. |
| 26 | + |
| 27 | +### Buffer Event Testing |
| 28 | + |
| 29 | +- **Buffer cleanup**: Tests use `with_buf()` wrapper that explicitly calls `vim.cmd.bdelete { bang = true }`, which fires all deletion events (`BufUnload`, `BufDelete`, `BufWipeout`) regardless of `bufhidden` settings |
| 30 | +- **Event testing**: To test buffer deletion events, use explicit `vim.api.nvim_buf_delete(bufnr, { force = true })` rather than Vim commands like `:enew` or `:tabclose`, which have inconsistent behavior depending on `bufhidden` |
| 31 | + |
| 32 | +### Testing Neovim Behaviors Interactively |
| 33 | + |
| 34 | +When you need to quickly test Neovim behaviors outside of the formal test suite: |
| 35 | + |
| 36 | +1. **Create a test script**: Create a standalone `.lua` file (e.g., `test_behavior.lua`) in the project root |
| 37 | +2. **Write the test**: Use standard Lua and Neovim API calls. The script should end with `vim.cmd.qall { bang = true }` to exit |
| 38 | +3. **Run the test**: Execute with `nvim --headless -u NONE -c "set rtp+=." -c "luafile test_behavior.lua" 2>&1` |
| 39 | + - `--headless`: Run without UI |
| 40 | + - `-u NONE`: Don't load user config |
| 41 | + - `-c "set rtp+=."`: Add current directory to runtime path so `require 'morph'` works |
| 42 | + - `-c "luafile test_behavior.lua"`: Execute your test script |
| 43 | + - `2>&1`: Capture all output |
| 44 | +4. **Clean up**: Delete test files when done (they should not be committed) |
| 45 | + |
| 46 | +**Example test script**: |
| 47 | +```lua |
| 48 | +#!/usr/bin/env nvim -l |
| 49 | +local Morph = require 'morph' |
| 50 | +-- Your test code here |
| 51 | +vim.print('Testing something...') |
| 52 | +vim.cmd.qall { bang = true } |
| 53 | +``` |
| 54 | + |
| 55 | +**Note**: Interactive nvim commands with input (like `nvim --headless -c "..."` where commands expect user input) will hang. Always use non-interactive commands or scripts. |
| 56 | + |
13 | 57 | ## Code Style Guidelines |
14 | 58 |
|
15 | 59 | ### Formatting |
|
20 | 64 | - Sort requires automatically |
21 | 65 |
|
22 | 66 | ### Type Annotations |
23 | | -- Use EmmyLua type annotations (`---@param`, `---@return`, `---@type`) |
| 67 | +- Use EmmyLua type annotations (`--- @param`, `--- @return`, `--- @type`) |
24 | 68 | - Follow patterns in existing code: `morph.Ctx<Props, State>` |
25 | 69 | - Component functions should annotate props and state types |
26 | 70 |
|
|
0 commit comments