├── .bumpversion.cfg ├── .github └── workflows │ └── tests.yml ├── .gitignore ├── .vimrc.lua ├── LICENSE ├── Makefile ├── README.md ├── doc └── nvim-test.txt ├── lua └── nvim-test │ ├── config.lua │ ├── info.lua │ ├── init.lua │ ├── notify.lua │ ├── runner.lua │ ├── runners │ ├── busted.lua │ ├── cargo-test.lua │ ├── cypress.lua │ ├── dotnet.lua │ ├── go-test.lua │ ├── hspec.lua │ ├── init.lua │ ├── jest.lua │ ├── mocha.lua │ ├── pytest.lua │ ├── pyunit.lua │ ├── rspec.lua │ ├── stack.lua │ ├── ts-mocha.lua │ ├── vusted.lua │ └── zig.lua │ ├── terms │ ├── callbacks.lua │ ├── terminal.lua │ └── toggleterm.lua │ └── utils.lua ├── packspec.json └── spec ├── conftest.lua ├── fixtures ├── Spec.hs ├── Tests.cs ├── go │ ├── go.mod │ └── mypackage_test.go ├── js │ ├── name.js │ └── name.test.js ├── rust │ ├── Cargo.lock │ ├── Cargo.toml │ ├── crate │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── lib.rs │ │ │ ├── nested │ │ │ └── mod.rs │ │ │ ├── nomod.rs │ │ │ └── somemod.rs │ ├── crate2 │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── some │ │ └── main.rs ├── test.lua ├── test.py ├── test.ts ├── test_spec.rb └── zig │ ├── .gitignore │ ├── build.zig │ └── src │ ├── main.zig │ ├── nested │ └── mod.zig │ └── somemod.zig ├── helpers.lua ├── init_spec.lua ├── runner_spec.lua ├── runners ├── busted_spec.lua ├── cargo-test_spec.lua ├── dotnet_spec.lua ├── go-test_spec.lua ├── hspec_spec.lua ├── init_spec.lua ├── jest_spec.lua ├── mocha_spec.lua ├── pytest_spec.lua ├── pyunit_spec.lua ├── rspec_spec.lua ├── stack_spec.lua ├── ts-mocha_spec.lua ├── vusted_spec.lua └── zig_spec.lua └── utils_spec.lua /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | commit = True 3 | current_version = 1.4.1 4 | tag = True 5 | tag_name = {new_version} 6 | message = build(version): {current_version} -> {new_version} 7 | 8 | [bumpversion:file:packspec.json] 9 | 10 | [bumpversion:file:README.md] 11 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | on: 3 | push: 4 | branches: [main] 5 | pull_request: 6 | branches: [main] 7 | 8 | jobs: 9 | test: 10 | name: Test 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | os: 15 | - ubuntu-latest 16 | - macos-latest 17 | # - windows-latest 18 | version: 19 | - 'v0.8.2' 20 | - 'v0.9.0' 21 | - 'nightly' 22 | 23 | steps: 24 | - uses: actions/checkout@v2 25 | 26 | # Setup nvim 27 | - uses: notomo/action-setup-nvim-lua@v1 28 | with: 29 | luarocks-version: '3.5.0' 30 | 31 | # Install vusted 32 | - run: luarocks install vusted 33 | 34 | - uses: rhysd/action-setup-vim@v1 35 | id: vim 36 | with: 37 | neovim: true 38 | version: ${{matrix.version}} 39 | 40 | - run: make test 41 | env: 42 | VUSTED_NVIM: ${{ steps.vim.outputs.executable }} 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /doc/tags 2 | /_ 3 | /nvim-treesitter 4 | /todo.txt 5 | /spec/fixtures/**/target/ 6 | -------------------------------------------------------------------------------- /.vimrc.lua: -------------------------------------------------------------------------------- 1 | require("nvim-test").setup { 2 | runners = { 3 | lua = "nvim-test.runners.vusted", 4 | }, 5 | } 6 | 7 | require("nvim-test.runners.vusted"):setup { 8 | args = { "--helper=spec/conftest.lua" }, 9 | env = { 10 | VIRTUAL_ENV = "", 11 | VUSTED_ARGS = "--headless --clean", 12 | }, 13 | 14 | find_files = function(filename) 15 | local path, _ = vim.fn.fnamemodify(filename, ":p:h"):gsub("lua/nvim%-test", "spec") 16 | return string.format("%s/%s_spec.lua", path, vim.fn.fnamemodify(filename, ":t:r")) 17 | end, 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 klen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | nvim-treesitter: 2 | git clone https://github.com/nvim-treesitter/nvim-treesitter.git --depth=1 3 | 4 | LUA_PATH := $(LUA_PATH):$(CURDIR) 5 | test t: nvim-treesitter 6 | @echo $(CURDIR) 7 | vusted \ 8 | --shuffle --lpath="./?.lua;./?/?.lua;./?/init.lua" \ 9 | --helper=$(CURDIR)/spec/conftest.lua 10 | .PHONY: test t 11 | 12 | RELEASE ?= patch 13 | release patch: 14 | bumpversion $(RELEASE) 15 | git push 16 | git push --tags 17 | 18 | minor: 19 | make release RELEASE=minor 20 | 21 | major: 22 | make release RELEASE=major 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # nvim-test 1.4.1 4 | 5 | Test Runner for neovim 6 | 7 | [![tests](https://github.com/klen/nvim-test/actions/workflows/tests.yml/badge.svg)](https://github.com/klen/nvim-test/actions/workflows/tests.yml) 8 | [![Awesome Neovim](https://awesome.re/badge-flat.svg)](https://github.com/rockerBOO/awesome-neovim) 9 | 10 | 11 | ## Features 12 | 13 | | Language | Test Runners | 14 | | -------------: | :------------------------------- | 15 | | **C Sharp** | `dotnet test` | 16 | | **Go** | `go-test` | 17 | | **Haskell** | `hspec`, `stack` | 18 | | **Javascript** | `jest`, `mocha` | 19 | | **Lua** | `busted`, `vusted` | 20 | | **Python** | `pytest`, `pyunit` | 21 | | **Ruby** | `rspec` | 22 | | **Rust** | `cargo-test` | 23 | | **Typescript** | `jest`, `mocha`, `ts-mocha` | 24 | 25 | ## Install 26 | 27 | with [packer](https://github.com/wbthomason/packer.nvim): 28 | 29 | ```lua 30 | 31 | use { 32 | "klen/nvim-test", 33 | config = function() 34 | require('nvim-test').setup() 35 | end 36 | } 37 | ``` 38 | 39 | ## Commands 40 | 41 | The plugin defines the commands: 42 | 43 | - `TestSuite` - run the whole test suite 44 | - `TestFile` - run all tests for the current file 45 | - `TestEdit` - edit tests for the current file 46 | - `TestNearest` - run the test nearest to the cursor 47 | - `TestLast` - rerun the latest test 48 | - `TestVisit` - open the last run test in the current buffer 49 | - `TestInfo` - show an information about the plugin 50 | 51 | ## Setup 52 | 53 | This plugin must be explicitly enabled by using `require("nvim-test").setup{}` 54 | 55 | Default options: 56 | 57 | ```lua 58 | require('nvim-test').setup { 59 | run = true, -- run tests (using for debug) 60 | commands_create = true, -- create commands (TestFile, TestLast, ...) 61 | filename_modifier = ":.", -- modify filenames before tests run(:h filename-modifiers) 62 | silent = false, -- less notifications 63 | term = "terminal", -- a terminal to run ("terminal"|"toggleterm") 64 | termOpts = { 65 | direction = "vertical", -- terminal's direction ("horizontal"|"vertical"|"float") 66 | width = 96, -- terminal's width (for vertical|float) 67 | height = 24, -- terminal's height (for horizontal|float) 68 | go_back = false, -- return focus to original window after executing 69 | stopinsert = "auto", -- exit from insert mode (true|false|"auto") 70 | keep_one = true, -- keep only one terminal for testing 71 | }, 72 | runners = { -- setup tests runners 73 | cs = "nvim-test.runners.dotnet", 74 | go = "nvim-test.runners.go-test", 75 | haskell = "nvim-test.runners.hspec", 76 | javascriptreact = "nvim-test.runners.jest", 77 | javascript = "nvim-test.runners.jest", 78 | lua = "nvim-test.runners.busted", 79 | python = "nvim-test.runners.pytest", 80 | ruby = "nvim-test.runners.rspec", 81 | rust = "nvim-test.runners.cargo-test", 82 | typescript = "nvim-test.runners.jest", 83 | typescriptreact = "nvim-test.runners.jest", 84 | } 85 | } 86 | ``` 87 | 88 | Setup a runner: 89 | ```lua 90 | require('nvim-test.runners.jest'):setup { 91 | command = "~/node_modules/.bin/jest", -- a command to run the test runner 92 | args = { "--collectCoverage=false" }, -- default arguments 93 | env = { CUSTOM_VAR = 'value' }, -- custom environment variables 94 | 95 | file_pattern = "\\v(__tests__/.*|(spec|test))\\.(js|jsx|coffee|ts|tsx)$", -- determine whether a file is a testfile 96 | find_files = { "{name}.test.{ext}", "{name}.spec.{ext}" }, -- find testfile for a file 97 | 98 | filename_modifier = nil, -- modify filename before tests run (:h filename-modifiers) 99 | working_directory = nil, -- set working directory (cwd by default) 100 | } 101 | ``` 102 | -------------------------------------------------------------------------------- /doc/nvim-test.txt: -------------------------------------------------------------------------------- 1 | *nvim-test.txt* nvim-test 2 | 3 | ============================================================================== 4 | INTRODUCTION *nvim-test-introduction* 5 | 6 | Test Runner for neovim 7 | 8 | ------------------------------------------------------------------------------ 9 | COMMANDS *nvim-test-command* 10 | 11 | :TestSuite *:TestSuite* 12 | Run the whole test suite 13 | 14 | :TestFile *:TestFile* 15 | Run all tests in the current file 16 | 17 | :TestEdit *:TestEdit* 18 | Edit tests for the current file 19 | 20 | :TestNearest *:TestNearest* 21 | Run the test nearest to the cursor 22 | 23 | :TestLast *:TestLast* 24 | Rerun the latest test 25 | 26 | :TestVisit *:TestVisit* 27 | Open the last run test in the current buffer 28 | 29 | :TestInfo *:TestInfo* 30 | Show an information about plugin 31 | 32 | ------------------------------------------------------------------------------ 33 | SETUP *nvim-test-setup* 34 | 35 | Setup the plugin (default values): > 36 | 37 | require('nvim-test').setup { 38 | run = true, -- run tests (using for debug) 39 | commands_create = true, -- create commands (TestFile, TestLast, ...) 40 | filename_modifier = ":.", -- modify filenames before tests run(:h filename-modifiers) 41 | silent = false, -- less notifications 42 | term = "terminal", -- a terminal to run ("terminal"|"toggleterm") 43 | termOpts = { 44 | direction = "vertical", -- terminal's direction ("horizontal"|"vertical"|"float") 45 | width = 96, -- terminal's width (for vertical|float) 46 | height = 24, -- terminal's height (for horizontal|float) 47 | go_back = false, -- return focus to original window after executing 48 | stopinsert = "auto", -- exit from insert mode (true|false|"auto") 49 | keep_one = true, -- keep only one terminal for testing 50 | }, 51 | runners = { -- setup tests runners 52 | go = "nvim-test.runners.go-test", 53 | javascript = "nvim-test.runners.jest", 54 | lua = "nvim-test.runners.busted", 55 | python = "nvim-test.runners.pytest", 56 | rust = "nvim-test.runners.cargo-test", 57 | typescript = "nvim-test.runners.jest", 58 | } 59 | } 60 | 61 | Setup a runner: > 62 | 63 | require('nvim-test.runners.jest'):setup { 64 | command = "~/node_modules/.bin/jest", -- a command to run the test runner 65 | args = { "--collectCoverage=false" }, -- default arguments 66 | env = { CUSTOM_VAR = 'value' }, -- custom environment variables 67 | 68 | file_pattern = "\\v(__tests__/.*|(spec|test))\\.(js|jsx|coffee|ts|tsx)$", -- determine whether a file is a testfile 69 | find_files = { "{name}.test.{ext}", "{name}.spec.{ext}" }, -- find testfile for a file 70 | 71 | filename_modifier = nil, -- modify filename before tests run (:h filename-modifiers) 72 | working_directory = nil, -- set working directory (cwd by default) 73 | } 74 | 75 | ------------------------------------------------------------------------------ 76 | RUNNERS *nvim-test-runners* 77 | 78 | *nvim-test-busted* 79 | 80 | Default options: > 81 | 82 | require('nvim-test.runners.busted'):setup { 83 | command = "busted", 84 | file_pattern = "\\v_spec\\.(lua|moon)$", 85 | find_files = "{name}_spec.{ext}", 86 | } 87 | < 88 | *nvim-test-cargo-test* 89 | 90 | Cargotest runner may find the nearest crate root. 91 | 92 | Default options: > 93 | 94 | require('nvim-test.runners.cargo-test'):setup { 95 | command = "cargo", 96 | args = { "test" }, 97 | 98 | package = false, -- Set to true, to find the nearest create root 99 | } 100 | < 101 | *nvim-test-cypress* 102 | 103 | Default options: > 104 | 105 | require('nvim-test.runners.cypress'):setup { 106 | command = "go", 107 | args = { "test", "-v" } 108 | } 109 | < 110 | *nvim-test-go-test* 111 | 112 | Default options: > 113 | 114 | require('nvim-test.runners.go-test'):setup { 115 | command = {"./node_modules/.bin/cypress", "cypress"}, 116 | args = { "run" }, 117 | file_pattern = "\\v(__tests__/.*|(spec|test))\\.(js|jsx|coffee|ts|tsx)$", 118 | find_files = { "{name}.test.{ext}", "{name}.spec.{ext}" }, 119 | } 120 | < 121 | *nvim-test-jest* 122 | 123 | Default options: > 124 | 125 | require('nvim-test.runners.jest'):setup { 126 | command = { "./node_modules/.bin/jest", "jest" }, 127 | file_pattern = "\\v(__tests__/.*|(spec|test))\\.(js|jsx|coffee|ts|tsx)$", 128 | find_files = { "{name}.test.{ext}", "{name}.spec.{ext}" }, 129 | } 130 | < 131 | *nvim-test-mocha* 132 | 133 | Default options: > 134 | 135 | require('nvim-test.runners.mocha'):setup { 136 | command = { "./node_modules/.bin/mocha", "mocha" }, 137 | file_pattern = "\\v(tests?/.*|test)\\.(js|jsx|coffee)$", 138 | find_files = { "{name}.test.{ext}" }, 139 | } 140 | < 141 | *nvim-test-pytest* 142 | 143 | Default options: > 144 | 145 | require('nvim-test.runners.pytest'):setup { 146 | command = { (vim.env.VIRTUAL_ENV or "venv") .. "/bin/pytest", "pytest" }, 147 | file_pattern = "\\v(test_[^.]+|[^.]+_test|tests)\\.py$", 148 | find_files = { "test_{name}.py", "{name}_test.py", "tests.py" }, 149 | } 150 | < 151 | *nvim-test-pyunit* 152 | 153 | Default options: > 154 | 155 | require('nvim-test.runners.pytest'):setup { 156 | command = { (vim.env.VIRTUAL_ENV or "venv") .. "/bin/python", "python" }, 157 | args = { "-m", "unittest" }, 158 | file_pattern = "\\v^test.*\\.py$", 159 | find_files = { "test_{name}.py" }, 160 | } 161 | < 162 | *nvim-test-ts-mocha* 163 | 164 | Default options: > 165 | 166 | require('nvim-test.runners.ts-mocha'):setup { 167 | command = { "./node_modules/.bin/ts-mocha", "ts-mocha" }, 168 | file_pattern = "\\v(tests?/.*|test)\\.(ts|tsx)$", 169 | find_files = { "{name}.test.{ext}" }, 170 | } 171 | < 172 | *nvim-test-ts-vusted* 173 | 174 | Default options: > 175 | 176 | require('nvim-test.runners.vusted'):setup { 177 | command = "vusted", 178 | file_pattern = "\\v_spec\\.(lua|moon)$", 179 | find_files = "{name}_spec.{ext}", 180 | } 181 | < 182 | 183 | ------------------------------------------------------------------------------ 184 | ABOUT *nvim-test-about* 185 | 186 | Author: Kirill Klenove 187 | License: Same terms as Vim itself (see |license|) 188 | 189 | Grab the latest version or report a bug on GitHub: 190 | 191 | https://github.com/klen/nvim-test 192 | 193 | vim:tw=78:et:ft=help:norl: 194 | 195 | -------------------------------------------------------------------------------- /lua/nvim-test/config.lua: -------------------------------------------------------------------------------- 1 | -- Default configuration 2 | -- 3 | -- stylua: ignore 4 | return { 5 | run = true, -- run tests (using for debug) 6 | commands_create = true, -- create commands (TestFile, TestLast, ...) 7 | filename_modifier = ":.", -- modify filenames before tests run(:h filename-modifiers) 8 | silent = false, -- less notifications 9 | term = "terminal", -- a terminal to run ("terminal"|"toggleterm") 10 | termOpts = { 11 | direction = "vertical", -- terminal's direction ("horizontal"|"vertical"|"float") 12 | width = 96, -- terminal's width (for vertical|float) 13 | height = 24, -- terminal's height (for horizontal|float) 14 | go_back = false, -- return focus to original window after executing 15 | stopinsert = "auto", -- exit from insert mode (true|false|"auto") 16 | keep_one = true, -- keep only one terminal for testing 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /lua/nvim-test/info.lua: -------------------------------------------------------------------------------- 1 | local function open_window() 2 | local width = math.floor(vim.o.columns * 0.7) 3 | local height = math.floor(vim.o.lines * 0.7) 4 | local bufnr = vim.api.nvim_create_buf(false, true) 5 | local win = vim.api.nvim_open_win(bufnr, true, { 6 | width = width, 7 | height = height, 8 | row = math.floor(((vim.o.lines - height) / 2) - 1), 9 | col = math.floor((vim.o.columns - width) / 2), 10 | relative = "editor", 11 | style = "minimal", 12 | border = { 13 | { " ", "NormalFloat" }, 14 | { " ", "NormalFloat" }, 15 | { " ", "NormalFloat" }, 16 | { " ", "NormalFloat" }, 17 | { " ", "NormalFloat" }, 18 | { " ", "NormalFloat" }, 19 | { " ", "NormalFloat" }, 20 | { " ", "NormalFloat" }, 21 | }, 22 | }) 23 | vim.api.nvim_win_set_buf(win, bufnr) 24 | vim.cmd "setlocal nocursorcolumn ts=2 sw=2" 25 | vim.api.nvim_buf_set_keymap(bufnr, "n", "", "bd", { noremap = true }) 26 | vim.api.nvim_buf_set_keymap(bufnr, "n", "", "bd", { noremap = true }) 27 | vim.api.nvim_command( 28 | string.format( 29 | "autocmd BufHidden,BufLeave ++once lua pcall(vim.api.nvim_win_close, %d, true)", 30 | win 31 | ) 32 | ) 33 | return { win = win, bufnr = bufnr } 34 | end 35 | 36 | local function print_table(t, indent) 37 | local result = {} 38 | if t then 39 | indent = indent == nil and "" or indent 40 | for key, value in pairs(t) do 41 | if type(value) == "table" then 42 | table.insert(result, indent .. key .. ": ") 43 | vim.list_extend(result, print_table(value, indent .. "\t")) 44 | else 45 | table.insert(result, indent .. key .. ": " .. vim.inspect(value)) 46 | end 47 | end 48 | end 49 | return result 50 | end 51 | 52 | return function() 53 | local plugin = require "nvim-test" 54 | local filetype = vim.bo.filetype 55 | local window = open_window() 56 | 57 | local lines = {} 58 | 59 | if filetype then 60 | vim.list_extend(lines, { "Detected filetype: *" .. filetype .. "*" }) 61 | local runner_module = plugin.runners[filetype] 62 | if runner_module then 63 | table.insert(lines, "Found test runner: *" .. runner_module .. "*") 64 | local _, runner = pcall(require, runner_module) 65 | if runner then 66 | vim.list_extend(lines, { "", "Runner Config:~", ">" }) 67 | vim.list_extend(lines, print_table(runner.config, "\t")) 68 | table.insert(lines, "<") 69 | end 70 | else 71 | table.insert(lines, "Test runner not found") 72 | end 73 | end 74 | 75 | if vim.g.test_latest then 76 | vim.list_extend(lines, { "", "Latest test params:~", ">" }) 77 | vim.list_extend(lines, print_table(vim.g.test_latest, "\t")) 78 | table.insert(lines, "<") 79 | end 80 | 81 | vim.list_extend(lines, { "", "Plugin Config:~", ">" }) 82 | vim.list_extend(lines, print_table(plugin.config, "\t")) 83 | table.insert(lines, "<") 84 | 85 | vim.api.nvim_buf_set_lines(window.bufnr, 0, -1, true, lines) 86 | vim.api.nvim_buf_set_option(window.bufnr, "modifiable", false) 87 | vim.api.nvim_buf_set_option(window.bufnr, "filetype", "help") 88 | end 89 | -------------------------------------------------------------------------------- /lua/nvim-test/init.lua: -------------------------------------------------------------------------------- 1 | local notifier = require "nvim-test.notify" 2 | local api = vim.api 3 | local suite_runner 4 | local Runner = require "nvim-test.runner" 5 | local M = { 6 | config = vim.deepcopy(require "nvim-test.config"), 7 | runners = require "nvim-test.runners", 8 | } 9 | 10 | -- Run tests 11 | --- 12 | ---@param scope string: (suite|file|nearest|last) 13 | function M.run(scope) 14 | -- Run latest 15 | if scope == "last" then 16 | return M.run_latest() 17 | end 18 | 19 | -- Check for is the filetype is supported 20 | local filetype = vim.bo.filetype 21 | local runner = M.get_runner(filetype, scope == "suite" and suite_runner or nil) 22 | if runner then 23 | suite_runner = runner 24 | local opts = {} 25 | local filename = nil 26 | 27 | -- Find tests 28 | if scope == "nearest" then 29 | opts.tests = runner:find_nearest_test(filetype) 30 | end 31 | 32 | -- Find file 33 | if scope ~= "suite" then 34 | filename = 35 | vim.fn.expand("%" .. (runner.config.filename_modifier or M.config.filename_modifier)) 36 | if not runner:is_testfile(filename) then 37 | filename = runner:find_file(filename) 38 | end 39 | end 40 | 41 | -- Find the current working directory 42 | local cwd = runner:find_working_directory(filename) 43 | if filename and cwd and #cwd > 0 then 44 | filename = string.gsub(filename, "^" .. cwd .. "/", "", 1) 45 | end 46 | 47 | -- Prepare run context 48 | local cmd = runner:build_cmd(filename, opts) 49 | local cfg = { env = runner.config.env, working_directory = cwd } 50 | 51 | -- Save last run 52 | vim.g.test_latest = { 53 | cmd = cmd, 54 | cfg = cfg, 55 | filename = filename, 56 | line = api.nvim_win_get_cursor(0)[0], 57 | } 58 | 59 | return M.run_cmd(cmd, cfg) 60 | end 61 | end 62 | 63 | --- Repeat a latest test command 64 | function M.run_last() 65 | local latest = vim.g.test_latest 66 | if not latest then 67 | return notifier:notify("No tests were run so far", 3) 68 | end 69 | return M.run_cmd(latest.cmd, latest.cfg) 70 | end 71 | 72 | ---Get a runner by the given filetype 73 | ---@return Runner runner 74 | function M.get_runner(filetype, default) 75 | local runner_module = M.runners[filetype] 76 | if runner_module then 77 | local _, runner = pcall(require, runner_module) 78 | if runner then 79 | return runner 80 | end 81 | end 82 | local runner = default 83 | if not runner then 84 | notifier:notify(string.format("Test runner for `%s` is not found", filetype), 4) 85 | end 86 | return runner 87 | end 88 | 89 | -- Visit the latest test 90 | function M.visit() 91 | local opts = vim.g.test_latest 92 | if opts and opts.filename then 93 | local args = opts.line and string.format("+%s", opts.line) or "" 94 | return api.nvim_command(string.format("edit %s%s", opts.filename, args)) 95 | end 96 | return notifier:notify("No tests were run so far", 3) 97 | end 98 | 99 | function M.edit() 100 | local runner = M.get_runner(vim.bo.filetype) 101 | local filename = 102 | vim.fn.expand("%" .. (runner.config.filename_modifier or M.config.filename_modifier)) 103 | if not runner:is_testfile(filename) then 104 | vim.api.nvim_command("edit " .. runner:find_file(filename, true)) 105 | end 106 | end 107 | 108 | --- Run the given command 109 | --- 110 | ---@param cmd table: a command to run 111 | ---@param cfg table: a runner's config 112 | function M.run_cmd(cmd, cfg) 113 | notifier:log(table.concat(cmd, " ")) 114 | if not M.config.run then 115 | return 116 | end 117 | local supported, termExec = pcall(require, "nvim-test.terms." .. M.config.term) 118 | if not supported then 119 | return notifier:notify(string.format("Term: %s is not supported", M.config.term), 4) 120 | end 121 | local opts = M.config.termOpts 122 | vim.validate { 123 | direction = { opts.direction, "string" }, 124 | width = { opts.width, "number" }, 125 | height = { opts.height, "number" }, 126 | go_back = { opts.go_back, "boolean" }, 127 | -- stopinsert = { opts.stopinsert, "boolean" }, 128 | } 129 | return termExec(cmd, cfg, opts) 130 | end 131 | 132 | -- Setup the plugin 133 | --- 134 | ---@param cfg table: a table with configuration 135 | function M.setup(cfg) 136 | -- Update config 137 | if cfg ~= nil then 138 | M.config = vim.tbl_deep_extend("force", M.config, cfg) 139 | end 140 | 141 | if M.config.runners then 142 | M.runners = vim.tbl_deep_extend("force", M.runners, M.config.runners) 143 | end 144 | 145 | -- Reset latest 146 | vim.g.test_latest = nil 147 | 148 | -- Setup notifies 149 | notifier:setup(M.config.silent) 150 | 151 | -- Create commands 152 | if M.config.commands_create then 153 | api.nvim_command "command! TestFile lua require'nvim-test'.run('file')" 154 | api.nvim_command "command! TestLast lua require'nvim-test'.run_last()" 155 | api.nvim_command "command! TestNearest lua require'nvim-test'.run('nearest')" 156 | api.nvim_command "command! TestSuite lua require'nvim-test'.run('suite')" 157 | api.nvim_command "command! TestVisit lua require'nvim-test'.visit()" 158 | api.nvim_command "command! TestInfo lua require'nvim-test.info'()" 159 | api.nvim_command "command! TestEdit lua require'nvim-test'.edit()" 160 | end 161 | end 162 | 163 | return M 164 | -------------------------------------------------------------------------------- /lua/nvim-test/notify.lua: -------------------------------------------------------------------------------- 1 | local Notifier = {} 2 | Notifier.__index = Notifier 3 | 4 | --Initialize hash helper 5 | ---@returns Notifier 6 | function Notifier:init() 7 | self = {} 8 | setmetatable(self, Notifier) 9 | self.silent = false 10 | self.prefix = "[nvim-test]: " 11 | return self 12 | end 13 | 14 | ---@param silent boolean: is silent mode enabled 15 | function Notifier:setup(silent) 16 | self.silent = silent 17 | return self 18 | end 19 | 20 | --Send notify 21 | function Notifier:notify(msg, level) 22 | vim.notify(self.prefix .. msg, level or 2) 23 | end 24 | 25 | --Send optional notify 26 | function Notifier:onotify(msg, level) 27 | if not self.silent then 28 | self:notify(msg, level) 29 | end 30 | end 31 | 32 | -- Log a message 33 | function Notifier:log(msg) 34 | vim.api.nvim_echo({ { self.prefix .. msg } }, true, {}) 35 | end 36 | 37 | --Ask for a confirmation 38 | function Notifier:confirm(msg, choices) 39 | local _, choice = pcall(vim.fn.confirm, self.prefix .. msg, choices, 1) 40 | return choice 41 | end 42 | 43 | return Notifier:init() 44 | -------------------------------------------------------------------------------- /lua/nvim-test/runner.lua: -------------------------------------------------------------------------------- 1 | ---@diagnostic disable: unused-local 2 | local utils = require "nvim-test.utils" 3 | local ts_utils = require "nvim-treesitter.ts_utils" 4 | local ts_parsers = require "nvim-treesitter.parsers" 5 | local ts = vim.treesitter 6 | 7 | ---@class Runner 8 | local Runner = { 9 | config = { 10 | args = {}, 11 | 12 | filename_modifier = nil, 13 | working_directory = nil, 14 | }, 15 | } 16 | Runner.__index = Runner 17 | 18 | function Runner:init(config, queries) 19 | self = setmetatable({}, Runner) 20 | self.queries = queries or {} 21 | for ft, query in pairs(self.queries) do 22 | local set_query = ts.query.set or ts.set_query -- neovim 0.8 support 23 | set_query(ft, "nvim-test", query) 24 | end 25 | self:setup(config) 26 | return self 27 | end 28 | 29 | function Runner:setup(config) 30 | if config then 31 | self.config = vim.tbl_deep_extend("force", self.config, config) 32 | end 33 | if type(self.config.command) == "table" then 34 | self.config.command = utils.check_executable(self.config.command) 35 | end 36 | return self 37 | end 38 | 39 | function Runner:find_nearest_test(filetype) 40 | local query_get = ts.query.get or ts.get_query -- neovim 0.8 support 41 | local query = query_get(ts_parsers.ft_to_lang(filetype), "nvim-test") 42 | local result = {} 43 | if query then 44 | local curnode = ts_utils.get_node_at_cursor() 45 | while curnode do 46 | local iter = query:iter_captures(curnode, 0) 47 | local capture_id, capture_node = iter() 48 | if capture_node == curnode and query.captures[capture_id] == "scope-root" then 49 | while query.captures[capture_id] ~= "test-name" do 50 | capture_id, capture_node = iter() 51 | if not capture_id then 52 | return result 53 | end 54 | end 55 | local name = self:parse_testname(ts.get_node_text(capture_node, 0)) 56 | table.insert(result, 1, name) 57 | end 58 | curnode = curnode:parent() 59 | end 60 | end 61 | return result 62 | end 63 | 64 | ---Check is the given filename is a test file 65 | -- 66 | ---@param filename string 67 | ---@return boolean 68 | function Runner:is_testfile(filename) 69 | local file_pattern = self.config.file_pattern 70 | if file_pattern and #file_pattern > 0 then 71 | return vim.fn.match(filename, self.config.file_pattern) >= 0 72 | end 73 | return true 74 | end 75 | 76 | ---Find a test file for the given filename 77 | -- 78 | ---@param filename string 79 | ---@return string 80 | function Runner:find_file(filename, force) 81 | local finder = self.config.find_files 82 | if not finder then 83 | return filename 84 | end 85 | if type(finder) == "function" then 86 | return finder(filename) 87 | end 88 | if type(finder) == "string" then 89 | finder = { finder } 90 | end 91 | return utils.find_file_by_patterns(filename, finder, force) 92 | end 93 | 94 | ---@param name string 95 | ---@return string 96 | function Runner:parse_testname(name) 97 | return name 98 | end 99 | 100 | -- Find root directory 101 | ---@param filename string 102 | ---@return string 103 | function Runner:find_working_directory(filename) 104 | return self.config.working_directory 105 | end 106 | 107 | -- Build command list 108 | --- 109 | ---@return table cmd command list 110 | function Runner:build_cmd(filename, opts) 111 | local args = utils.concat({}, self.config.args) 112 | self:build_args(args, filename, opts or {}) 113 | table.insert(args, 1, self.config.command) 114 | return args 115 | end 116 | 117 | -- Build arguments 118 | function Runner:build_args(args, filename, opts) 119 | if filename then 120 | table.insert(args, filename) 121 | end 122 | if opts.tests and #opts.tests > 0 then 123 | self:build_test_args(args, opts.tests) 124 | end 125 | end 126 | 127 | ---@return table test_args test arguments list 128 | function Runner:build_test_args(args, tests) end 129 | 130 | return Runner 131 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/busted.lua: -------------------------------------------------------------------------------- 1 | local Runner = require "nvim-test.runner" 2 | 3 | local busted = Runner:init({ 4 | command = "busted", 5 | file_pattern = "\\v_spec\\.(lua|moon)$", 6 | find_files = "{name}_spec.{ext}", 7 | }, { 8 | lua = [[ 9 | ((function_call (identifier) (arguments (string) @test-name (function_definition))) @scope-root) 10 | ]], 11 | }) 12 | 13 | function busted:parse_testname(name) 14 | return name:gsub("^[\"']", ""):gsub("[\"']$", "") 15 | end 16 | 17 | function busted:build_test_args(args, tests) 18 | table.insert(args, "--filter") 19 | table.insert(args, table.concat(tests, " ")) 20 | end 21 | 22 | return busted 23 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/cargo-test.lua: -------------------------------------------------------------------------------- 1 | -- TODO 2 | -- 3 | local Runner = require "nvim-test.runner" 4 | 5 | local cargotest = Runner:init({ command = "cargo", args = { "test" }, package = false }, { 6 | rust = [[ 7 | ( 8 | ( 9 | mod_item name: (identifier) @test-name 10 | (#match? @test-name "[Tt]est") 11 | ) 12 | @scope-root) 13 | 14 | ( 15 | ( 16 | function_item name: (identifier) @test-name 17 | (#match? @test-name "[Tt]est") 18 | ) 19 | @scope-root) 20 | ]], 21 | }) 22 | 23 | function cargotest:build_args(args, filename, opts) 24 | -- for whole suite do nothing 25 | if not filename then 26 | return 27 | end 28 | 29 | -- Find a package 30 | if self.config.package then 31 | local crate = vim.fn.findfile("Cargo.toml", vim.fn.fnamemodify(filename, ":p") .. ";") 32 | if crate and #crate > 0 then 33 | table.insert(args, "-p") 34 | table.insert(args, vim.fn.fnamemodify(crate, ":p:h:t")) 35 | end 36 | end 37 | 38 | if opts.tests and #opts.tests > 0 then 39 | table.insert(args, table.concat(opts.tests, "::")) 40 | table.insert(args, "--") 41 | table.insert(args, "--exact") 42 | else 43 | local parts = vim.fn.split(vim.fn.fnamemodify(filename, ":.:r"), "/") 44 | if parts[#parts] == "main" or parts[#parts] == "lib" or parts[#parts] == "mod" then 45 | parts[#parts] = nil 46 | end 47 | if parts[1] == "src" then 48 | table.remove(parts, 1) 49 | end 50 | 51 | local modname = (#parts > 0) and table.concat(parts, "::") 52 | if modname then 53 | table.insert(args, modname .. "::") 54 | end 55 | end 56 | end 57 | 58 | return cargotest 59 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/cypress.lua: -------------------------------------------------------------------------------- 1 | local Runner = require "nvim-test.runner" 2 | local jest = require "nvim-test.runners.jest" 3 | 4 | local cypress = Runner:init({ 5 | command = { "./node_modules/.bin/cypress", "cypress" }, 6 | args = { "run" }, 7 | file_pattern = jest.config.file_pattern, 8 | find_files = jest.config.find_files, 9 | }, { 10 | javascript = jest.queries.javascript, 11 | }) 12 | 13 | function cypress:build_args(args, filename, _) 14 | if filename then 15 | table.insert(args, "--spec") 16 | table.insert(args, filename) 17 | end 18 | end 19 | 20 | return cypress 21 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/dotnet.lua: -------------------------------------------------------------------------------- 1 | local Runner = require "nvim-test.runner" 2 | 3 | local cstest = Runner:init({ 4 | command = "dotnet", 5 | args = { "test" }, 6 | file_pattern = "\\v(test/.*|Tests)\\.cs$", 7 | find_files = { "{name}Tests.{ext}", "Tests.{ext}" }, -- find testfile for a file 8 | }, { 9 | c_sharp = [[ 10 | ; Namespace 11 | ((namespace_declaration name: (identifier) @test-name) @scope-root) 12 | 13 | ; Class 14 | ((class_declaration name: (identifier) @test-name) @scope-root) 15 | 16 | ; Method 17 | ((method_declaration 18 | (attribute_list 19 | (attribute name: (identifier) @attribute-name 20 | (#match? @attribute-name "(Fact|Theory|Test|TestMethod)") 21 | ; attributes used by xunit, nunit and mstest 22 | )) 23 | name: (identifier) @test-name) 24 | @scope-root) 25 | 26 | ]], 27 | }) 28 | 29 | function cstest:build_test_args(args, tests) 30 | table.insert(args, "--filter") 31 | table.insert(args, "FullyQualifiedName=" .. table.concat(tests, ".")) 32 | end 33 | 34 | return cstest 35 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/go-test.lua: -------------------------------------------------------------------------------- 1 | -- TODO 2 | -- 3 | local Runner = require "nvim-test.runner" 4 | 5 | local gotest = Runner:init({ 6 | command = "go", 7 | args = { "test", "-v" }, 8 | file_pattern = "\\v([^.]+_test)\\.go$", -- determine whether a file is a testfile 9 | find_files = { "{name}_test.go" }, -- find testfile for a file 10 | }, { 11 | go = [[ 12 | ( 13 | ( 14 | function_declaration name: (identifier) @test-name 15 | (#match? @test-name "^(Test|Benchmark|Fuzz)") 16 | ) 17 | @scope-root) 18 | ]], 19 | }) 20 | 21 | function gotest:build_args(args, filename, opts) 22 | if filename then 23 | local path = vim.fn.fnamemodify(filename, ":.:h") 24 | if path ~= "." then 25 | table.insert(args, string.format("./%s/...", path)) 26 | end 27 | if opts.tests and next(opts.tests) ~= nil then 28 | table.insert(args, "-run") 29 | table.insert(args, opts.tests[1] .. "$") 30 | end 31 | else 32 | table.insert(args, "./...") 33 | end 34 | end 35 | 36 | return gotest 37 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/hspec.lua: -------------------------------------------------------------------------------- 1 | local Runner = require "nvim-test.runner" 2 | 3 | local hspec = Runner:init({ 4 | command = { "runhaskell" }, 5 | file_pattern = "\\v(Spec)\\.hs$", 6 | find_files = { "{name}Spec.hs", "Spec.hs" }, 7 | }, { 8 | haskell = [[ 9 | ((stmt (exp_infix (exp_apply 10 | (exp_name) @exp-name 11 | (#match? @exp-name "^(describe|it)") 12 | (exp_literal) @test-name 13 | ) 14 | )) 15 | @scope-root) 16 | ]], 17 | }) 18 | 19 | function hspec:parse_testname(name) 20 | return name:gsub("^[\"'`]", ""):gsub("[\"'`]$", "") 21 | end 22 | 23 | function hspec:build_test_args(args, tests) 24 | table.insert(args, "--match") 25 | table.insert(args, table.concat(tests, "/")) 26 | end 27 | 28 | return hspec 29 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/init.lua: -------------------------------------------------------------------------------- 1 | return { 2 | cs = "nvim-test.runners.dotnet", 3 | go = "nvim-test.runners.go-test", 4 | haskell = "nvim-test.runners.hspec", 5 | javascript = "nvim-test.runners.jest", 6 | javascriptreact = "nvim-test.runners.jest", 7 | lua = "nvim-test.runners.busted", 8 | python = "nvim-test.runners.pytest", 9 | ruby = "nvim-test.runners.rspec", 10 | rust = "nvim-test.runners.cargo-test", 11 | typescript = "nvim-test.runners.jest", 12 | typescriptreact = "nvim-test.runners.jest", 13 | zig = "nvim-test.runners.zig", 14 | } 15 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/jest.lua: -------------------------------------------------------------------------------- 1 | local Runner = require "nvim-test.runner" 2 | local utils = require "nvim-test.utils" 3 | 4 | local query = [[ 5 | ((expression_statement 6 | (call_expression 7 | function: (identifier) @method-name 8 | (#match? @method-name "^(describe|test|it)") 9 | arguments: (arguments [ 10 | ((string) @test-name) 11 | ((template_string) @test-name) 12 | ] 13 | ))) 14 | @scope-root) 15 | ]] 16 | 17 | local jest = Runner:init({ 18 | command = { "./node_modules/.bin/jest", "jest" }, 19 | file_pattern = "\\v(__tests__/.*|(spec|test))\\.(js|jsx|coffee|ts|tsx)$", 20 | find_files = { "{name}.test.{ext}", "{name}.spec.{ext}" }, 21 | }, { 22 | javascript = query, 23 | typescript = query, 24 | }) 25 | 26 | function jest:parse_testname(name) 27 | return name:gsub("^[\"'`]", ""):gsub("[\"'`]$", "") 28 | end 29 | 30 | function jest:build_test_args(args, tests) 31 | table.insert(args, "-t") 32 | table.insert(args, "^" .. table.concat(tests, " ") .. "$") 33 | end 34 | 35 | function jest:find_working_directory(filename) 36 | local root = self.config.working_directory 37 | if not root then 38 | root = utils.find_relative_root(filename, "package.json") 39 | end 40 | return root 41 | end 42 | 43 | return jest 44 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/mocha.lua: -------------------------------------------------------------------------------- 1 | local Runner = require "nvim-test.runner" 2 | local jest = require "nvim-test.runners.jest" 3 | 4 | local mocha = Runner:init({ 5 | command = { "./node_modules/.bin/mocha", "mocha" }, 6 | file_pattern = "\\v(tests?/.*|test)\\.(js|jsx|coffee)$", 7 | find_files = { "{name}.test.{ext}" }, 8 | }, { 9 | javascript = jest.queries.javascript, 10 | typescript = jest.queries.typescript, 11 | }) 12 | 13 | function mocha:parse_testname(name) 14 | return jest:parse_testname(name) 15 | end 16 | 17 | function mocha:build_test_args(args, tests) 18 | table.insert(args, "-f") 19 | table.insert(args, table.concat(tests, " ")) 20 | end 21 | 22 | return mocha 23 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/pytest.lua: -------------------------------------------------------------------------------- 1 | local Runner = require "nvim-test.runner" 2 | 3 | local pytest = Runner:init({ 4 | command = { (vim.env.VIRTUAL_ENV or "venv") .. "/bin/pytest", "pytest" }, 5 | file_pattern = "\\v(test_[^.]+|[^.]+_test|tests)\\.py$", 6 | find_files = { "test_{name}.py", "{name}_test.py", "tests.py", "tests" }, 7 | }, { 8 | python = [[ 9 | ; Class 10 | ( 11 | ( 12 | class_definition name: (identifier) @test-name 13 | (#match? @test-name "[Tt]est") 14 | ) 15 | @scope-root) 16 | 17 | ; Function 18 | ( 19 | ( 20 | function_definition name: (identifier) @test-name 21 | (#match? @test-name "^[Tt]est") 22 | ) 23 | @scope-root) 24 | ]], 25 | }) 26 | 27 | function pytest:build_test_args(args, tests) 28 | args[#args] = args[#args] .. "::" .. table.concat(tests, "::") 29 | end 30 | 31 | return pytest 32 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/pyunit.lua: -------------------------------------------------------------------------------- 1 | local Runner = require "nvim-test.runner" 2 | local pytest = require "nvim-test.runners.pytest" 3 | 4 | local pyunit = Runner:init({ 5 | command = { (vim.env.VIRTUAL_ENV or "venv") .. "/bin/python", "python" }, 6 | args = { "-m", "unittest" }, 7 | file_pattern = "\\v^test.*\\.py$", 8 | find_files = { "test_{name}.py" }, 9 | }, { 10 | python = pytest.queries.python, 11 | }) 12 | 13 | function pyunit:build_args(args, filename, opts) 14 | if filename then 15 | local path, _ = vim.fn.fnamemodify(filename, ":.:r"):gsub("/", ".") 16 | table.insert(args, path) 17 | end 18 | if opts.tests and #opts.tests > 0 then 19 | args[#args] = args[#args] .. "." .. table.concat(opts.tests, ".") 20 | end 21 | end 22 | 23 | return pyunit 24 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/rspec.lua: -------------------------------------------------------------------------------- 1 | local Runner = require "nvim-test.runner" 2 | local utils = require "nvim-test.utils" 3 | 4 | local rspec = Runner:init({ 5 | command = { "rspec", "bundle" }, 6 | file_pattern = "\\v(spec_[^.]+|[^.]+_spec)\\.rb$", 7 | find_files = { "{name}_spec.rb" }, 8 | }, { 9 | ruby = [[ 10 | ( 11 | (call 12 | method: (identifier) @method-name 13 | (#match? @method-name "(describe|it|context)") 14 | arguments: (argument_list (string (string_content) @test-name)) 15 | ) 16 | @scope-root) 17 | ]], 18 | }) 19 | 20 | function rspec:find_working_directory(filename) 21 | local root = self.config.working_directory 22 | if not root then 23 | root = utils.find_relative_root(filename, "Gemfile") 24 | end 25 | return root 26 | end 27 | 28 | function rspec:build_args(args, filename, opts) 29 | if self.config.command == "bundle" then 30 | table.insert(args, "exec") 31 | table.insert(args, "rspec") 32 | end 33 | 34 | if filename then 35 | table.insert(args, filename) 36 | end 37 | if opts.tests and #opts.tests > 0 then 38 | self:build_test_args(args, opts.tests) 39 | end 40 | end 41 | 42 | function rspec:build_test_args(args, tests) 43 | table.insert(args, "--example") 44 | table.insert(args, table.concat(tests, " ")) 45 | end 46 | 47 | return rspec 48 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/stack.lua: -------------------------------------------------------------------------------- 1 | local Runner = require "nvim-test.runner" 2 | local hspec = require "nvim-test.runners.hspec" 3 | 4 | local stack = Runner:init({ 5 | command = { "stack" }, 6 | args = { "test" }, 7 | file_pattern = hspec.config.file_pattern, 8 | find_files = hspec.config.find_files, 9 | }, { 10 | haskell = hspec.queries.haskell, 11 | }) 12 | 13 | function stack:parse_testname(name) 14 | return hspec:parse_testname(name) 15 | end 16 | 17 | function stack:build_test_args(args, tests) 18 | table.insert( 19 | args, 20 | "--test-arguments=" .. string.format("'--match \"%s\"'", table.concat(tests, "/")) 21 | ) 22 | end 23 | 24 | return stack 25 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/ts-mocha.lua: -------------------------------------------------------------------------------- 1 | local Runner = require "nvim-test.runner" 2 | local mocha = require "nvim-test.runners.mocha" 3 | 4 | local tsmocha = Runner:init({ 5 | command = { "./node_modules/.bin/ts-mocha", "ts-mocha" }, 6 | file_pattern = "\\v(tests?/.*|test)\\.(ts|tsx)$", 7 | find_files = { "{name}.test.{ext}" }, 8 | }, { 9 | typescript = mocha.queries.typescript, 10 | }) 11 | 12 | function tsmocha:parse_testname(name) 13 | return mocha:parse_testname(name) 14 | end 15 | 16 | function tsmocha:build_test_args(args, tests) 17 | return mocha:build_test_args(args, tests) 18 | end 19 | 20 | return tsmocha 21 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/vusted.lua: -------------------------------------------------------------------------------- 1 | local Runner = require "nvim-test.runner" 2 | local busted = require "nvim-test.runners.busted" 3 | 4 | local vusted = Runner:init({ 5 | command = "vusted", 6 | file_pattern = busted.config.file_pattern, 7 | find_files = busted.config.find_files, 8 | }, { 9 | lua = busted.queries.lua, 10 | }) 11 | 12 | function vusted:parse_testname(name) 13 | return busted:parse_testname(name) 14 | end 15 | 16 | function vusted:build_test_args(args, tests) 17 | return busted:build_test_args(args, tests) 18 | end 19 | 20 | return vusted 21 | -------------------------------------------------------------------------------- /lua/nvim-test/runners/zig.lua: -------------------------------------------------------------------------------- 1 | local Runner = require("nvim-test.runner") 2 | 3 | local zig_test = Runner:init({ command = "zig" }, { 4 | zig = [[ 5 | (TestDecl . [(STRINGLITERALSINGLE) @test-name (IDENTIFIER) @test-name]) @scope-root 6 | ]], 7 | }) 8 | 9 | function zig_test:parse_testname(name) 10 | return name:gsub('^@?"', ""):gsub('"$', "") 11 | end 12 | 13 | function zig_test:build_args(args, filename, opts) 14 | if not filename then 15 | table.insert(args, "build") 16 | table.insert(args, "test") 17 | return 18 | end 19 | 20 | table.insert(args, "test") 21 | table.insert(args, filename) 22 | 23 | if opts.tests and #opts.tests > 0 then 24 | for _, test in ipairs(opts.tests) do 25 | table.insert(args, "--test-filter") 26 | table.insert(args, test) 27 | end 28 | end 29 | end 30 | 31 | return zig_test 32 | -------------------------------------------------------------------------------- /lua/nvim-test/terms/callbacks.lua: -------------------------------------------------------------------------------- 1 | local notifier = require "nvim-test.notify" 2 | 3 | local M = {} 4 | 5 | ---Bind on_exit callback 6 | ---@param cfg table 7 | ---@return function 8 | function M.bind_on_exit(cfg) 9 | return function(_, status) 10 | local stopinsert = cfg.stopinsert 11 | if status ~= 0 then 12 | notifier:onotify("Tests are failed", 3) 13 | if stopinsert == "auto" then 14 | stopinsert = true 15 | end 16 | end 17 | if stopinsert == true or cfg.go_back then 18 | vim.cmd "stopinsert!" 19 | end 20 | if cfg.go_back then 21 | vim.cmd "wincmd p" 22 | end 23 | end 24 | end 25 | 26 | return M 27 | -------------------------------------------------------------------------------- /lua/nvim-test/terms/terminal.lua: -------------------------------------------------------------------------------- 1 | local callbacks = require "nvim-test.terms.callbacks" 2 | 3 | local directionsMap = { 4 | vertical = "vsplit", 5 | horizontal = "split", 6 | } 7 | local term = nil 8 | local next = next 9 | 10 | local exec = function(cmd, cfg, termCfg) 11 | local opts = { 12 | on_exit = callbacks.bind_on_exit(termCfg), 13 | } 14 | if cfg.env and next(cfg.env) then 15 | opts.env = cfg.env 16 | end 17 | if cfg.working_directory and #cfg.working_directory > 0 then 18 | opts.cwd = cfg.working_directory 19 | end 20 | return vim.fn.termopen(cmd, opts) 21 | end 22 | 23 | return function(cmd, cfg, termCfg) 24 | if termCfg.direction == "float" then 25 | local bufnr = vim.api.nvim_create_buf(false, false) 26 | vim.api.nvim_open_win(bufnr, true, { 27 | row = math.ceil(vim.o.lines - termCfg.height) / 2 - 1, 28 | col = math.ceil(vim.o.columns - termCfg.width) / 2 - 1, 29 | relative = "editor", 30 | width = termCfg.width, 31 | height = termCfg.height, 32 | style = "minimal", 33 | border = "single", 34 | }) 35 | return exec(cmd, cfg, termCfg) 36 | end 37 | 38 | local split = directionsMap[termCfg.direction] 39 | if termCfg.direction == "vertical" and termCfg.width then 40 | split = termCfg.width .. split 41 | end 42 | if termCfg.direction == "horizontal" and termCfg.height then 43 | split = termCfg.height .. split 44 | end 45 | 46 | -- Clean buffers 47 | if termCfg.keep_one and term then 48 | if vim.fn.bufexists(term) > 0 then 49 | vim.api.nvim_buf_delete(term, { force = true }) 50 | end 51 | end 52 | 53 | vim.cmd(string.format("botright %s new", split)) 54 | exec(cmd, cfg, termCfg) 55 | term = vim.api.nvim_get_current_buf() 56 | end 57 | -------------------------------------------------------------------------------- /lua/nvim-test/terms/toggleterm.lua: -------------------------------------------------------------------------------- 1 | local callbacks = require "nvim-test.terms.callbacks" 2 | 3 | local terminal = require "toggleterm.terminal" 4 | -- local ok, terminal = pcall(require, "toggleterm.terminal") 5 | -- if not ok then 6 | -- error "Install toggleterm.nvim to use toggleterm" 7 | -- end 8 | 9 | local term = nil 10 | 11 | ---Run terminal 12 | ---@param cmd table 13 | ---@param cfg table 14 | ---@param termCfg table 15 | return function(cmd, cfg, termCfg) 16 | local command = cmd[1] 17 | for i = 2, #cmd do 18 | command = command .. " " .. vim.fn.shellescape(cmd[i]) 19 | end 20 | local on_exit = callbacks.bind_on_exit(termCfg) 21 | 22 | -- Clean terminals 23 | if termCfg.keep_one and term then 24 | term:close() 25 | end 26 | 27 | term = terminal.Terminal:new { 28 | cmd = command, 29 | dir = cfg.working_directory, 30 | direction = termCfg.direction, 31 | close_on_exit = false, 32 | on_exit = function(_, _, status) 33 | on_exit(_, status) 34 | end, 35 | } 36 | term:open( 37 | termCfg.direction == "vertical" and termCfg.width or termCfg.height, 38 | termCfg.direction, 39 | true 40 | ) 41 | end 42 | -------------------------------------------------------------------------------- /lua/nvim-test/utils.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | ---Get a text from the given treesitter node 4 | ---@return string s a text 5 | function M.get_node_text(node, bufnr) 6 | bufnr = bufnr or vim.api.nvim_get_current_buf() 7 | local start_row, start_col, _, end_col = node:range() 8 | local line = vim.api.nvim_buf_get_lines(bufnr, start_row, start_row + 1, false)[1] 9 | return line and string.sub(line, start_col + 1, end_col) or "" 10 | end 11 | 12 | function M.get_node_at_cursor() 13 | local cursor = vim.api.nvim_win_get_cursor(0) 14 | local line = cursor[1] - 1 15 | local col = cursor[2] 16 | local parser = vim.treesitter.get_parser() 17 | if not parser then 18 | return 19 | end 20 | local lang_tree = parser:language_for_range { line, col, line, col } 21 | for _, tree in ipairs(lang_tree:trees()) do 22 | local root = tree:root() 23 | local node = root:named_descendant_for_range(line, col, line, col) 24 | if node then 25 | return node 26 | end 27 | end 28 | end 29 | 30 | ---Concat tables 31 | -- 32 | ---@param r table a target table 33 | ---@param t table a table 34 | ---@return table r a target table 35 | function M.concat(r, t) 36 | for _, value in ipairs(t) do 37 | table.insert(r, value) 38 | end 39 | return r 40 | end 41 | 42 | function M.check_executable(cmds) 43 | for _, cmd in ipairs(cmds) do 44 | if vim.fn.executable(cmd) == 1 then 45 | return cmd 46 | end 47 | end 48 | return cmds[#cmds] 49 | end 50 | 51 | ---Find file by patterns 52 | -- 53 | ---@param source string 54 | ---@param patterns table 55 | ---@return string 56 | function M.find_file_by_patterns(source, patterns, force) 57 | local ctx = { 58 | name = vim.fn.fnamemodify(source, ":t:r"), 59 | ext = vim.fn.fnamemodify(source, ":e"), 60 | } 61 | for _, pat in ipairs(patterns) do 62 | local filename = M.format_pattern(pat, ctx) 63 | local testfile = vim.fn.findfile(filename, source .. ";") 64 | if #testfile > 0 then 65 | return testfile 66 | end 67 | testfile = vim.fn.finddir(filename, source .. ";") 68 | if #testfile > 0 then 69 | return testfile 70 | end 71 | end 72 | if force then 73 | return vim.fn.fnamemodify(source, ":h") .. "/" .. M.format_pattern(patterns[1], ctx) 74 | end 75 | return source 76 | end 77 | 78 | ---@param pattern string 79 | ---@return string 80 | function M.format_pattern(pattern, ctx) 81 | local res = pattern 82 | for var in pattern:gmatch "{[^}]+}" do 83 | var = var:gsub("{", ""):gsub("}", "") 84 | res = res:gsub("{" .. var .. "}", ctx[var] or "") 85 | end 86 | return res 87 | end 88 | 89 | ---Find the project root based on an indicating filename 90 | ---@param source string 91 | ---@param indicator string 92 | ---@return string 93 | function M.find_relative_root(source, indicator) 94 | local path = vim.fn.findfile(indicator, vim.fn.fnamemodify(source, ":p") .. ";") 95 | if path and #path > 0 then 96 | path = vim.fn.fnamemodify(path, ":p:h") 97 | end 98 | return path 99 | end 100 | 101 | return M 102 | -------------------------------------------------------------------------------- /packspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "package": "nvim-test", 3 | "version": "1.4.1", 4 | "source": "git://github.com/klen/nvim-test.git", 5 | "description": { 6 | "summary": "Test Runner for Neovim", 7 | "homepage": "https://github.com/klen/nvim-test/", 8 | "license": "MIT" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /spec/conftest.lua: -------------------------------------------------------------------------------- 1 | -- Setup tests 2 | 3 | -- -- Setup nvim-test 4 | -- local nvim_test = require "nvim-test" 5 | -- nvim_test.setup { 6 | -- run = false, 7 | -- } 8 | 9 | -- Setup nvim-treesitter 10 | vim.o.runtimepath = vim.fn.getcwd() .. "/nvim-treesitter," .. vim.o.runtimepath 11 | local nvim_treesitter = require "nvim-treesitter.configs" 12 | nvim_treesitter.setup { 13 | ensure_installed = { 14 | "c_sharp", 15 | "go", 16 | "haskell", 17 | "javascript", 18 | "lua", 19 | "python", 20 | "ruby", 21 | "rust", 22 | "typescript", 23 | "zig", 24 | }, 25 | sync_install = true, 26 | } 27 | 28 | return true 29 | -------------------------------------------------------------------------------- /spec/fixtures/Spec.hs: -------------------------------------------------------------------------------- 1 | import Test.Hspec 2 | import Test.QuickCheck 3 | import Control.Exception (evaluate) 4 | 5 | main :: IO () 6 | main = hspec $ do 7 | describe "Prelude.head" $ do 8 | it "returns the first element of a list" $ do 9 | head [23 ..] `shouldBe` (23 :: Int) 10 | 11 | it "returns the first element of an *arbitrary* list" $ 12 | property $ \x xs -> head (x:xs) == (x :: Int) 13 | 14 | describe "nested" $ do 15 | it "throws an exception if used with an empty list" $ do 16 | evaluate (head []) `shouldThrow` anyException 17 | -------------------------------------------------------------------------------- /spec/fixtures/Tests.cs: -------------------------------------------------------------------------------- 1 | namespace Namespace 2 | { 3 | public class Tests 4 | { 5 | 6 | [Fact] 7 | public void Test() 8 | { 9 | Assert.Equal(true, false); 10 | } 11 | 12 | [Fact] 13 | public async void TestAsync() 14 | { 15 | Assert.Equal(true, false); 16 | } 17 | 18 | [Fact] 19 | public async Task TestAsyncWithTaskReturn() 20 | { 21 | Assert.Equal(true, false); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /spec/fixtures/go/go.mod: -------------------------------------------------------------------------------- 1 | module nvim-test/m 2 | 3 | go 1.17 4 | -------------------------------------------------------------------------------- /spec/fixtures/go/mypackage_test.go: -------------------------------------------------------------------------------- 1 | package mypackage 2 | 3 | import "testing" 4 | 5 | func TestNumbers(*testing.T) { 6 | // assertions 7 | } 8 | 9 | func Testテスト(*testing.T) { 10 | // assertions 11 | } 12 | 13 | func ExampleSomething() { 14 | // Output: 15 | } 16 | 17 | func Something() { 18 | } 19 | -------------------------------------------------------------------------------- /spec/fixtures/js/name.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klen/nvim-test/e06f3d029ee161f3ead6193cf27354d1eb8723c3/spec/fixtures/js/name.js -------------------------------------------------------------------------------- /spec/fixtures/js/name.test.js: -------------------------------------------------------------------------------- 1 | describe('jstest', function () { 2 | describe(`ns`, function () { 3 | it('test1', function () { 4 | // assertions 5 | some('some', function () { 6 | console.log('passed') 7 | }) 8 | }) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /spec/fixtures/rust/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "nvim-test" 5 | version = "0.0.1" 6 | dependencies = [ 7 | "tokio", 8 | ] 9 | 10 | [[package]] 11 | name = "nvim-test2" 12 | version = "0.0.1" 13 | 14 | [[package]] 15 | name = "pin-project-lite" 16 | version = "0.2.8" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" 19 | 20 | [[package]] 21 | name = "tokio" 22 | version = "1.17.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" 25 | dependencies = [ 26 | "pin-project-lite", 27 | ] 28 | -------------------------------------------------------------------------------- /spec/fixtures/rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "crate", "crate2" 4 | ] 5 | -------------------------------------------------------------------------------- /spec/fixtures/rust/crate/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "nvim-test" 5 | version = "0.0.1" 6 | dependencies = [ 7 | "tokio", 8 | ] 9 | 10 | [[package]] 11 | name = "pin-project-lite" 12 | version = "0.2.8" 13 | source = "registry+https://github.com/rust-lang/crates.io-index" 14 | checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" 15 | 16 | [[package]] 17 | name = "tokio" 18 | version = "1.17.0" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" 21 | dependencies = [ 22 | "pin-project-lite", 23 | ] 24 | -------------------------------------------------------------------------------- /spec/fixtures/rust/crate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nvim-test" 3 | version = "0.0.1" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | tokio = "1.17.0" 8 | -------------------------------------------------------------------------------- /spec/fixtures/rust/crate/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | #![cfg(feature = "full")] 3 | 4 | mod tests { 5 | #[test] 6 | fn first_test () { 7 | // body 8 | } 9 | 10 | #[test] 11 | fn second_test () { 12 | // body 13 | } 14 | 15 | #[test] 16 | fn third_test () { 17 | // body 18 | } 19 | 20 | #[tokio::test] 21 | async fn tokio_async_test() { 22 | // body 23 | } 24 | 25 | #[rstest(input, 26 | case(1), 27 | case(2), 28 | )] 29 | fn rstest_test(_: u8) { 30 | // body 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /spec/fixtures/rust/crate/src/nested/mod.rs: -------------------------------------------------------------------------------- 1 | fn main() {} 2 | 3 | mod tests { 4 | #[test] 5 | fn first_test() { 6 | // body 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /spec/fixtures/rust/crate/src/nomod.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn first_test() { 3 | // body 4 | } 5 | 6 | #[test] 7 | fn second_test() { 8 | // body 9 | } 10 | 11 | #[test] 12 | fn third_test() { 13 | // body 14 | } 15 | -------------------------------------------------------------------------------- /spec/fixtures/rust/crate/src/somemod.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klen/nvim-test/e06f3d029ee161f3ead6193cf27354d1eb8723c3/spec/fixtures/rust/crate/src/somemod.rs -------------------------------------------------------------------------------- /spec/fixtures/rust/crate2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nvim-test2" 3 | version = "0.0.1" 4 | edition = "2018" 5 | -------------------------------------------------------------------------------- /spec/fixtures/rust/crate2/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() {} 2 | 3 | mod tests { 4 | #[test] 5 | fn first_test() { 6 | // body 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /spec/fixtures/rust/some/main.rs: -------------------------------------------------------------------------------- 1 | fn main() {} 2 | 3 | mod tests { 4 | #[test] 5 | fn first_test() { 6 | // body 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /spec/fixtures/test.lua: -------------------------------------------------------------------------------- 1 | describe("luatest", function() 2 | it("test1", function() 3 | assert.is_true(true) 4 | end) 5 | 6 | it("test2", function() 7 | assert.is_true(true) 8 | end) 9 | end) 10 | -------------------------------------------------------------------------------- /spec/fixtures/test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | def test_base(): 5 | assert True 6 | 7 | 8 | class MyTest(unittest.TestCase): 9 | def test_method1(self): 10 | assert True 11 | 12 | def test_method2(self): 13 | assert True 14 | -------------------------------------------------------------------------------- /spec/fixtures/test.ts: -------------------------------------------------------------------------------- 1 | describe("tstest", (): void => { 2 | describe(`ns`, (): void => { 3 | it("test1", (): void => { 4 | // assertions 5 | }); 6 | }) 7 | }); 8 | -------------------------------------------------------------------------------- /spec/fixtures/test_spec.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe Game do 2 | describe '#score' do 3 | it 'returns 0 for an all gutter game' do 4 | game = Game.new 5 | 20.times { game.roll(0) } 6 | expect(game.score).to eq(0) 7 | end 8 | end 9 | end 10 | 11 | -------------------------------------------------------------------------------- /spec/fixtures/zig/.gitignore: -------------------------------------------------------------------------------- 1 | zig-out/ zig-cache/ 2 | -------------------------------------------------------------------------------- /spec/fixtures/zig/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | // Although this function looks imperative, note that its job is to 4 | // declaratively construct a build graph that will be executed by an external 5 | // runner. 6 | pub fn build(b: *std.Build) void { 7 | // Standard target options allows the person running `zig build` to choose 8 | // what target to build for. Here we do not override the defaults, which 9 | // means any target is allowed, and the default is native. Other options 10 | // for restricting supported target set are available. 11 | const target = b.standardTargetOptions(.{}); 12 | 13 | // Standard optimization options allow the person running `zig build` to select 14 | // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not 15 | // set a preferred release mode, allowing the user to decide how to optimize. 16 | const optimize = b.standardOptimizeOption(.{}); 17 | 18 | const lib = b.addStaticLibrary(.{ 19 | .name = "zig", 20 | // In this case the main source file is merely a path, however, in more 21 | // complicated build scripts, this could be a generated file. 22 | .root_source_file = .{ .path = "src/main.zig" }, 23 | .target = target, 24 | .optimize = optimize, 25 | }); 26 | 27 | // This declares intent for the library to be installed into the standard 28 | // location when the user invokes the "install" step (the default step when 29 | // running `zig build`). 30 | lib.install(); 31 | 32 | // Creates a step for unit testing. 33 | const main_tests = b.addTest(.{ 34 | .root_source_file = .{ .path = "src/main.zig" }, 35 | .target = target, 36 | .optimize = optimize, 37 | }); 38 | 39 | // This creates a build step. It will be visible in the `zig build --help` menu, 40 | // and can be selected like this: `zig build test` 41 | // This will evaluate the `test` step rather than the default, which is "install". 42 | const test_step = b.step("test", "Run library tests"); 43 | test_step.dependOn(&main_tests.step); 44 | } 45 | -------------------------------------------------------------------------------- /spec/fixtures/zig/src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const testing = std.testing; 3 | 4 | export fn add(a: i32, b: i32) i32 { 5 | return a + b; 6 | } 7 | 8 | test "basic add functionality" { 9 | try testing.expect(add(3, 7) == 10); 10 | } 11 | 12 | test "other functionality" { 13 | try testing.expect(add(3, 7) == 10); 14 | } 15 | -------------------------------------------------------------------------------- /spec/fixtures/zig/src/nested/mod.zig: -------------------------------------------------------------------------------- 1 | test "some nested test" {} 2 | -------------------------------------------------------------------------------- /spec/fixtures/zig/src/somemod.zig: -------------------------------------------------------------------------------- 1 | test "some other test" {} 2 | -------------------------------------------------------------------------------- /spec/helpers.lua: -------------------------------------------------------------------------------- 1 | -- local plugin_name = vim.split((...):gsub("%.", "/"), "/", true)[1] 2 | local M = require "vusted.helper" 3 | 4 | -- print(plugin_name, (...):gsub("%", "/")) 5 | -- M.root = M.find_plugin_root(plugin_name) 6 | 7 | function M.before_each(config) 8 | vim.cmd "filetype on" 9 | vim.cmd "syntax enable" 10 | require("nvim-test").setup(config or { run = false }) 11 | end 12 | 13 | function M.after_each() 14 | -- vim.cmd "tabedit" 15 | -- vim.cmd "tabonly!" 16 | vim.cmd "silent %bwipeout!" 17 | vim.cmd "filetype off" 18 | vim.cmd "syntax off" 19 | M.cleanup_loaded_modules "nvim-test" 20 | print " " 21 | end 22 | 23 | function M.set_lines(lines) 24 | vim.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(lines, "\n")) 25 | end 26 | 27 | function M.input(text) 28 | vim.api.nvim_put({ text }, "c", true, true) 29 | end 30 | 31 | function M.edit(filename, line) 32 | local opts = line and string.format("+%s ", line) or "" 33 | vim.api.nvim_command(string.format("edit %s%s", opts, filename)) 34 | end 35 | 36 | function M.view(filename, line) 37 | local opts = line and string.format("+%s ", line) or "" 38 | vim.api.nvim_command(string.format("view %s%s", opts, filename)) 39 | end 40 | 41 | function M.debug(val) 42 | print(vim.inspect(val)) 43 | end 44 | 45 | function M.search(pattern) 46 | local result = vim.fn.search(pattern) 47 | if result == 0 then 48 | local info = debug.getinfo(2) 49 | local pos = ("%s:%d"):format(info.source, info.currentline) 50 | local lines = table.concat(vim.fn.getbufline("%", 1, "$"), "\n") 51 | local msg = ("on %s: `%s` not found in buffer:\n%s"):format(pos, pattern, lines) 52 | assert(false, msg) 53 | end 54 | return result 55 | end 56 | 57 | local asserts = require("vusted.assert").asserts 58 | 59 | asserts.create("filetype"):register_eq(function() 60 | return vim.bo.filetype 61 | end) 62 | 63 | asserts.create("buffer"):register_eq(function() 64 | return vim.api.nvim_buf_get_name(0) 65 | end) 66 | 67 | asserts.create("bufnr"):register_eq(function() 68 | return vim.api.nvim_get_current_buf() 69 | end) 70 | 71 | asserts.create("window"):register_eq(function() 72 | return vim.api.nvim_get_current_win() 73 | end) 74 | 75 | asserts.create("tab_count"):register_eq(function() 76 | return vim.fn.tabpagenr "$" 77 | end) 78 | 79 | asserts.create("window_count"):register_eq(function() 80 | return vim.fn.tabpagewinnr(vim.fn.tabpagenr(), "$") 81 | end) 82 | 83 | asserts.create("current_line"):register_eq(function() 84 | return vim.fn.getline "." 85 | end) 86 | 87 | asserts.create("current_col"):register_eq(function() 88 | return vim.fn.col "." 89 | end) 90 | 91 | asserts.create("current_row"):register_eq(function() 92 | return vim.fn.line "." 93 | end) 94 | 95 | asserts.create("current_word"):register_eq(function() 96 | return vim.fn.expand "" 97 | end) 98 | 99 | asserts.create("exists_pattern"):register(function(self) 100 | return function(_, args) 101 | local pattern = args[1] 102 | pattern = pattern:gsub("\n", "\\n") 103 | local result = vim.fn.search(pattern, "n") 104 | self:set_positive(("`%s` not found"):format(pattern)) 105 | self:set_negative(("`%s` found"):format(pattern)) 106 | return result ~= 0 107 | end 108 | end) 109 | 110 | asserts.create("exists_message"):register(function(self) 111 | return function(_, args) 112 | local expected = args[1] 113 | self:set_positive(("`%s` not found message"):format(expected)) 114 | self:set_negative(("`%s` found message"):format(expected)) 115 | local messages = vim.split(vim.api.nvim_exec("messages", true), "\n") 116 | for _, msg in ipairs(messages) do 117 | if msg:match(expected) then 118 | return true 119 | end 120 | end 121 | return false 122 | end 123 | end) 124 | 125 | return M 126 | -------------------------------------------------------------------------------- /spec/init_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("nvim-test", function() 4 | after_each(helpers.after_each) 5 | before_each(helpers.before_each) 6 | 7 | it("test config", function() 8 | local nvim_test = require "nvim-test" 9 | nvim_test.setup { split = "abo split" } 10 | assert.are.equal(nvim_test.config.split, "abo split") 11 | end) 12 | 13 | it("test commands", function() 14 | assert.is_true(vim.fn.exists ":TestSuite" > 0) 15 | assert.is_true(vim.fn.exists ":TestFile" > 0) 16 | assert.is_true(vim.fn.exists ":TestNearest" > 0) 17 | assert.is_true(vim.fn.exists ":TestLast" > 0) 18 | assert.is_true(vim.fn.exists ":TestVisit" > 0) 19 | end) 20 | 21 | it("test visit", function() 22 | local filename = vim.fn.fnamemodify("spec/fixtures/test.lua", ":p") 23 | helpers.view(filename) 24 | vim.api.nvim_command "TestFile" 25 | helpers.view "unkwnown" 26 | vim.api.nvim_command "TestVisit" 27 | assert.buffer(filename) 28 | end) 29 | 30 | it("test edit", function() 31 | helpers.view "spec/fixtures/unknown.py" 32 | vim.api.nvim_command "TestEdit" 33 | assert.buffer(vim.fn.fnamemodify("spec/fixtures/test_unknown.py", ":p")) 34 | end) 35 | 36 | it("test suite", function() 37 | local filename = "spec/lua/test/fixtures/test.lua" 38 | helpers.view(filename) 39 | vim.api.nvim_command "TestFile" 40 | helpers.view "unkwnown" 41 | vim.api.nvim_command "TestSuite" 42 | assert.are.same(vim.g.test_latest.cmd, { "busted" }) 43 | end) 44 | end) 45 | -------------------------------------------------------------------------------- /spec/runner_spec.lua: -------------------------------------------------------------------------------- 1 | describe("runner", function() 2 | it("test runners", function() 3 | local nvim_test = require "nvim-test" 4 | local runner = nvim_test.get_runner "javascript" 5 | assert.are.equal(runner.config.command, "jest") 6 | 7 | nvim_test.setup { runners = { javascript = "nvim-test.runners.mocha" } } 8 | assert.are.equal(nvim_test.config.runners.javascript, "nvim-test.runners.mocha") 9 | 10 | runner = nvim_test.get_runner "javascript" 11 | assert.are.equal(runner.config.command, "mocha") 12 | end) 13 | end) 14 | -------------------------------------------------------------------------------- /spec/runners/busted_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("busted", function() 4 | before_each(helpers.before_each) 5 | after_each(helpers.after_each) 6 | 7 | local filename = "spec/fixtures/test.lua" 8 | 9 | it("runner", function() 10 | local runner = require "nvim-test.runners.busted" 11 | assert.is.truthy(runner) 12 | 13 | assert.is_false(runner:is_testfile "somefile.lua") 14 | assert.is_true(runner:is_testfile "somefile_spec.lua") 15 | assert.is_true(runner:is_testfile "somefile_spec.moon") 16 | end) 17 | 18 | it("run suite", function() 19 | helpers.view(filename) 20 | vim.api.nvim_command "TestSuite" 21 | assert.are.same({ "busted" }, vim.g.test_latest.cmd) 22 | end) 23 | 24 | it("run file", function() 25 | helpers.view(filename) 26 | vim.api.nvim_command "TestFile" 27 | assert.are.same({ "busted", filename }, vim.g.test_latest.cmd) 28 | end) 29 | 30 | it("run nearest function", function() 31 | helpers.view(filename, 4) 32 | vim.api.nvim_command "TestNearest" 33 | assert.are.same({ "busted", filename, "--filter", "luatest test1" }, vim.g.test_latest.cmd) 34 | end) 35 | 36 | it("run latest", function() 37 | helpers.view(filename) 38 | vim.api.nvim_command "TestFile" 39 | assert.are.same(vim.g.test_latest.cmd, { "busted", filename }) 40 | 41 | vim.api.nvim_command "TestLast" 42 | assert.are.same(vim.g.test_latest.cmd, { "busted", filename }) 43 | end) 44 | end) 45 | -------------------------------------------------------------------------------- /spec/runners/cargo-test_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("cargotest", function() 4 | before_each(function() 5 | helpers.before_each() 6 | vim.api.nvim_command "cd spec/fixtures/rust/crate" 7 | end) 8 | after_each(function() 9 | helpers.after_each() 10 | vim.api.nvim_command "cd -" 11 | end) 12 | 13 | it("run suite", function() 14 | helpers.view "src/main.rs" 15 | vim.api.nvim_command "TestSuite" 16 | assert.are.same(vim.g.test_latest.cmd, { "cargo", "test" }) 17 | end) 18 | 19 | it("run file", function() 20 | helpers.view "src/main.rs" 21 | vim.api.nvim_command "TestFile" 22 | assert.are.same(vim.g.test_latest.cmd, { "cargo", "test" }) 23 | 24 | helpers.view "src/somemod.rs" 25 | vim.api.nvim_command "TestFile" 26 | assert.are.same(vim.g.test_latest.cmd, { "cargo", "test", "somemod::" }) 27 | 28 | helpers.view "src/nested/mod.rs" 29 | vim.api.nvim_command "TestFile" 30 | assert.are.same(vim.g.test_latest.cmd, { "cargo", "test", "nested::" }) 31 | end) 32 | 33 | it("run nearest function", function() 34 | helpers.view("src/lib.rs", 7) 35 | assert.exists_pattern "first_test" 36 | vim.api.nvim_command "TestNearest" 37 | assert.are.same( 38 | { "cargo", "test", "tests::first_test", "--", "--exact" }, 39 | vim.g.test_latest.cmd 40 | ) 41 | end) 42 | 43 | it("run latest", function() 44 | helpers.view "src/main.rs" 45 | vim.api.nvim_command "TestFile" 46 | assert.are.same(vim.g.test_latest.cmd, { "cargo", "test" }) 47 | 48 | vim.api.nvim_command "TestLast" 49 | assert.are.same(vim.g.test_latest.cmd, { "cargo", "test" }) 50 | end) 51 | end) 52 | -------------------------------------------------------------------------------- /spec/runners/dotnet_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("dotnet", function() 4 | before_each(helpers.before_each) 5 | after_each(helpers.after_each) 6 | 7 | local filename = "spec/fixtures/Tests.cs" 8 | 9 | it("runner", function() 10 | local runner = require "nvim-test.runners.dotnet" 11 | assert.is.truthy(runner) 12 | assert.is.equal("dotnet", runner.config.command) 13 | -- 14 | assert.is_false(runner:is_testfile "somefile.cs") 15 | assert.is_true(runner:is_testfile "test/somefile.cs") 16 | assert.is_true(runner:is_testfile "Tests.cs") 17 | end) 18 | 19 | it("run suite", function() 20 | helpers.view(filename) 21 | vim.api.nvim_command "TestSuite" 22 | assert.are.same({ "dotnet", "test" }, vim.g.test_latest.cmd) 23 | end) 24 | 25 | it("run file", function() 26 | helpers.view(filename) 27 | vim.api.nvim_command "TestFile" 28 | assert.are.same({ "dotnet", "test", filename }, vim.g.test_latest.cmd) 29 | end) 30 | 31 | it("run nearest function", function() 32 | helpers.view(filename, 4) 33 | vim.api.nvim_command "TestNearest" 34 | assert.are.same( 35 | { "dotnet", "test", filename, "--filter", "FullyQualifiedName=Namespace.Tests" }, 36 | vim.g.test_latest.cmd 37 | ) 38 | helpers.view(filename, 8) 39 | vim.api.nvim_command "TestNearest" 40 | assert.are.same( 41 | { "dotnet", "test", filename, "--filter", "FullyQualifiedName=Namespace.Tests.Test" }, 42 | vim.g.test_latest.cmd 43 | ) 44 | end) 45 | 46 | it("run latest", function() 47 | helpers.view(filename) 48 | vim.api.nvim_command "TestFile" 49 | assert.are.same({ "dotnet", "test", filename }, vim.g.test_latest.cmd) 50 | 51 | vim.api.nvim_command "TestLast" 52 | assert.are.same({ "dotnet", "test", filename }, vim.g.test_latest.cmd) 53 | end) 54 | end) 55 | -------------------------------------------------------------------------------- /spec/runners/go-test_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("gotest", function() 4 | local pwd 5 | 6 | before_each(function() 7 | helpers.before_each() 8 | pwd = vim.fn.getcwd() 9 | vim.api.nvim_command "cd spec/fixtures/go" 10 | end) 11 | after_each(function() 12 | helpers.after_each() 13 | vim.api.nvim_command("cd " .. pwd) 14 | end) 15 | 16 | local filename = "mypackage_test.go" 17 | 18 | it("run suite", function() 19 | helpers.view(filename) 20 | vim.api.nvim_command "TestSuite" 21 | assert.are.same(vim.g.test_latest.cmd, { "go", "test", "-v", "./..." }) 22 | end) 23 | 24 | it("run file", function() 25 | helpers.view(filename) 26 | vim.api.nvim_command "TestFile" 27 | assert.are.same(vim.g.test_latest.cmd, { "go", "test", "-v" }) 28 | end) 29 | 30 | it("run nested file", function() 31 | helpers.view(filename) 32 | vim.api.nvim_command "cd ../" 33 | vim.api.nvim_command "TestFile" 34 | assert.are.same(vim.g.test_latest.cmd, { "go", "test", "-v", "./go/..." }) 35 | end) 36 | 37 | it("run nearest function", function() 38 | helpers.view(filename, 6) 39 | vim.api.nvim_command "TestNearest" 40 | assert.are.same(vim.g.test_latest.cmd, { "go", "test", "-v", "-run", "TestNumbers$" }) 41 | end) 42 | 43 | it("run latest", function() 44 | helpers.view(filename) 45 | vim.api.nvim_command "TestFile" 46 | assert.are.same(vim.g.test_latest.cmd, { "go", "test", "-v" }) 47 | 48 | vim.api.nvim_command "TestLast" 49 | assert.are.same(vim.g.test_latest.cmd, { "go", "test", "-v" }) 50 | end) 51 | end) 52 | -------------------------------------------------------------------------------- /spec/runners/hspec_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("hspec", function() 4 | before_each(helpers.before_each) 5 | after_each(helpers.after_each) 6 | 7 | local filename = "spec/fixtures/Spec.hs" 8 | 9 | it("run suite", function() 10 | helpers.view(filename) 11 | vim.api.nvim_command "TestSuite" 12 | assert.are.same({ "runhaskell" }, vim.g.test_latest.cmd) 13 | end) 14 | 15 | it("run file", function() 16 | helpers.view(filename) 17 | vim.api.nvim_command "TestFile" 18 | assert.are.same({ "runhaskell", filename }, vim.g.test_latest.cmd) 19 | end) 20 | 21 | it("run nearest function", function() 22 | helpers.view(filename, 16) 23 | vim.api.nvim_command "TestNearest" 24 | assert.are.same({ 25 | "runhaskell", 26 | filename, 27 | "--match", 28 | "Prelude.head/nested/throws an exception if used with an empty list", 29 | }, vim.g.test_latest.cmd) 30 | end) 31 | 32 | it("run latest", function() 33 | helpers.view(filename) 34 | vim.api.nvim_command "TestFile" 35 | assert.are.same({ "runhaskell", filename }, vim.g.test_latest.cmd) 36 | 37 | vim.api.nvim_command "TestLast" 38 | assert.are.same({ "runhaskell", filename }, vim.g.test_latest.cmd) 39 | end) 40 | end) 41 | -------------------------------------------------------------------------------- /spec/runners/init_spec.lua: -------------------------------------------------------------------------------- 1 | describe("runners", function() 2 | it("basic", function() 3 | local runners = require "nvim-test.runners" 4 | assert.is.truthy(runners) 5 | end) 6 | end) 7 | -------------------------------------------------------------------------------- /spec/runners/jest_spec.lua: -------------------------------------------------------------------------------- 1 | -- Type: test 2 | -- @spec: jest_spec.lua 3 | -- @tags: jest 4 | -- @description: Jest test runner 5 | 6 | local helpers = require "spec.helpers" 7 | 8 | describe("jest", function() 9 | before_each(helpers.before_each) 10 | after_each(helpers.after_each) 11 | 12 | local filename = "spec/fixtures/js/name.test.js" 13 | 14 | it("runner", function() 15 | local runner = require "nvim-test.runners.jest" 16 | assert.is.truthy(runner) 17 | assert.is.equal("jest", runner.config.command) 18 | 19 | assert.is_false(runner:is_testfile "somefile.js") 20 | assert.is_true(runner:is_testfile "somefile.spec.js") 21 | assert.is_true(runner:is_testfile "somefile.test.js") 22 | assert.is_true(runner:is_testfile "__tests__/somefile.js") 23 | 24 | assert.is.equal("spec/fixtures/js/name.test.js", runner:find_file "spec/fixtures/js/name.js") 25 | end) 26 | 27 | it("run suite", function() 28 | helpers.view(filename) 29 | vim.api.nvim_command "TestSuite" 30 | assert.are.same({ "jest" }, vim.g.test_latest.cmd) 31 | end) 32 | 33 | it("run file", function() 34 | helpers.view(filename) 35 | vim.api.nvim_command "TestFile" 36 | assert.are.same({ "jest", filename }, vim.g.test_latest.cmd) 37 | end) 38 | 39 | it("run nearest function", function() 40 | helpers.view(filename, 4) 41 | vim.api.nvim_command "TestNearest" 42 | assert.are.same({ "jest", filename, "-t", "^jstest ns test1$" }, vim.g.test_latest.cmd) 43 | helpers.view(filename, 6) 44 | vim.api.nvim_command "TestNearest" 45 | assert.are.same({ "jest", filename, "-t", "^jstest ns test1$" }, vim.g.test_latest.cmd) 46 | end) 47 | 48 | it("run latest", function() 49 | helpers.view(filename) 50 | vim.api.nvim_command "TestFile" 51 | assert.are.same({ "jest", filename }, vim.g.test_latest.cmd) 52 | 53 | vim.api.nvim_command "TestLast" 54 | assert.are.same({ "jest", filename }, vim.g.test_latest.cmd) 55 | end) 56 | end) 57 | -------------------------------------------------------------------------------- /spec/runners/mocha_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("mocha", function() 4 | before_each(function() 5 | helpers.before_each { run = false, runners = { javascript = "nvim-test.runners.mocha" } } 6 | end) 7 | after_each(helpers.after_each) 8 | 9 | local filename = "spec/fixtures/js/name.test.js" 10 | 11 | it("runner", function() 12 | local runner = require "nvim-test.runners.mocha" 13 | assert.is.truthy(runner) 14 | 15 | assert.is_false(runner:is_testfile "somefile.js") 16 | assert.is_true(runner:is_testfile "somefile.test.js") 17 | assert.is_true(runner:is_testfile "test/somefile.js") 18 | end) 19 | 20 | it("run suite", function() 21 | helpers.view(filename) 22 | vim.api.nvim_command "TestSuite" 23 | assert.are.same(vim.g.test_latest.cmd, { "mocha" }) 24 | end) 25 | 26 | it("run file", function() 27 | helpers.view(filename) 28 | vim.api.nvim_command "TestFile" 29 | assert.are.same(vim.g.test_latest.cmd, { "mocha", filename }) 30 | end) 31 | 32 | it("run nearest function", function() 33 | helpers.view(filename, 4) 34 | vim.api.nvim_command "TestNearest" 35 | assert.are.same(vim.g.test_latest.cmd, { "mocha", filename, "-f", "jstest ns test1" }) 36 | end) 37 | 38 | it("run latest", function() 39 | helpers.view(filename) 40 | vim.api.nvim_command "TestFile" 41 | assert.are.same(vim.g.test_latest.cmd, { "mocha", filename }) 42 | 43 | vim.api.nvim_command "TestLast" 44 | assert.are.same(vim.g.test_latest.cmd, { "mocha", filename }) 45 | end) 46 | end) 47 | -------------------------------------------------------------------------------- /spec/runners/pytest_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("pytest", function() 4 | before_each(helpers.before_each) 5 | after_each(helpers.after_each) 6 | 7 | local filename = "spec/fixtures/test.py" 8 | 9 | it("runner", function() 10 | local runner = require "nvim-test.runners.pytest" 11 | assert.is.truthy(runner) 12 | assert.is.equal("pytest", runner.config.command) 13 | 14 | assert.is_false(runner:is_testfile "somefile.py") 15 | assert.is_true(runner:is_testfile "somefile_test.py") 16 | assert.is_true(runner:is_testfile "test_somefile.py") 17 | assert.is_true(runner:is_testfile "tests.py") 18 | end) 19 | 20 | it("run suite", function() 21 | helpers.view(filename) 22 | vim.api.nvim_command "TestSuite" 23 | assert.are.same(vim.g.test_latest.cmd, { "pytest" }) 24 | end) 25 | 26 | it("run file", function() 27 | helpers.view(filename) 28 | vim.api.nvim_command "TestFile" 29 | assert.are.same(vim.g.test_latest.cmd, { "pytest", filename }) 30 | end) 31 | 32 | it("run nearest function", function() 33 | helpers.view(filename, 4) 34 | vim.api.nvim_command "TestNearest" 35 | assert.are.same(vim.g.test_latest.cmd, { "pytest", filename .. "::test_base" }) 36 | end) 37 | 38 | it("run nearest method", function() 39 | helpers.view(filename, 13) 40 | vim.api.nvim_command "TestNearest" 41 | assert.are.same(vim.g.test_latest.cmd, { "pytest", filename .. "::MyTest::test_method2" }) 42 | end) 43 | 44 | it("run latest", function() 45 | helpers.view(filename) 46 | vim.api.nvim_command "TestFile" 47 | assert.are.same(vim.g.test_latest.cmd, { "pytest", filename }) 48 | 49 | vim.api.nvim_command "TestLast" 50 | assert.are.same(vim.g.test_latest.cmd, { "pytest", filename }) 51 | end) 52 | 53 | it("setup args", function() 54 | require("nvim-test.runners.pytest"):setup { args = { "-v" } } 55 | helpers.view(filename) 56 | vim.api.nvim_command "TestFile" 57 | assert.are.same(vim.g.test_latest.cmd, { "pytest", "-v", filename }) 58 | end) 59 | end) 60 | -------------------------------------------------------------------------------- /spec/runners/pyunit_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("pyunit", function() 4 | before_each(function() 5 | helpers.before_each { run = false, runners = { python = "nvim-test.runners.pyunit" } } 6 | end) 7 | after_each(helpers.after_each) 8 | 9 | local filename = "spec/fixtures/test.py" 10 | 11 | it("runner", function() 12 | local runner = require "nvim-test.runners.pyunit" 13 | assert.is.truthy(runner) 14 | 15 | assert.is_false(runner:is_testfile "somefile.py") 16 | assert.is_true(runner:is_testfile "test_somefile.py") 17 | end) 18 | 19 | it("run suite", function() 20 | helpers.view(filename) 21 | vim.api.nvim_command "TestSuite" 22 | assert.are.same(vim.g.test_latest.cmd, { "python", "-m", "unittest" }) 23 | end) 24 | 25 | it("run file", function() 26 | helpers.view(filename) 27 | vim.api.nvim_command "TestFile" 28 | assert.are.same(vim.g.test_latest.cmd, { "python", "-m", "unittest", "spec.fixtures.test" }) 29 | end) 30 | 31 | it("run nearest function", function() 32 | helpers.view(filename, 4) 33 | vim.api.nvim_command "TestNearest" 34 | assert.are.same( 35 | vim.g.test_latest.cmd, 36 | { "python", "-m", "unittest", "spec.fixtures.test.test_base" } 37 | ) 38 | end) 39 | 40 | it("run nearest method", function() 41 | helpers.view(filename, 13) 42 | vim.api.nvim_command "TestNearest" 43 | assert.are.same( 44 | vim.g.test_latest.cmd, 45 | { "python", "-m", "unittest", "spec.fixtures.test.MyTest.test_method2" } 46 | ) 47 | end) 48 | 49 | it("run latest", function() 50 | helpers.view(filename) 51 | vim.api.nvim_command "TestFile" 52 | assert.are.same(vim.g.test_latest.cmd, { "python", "-m", "unittest", "spec.fixtures.test" }) 53 | 54 | vim.api.nvim_command "TestLast" 55 | assert.are.same(vim.g.test_latest.cmd, { "python", "-m", "unittest", "spec.fixtures.test" }) 56 | end) 57 | end) 58 | -------------------------------------------------------------------------------- /spec/runners/rspec_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("rspec", function() 4 | before_each(helpers.before_each) 5 | after_each(helpers.after_each) 6 | 7 | local filename = "spec/fixtures/test_spec.rb" 8 | 9 | it("run suite", function() 10 | helpers.view(filename) 11 | vim.api.nvim_command "TestSuite" 12 | assert.are.same({ "bundle", "exec", "rspec" }, vim.g.test_latest.cmd) 13 | end) 14 | 15 | it("run file", function() 16 | helpers.view(filename) 17 | vim.api.nvim_command "TestFile" 18 | assert.are.same({ "bundle", "exec", "rspec", filename }, vim.g.test_latest.cmd) 19 | end) 20 | 21 | it("run nearest function", function() 22 | helpers.view(filename, 4) 23 | vim.api.nvim_command "TestNearest" 24 | assert.are.same({ 25 | "bundle", 26 | "exec", 27 | "rspec", 28 | filename, 29 | "--example", 30 | "#score returns 0 for an all gutter game", 31 | }, vim.g.test_latest.cmd) 32 | end) 33 | 34 | it("run latest", function() 35 | helpers.view(filename) 36 | vim.api.nvim_command "TestFile" 37 | assert.are.same({ "bundle", "exec", "rspec", filename }, vim.g.test_latest.cmd) 38 | 39 | vim.api.nvim_command "TestLast" 40 | assert.are.same({ "bundle", "exec", "rspec", filename }, vim.g.test_latest.cmd) 41 | end) 42 | end) 43 | -------------------------------------------------------------------------------- /spec/runners/stack_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("hspec", function() 4 | before_each(function() 5 | helpers.before_each { run = false, runners = { haskell = "nvim-test.runners.stack" } } 6 | end) 7 | after_each(helpers.after_each) 8 | 9 | local filename = "spec/fixtures/Spec.hs" 10 | 11 | it("run suite", function() 12 | helpers.view(filename) 13 | vim.api.nvim_command "TestSuite" 14 | assert.are.same({ "stack", "test" }, vim.g.test_latest.cmd) 15 | end) 16 | 17 | it("run file", function() 18 | helpers.view(filename) 19 | vim.api.nvim_command "TestFile" 20 | assert.are.same({ "stack", "test", filename }, vim.g.test_latest.cmd) 21 | end) 22 | 23 | it("run nearest function", function() 24 | helpers.view(filename, 16) 25 | vim.api.nvim_command "TestNearest" 26 | assert.are.same({ 27 | "stack", 28 | "test", 29 | filename, 30 | "--test-arguments='--match \"Prelude.head/nested/throws an exception if used with an empty list\"'", 31 | }, vim.g.test_latest.cmd) 32 | end) 33 | 34 | it("run latest", function() 35 | helpers.view(filename) 36 | vim.api.nvim_command "TestFile" 37 | assert.are.same({ "stack", "test", filename }, vim.g.test_latest.cmd) 38 | 39 | vim.api.nvim_command "TestLast" 40 | assert.are.same({ "stack", "test", filename }, vim.g.test_latest.cmd) 41 | end) 42 | end) 43 | -------------------------------------------------------------------------------- /spec/runners/ts-mocha_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("tsmocha", function() 4 | before_each(function() 5 | helpers.before_each { run = false, runners = { typescript = "nvim-test.runners.ts-mocha" } } 6 | end) 7 | after_each(helpers.after_each) 8 | 9 | local filename = "spec/fixtures/test.ts" 10 | 11 | it("run suite", function() 12 | helpers.view(filename) 13 | vim.api.nvim_command "TestSuite" 14 | assert.are.same(vim.g.test_latest.cmd, { "ts-mocha" }) 15 | end) 16 | 17 | it("run file", function() 18 | helpers.view(filename) 19 | vim.api.nvim_command "TestFile" 20 | assert.are.same(vim.g.test_latest.cmd, { "ts-mocha", filename }) 21 | end) 22 | 23 | it("run nearest function", function() 24 | helpers.view(filename, 4) 25 | vim.api.nvim_command "TestNearest" 26 | assert.are.same(vim.g.test_latest.cmd, { "ts-mocha", filename, "-f", "tstest ns test1" }) 27 | end) 28 | 29 | it("run latest", function() 30 | helpers.view(filename) 31 | vim.api.nvim_command "TestFile" 32 | assert.are.same(vim.g.test_latest.cmd, { "ts-mocha", filename }) 33 | 34 | vim.api.nvim_command "TestLast" 35 | assert.are.same(vim.g.test_latest.cmd, { "ts-mocha", filename }) 36 | end) 37 | end) 38 | -------------------------------------------------------------------------------- /spec/runners/vusted_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require "spec.helpers" 2 | 3 | describe("vusted", function() 4 | before_each(function() 5 | helpers.before_each { run = false, runners = { lua = "nvim-test.runners.vusted" } } 6 | end) 7 | after_each(helpers.after_each) 8 | 9 | require("nvim-test").setup { runners = { lua = "nvim-test.runners.vusted" } } 10 | 11 | local filename = "spec/fixtures/test.lua" 12 | 13 | it("runner", function() 14 | local runner = require "nvim-test.runners.vusted" 15 | assert.is.truthy(runner) 16 | 17 | assert.is_false(runner:is_testfile "somefile.lua") 18 | assert.is_true(runner:is_testfile "somefile_spec.lua") 19 | assert.is_true(runner:is_testfile "somefile_spec.moon") 20 | end) 21 | 22 | it("run suite", function() 23 | helpers.view(filename) 24 | vim.api.nvim_command "TestSuite" 25 | assert.are.same({ "vusted" }, vim.g.test_latest.cmd) 26 | end) 27 | 28 | it("run file", function() 29 | helpers.view(filename) 30 | vim.api.nvim_command "TestFile" 31 | assert.are.same({ "vusted", filename }, vim.g.test_latest.cmd) 32 | end) 33 | 34 | it("run nearest function", function() 35 | helpers.view(filename, 4) 36 | vim.api.nvim_command "TestNearest" 37 | assert.are.same({ "vusted", filename, "--filter", "luatest test1" }, vim.g.test_latest.cmd) 38 | end) 39 | 40 | it("run latest", function() 41 | helpers.view(filename) 42 | vim.api.nvim_command "TestFile" 43 | assert.are.same({ "vusted", filename }, vim.g.test_latest.cmd) 44 | 45 | vim.api.nvim_command "TestLast" 46 | assert.are.same({ "vusted", filename }, vim.g.test_latest.cmd) 47 | end) 48 | end) 49 | -------------------------------------------------------------------------------- /spec/runners/zig_spec.lua: -------------------------------------------------------------------------------- 1 | local helpers = require("spec.helpers") 2 | 3 | describe("zigtest", function() 4 | before_each(function() 5 | helpers.before_each() 6 | vim.api.nvim_command("cd spec/fixtures/zig") 7 | end) 8 | after_each(function() 9 | helpers.after_each() 10 | vim.api.nvim_command("cd -") 11 | end) 12 | 13 | it("run suite", function() 14 | helpers.view("src/main.zig") 15 | vim.api.nvim_command("TestSuite") 16 | assert.are.same(vim.g.test_latest.cmd, { "zig", "build", "test" }) 17 | end) 18 | 19 | it("run file", function() 20 | helpers.view("src/main.zig") 21 | vim.api.nvim_command("TestFile") 22 | assert.are.same(vim.g.test_latest.cmd, { "zig", "test", "src/main.zig" }) 23 | 24 | helpers.view("src/somemod.zig") 25 | vim.api.nvim_command("TestFile") 26 | assert.are.same(vim.g.test_latest.cmd, { "zig", "test", "src/somemod.zig" }) 27 | 28 | helpers.view("src/nested/mod.zig") 29 | vim.api.nvim_command("TestFile") 30 | assert.are.same(vim.g.test_latest.cmd, { "zig", "test", "src/nested/mod.zig" }) 31 | end) 32 | 33 | it("run nearest function", function() 34 | helpers.view("src/main.zig", 8) 35 | -- assert.exists_pattern("first_test") 36 | vim.api.nvim_command("TestNearest") 37 | assert.are.same( 38 | { "zig", "test", "src/main.zig", "--test-filter", "basic add functionality" }, 39 | vim.g.test_latest.cmd 40 | ) 41 | end) 42 | 43 | it("run latest", function() 44 | helpers.view("src/main.zig") 45 | vim.api.nvim_command("TestFile") 46 | assert.are.same(vim.g.test_latest.cmd, { "zig", "test", "src/main.zig" }) 47 | 48 | vim.api.nvim_command("TestLast") 49 | assert.are.same(vim.g.test_latest.cmd, { "zig", "test", "src/main.zig" }) 50 | end) 51 | end) 52 | -------------------------------------------------------------------------------- /spec/utils_spec.lua: -------------------------------------------------------------------------------- 1 | describe("utils", function() 2 | local utils = require "nvim-test.utils" 3 | it("find file by patterns", function() 4 | assert.is.equal( 5 | "spec/fixtures/js/name.test.js", 6 | utils.find_file_by_patterns( 7 | "spec/fixtures/js/name.js", 8 | { "{name}.spec.{ext}", "{name}.test.{ext}" } 9 | ) 10 | ) 11 | assert.is.equal( 12 | "spec/fixtures/js/unknown.js", 13 | utils.find_file_by_patterns( 14 | "spec/fixtures/js/unknown.js", 15 | { "{name}.spec.{ext}", "{name}.test.{ext}" } 16 | ) 17 | ) 18 | assert.is.equal( 19 | "spec/fixtures/js/unknown.spec.js", 20 | utils.find_file_by_patterns( 21 | "spec/fixtures/js/unknown.js", 22 | { "{name}.spec.{ext}", "{name}.test.{ext}" }, 23 | true 24 | ) 25 | ) 26 | end) 27 | end) 28 | --------------------------------------------------------------------------------