create colored summary output for all commands

This commit is contained in:
2025-12-27 15:13:28 +01:00
parent 88aa1de902
commit 519fc38769
2 changed files with 752 additions and 2 deletions

View File

@@ -164,6 +164,161 @@ describe("test-samurai output formatting", function()
assert.is_true(has_fail)
end)
it("applies PASS/FAIL/SKIP highlights to parsed output", function()
local json = vim.json.encode({
testResults = {
{
assertionResults = {
{ status = "passed", title = "inner 1", fullName = "outer inner 1" },
{ status = "skipped", title = "inner skip", fullName = "outer inner skip" },
{ status = "failed", 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, 1, nil)
end
return 1
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_highlight_parsed.test.ts")
vim.bo[bufnr].filetype = "typescript"
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'describe("outer", function() {',
' it("inner 1", function() {',
" -- inside 1",
" })",
"",
' it("inner 2", function() {',
" -- inside 2",
" })",
"})",
})
vim.api.nvim_set_current_buf(bufnr)
vim.api.nvim_win_set_cursor(0, { 7, 0 })
core.run_nearest()
local out_buf = vim.api.nvim_get_current_buf()
local ns = vim.api.nvim_create_namespace("TestSamuraiResult")
local extmarks = vim.api.nvim_buf_get_extmarks(out_buf, ns, 0, -1, { details = true })
vim.fn.jobstart = orig_jobstart
local groups = {}
for _, mark in ipairs(extmarks) do
local details = mark[4] or {}
if details.hl_group then
groups[details.hl_group] = true
end
end
assert.is_true(groups.TestSamuraiResultPass)
assert.is_true(groups.TestSamuraiResultFail)
assert.is_true(groups.TestSamuraiResultSkip)
end)
it("sets pass border when there are only passing tests", function()
local json = vim.json.encode({
testResults = {
{
assertionResults = {
{ status = "passed", title = "inner 1", fullName = "outer inner 1" },
},
},
},
})
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_border_pass.test.ts")
vim.bo[bufnr].filetype = "typescript"
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'describe("outer", function() {',
' it("inner 1", function() {',
" -- inside 1",
" })",
"})",
})
vim.api.nvim_set_current_buf(bufnr)
vim.api.nvim_win_set_cursor(0, { 3, 0 })
core.run_nearest()
local win = vim.api.nvim_get_current_win()
local hl = vim.api.nvim_win_get_option(win, "winhighlight")
vim.fn.jobstart = orig_jobstart
assert.equals("FloatBorder:TestSamuraiBorderPass", hl)
end)
it("sets fail border when there are failing tests", function()
local json = vim.json.encode({
testResults = {
{
assertionResults = {
{ status = "failed", 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, 1, nil)
end
return 1
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_border_fail.test.ts")
vim.bo[bufnr].filetype = "typescript"
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'describe("outer", function() {',
' it("inner 2", function() {',
" -- inside 2",
" })",
"})",
})
vim.api.nvim_set_current_buf(bufnr)
vim.api.nvim_win_set_cursor(0, { 3, 0 })
core.run_nearest()
local win = vim.api.nvim_get_current_win()
local hl = vim.api.nvim_win_get_option(win, "winhighlight")
vim.fn.jobstart = orig_jobstart
assert.equals("FloatBorder:TestSamuraiBorderFail", hl)
end)
it("does not print raw JSON output for jest runs", function()
local json = vim.json.encode({
testResults = {
@@ -334,7 +489,7 @@ describe("test-samurai output formatting", function()
has_skip = true
elseif line == "[ FAIL ] - inner 2" then
has_fail = true
elseif line:match("^%s*PASS%s+") then
elseif line:match("^%s*PASS%s+") and line ~= " PASS 1 - SKIPPED 1 - FAILED 1" then
has_raw_verbose = true
end
end
@@ -468,7 +623,7 @@ describe("test-samurai output formatting", function()
has_skip = true
elseif line == "[ FAIL ] - inner 2" then
has_fail = true
elseif line:match("^%s*PASS%s+") then
elseif line:match("^%s*PASS%s+") and line ~= " PASS 1 - SKIPPED 1 - FAILED 1" then
has_raw_verbose = true
end
end
@@ -479,6 +634,365 @@ describe("test-samurai output formatting", function()
assert.is_false(has_raw_verbose)
end)
it("adds a summary line for TSamFile output", function()
local json = vim.json.encode({
testResults = {
{
assertionResults = {
{ status = "passed", title = "inner 1", fullName = "outer inner 1" },
{ status = "skipped", title = "inner skip", fullName = "outer inner skip" },
{ status = "failed", 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 orig_hrtime = vim.loop.hrtime
local hr_calls = 0
vim.loop.hrtime = function()
hr_calls = hr_calls + 1
if hr_calls == 1 then
return 1000000000
end
return 3500000000
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_summary_file.test.ts")
vim.bo[bufnr].filetype = "typescript"
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'describe("outer", function() {',
' it("inner 1", function() {',
" -- inside 1",
" })",
"",
' it("inner 2", function() {',
" -- inside 2",
" })",
"})",
})
vim.api.nvim_set_current_buf(bufnr)
vim.api.nvim_win_set_cursor(0, { 7, 0 })
core.run_file()
local out_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
vim.fn.jobstart = orig_jobstart
vim.loop.hrtime = orig_hrtime
local has_total = false
local has_breakdown = false
local has_duration = false
local saw_blank = false
for _, line in ipairs(lines) do
if line == "" then
saw_blank = true
elseif line == "TOTAL 3" then
has_total = true
elseif line == "DURATION 00m 02s" then
has_duration = true
elseif line == " PASS 1 - SKIPPED 1 - FAILED 1" then
has_breakdown = true
end
end
assert.is_true(saw_blank)
assert.is_true(has_total)
assert.is_true(has_breakdown)
assert.is_true(has_duration)
end)
it("adds a summary line for TSamAll output", function()
local json = vim.json.encode({
testResults = {
{
assertionResults = {
{ status = "passed", title = "inner 1", fullName = "outer inner 1" },
{ status = "skipped", title = "inner skip", fullName = "outer inner skip" },
{ status = "failed", 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 orig_hrtime = vim.loop.hrtime
local hr_calls = 0
vim.loop.hrtime = function()
hr_calls = hr_calls + 1
if hr_calls == 1 then
return 500000000
end
return 2000000000
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_summary_all.test.ts")
vim.bo[bufnr].filetype = "typescript"
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'describe("outer", function() {',
' it("inner 1", function() {',
" -- inside 1",
" })",
"",
' it("inner 2", function() {',
" -- inside 2",
" })",
"})",
})
vim.api.nvim_set_current_buf(bufnr)
vim.api.nvim_win_set_cursor(0, { 7, 0 })
core.run_all()
local out_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
vim.fn.jobstart = orig_jobstart
vim.loop.hrtime = orig_hrtime
local has_total = false
local has_breakdown = false
local has_duration = false
local saw_blank = false
for _, line in ipairs(lines) do
if line == "" then
saw_blank = true
elseif line == "TOTAL 3" then
has_total = true
elseif line == "DURATION 00m 01s" then
has_duration = true
elseif line == " PASS 1 - SKIPPED 1 - FAILED 1" then
has_breakdown = true
end
end
assert.is_true(saw_blank)
assert.is_true(has_total)
assert.is_true(has_breakdown)
assert.is_true(has_duration)
end)
it("adds a summary line for TSamNearest output", function()
local json = vim.json.encode({
testResults = {
{
assertionResults = {
{ status = "passed", title = "inner 1", fullName = "outer inner 1" },
{ status = "skipped", title = "inner skip", fullName = "outer inner skip" },
{ status = "failed", 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 orig_hrtime = vim.loop.hrtime
local hr_calls = 0
vim.loop.hrtime = function()
hr_calls = hr_calls + 1
if hr_calls == 1 then
return 2000000000
end
return 4500000000
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_summary_nearest.test.ts")
vim.bo[bufnr].filetype = "typescript"
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'describe("outer", function() {',
' it("inner 1", function() {',
" -- inside 1",
" })",
"",
' it("inner 2", function() {',
" -- inside 2",
" })",
"})",
})
vim.api.nvim_set_current_buf(bufnr)
vim.api.nvim_win_set_cursor(0, { 3, 0 })
core.run_nearest()
local out_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
vim.fn.jobstart = orig_jobstart
vim.loop.hrtime = orig_hrtime
local has_total = false
local has_breakdown = false
local has_duration = false
local saw_blank = false
for _, line in ipairs(lines) do
if line == "" then
saw_blank = true
elseif line == "TOTAL 3" then
has_total = true
elseif line == "DURATION 00m 02s" then
has_duration = true
elseif line == " PASS 1 - SKIPPED 1 - FAILED 1" then
has_breakdown = true
end
end
assert.is_true(saw_blank)
assert.is_true(has_total)
assert.is_true(has_breakdown)
assert.is_true(has_duration)
end)
it("applies summary highlights for TSamAll output", function()
local json = vim.json.encode({
testResults = {
{
assertionResults = {
{ status = "passed", title = "inner 1", fullName = "outer inner 1" },
{ status = "skipped", title = "inner skip", fullName = "outer inner skip" },
{ status = "failed", 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 orig_hrtime = vim.loop.hrtime
local hr_calls = 0
vim.loop.hrtime = function()
hr_calls = hr_calls + 1
if hr_calls == 1 then
return 1000000000
end
return 2500000000
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_summary_highlight_all.test.ts")
vim.bo[bufnr].filetype = "typescript"
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
'describe("outer", function() {',
' it("inner 1", function() {',
" -- inside 1",
" })",
"",
' it("inner 2", function() {',
" -- inside 2",
" })",
"})",
})
vim.api.nvim_set_current_buf(bufnr)
vim.api.nvim_win_set_cursor(0, { 7, 0 })
core.run_all()
local out_buf = vim.api.nvim_get_current_buf()
local ns = vim.api.nvim_create_namespace("TestSamuraiSummary")
local extmarks = vim.api.nvim_buf_get_extmarks(out_buf, ns, 0, -1, { details = true })
vim.fn.jobstart = orig_jobstart
vim.loop.hrtime = orig_hrtime
local groups = {}
for _, mark in ipairs(extmarks) do
local details = mark[4] or {}
if details.hl_group then
groups[details.hl_group] = true
end
end
assert.is_true(groups.TestSamuraiSummaryBold)
assert.is_true(groups.TestSamuraiSummaryPass)
assert.is_true(groups.TestSamuraiSummaryFail)
assert.is_true(groups.TestSamuraiSummarySkip)
end)
it("derives summary highlight colors from diagnostic fallbacks", function()
local orig_get_hl = vim.api.nvim_get_hl
local orig_set_hl = vim.api.nvim_set_hl
local set_calls = {}
vim.api.nvim_get_hl = function(_ns, opts)
if opts.name == "DiffAdd" or opts.name == "DiffDelete" then
return {}
end
if opts.name == "DiagnosticOk" then
return { fg = 111 }
end
if opts.name == "DiagnosticError" then
return { fg = 222 }
end
if opts.name == "DiagnosticInfo" then
return { fg = 333 }
end
if opts.name == "Normal" then
return { fg = 99 }
end
return {}
end
vim.api.nvim_set_hl = function(_ns, name, opts)
set_calls[name] = opts
end
core.setup()
vim.api.nvim_get_hl = orig_get_hl
vim.api.nvim_set_hl = orig_set_hl
assert.is_true(set_calls.TestSamuraiSummaryPass.fg == 111)
assert.is_true(set_calls.TestSamuraiSummaryFail.fg == 222)
assert.is_true(set_calls.TestSamuraiSummarySkip.fg == 333)
end)
it("formats go subtests as short names", function()
local json_line = vim.json.encode({
Action = "pass",