SkillAgentSearch skills...

Quicktest.nvim

Run your tests inside nvim in split window or popup with live feedback

Install / Use

/learn @quolpr/Quicktest.nvim
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Quicktest

  • Contextual Test Triggering: Run tests directly from where your cursor is located or execute all tests in the entire file/dir/project.
  • Flexible Test Reruns: Rerun tests from any location(with require('quicktest').run_previous(), keybind is in usage example), automatically opening window or using an existing if it's open.
  • Live-Scrolling Results: Continuously scroll through test results as they are generated. But stop scrolling if you decided to scroll up.
  • Real-Time Feedback: View the results of tests immediately as they run, without waiting for the completion of the test suite.
  • Test Duration Timer: Display a timer to monitor the duration of ongoing tests.
  • ANSI colors builtin support.
  • Easy to write your own adapter: It's just all about running cmd and piping results to quicktest.
  • Persistent previous run: After restarting Neovim, Quicktest will remember the previous run and be able to rerun it.

https://github.com/user-attachments/assets/9fcb3e17-f521-4660-9d9a-d9f763de5a1b

Installation

With Lazy:

{
  "quolpr/quicktest.nvim",
  config = function()
    local qt = require("quicktest")

    qt.setup({
      -- Choose your adapter, here all supported adapters are listed
      adapters = {
        require("quicktest.adapters.golang")({}),
        require("quicktest.adapters.vitest")({}),
        require("quicktest.adapters.playwright")({}),
        require("quicktest.adapters.pytest")({}),
        require("quicktest.adapters.elixir"),
        require("quicktest.adapters.criterion"),
        require("quicktest.adapters.dart"),
        require("quicktest.adapters.rspec"),
      },
      -- split or popup mode, when argument not specified
      default_win_mode = "split",
      use_builtin_colorizer = true
    })
  end,
  dependencies = {
    "nvim-lua/plenary.nvim",
    "MunifTanjim/nui.nvim",
  },
  keys = {
    {
      "<leader>tl",
      function()
        local qt = require("quicktest")
        -- current_win_mode return currently opened panel, split or popup
        qt.run_line()
        -- You can force open split or popup like this:
        -- qt.run_line('split')
        -- qt.run_line('popup')
      end,
      desc = "[T]est Run [L]line",
    },
    {
      "<leader>tf",
      function()
        local qt = require("quicktest")

        qt.run_file()
      end,
      desc = "[T]est Run [F]ile",
    },
    {
      '<leader>td',
      function()
        local qt = require 'quicktest'

        qt.run_dir()
      end,
      desc = '[T]est Run [D]ir',
    },
    {
      '<leader>ta',
      function()
        local qt = require 'quicktest'

        qt.run_all()
      end,
      desc = '[T]est Run [A]ll',
    },
    {
      "<leader>tp",
      function()
        local qt = require("quicktest")

        qt.run_previous()
      end,
      desc = "[T]est Run [P]revious",
    },
    {
      "<leader>tt",
      function()
        local qt = require("quicktest")

        qt.toggle_win("split")
      end,
      desc = "[T]est [T]oggle Window",
    },
    {
      "<leader>tc",
      function()
        local qt = require("quicktest")

        qt.cancel_current_run()
      end,
      desc = "[T]est [C]ancel Current Run",
    },
  },
}

Without Lazy:

local qt = require("quicktest")

-- Choose your adapter, here all supported adapters are listed
qt.setup({
  adapters = {
    require("quicktest.adapters.golang"),
    require("quicktest.adapters.vitest")({}),
    require("quicktest.adapters.playwright")({}),
    require("quicktest.adapters.pytest")({}),
    require("quicktest.adapters.elixir"),
    require("quicktest.adapters.criterion"),
    require("quicktest.adapters.dart"),
    require("quicktest.adapters.rspec"),
  },
  -- split or popup mode, when argument not specified
  default_win_mode = "split",
  use_builtin_colorizer = true
})

vim.keymap.set("n", "<leader>tl", qt.run_line, {
  desc = "[T]est Run [L]line",
})
vim.keymap.set("n", "<leader>tf", qt.run_file, {
  desc = "[T]est Run [F]ile",
})
vim.keymap.set("n", "<leader>td", qt.run_dir, {
  desc = "[T]est Run [D]ir",
})
vim.keymap.set("n", "<leader>ta", qt.run_all, {
  desc = "[T]est Run [A]ll",
})
vim.keymap.set("n", "<leader>tR", qt.run_previous, {
  desc = "[T]est Run [P]revious",
})
-- vim.keymap.set("n", "<leader>tt", function()
--   qt.toggle_win("popup")
-- end, {
--   desc = "[T]est [T]oggle popup window",
-- })
vim.keymap.set("n", "<leader>tt", function()
  qt.toggle_win("split")
end, {
  desc = "[T]est [T]oggle Window",
})
vim.keymap.set("n", "<leader>tc", function()
  qt.cancel_current_run()
end, {
  desc = "[T]est [C]ancel Current Run",
})

Commands

:QuicktestRun[Line/File/Dir/All] <win_mode> <adapter> ...<args>

Examples:

:QuicktestRunLine auto auto --my=arg
:QuicktestRunLine popup auto --my=arg
:QuicktestRunLine split auto --my=arg
:QuicktestRunLine split go --my=arg


:QuicktestRunFile split go --my=arg
:QuicktestRunDir split go --my=arg
:QuicktestRunAll split go --my=arg

Api

local qt = require 'quicktest'

-- Choose your adapter, here all supported adapters are listed
qt.setup({
  adapters = {
    require("quicktest.adapters.golang")({
      ---@field cwd (fun(bufnr: integer, current: string?): string)?
      ---@field bin (fun(bufnr: integer, current: string?): string)?
      ---@field additional_args (fun(bufnr: integer): string[])?
      ---@field args (fun(bufnr: integer, current: string[]): string[])?
      ---@field env (fun(bufnr: integer, current: table<string, string>): table<string, string>)?
      ---@field is_enabled (fun(bufnr: integer, type: RunType, current: boolean): boolean)?

      additional_args = function(bufnr) return { '-race', '-count=1' } end
      -- bin = function(bufnr, current) return current end
      -- cwd = function(bufnr, current) return current end
    }),
    require("quicktest.adapters.vitest")({
      ---@class VitestAdapterOptions
      ---@field cwd (fun(bufnr: integer, current: string?): string)?
      ---@field bin (fun(bufnr: integer, current: string?): string)?
      ---@field config_path (fun(bufnr: integer, current: string): string)?
      ---@field args (fun(bufnr: integer, current: string[]): string[])?
      ---@field env (fun(bufnr: integer, current: table<string, string>): table<string, string>)?
      ---@field is_enabled (fun(bufnr: integer, type: RunType, current: boolean): boolean)?

      -- bin = function(bufnr, current) return current end
      -- cwd = function(bufnr, current) return current end
      -- config_path = function(bufnr, current) return current end
    }),
    require("quicktest.adapters.elixir")({
      ---@class ElixirAdapterOptions
      ---@field cwd (fun(bufnr: integer, current: string?): string)?
      ---@field bin (fun(bufnr: integer, current: string?): string)?
      ---@field args (fun(bufnr: integer, current: string[]): string[])?
      ---@field env (fun(bufnr: integer, current: table<string, string>): table<string, string>)?
      ---@field is_enabled (fun(bufnr: integer, type: RunType, current: boolean): boolean)?
    }),
    require("quicktest.adapters.playwright")({
      ---@class PlaywrightAdapterOptions
      ---@field cwd (fun(bufnr: integer, current: string?): string)?
      ---@field bin (fun(bufnr: integer, current: string?): string)?
      ---@field config_path (fun(bufnr: integer, current: string): string)?
      ---@field args (fun(bufnr: integer, current: string[]): string[])?
      ---@field env (fun(bufnr: integer, current: table<string, string>): table<string, string>)?
      ---@field is_enabled (fun(bufnr: integer, type: RunType, current: boolean): boolean)?
    }),
    require("quicktest.adapters.pytest")({
      ---@class PytestAdapterOptions
      ---@field cwd (fun(bufnr: integer, current: string?): string)?
      ---@field bin (fun(bufnr: integer, current: string?): string)?
      ---@field args (fun(bufnr: integer, current: string[]): string[])?
      ---@field env (fun(bufnr: integer, current: table<string, string>): table<string, string>)?
      ---@field is_enabled (fun(bufnr: integer, type: RunType, current: boolean): boolean)?

      -- bin = function(bufnr, current) return current end
      -- cwd = function(bufnr, current) return current end
    }),
    require("quicktest.adapters.elixir")({
      ---@class ElixirAdapterOptions
      ---@field cwd (fun(bufnr: integer, current: string?): string)?
      ---@field bin (fun(bufnr: integer, current: string?): string)?
      ---@field args (fun(bufnr: integer, current: string[]): string[])?
      ---@field env (fun(bufnr: integer, current: table<string, string>): table<string, string>)?
      ---@field is_enabled (fun(bufnr: integer, type: RunType, current: boolean): boolean)?
    }),
    require("quicktest.adapters.criterion")({
      builddir = function(bufnr) return "build" end,
      additional_args = function(bufnr) return {'arg1', 'arg2'} end,
    }),
    require("quicktest.adapters.dart")({
      ---@class DartAdapterOptions
      ---@field cwd (fun(bufnr: integer, current: string?): string)?
      ---@field bin (fun(bufnr: integer, current: string?): string)?
      ---@field args (fun(bufnr: integer, current: string[]): string[])?
      ---@field env (fun(bufnr: integer, current: table<string, string>): table<string, string>)?
      ---@field is_enabled (fun(bufnr: integer, type: RunType, current: boolean): boolean)?
    }),
    require("quicktest.adapters.rspec")({
      ---@class RspecAdapterOptions
      ---@field bin (fun(bufnr: integer, fallback: string): string)?
      ---@field cwd (fun(bufnr: integer, fallback: string): string)?
      ---@field is_enabled (fun(bufnr: integer, fallback: boolean): boolean)?
    }),
  },
  -- split or popup mode, when argument not specified
  default_win_mode = "split",
})

-- Find nearest test under cursor and run in popup
qt.run_line('popup')
-- Find nearest test under cursor and run in split
qt.run_line('split')
-- Find near

Related Skills

View on GitHub
GitHub Stars104
CategoryDevelopment
Updated1mo ago
Forks9

Languages

C++

Security Score

100/100

Audited on Jan 27, 2026

No findings