Files
test-samurai.nvim/tests/test_samurai_core_spec.lua
M.Schirmer 924584d8b3
All checks were successful
tests / test (push) Successful in 8s
add rerun function from within the listing-float
2026-01-07 20:11:53 +01:00

520 lines
15 KiB
Lua

local test_samurai = require("test-samurai")
local core = require("test-samurai.core")
local config = require("test-samurai.config")
describe("test-samurai core (no bundled runners)", function()
before_each(function()
test_samurai.setup()
end)
it("defaults to an empty runner_modules list", function()
local cfg = config.get()
assert.is_true(type(cfg.runner_modules) == "table")
assert.equals(0, #cfg.runner_modules)
end)
it("warns when no runner is installed for a test file", function()
local notified = {}
local orig_notify = vim.notify
vim.notify = function(msg, level)
table.insert(notified, { msg = msg, level = level })
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/no_runner_test.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
core.run_nearest()
vim.notify = orig_notify
assert.equals(1, #notified)
assert.equals("[test-samurai] no runner installed for this kind of test", notified[1].msg)
end)
it("fills quickfix after failed-only runs using last failures", function()
local runner = {
name = "test-runner",
}
function runner.is_test_file(_bufnr)
return true
end
function runner.find_nearest(bufnr, _row, _col)
return { file = vim.api.nvim_buf_get_name(bufnr), cwd = vim.loop.cwd(), test_name = "TestA" }
end
function runner.build_command(spec)
return { cmd = { "echo", "nearest" }, cwd = spec.cwd }
end
function runner.build_file_command(_bufnr)
return { cmd = { "echo", "file" } }
end
function runner.build_all_command(_bufnr)
return { cmd = { "echo", "all" } }
end
function runner.build_failed_command(last_command, _failures, _scope_kind)
return { cmd = { "echo", "failed" }, cwd = last_command and last_command.cwd or nil }
end
function runner.parse_results(output)
local passes = {}
local failures = {}
if type(output) == "string" then
if output:find("FAIL TestA", 1, true) then
failures = { "TestA" }
end
if output:find("PASS TestA", 1, true) then
passes = { "TestA" }
end
end
return { passes = passes, failures = failures, skips = {} }
end
function runner.output_parser()
return {
on_line = function(line, _state)
if line == "FAIL TestA" then
return { passes = {}, failures = { "TestA" }, skips = {} }
end
if line == "PASS TestA" then
return { passes = { "TestA" }, failures = {}, skips = {} }
end
return nil
end,
on_complete = function(output, _state)
return runner.parse_results(output)
end,
}
end
function runner.parse_test_output(_output)
return {}
end
function runner.collect_failed_locations(failures, _command, _scope_kind)
local items = {}
for _, name in ipairs(failures or {}) do
table.insert(items, { filename = "file", lnum = 1, col = 1, text = name })
end
return items
end
package.loaded["test-samurai-test-runner"] = runner
test_samurai.setup({ runner_modules = { "test-samurai-test-runner" } })
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/test_runner_quickfix.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
local qf_calls = {}
local orig_setqflist = vim.fn.setqflist
vim.fn.setqflist = function(_, _, opts)
if opts and type(opts.items) == "table" then
table.insert(qf_calls, opts.items)
end
end
local job_outputs = {
{ "FAIL TestA" },
{ "PASS TestA" },
}
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
local lines = table.remove(job_outputs, 1) or {}
if opts.on_stdout then
opts.on_stdout(nil, lines, nil)
end
if opts.on_exit then
opts.on_exit(nil, 0, nil)
end
return 1
end
core.run_nearest()
core.run_failed_only()
vim.fn.jobstart = orig_jobstart
vim.fn.setqflist = orig_setqflist
local last = qf_calls[#qf_calls]
assert.is_true(type(last) == "table")
assert.equals(1, #last)
assert.equals("TestA", last[1].text)
end)
it("shows help with TSam commands and keymaps in the detail float", function()
local runner = {
name = "test-runner-help",
}
function runner.is_test_file(_bufnr)
return true
end
function runner.find_nearest(bufnr, _row, _col)
return { file = vim.api.nvim_buf_get_name(bufnr), cwd = vim.loop.cwd(), test_name = "TestA" }
end
function runner.build_command(spec)
return { cmd = { "echo", "nearest" }, cwd = spec.cwd }
end
function runner.build_file_command(_bufnr)
return { cmd = { "echo", "file" } }
end
function runner.build_all_command(_bufnr)
return { cmd = { "echo", "all" } }
end
function runner.build_failed_command(last_command, _failures, _scope_kind)
return { cmd = { "echo", "failed" }, cwd = last_command and last_command.cwd or nil }
end
function runner.parse_results(_output)
return { passes = {}, failures = {}, skips = {} }
end
function runner.output_parser()
return {
on_line = function(_line, _state)
return nil
end,
on_complete = function(output, _state)
return runner.parse_results(output)
end,
}
end
function runner.parse_test_output(_output)
return {}
end
function runner.collect_failed_locations(_failures, _command, _scope_kind)
return {}
end
package.loaded["test-samurai-help-runner"] = runner
test_samurai.setup({ runner_modules = { "test-samurai-help-runner" } })
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/test_samurai_help.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts.on_exit then
opts.on_exit(nil, 0, nil)
end
return 1
end
core.run_nearest()
local listing_buf = vim.api.nvim_get_current_buf()
local maps = vim.api.nvim_buf_get_keymap(listing_buf, "n")
local has_help = false
for _, map in ipairs(maps) do
if map.lhs == "?" then
has_help = true
break
end
end
assert.is_true(has_help)
core.show_help()
local detail_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(detail_buf, 0, -1, false)
local joined = table.concat(lines, "\n")
assert.is_true(joined:find("TSamNearest", 1, true) ~= nil)
assert.is_true(joined:find("TSamShowOutput", 1, true) ~= nil)
assert.is_true(joined:find("<leader>tn", 1, true) ~= nil)
assert.is_true(joined:find("<leader>to", 1, true) ~= nil)
vim.fn.jobstart = orig_jobstart
end)
it("filters listing entries and restores them", function()
local runner = {
name = "test-runner-filter",
}
function runner.is_test_file(_bufnr)
return true
end
function runner.find_nearest(bufnr, _row, _col)
return { file = vim.api.nvim_buf_get_name(bufnr), cwd = vim.loop.cwd(), test_name = "TestA" }
end
function runner.build_command(spec)
return { cmd = { "echo", "nearest" }, cwd = spec.cwd }
end
function runner.build_file_command(_bufnr)
return { cmd = { "echo", "file" } }
end
function runner.build_all_command(_bufnr)
return { cmd = { "echo", "all" } }
end
function runner.build_failed_command(last_command, _failures, _scope_kind)
return { cmd = { "echo", "failed" }, cwd = last_command and last_command.cwd or nil }
end
function runner.parse_results(_output)
return { passes = { "TestA" }, failures = { "TestC" }, skips = { "TestB" } }
end
function runner.output_parser()
return {
on_line = function(_line, _state)
return nil
end,
on_complete = function(output, _state)
return runner.parse_results(output)
end,
}
end
function runner.parse_test_output(_output)
return {}
end
function runner.collect_failed_locations(_failures, _command, _scope_kind)
return {}
end
package.loaded["test-samurai-filter-runner"] = runner
test_samurai.setup({ runner_modules = { "test-samurai-filter-runner" } })
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/test_samurai_filter.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts.on_exit then
opts.on_exit(nil, 0, nil)
end
return 1
end
core.run_nearest()
local listing_buf = vim.api.nvim_get_current_buf()
local original = vim.api.nvim_buf_get_lines(listing_buf, 0, -1, false)
core.filter_listing_failures()
local failures_only = vim.api.nvim_buf_get_lines(listing_buf, 0, -1, false)
local failures_joined = table.concat(failures_only, "\n")
assert.is_true(failures_joined:find("[ FAIL ] - TestC", 1, true) ~= nil)
assert.is_true(failures_joined:find("[ SKIP ] - TestB", 1, true) == nil)
assert.equals(original[1], failures_only[1])
assert.equals("", failures_only[2])
assert.is_true(failures_joined:find("TOTAL", 1, true) ~= nil)
core.filter_listing_skips()
local skips_only = vim.api.nvim_buf_get_lines(listing_buf, 0, -1, false)
local skips_joined = table.concat(skips_only, "\n")
assert.is_true(skips_joined:find("[ SKIP ] - TestB", 1, true) ~= nil)
assert.is_true(skips_joined:find("[ FAIL ] - TestC", 1, true) == nil)
core.filter_listing_all()
local restored = vim.api.nvim_buf_get_lines(listing_buf, 0, -1, false)
assert.equals(table.concat(original, "\n"), table.concat(restored, "\n"))
vim.fn.jobstart = orig_jobstart
end)
it("keeps the listing unchanged when no filter matches exist", function()
local runner = {
name = "test-runner-no-matches",
}
function runner.is_test_file(_bufnr)
return true
end
function runner.find_nearest(bufnr, _row, _col)
return { file = vim.api.nvim_buf_get_name(bufnr), cwd = vim.loop.cwd(), test_name = "TestA" }
end
function runner.build_command(spec)
return { cmd = { "echo", "nearest" }, cwd = spec.cwd }
end
function runner.build_file_command(_bufnr)
return { cmd = { "echo", "file" } }
end
function runner.build_all_command(_bufnr)
return { cmd = { "echo", "all" } }
end
function runner.build_failed_command(last_command, _failures, _scope_kind)
return { cmd = { "echo", "failed" }, cwd = last_command and last_command.cwd or nil }
end
function runner.parse_results(_output)
return { passes = { "TestA" }, failures = {}, skips = {} }
end
function runner.output_parser()
return {
on_line = function(_line, _state)
return nil
end,
on_complete = function(output, _state)
return runner.parse_results(output)
end,
}
end
function runner.parse_test_output(_output)
return {}
end
function runner.collect_failed_locations(_failures, _command, _scope_kind)
return {}
end
package.loaded["test-samurai-no-match-runner"] = runner
test_samurai.setup({ runner_modules = { "test-samurai-no-match-runner" } })
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/test_samurai_no_match.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts.on_exit then
opts.on_exit(nil, 0, nil)
end
return 1
end
core.run_nearest()
local listing_buf = vim.api.nvim_get_current_buf()
local original = vim.api.nvim_buf_get_lines(listing_buf, 0, -1, false)
core.filter_listing_failures()
core.filter_listing_skips()
local after = vim.api.nvim_buf_get_lines(listing_buf, 0, -1, false)
assert.equals(table.concat(original, "\n"), table.concat(after, "\n"))
vim.fn.jobstart = orig_jobstart
end)
it("runs the test under the cursor from the listing", function()
local runner = {
name = "test-runner-run-cursor",
}
function runner.is_test_file(_bufnr)
return true
end
function runner.find_nearest(bufnr, _row, _col)
return { file = vim.api.nvim_buf_get_name(bufnr), cwd = vim.loop.cwd(), test_name = "TestA" }
end
local build_specs = {}
function runner.build_command(spec)
table.insert(build_specs, vim.deepcopy(spec))
return { cmd = { "echo", "single" }, cwd = spec.cwd }
end
function runner.build_file_command(_bufnr)
return { cmd = { "echo", "file" } }
end
function runner.build_all_command(_bufnr)
return { cmd = { "echo", "all" } }
end
function runner.build_failed_command(last_command, _failures, _scope_kind)
return { cmd = { "echo", "failed" }, cwd = last_command and last_command.cwd or nil }
end
function runner.parse_results(_output)
return { passes = { "TestA" }, failures = { "TestC" }, skips = { "TestB" } }
end
function runner.output_parser()
return {
on_line = function(_line, _state)
return nil
end,
on_complete = function(output, _state)
return runner.parse_results(output)
end,
}
end
function runner.parse_test_output(_output)
return {}
end
function runner.collect_failed_locations(_failures, _command, _scope_kind)
return {}
end
package.loaded["test-samurai-run-cursor-runner"] = runner
test_samurai.setup({ runner_modules = { "test-samurai-run-cursor-runner" } })
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/test_samurai_run_cursor.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_set_current_buf(bufnr)
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts.on_exit then
opts.on_exit(nil, 0, nil)
end
return 1
end
runner._last_mocha_titles = { TestC = "Suite TestC" }
core.run_nearest()
local listing_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(listing_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_true(target ~= nil)
vim.api.nvim_win_set_cursor(0, { target, 0 })
core.run_test_at_cursor()
vim.api.nvim_win_set_cursor(0, { 1, 0 })
core.run_test_at_cursor()
vim.fn.jobstart = orig_jobstart
assert.equals(2, #build_specs)
assert.equals("TestC", build_specs[2].test_name)
assert.equals("TestC", build_specs[2].full_name)
assert.equals("Suite TestC", build_specs[2].mocha_full_title)
end)
end)