Files
watchexec.nvim/tests/watchexec/window_spec.lua
T
Stevan Freeborn 9dc2961180 feat: add configuration system and output window
Introduce config module for managing user options, defaults, and watchexec
binary discovery. Add window module for creating and managing the output
window (float or split) with append, clear, resize, and keymap support.
2026-07-06 19:51:29 -05:00

307 lines
7.2 KiB
Lua

local config = require("watchexec.config")
local window = require("watchexec.window")
local indicator = require("watchexec.indicator")
local stub = require("luassert.stub")
describe("watchexec window", function()
before_each(function()
config.reset()
config.setup({})
window.cleanup()
stub(indicator, "refresh")
stub(indicator, "reset")
end)
after_each(function()
window.cleanup()
config.reset()
indicator.refresh:revert()
indicator.reset:revert()
end)
describe("open()", function()
it("opens a float window by default", function()
window.open()
local win = window.get_win()
local win_config = vim.api.nvim_win_get_config(win)
assert.equals("editor", win_config.relative)
assert.is_true(vim.api.nvim_win_is_valid(win))
assert.is_true(window.is_visible())
end)
it("opens a float window when configured", function()
config.setup({
window = { type = "float" },
})
window.open()
local win = window.get_win()
assert.is_true(vim.api.nvim_win_is_valid(win))
local win_config = vim.api.nvim_win_get_config(win)
assert.equals("editor", win_config.relative)
end)
it("reuses existing window if still valid", function()
window.open()
window.close()
window.open()
local second_win = window.get_win()
assert.is_true(vim.api.nvim_win_is_valid(second_win))
end)
end)
describe("close()", function()
it("closes the open window", function()
window.open()
local wins_before = #vim.api.nvim_list_wins()
window.close()
local wins_after = #vim.api.nvim_list_wins()
assert.equals(wins_before - 1, wins_after)
assert.is_nil(window.get_win())
assert.is_false(window.is_visible())
end)
it("does nothing if no window is open", function()
assert.is_nil(window.get_win())
window.close()
assert.is_nil(window.get_win())
end)
end)
describe("toggle()", function()
it("opens the window if closed", function()
window.toggle()
assert.not_nil(window.get_win())
end)
it("closes the window if open", function()
window.open()
window.toggle()
assert.is_nil(window.get_win())
end)
end)
describe("cleanup()", function()
it("closes the window and deletes the buffer", function()
window.open()
local buf = window.get_buf()
window.cleanup()
assert.is_false(vim.api.nvim_buf_is_valid(buf))
assert.is_nil(window.get_buf())
assert.is_nil(window.get_win())
end)
end)
describe("is_visible()", function()
it("returns true after open", function()
window.open()
assert.is_true(window.is_visible())
end)
it("returns false after close", function()
window.open()
window.close()
assert.is_false(window.is_visible())
end)
end)
describe("resize_float()", function()
it("recalculates float dimensions after terminal resize", function()
config.setup({
window = { type = "float" },
})
window.open()
local win = window.get_win()
local before = vim.api.nvim_win_get_config(win)
local orig_cols = vim.o.columns
local orig_lines = vim.o.lines
vim.o.columns = orig_cols + 20
vim.o.lines = orig_lines + 10
window.resize_float()
local after = vim.api.nvim_win_get_config(win)
vim.o.columns = orig_cols
vim.o.lines = orig_lines
assert.is_not.equals(before.width, after.width)
assert.is_not.equals(before.height, after.height)
end)
it("does nothing when no window is open", function()
window.resize_float()
end)
it("does nothing for split windows", function()
window.open()
window.resize_float()
end)
end)
describe("get_buf() / get_win()", function()
it("returns nil before open", function()
assert.is_nil(window.get_buf())
assert.is_nil(window.get_win())
end)
it("returns values after open", function()
window.open()
assert.not_nil(window.get_buf())
assert.not_nil(window.get_win())
end)
end)
describe("append()", function()
it("appends text to the buffer", function()
window.open()
local buf = window.get_buf()
window.append("line one")
window.append("line two")
local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
assert.equals("line one", lines[1])
assert.equals("line two", lines[2])
end)
it("does nothing when buffer is invalid", function()
window.append("should not error")
end)
it("replaces the waiting placeholder on first append", function()
window.open()
local buf = window.get_buf()
vim.api.nvim_set_option_value("modifiable", true, { buf = buf })
vim.api.nvim_buf_set_lines(
buf,
0,
-1,
false,
{ " No job running. Use :WatchexecRun <command> to start one.", "" }
)
vim.api.nvim_set_option_value("modifiable", false, { buf = buf })
window.append("first output")
local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
assert.equals("first output", lines[1])
end)
it("truncates to max_lines when exceeded", function()
config.setup({
max_lines = 3,
})
window.open()
local buf = window.get_buf()
window.append("a")
window.append("b")
window.append("c")
window.append("d")
local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
assert.equals(3, #lines)
assert.equals("b", lines[1])
assert.equals("c", lines[2])
assert.equals("d", lines[3])
end)
it("scrolls to bottom when auto_scroll is enabled", function()
config.setup({ auto_scroll = true })
window.open()
window.append("line one")
window.append("line two")
local win = window.get_win()
local cursor = vim.api.nvim_win_get_cursor(win)
local buf = window.get_buf()
local line_count = vim.api.nvim_buf_line_count(buf)
assert.equals(line_count, cursor[1])
end)
end)
describe("keymaps", function()
it("maps <Esc> to close the window", function()
window.open()
local buf = window.get_buf()
local maps = vim.api.nvim_buf_get_keymap(buf, "n")
local found = false
for _, m in ipairs(maps) do
if m.lhs == "<Esc>" then
found = true
break
end
end
assert.is_true(found)
end)
it("maps q to close the window", function()
window.open()
local buf = window.get_buf()
local maps = vim.api.nvim_buf_get_keymap(buf, "n")
local found = false
for _, m in ipairs(maps) do
if m.lhs == "q" then
found = true
break
end
end
assert.is_true(found)
end)
it("calls window.close() via the <Esc> keymap", function()
window.open()
assert.is_true(window.is_visible())
vim.cmd("normal " .. "\027")
assert.is_false(window.is_visible())
end)
it("calls window.close() via the q keymap", function()
window.open()
assert.is_true(window.is_visible())
vim.cmd("normal q")
assert.is_false(window.is_visible())
end)
end)
end)