Files
test-samurai.nvim/tests/test_samurai_output_spec.lua

1403 lines
37 KiB
Lua

local test_samurai = require("test-samurai")
local core = require("test-samurai.core")
describe("test-samurai public API", function()
it("delegates show_output to core", function()
local called = false
local orig = core.show_output
core.show_output = function()
called = true
end
test_samurai.show_output()
core.show_output = orig
assert.is_true(called)
end)
it("delegates test_nearest to core.run_nearest", function()
local called = false
local orig = core.run_nearest
core.run_nearest = function()
called = true
end
test_samurai.test_nearest()
core.run_nearest = orig
assert.is_true(called)
end)
it("delegates test_file to core.run_file", function()
local called = false
local orig = core.run_file
core.run_file = function()
called = true
end
test_samurai.test_file()
core.run_file = orig
assert.is_true(called)
end)
it("delegates test_all to core.run_all", function()
local called = false
local orig = core.run_all
core.run_all = function()
called = true
end
test_samurai.test_all()
core.run_all = orig
assert.is_true(called)
end)
it("delegates test_last to core.run_last", function()
local called = false
local orig = core.run_last
core.run_last = function()
called = true
end
test_samurai.test_last()
core.run_last = orig
assert.is_true(called)
end)
it("delegates test_failed_only to core.run_failed_only", function()
local called = false
local orig = core.run_failed_only
core.run_failed_only = function()
called = true
end
test_samurai.test_failed_only()
core.run_failed_only = orig
assert.is_true(called)
end)
end)
describe("test-samurai output formatting", function()
before_each(function()
test_samurai.setup()
end)
it("formats JSON output as PASS/FAIL lines", 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_format.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 lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
vim.fn.jobstart = orig_jobstart
local has_pass = false
local has_skip = false
local has_fail = false
for _, line in ipairs(lines) do
if line == "[ PASS ] - inner 1" then
has_pass = true
elseif line == "[ SKIP ] - inner skip" then
has_skip = true
elseif line == "[ FAIL ] - inner 2" then
has_fail = true
end
end
assert.is_true(has_pass)
assert.is_true(has_skip)
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 = {
{
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_raw_json.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 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
local has_raw_json = false
for _, line in ipairs(lines) do
if line == json then
has_raw_json = true
break
end
end
assert.is_false(has_raw_json)
end)
it("formats multi-line jest JSON output and ignores non-JSON lines", function()
local lines_out = {
"Some log line",
"{",
' "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, lines_out, 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_multiline_json.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 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
local has_pass = false
local has_raw_json = false
for _, line in ipairs(lines) do
if line == "[ PASS ] - inner 1" then
has_pass = true
elseif line == ' "testResults": [' then
has_raw_json = true
end
end
assert.is_true(has_pass)
assert.is_false(has_raw_json)
end)
it("formats jest verbose output as PASS/FAIL/SKIP lines", function()
local check = string.char(0xE2, 0x9C, 0x93)
local cross = string.char(0xE2, 0x9C, 0x95)
local circle = string.char(0xE2, 0x97, 0x8B)
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, {
" PASS /tmp/output_verbose.test.ts",
" " .. check .. " inner 1 (5 ms)",
" " .. circle .. " inner skip (skipped)",
" " .. cross .. " inner 2 (1 ms)",
}, 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_verbose.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 lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
vim.fn.jobstart = orig_jobstart
local has_pass = false
local has_skip = false
local has_fail = false
local has_raw_verbose = false
for _, line in ipairs(lines) do
if line == "[ PASS ] - inner 1" then
has_pass = true
elseif line == "[ SKIP ] - inner skip" then
has_skip = true
elseif line == "[ FAIL ] - inner 2" then
has_fail = true
elseif line:match("^%s*PASS%s+") and line ~= " PASS 1 - SKIPPED 1 - FAILED 1" then
has_raw_verbose = true
end
end
assert.is_true(has_pass)
assert.is_true(has_skip)
assert.is_true(has_fail)
assert.is_false(has_raw_verbose)
end)
it("formats jest JSON output for TSamAll as full names", 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_fullname_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
local has_pass = false
local has_skip = false
local has_fail = false
for _, line in ipairs(lines) do
if line == "[ PASS ] - outer inner 1" then
has_pass = true
elseif line == "[ SKIP ] - outer inner skip" then
has_skip = true
elseif line == "[ FAIL ] - outer inner 2" then
has_fail = true
end
end
assert.is_true(has_pass)
assert.is_true(has_skip)
assert.is_true(has_fail)
end)
it("formats jest verbose output for TSamAll as short names", function()
local check = string.char(0xE2, 0x9C, 0x93)
local cross = string.char(0xE2, 0x9C, 0x95)
local circle = string.char(0xE2, 0x97, 0x8B)
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, {
" PASS /tmp/output_verbose_all.test.ts",
" " .. check .. " inner 1 (5 ms)",
" " .. circle .. " inner skip (skipped)",
" " .. cross .. " inner 2 (1 ms)",
}, 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_verbose_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
local has_pass = false
local has_skip = false
local has_fail = false
local has_raw_verbose = false
for _, line in ipairs(lines) do
if line == "[ PASS ] - inner 1" then
has_pass = true
elseif line == "[ SKIP ] - inner skip" then
has_skip = true
elseif line == "[ FAIL ] - inner 2" then
has_fail = true
elseif line:match("^%s*PASS%s+") and line ~= " PASS 1 - SKIPPED 1 - FAILED 1" then
has_raw_verbose = true
end
end
assert.is_true(has_pass)
assert.is_true(has_skip)
assert.is_true(has_fail)
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",
Test = "TestHandleGet/returns_200",
})
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, { json_line }, 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_go_short_test.go")
vim.bo[bufnr].filetype = "go"
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
"package main",
"import \"testing\"",
"",
"func TestHandleGet(t *testing.T) {",
" t.Run(\"returns_200\", func(t *testing.T) {",
" -- inside test",
" })",
"}",
})
vim.api.nvim_set_current_buf(bufnr)
vim.api.nvim_win_set_cursor(0, { 6, 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
local has_pass = false
local has_raw_json = false
for _, line in ipairs(lines) do
if line == "[ PASS ] - returns_200" then
has_pass = true
elseif line == json_line then
has_raw_json = true
end
end
assert.is_true(has_pass)
assert.is_false(has_raw_json)
end)
it("does not print raw JSON output for mocha json-stream", function()
test_samurai.setup({
runner_modules = {
"test-samurai.runners.js-mocha",
},
})
local json_line = vim.json.encode({
event = "pass",
fullTitle = "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_line }, 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_raw_json.test.js")
vim.bo[bufnr].filetype = "javascript"
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 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
local has_raw_json = false
for _, line in ipairs(lines) do
if line == json_line then
has_raw_json = true
break
end
end
assert.is_false(has_raw_json)
end)
it("formats mocha json-stream array output as PASS/FAIL lines", function()
test_samurai.setup({
runner_modules = {
"test-samurai.runners.js-mocha",
},
})
local pass_line = vim.json.encode({
"pass",
{
title = "GET: /",
fullTitle = "API :: /brands... GET: /",
},
})
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, { pass_line }, 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_mocha_json_stream.test.js")
vim.bo[bufnr].filetype = "javascript"
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 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
local has_pass = false
local has_raw_json = false
for _, line in ipairs(lines) do
if line == "[ PASS ] - GET: /" then
has_pass = true
elseif line == pass_line then
has_raw_json = true
end
end
assert.is_true(has_pass)
assert.is_false(has_raw_json)
end)
it("does not print raw JSON when JSON arrives on stdout and stderr", function()
test_samurai.setup({
runner_modules = {
"test-samurai.runners.js-jest",
},
})
local json1 = vim.json.encode({
testResults = {
{
assertionResults = {
{ status = "passed", title = "inner 1", fullName = "outer inner 1" },
},
},
},
})
local json2 = 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, { json1 }, nil)
end
if opts and opts.on_stderr then
opts.on_stderr(1, { json2 }, 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_raw_json_both.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 lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
vim.fn.jobstart = orig_jobstart
local has_raw_json = false
for _, line in ipairs(lines) do
if line == json1 or line == json2 then
has_raw_json = true
break
end
end
assert.is_false(has_raw_json)
end)
it("handles mixed mocha json-stream events and tracks failures for failed-only", function()
test_samurai.setup({
runner_modules = {
"test-samurai.runners.js-mocha",
},
})
local pass_line = vim.json.encode({
event = "pass",
title = "inner 1",
fullTitle = "outer inner 1",
})
local fail_line = vim.json.encode({
event = "fail",
title = "inner 2",
fullTitle = "outer inner 2",
})
local job_calls = {}
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(cmd, opts)
table.insert(job_calls, { cmd = cmd, opts = opts })
if #job_calls == 1 then
if opts and opts.on_stdout then
opts.on_stdout(1, { pass_line, fail_line }, nil)
end
if opts and opts.on_exit then
opts.on_exit(1, 1, nil)
end
else
if opts and opts.on_exit then
opts.on_exit(1, 1, nil)
end
end
return 1
end
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_name(bufnr, "/tmp/output_mixed_json.test.js")
vim.bo[bufnr].filetype = "javascript"
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 lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
core.run_failed_only()
vim.fn.jobstart = orig_jobstart
local has_pass = false
local has_fail = false
for _, line in ipairs(lines) do
if line == "[ PASS ] - inner 1" then
has_pass = true
elseif line == "[ FAIL ] - inner 2" then
has_fail = true
end
end
assert.is_true(has_pass)
assert.is_true(has_fail)
assert.is_true(#job_calls >= 2)
local failed_cmd = job_calls[2].cmd or {}
local saw_grep = false
local saw_fgrep = false
local saw_title = false
for _, arg in ipairs(failed_cmd) do
if arg == "--grep" then
saw_grep = true
elseif arg == "--fgrep" then
saw_fgrep = true
elseif arg == "outer inner 2" then
saw_title = true
end
end
assert.is_false(saw_grep)
assert.is_true(saw_fgrep)
assert.is_true(saw_title)
end)
it("formats TAP output as PASS/FAIL lines", function()
test_samurai.setup({
runner_modules = {
"test-samurai.runners.js-vitest",
},
})
local orig_jobstart = vim.fn.jobstart
vim.fn.jobstart = function(_cmd, opts)
if opts and opts.on_stdout then
opts.on_stdout(1, {
"TAP version 13",
"1..2",
"ok 1 - outer > inner 1 # time=1.00ms",
"ok 2 - outer > inner skip # SKIP not now",
"not ok 2 - outer > inner 2 # time=2.00ms",
}, 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_format.tap.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 lines = vim.api.nvim_buf_get_lines(out_buf, 0, -1, false)
vim.fn.jobstart = orig_jobstart
local has_pass = false
local has_skip = false
local has_fail = false
for _, line in ipairs(lines) do
if line == "[ PASS ] - inner 1" then
has_pass = true
elseif line == "[ SKIP ] - inner skip" then
has_skip = true
elseif line == "[ FAIL ] - inner 2" then
has_fail = true
end
end
assert.is_true(has_pass)
assert.is_true(has_skip)
assert.is_true(has_fail)
end)
end)