extend simple test listing to a list-detail-view window

This commit is contained in:
2025-12-27 22:33:46 +01:00
parent 519fc38769
commit 60960322ac
4 changed files with 1108 additions and 20 deletions

View File

@@ -1400,3 +1400,430 @@ describe("test-samurai output formatting", function()
assert.is_true(has_fail)
end)
end)
describe("test-samurai output detail view", function()
before_each(function()
test_samurai.setup()
end)
local function find_float_wins()
local wins = vim.api.nvim_tabpage_list_wins(0)
local out = {}
for _, win in ipairs(wins) do
local cfg = vim.api.nvim_win_get_config(win)
if cfg.relative ~= "" then
table.insert(out, win)
end
end
return out
end
local function find_non_float_win()
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
local cfg = vim.api.nvim_win_get_config(win)
if cfg.relative == "" then
return win
end
end
return nil
end
it("opens failing test output in a right vsplit", function()
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, {
vim.json.encode({ Action = "output", Test = "TestFoo/Sub", Output = "=== RUN TestFoo/Sub\n" }),
vim.json.encode({ Action = "output", Test = "TestFoo/Sub", Output = " foo_test.go:10: expected\n" }),
vim.json.encode({ Action = "fail", Test = "TestFoo/Sub" }),
}, nil)
end
if opts and opts.on_exit then
opts.on_exit(1, 1, nil)
end
return 1
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_detail_test.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
test_samurai.test_file()
local out_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
local target = nil
for i, line in ipairs(lines) do
if line:match("^%[ FAIL %] %- ") then
target = i
break
end
end
assert.is_not_nil(target)
vim.api.nvim_win_set_cursor(0, { target, 0 })
local output_win = vim.api.nvim_get_current_win()
core.open_test_output_at_cursor()
local wins = find_float_wins()
assert.equals(2, #wins)
local right = nil
for _, win in ipairs(wins) do
if win ~= output_win then
right = win
break
end
end
assert.is_not_nil(right)
local left_cfg = vim.api.nvim_win_get_config(output_win)
local right_cfg = vim.api.nvim_win_get_config(right)
assert.equals(left_cfg.row, right_cfg.row)
assert.equals(left_cfg.height, right_cfg.height)
assert.equals(left_cfg.col + left_cfg.width, right_cfg.col)
local total_width = left_cfg.width + right_cfg.width
local expected_left = math.floor(total_width * 0.2)
assert.is_true(math.abs(left_cfg.width - expected_left) <= 1)
local right_buf = vim.api.nvim_win_get_buf(right)
local detail = vim.api.nvim_buf_get_lines(right_buf, 0, -1, false)
assert.are.same({
"=== RUN TestFoo/Sub",
" foo_test.go:10: expected",
}, detail)
vim.fn.jobstart = orig_jobstart
end)
it("reuses an existing right split for test output", function()
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, {
vim.json.encode({ Action = "output", Test = "TestFoo/Sub", Output = "=== RUN TestFoo/Sub\n" }),
vim.json.encode({ Action = "output", Test = "TestFoo/Sub", Output = " foo_test.go:10: expected\n" }),
vim.json.encode({ Action = "fail", Test = "TestFoo/Sub" }),
}, nil)
end
if opts and opts.on_exit then
opts.on_exit(1, 1, nil)
end
return 1
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_detail_reuse_test.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
test_samurai.test_file()
local output_win = vim.api.nvim_get_current_win()
local out_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
local target = nil
for i, line in ipairs(lines) do
if line:match("^%[ FAIL %] %- ") then
target = i
break
end
end
assert.is_not_nil(target)
vim.api.nvim_win_set_cursor(0, { target, 0 })
local output_win = vim.api.nvim_get_current_win()
core.open_test_output_at_cursor()
local wins = find_float_wins()
local right = nil
for _, win in ipairs(wins) do
if win ~= output_win then
right = win
break
end
end
assert.is_not_nil(right)
local right_buf = vim.api.nvim_win_get_buf(right)
vim.api.nvim_buf_set_lines(right_buf, 0, -1, false, { "old output" })
vim.api.nvim_set_current_win(output_win)
core.open_test_output_at_cursor()
local updated = find_float_wins()
local updated_right = nil
for _, win in ipairs(updated) do
if win ~= output_win then
updated_right = win
break
end
end
assert.equals(right, updated_right)
local detail = vim.api.nvim_buf_get_lines(right_buf, 0, -1, false)
assert.are.same({
"=== RUN TestFoo/Sub",
" foo_test.go:10: expected",
}, detail)
vim.fn.jobstart = orig_jobstart
end)
it("translates ANSI codes into highlights for detail output", function()
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, {
vim.json.encode({ Action = "output", Test = "TestAnsi/Sub", Output = "\27[31mFAIL\27[0m bad\n" }),
vim.json.encode({ Action = "fail", Test = "TestAnsi/Sub" }),
}, nil)
end
if opts and opts.on_exit then
opts.on_exit(1, 1, nil)
end
return 1
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_detail_ansi_test.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
test_samurai.test_file()
local out_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
local target = nil
for i, line in ipairs(lines) do
if line:match("^%[ FAIL %] %- ") then
target = i
break
end
end
assert.is_not_nil(target)
vim.api.nvim_win_set_cursor(0, { target, 0 })
local output_win = vim.api.nvim_get_current_win()
core.open_test_output_at_cursor()
local wins = find_float_wins()
local right = nil
for _, win in ipairs(wins) do
if win ~= output_win then
right = win
break
end
end
assert.is_not_nil(right)
local right_buf = vim.api.nvim_win_get_buf(right)
local detail = vim.api.nvim_buf_get_lines(right_buf, 0, -1, false)
assert.are.same({ "FAIL bad" }, detail)
local ns = vim.api.nvim_get_namespaces()["TestSamuraiDetailAnsi"]
assert.is_not_nil(ns)
local marks = vim.api.nvim_buf_get_extmarks(right_buf, ns, 0, -1, { details = true })
assert.is_true(#marks > 0)
assert.is_not_nil(marks[1][4].hl_group)
vim.fn.jobstart = orig_jobstart
end)
it("closes detail float and restores listing width", function()
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, {
vim.json.encode({ Action = "output", Test = "TestFoo/Sub", Output = "=== RUN TestFoo/Sub\n" }),
vim.json.encode({ Action = "fail", Test = "TestFoo/Sub" }),
}, nil)
end
if opts and opts.on_exit then
opts.on_exit(1, 1, nil)
end
return 1
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_detail_close_test.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
test_samurai.test_file()
local out_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
local target = nil
for i, line in ipairs(lines) do
if line:match("^%[ FAIL %] %- ") then
target = i
break
end
end
assert.is_not_nil(target)
vim.api.nvim_win_set_cursor(0, { target, 0 })
local output_win = vim.api.nvim_get_current_win()
core.open_test_output_at_cursor()
local wins = find_float_wins()
assert.equals(2, #wins)
local right = nil
for _, win in ipairs(wins) do
if win ~= output_win then
right = win
break
end
end
assert.is_not_nil(right)
local left_cfg = vim.api.nvim_win_get_config(output_win)
local right_cfg = vim.api.nvim_win_get_config(right)
local total_width = left_cfg.width + right_cfg.width
vim.api.nvim_win_close(right, true)
local remaining = find_float_wins()
assert.equals(1, #remaining)
local cfg = vim.api.nvim_win_get_config(remaining[1])
assert.equals(total_width, cfg.width)
vim.fn.jobstart = orig_jobstart
end)
it("closes container when listing float is closed", function()
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, {
vim.json.encode({ Action = "output", Test = "TestFoo/Sub", Output = "=== RUN TestFoo/Sub\n" }),
vim.json.encode({ Action = "fail", Test = "TestFoo/Sub" }),
}, nil)
end
if opts and opts.on_exit then
opts.on_exit(1, 1, nil)
end
return 1
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_detail_close_listing_test.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
test_samurai.test_file()
local out_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
local target = nil
for i, line in ipairs(lines) do
if line:match("^%[ FAIL %] %- ") then
target = i
break
end
end
assert.is_not_nil(target)
vim.api.nvim_win_set_cursor(0, { target, 0 })
local output_win = vim.api.nvim_get_current_win()
core.open_test_output_at_cursor()
vim.api.nvim_win_close(output_win, true)
local remaining = find_float_wins()
assert.equals(0, #remaining)
vim.fn.jobstart = orig_jobstart
end)
it("closes container when navigating out of floats", function()
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, {
vim.json.encode({ Action = "output", Test = "TestFoo/Sub", Output = "=== RUN TestFoo/Sub\n" }),
vim.json.encode({ Action = "fail", Test = "TestFoo/Sub" }),
}, nil)
end
if opts and opts.on_exit then
opts.on_exit(1, 1, nil)
end
return 1
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_detail_nav_close_test.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
test_samurai.test_file()
local out_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
local target = nil
for i, line in ipairs(lines) do
if line:match("^%[ FAIL %] %- ") then
target = i
break
end
end
assert.is_not_nil(target)
vim.api.nvim_win_set_cursor(0, { target, 0 })
core.open_test_output_at_cursor()
local non_float = find_non_float_win()
assert.is_not_nil(non_float)
vim.api.nvim_set_current_win(non_float)
local remaining = find_float_wins()
assert.equals(0, #remaining)
vim.fn.jobstart = orig_jobstart
end)
it("keeps container open when focusing listing from detail", function()
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, {
vim.json.encode({ Action = "output", Test = "TestFoo/Sub", Output = "=== RUN TestFoo/Sub\n" }),
vim.json.encode({ Action = "fail", Test = "TestFoo/Sub" }),
}, nil)
end
if opts and opts.on_exit then
opts.on_exit(1, 1, nil)
end
return 1
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_detail_focus_listing_test.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
test_samurai.test_file()
local out_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
local target = nil
for i, line in ipairs(lines) do
if line:match("^%[ FAIL %] %- ") then
target = i
break
end
end
assert.is_not_nil(target)
vim.api.nvim_win_set_cursor(0, { target, 0 })
local output_win = vim.api.nvim_get_current_win()
core.open_test_output_at_cursor()
local wins = find_float_wins()
local detail_win = nil
for _, win in ipairs(wins) do
if win ~= output_win then
detail_win = win
break
end
end
assert.is_not_nil(detail_win)
vim.api.nvim_set_current_win(detail_win)
core.focus_listing()
assert.equals(output_win, vim.api.nvim_get_current_win())
local remaining = find_float_wins()
assert.equals(2, #remaining)
vim.fn.jobstart = orig_jobstart
end)
end)