local runner = require("test-samurai-mocha-runner") local function write_file(path, content) local dir = vim.fn.fnamemodify(path, ":h") vim.fn.mkdir(dir, "p") vim.fn.writefile(vim.split(content, "\n"), path) end local function make_buffer(path, content) local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_name(bufnr, path) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.split(content, "\n")) return bufnr end local function with_project(structure, fn) local root = vim.fn.tempname() vim.fn.mkdir(root, "p") root = vim.loop.fs_realpath(root) or root for rel_path, content in pairs(structure) do write_file(root .. "/" .. rel_path, content) end fn(root) end describe("test-samurai-mocha-runner", function() it("detects mocha test files via package.json", function() with_project({ ["package.json"] = [[{"devDependencies":{"mocha":"10.0.0"}}]], }, function(root) local bufnr = make_buffer(root .. "/test/sample.spec.js", "describe('x', function() {})") assert.is_true(runner.is_test_file(bufnr)) end) end) it("rejects non-mocha projects", function() with_project({ ["package.json"] = [[{"devDependencies":{"jest":"29.0.0"}}]], }, function(root) local bufnr = make_buffer(root .. "/test/sample.spec.js", "describe('x', function() {})") assert.is_false(runner.is_test_file(bufnr)) end) end) it("finds nearest with test > suite > file priority", function() with_project({ ["package.json"] = [[{"devDependencies":{"mocha":"10.0.0"}}]], }, function(root) local content = table.concat({ "describe(\"Math\", function() {", " it(\"adds\", function() {", " expect(1).to.equal(1)", " })", "", " it(\"subs\", function() {", " expect(1).to.equal(1)", " })", "})", "", "const value = 1", }, "\n") local bufnr = make_buffer(root .. "/test/math.spec.js", content) local spec_test = assert(runner.find_nearest(bufnr, 3, 0)) assert.equals("test", spec_test.kind) assert.equals("Math/adds", spec_test.full_name) local spec_suite = assert(runner.find_nearest(bufnr, 5, 0)) assert.equals("suite", spec_suite.kind) assert.equals("Math", spec_suite.full_name) local spec_file = assert(runner.find_nearest(bufnr, 11, 0)) assert.equals("file", spec_file.kind) end) end) it("returns error when no package.json found", function() local content = table.concat({ "describe(\"Math\", function() {", " it(\"adds\", function() {", " expect(1).to.equal(1)", " })", "})", }, "\n") local bufnr = make_buffer("/tmp/no-root.test.js", content) local spec, err = runner.find_nearest(bufnr, 2, 0) assert.is_nil(spec) assert.equals("no package.json found", err) local command = runner.build_file_command(bufnr) assert.are.same({ "echo", "no package.json found" }, command.cmd) end) it("builds command with mocha json-stream and grep", function() with_project({ ["package.json"] = [[{"devDependencies":{"mocha":"10.0.0"}}]], }, function(root) local spec = { file = root .. "/test/math.spec.js", cwd = root, kind = "test", mocha_full_title = "Math adds", full_name = "Math/adds", } local command = runner.build_command(spec) assert.equals("npx", command.cmd[1]) assert.equals("mocha", command.cmd[2]) assert.is_true(vim.tbl_contains(command.cmd, "--reporter")) assert.is_true(vim.tbl_contains(command.cmd, "json-stream")) assert.is_true(vim.tbl_contains(command.cmd, "--grep")) end) end) it("builds TSamAll with test glob", function() with_project({ ["package.json"] = [[{"devDependencies":{"mocha":"10.0.0"}}]], }, function(root) local bufnr = make_buffer(root .. "/test/sample.spec.js", "") local command = runner.build_all_command(bufnr) assert.is_true(vim.tbl_contains(command.cmd, "test/**/*.{test,spec}.{t,j}s")) end) end) it("streams results without duplicates", function() local output_lines = { [=["suite",{"title":"Math","fullTitle":"Math"}]=], [=["pass",{"title":"adds","fullTitle":"Math adds","file":"/tmp/math.spec.js"}]=], [=["pass",{"title":"adds","fullTitle":"Math adds","file":"/tmp/math.spec.js"}]=], [=["fail",{"title":"subs","fullTitle":"Math subs","file":"/tmp/math.spec.js","err":"oops","stack":"Error: oops\n at Context. (/tmp/math.spec.js:10:5)"}]=], [=["pending",{"title":"skips","fullTitle":"Math skips","file":"/tmp/math.spec.js"}]=], [=["suite end",{"title":"Math","fullTitle":"Math"}]=], } local parser = runner.output_parser() local state = {} local aggregated = { passes = {}, failures = {}, skips = {} } for _, line in ipairs(output_lines) do local results = parser.on_line("[" .. line .. "]", state) if results then for _, name in ipairs(results.passes or {}) do table.insert(aggregated.passes, name) end for _, name in ipairs(results.failures or {}) do table.insert(aggregated.failures, name) end for _, name in ipairs(results.skips or {}) do table.insert(aggregated.skips, name) end end end assert.equals("Math/adds", aggregated.passes[1]) assert.equals(1, #aggregated.passes) assert.equals("Math/subs", aggregated.failures[1]) assert.equals("Math/skips", aggregated.skips[1]) local items = runner.collect_failed_locations(aggregated.failures, {}, "nearest") assert.equals("/tmp/math.spec.js", items[1].filename) assert.equals(10, items[1].lnum) assert.equals(5, items[1].col) end) it("builds failed-only command with grep pattern", function() runner._last_mocha_titles = { ["Math/adds"] = "Math adds", ["Math/subs"] = "Math subs", } local command = runner.build_failed_command({ cwd = "/tmp" }, { "Math/adds", "Math/subs" }, "file") assert.equals("npx", command.cmd[1]) assert.is_true(vim.tbl_contains(command.cmd, "--grep")) local grep_index for idx, value in ipairs(command.cmd) do if value == "--grep" then grep_index = idx + 1 break end end assert.is_true(command.cmd[grep_index]:match("Math%.%*adds") ~= nil) end) it("parses results and per-test output", function() local output = table.concat({ [=["suite",{"title":"Math","fullTitle":"Math"}]=], [=["fail",{"title":"subs","fullTitle":"Math subs","file":"/tmp/math.spec.js","err":"oops","stack":"Error: oops\n at Context. (/tmp/math.spec.js:10:5)\n at processImmediate"}]=], [=["suite end",{"title":"Math","fullTitle":"Math"}]=], }, "\n") local results = runner.parse_results("[" .. output:gsub("\n", "]\n[") .. "]") assert.equals("Math/subs", results.failures[1]) local outputs = runner.parse_test_output("[" .. output:gsub("\n", "]\n[") .. "]") assert.is_true(outputs["Math/subs"] ~= nil) end) it("does not return results on complete", function() local parser = runner.output_parser() local state = {} local output = "[" .. [=["pass",{"title":"adds","fullTitle":"Math adds","file":"/tmp/math.spec.js"}]=] .. "]" local results = parser.on_complete(output, state) assert.is_nil(results) end) end)