add quick navigation within the listing-float

This commit is contained in:
2025-12-30 14:14:55 +01:00
parent 3615ac0e2f
commit dcb4320040
7 changed files with 576 additions and 0 deletions

View File

@@ -149,6 +149,212 @@ describe("test-samurai public API", function()
end)
end)
describe("test-samurai output listing fail navigation", function()
before_each(function()
test_samurai.setup()
end)
after_each(function()
close_output_container()
end)
local function find_listing_win()
local current = vim.api.nvim_get_current_win()
local cfg = vim.api.nvim_win_get_config(current)
if cfg.relative ~= "" then
return current
end
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
local win_cfg = vim.api.nvim_win_get_config(win)
if win_cfg.relative ~= "" then
return win
end
end
return nil
end
local function collect_fail_lines(buf)
local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
local out = {}
for i, line in ipairs(lines) do
if line:match("^%[ FAIL %] %- ") then
table.insert(out, i)
end
end
return out
end
local function press(keys)
local mapped = vim.api.nvim_replace_termcodes(keys, true, false, true)
vim.api.nvim_feedkeys(mapped, "x", false)
vim.wait(20)
end
it("jumps to the next fail and wraps to the first", function()
local json = vim.json.encode({
testResults = {
{
assertionResults = {
{ status = "failed", title = "inner 1", fullName = "outer inner 1" },
{ status = "passed", title = "inner 2", fullName = "outer inner 2" },
{ status = "failed", title = "inner 3", fullName = "outer inner 3" },
},
},
},
})
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, { json }, 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_listing_next_fail.test.ts")
vim.bo[bufnr].filetype = "typescript"
vim.api.nvim_set_current_buf(bufnr)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'describe("outer", function() {',
' it("inner 1", function() {',
" })",
' it("inner 2", function() {',
" })",
' it("inner 3", function() {',
" })",
"})",
})
core.run_nearest()
local listing = find_listing_win()
assert.is_not_nil(listing)
vim.api.nvim_set_current_win(listing)
local listing_buf = vim.api.nvim_win_get_buf(listing)
local fails = collect_fail_lines(listing_buf)
assert.equals(2, #fails)
vim.api.nvim_win_set_cursor(listing, { fails[1], 0 })
press("<leader>nf")
assert.equals(fails[2], vim.api.nvim_win_get_cursor(listing)[1])
press("<leader>nf")
assert.equals(fails[1], vim.api.nvim_win_get_cursor(listing)[1])
vim.fn.jobstart = orig_jobstart
end)
it("jumps to the previous fail and wraps to the last", function()
local json = vim.json.encode({
testResults = {
{
assertionResults = {
{ status = "failed", title = "inner 1", fullName = "outer inner 1" },
{ status = "passed", title = "inner 2", fullName = "outer inner 2" },
{ status = "failed", title = "inner 3", fullName = "outer inner 3" },
},
},
},
})
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, { json }, 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_listing_prev_fail.test.ts")
vim.bo[bufnr].filetype = "typescript"
vim.api.nvim_set_current_buf(bufnr)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'describe("outer", function() {',
' it("inner 1", function() {',
" })",
' it("inner 2", function() {',
" })",
' it("inner 3", function() {',
" })",
"})",
})
core.run_nearest()
local listing = find_listing_win()
assert.is_not_nil(listing)
vim.api.nvim_set_current_win(listing)
local listing_buf = vim.api.nvim_win_get_buf(listing)
local fails = collect_fail_lines(listing_buf)
assert.equals(2, #fails)
vim.api.nvim_win_set_cursor(listing, { fails[2], 0 })
press("<leader>pf")
assert.equals(fails[1], vim.api.nvim_win_get_cursor(listing)[1])
press("<leader>pf")
assert.equals(fails[2], vim.api.nvim_win_get_cursor(listing)[1])
vim.fn.jobstart = orig_jobstart
end)
it("does nothing when there are no fail lines", function()
local json = vim.json.encode({
testResults = {
{
assertionResults = {
{ status = "passed", title = "inner 1", fullName = "outer inner 1" },
{ status = "skipped", title = "inner 2", fullName = "outer inner 2" },
},
},
},
})
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, { json }, nil)
end
if opts and opts.on_exit then
opts.on_exit(1, 0, nil)
end
return 1
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_listing_no_fail.test.ts")
vim.bo[bufnr].filetype = "typescript"
vim.api.nvim_set_current_buf(bufnr)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'describe("outer", function() {',
' it("inner 1", function() {',
" })",
' it("inner 2", function() {',
" })",
"})",
})
core.run_nearest()
local listing = find_listing_win()
assert.is_not_nil(listing)
vim.api.nvim_set_current_win(listing)
local before = vim.api.nvim_win_get_cursor(listing)[1]
press("<leader>nf")
assert.equals(before, vim.api.nvim_win_get_cursor(listing)[1])
press("<leader>pf")
assert.equals(before, vim.api.nvim_win_get_cursor(listing)[1])
vim.fn.jobstart = orig_jobstart
end)
end)
describe("test-samurai output formatting", function()
before_each(function()
test_samurai.setup()
@@ -2258,6 +2464,203 @@ describe("test-samurai output detail view", function()
vim.fn.jobstart = orig_jobstart
end)
it("schliesst den Test-Container und springt mit <leader>o zum Test der Listing-Zeile", 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 = "pass", Test = "TestFoo" }),
}, nil)
end
if opts and opts.on_exit then
opts.on_exit(1, 0, nil)
end
return 1
end
local root = vim.fs.joinpath(vim.loop.cwd(), "tests", "tmp_qf_jump")
vim.fn.mkdir(root, "p")
local target = root .. "/output_detail_o_test.go"
vim.fn.writefile({
"package foo",
"",
"func TestFoo(t *testing.T) {",
"}",
}, target)
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, target)
vim.bo[bufnr].filetype = "go"
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
"package foo",
"",
"func TestFoo(t *testing.T) {",
"}",
})
vim.api.nvim_set_current_buf(bufnr)
test_samurai.test_file()
local wins = find_float_wins()
assert.equals(1, #wins)
local out_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
local target_line = nil
for i, line in ipairs(lines) do
if line:match("^%[ PASS %] %- ") then
target_line = i
break
end
end
assert.is_not_nil(target_line)
vim.api.nvim_win_set_cursor(0, { target_line, 0 })
local keys = vim.api.nvim_replace_termcodes("<leader>o", true, false, true)
vim.api.nvim_feedkeys(keys, "x", false)
vim.wait(20, function()
return #find_float_wins() == 0
end)
assert.equals(target, vim.api.nvim_buf_get_name(0))
local cursor = vim.api.nvim_win_get_cursor(0)
assert.equals(3, cursor[1])
vim.fn.jobstart = orig_jobstart
end)
it("ignoriert <leader>o auf Nicht-Ergebniszeilen im Listing", 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 = "pass", Test = "TestFoo" }),
}, nil)
end
if opts and opts.on_exit then
opts.on_exit(1, 0, nil)
end
return 1
end
local root = vim.fs.joinpath(vim.loop.cwd(), "tests", "tmp_qf_jump")
vim.fn.mkdir(root, "p")
local target = root .. "/output_detail_o_ignore_test.go"
vim.fn.writefile({
"package foo",
"",
"func TestFoo(t *testing.T) {",
"}",
}, target)
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, target)
vim.bo[bufnr].filetype = "go"
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
"package foo",
"",
"func TestFoo(t *testing.T) {",
"}",
})
vim.api.nvim_set_current_buf(bufnr)
test_samurai.test_file()
local wins = find_float_wins()
assert.equals(1, #wins)
vim.api.nvim_win_set_cursor(0, { 1, 0 })
local keys = vim.api.nvim_replace_termcodes("<leader>o", true, false, true)
vim.api.nvim_feedkeys(keys, "x", false)
vim.wait(20)
local remaining = find_float_wins()
assert.equals(1, #remaining)
assert.is_true(vim.api.nvim_buf_get_name(0) ~= target)
vim.fn.jobstart = orig_jobstart
end)
it("oeffnet mit <leader>o den nicht geladenen Buffer fuer Mocha-TSamAll", function()
test_samurai.setup({
runner_modules = {
"test-samurai.runners.js-mocha",
},
})
local root = vim.fs.joinpath(vim.loop.cwd(), "tests", "tmp_mocha_jump")
local test_dir = root .. "/test"
vim.fn.mkdir(test_dir, "p")
vim.fn.writefile({ '{ "name": "mocha-jump" }' }, root .. "/package.json")
local file1 = test_dir .. "/one.test.js"
local file2 = test_dir .. "/two.test.js"
vim.fn.writefile({
'describe("suite one", function() {',
' it("test one", function() {',
" })",
"})",
}, file1)
vim.fn.writefile({
'describe("suite two", function() {',
' it("test two", function() {',
" })",
"})",
}, file2)
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({ event = "pass", fullTitle = "suite one test one", title = "test one" }),
vim.json.encode({ event = "pass", fullTitle = "suite two test two", title = "test two" }),
}, nil)
end
if opts and opts.on_exit then
opts.on_exit(1, 0, nil)
end
return 1
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, file1)
vim.bo[bufnr].filetype = "javascript"
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'describe("suite one", function() {',
' it("test one", function() {',
" })",
"})",
})
vim.api.nvim_set_current_buf(bufnr)
test_samurai.test_all()
local out_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
local target_line = nil
for i, line in ipairs(lines) do
if line == "[ PASS ] - suite two test two" then
target_line = i
break
end
end
assert.is_not_nil(target_line)
vim.api.nvim_win_set_cursor(0, { target_line, 0 })
local keys = vim.api.nvim_replace_termcodes("<leader>o", true, false, true)
vim.api.nvim_feedkeys(keys, "x", false)
vim.wait(20, function()
return #find_float_wins() == 0
end)
assert.equals(file2, vim.api.nvim_buf_get_name(0))
local cursor = vim.api.nvim_win_get_cursor(0)
assert.equals(2, cursor[1])
vim.fn.jobstart = orig_jobstart
end)
it("disables hardtime in listing/detail and restores on close", function()
local orig_hardtime = package.loaded["hardtime"]
local disable_calls = 0