Skip to content

mrcjkb/neotest-haskell

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation


neotest-haskell

Report Bug

A neotest adapter for Haskell.

πŸ¦₯

Neovim Lua Haskell Nix

GPL2 License Issues Build Status LuaRocks

All Contributors

Quick links

Features

  • Supports Cabal (single/multi-package) projects.
  • Supports Stack (single/multi-package) projects.
  • Parses Hspec and Sydtest --match filters for the cursor's position using tree-sitter.
  • Parses Tasty --pattern filters for the cursor's position using tree-sitter.
  • Parses test results and displays error messages as diagnostics.
neotest.mp4

Requirements

Installation

rocks.nvim

:Rocks install neotest-haskell

rocks.nvim will install all dependencies if not already installed (including tree-sitter-haskell).

Other plugin managers

See also: neotest installation instructions.

  • Requires the tree-sitter parser for haskell to be installed.

The following example uses lazy.nvim:

{
  'nvim-neotest/neotest',
  dependencies = {
    -- ...,
    'mrcjkb/neotest-haskell',
    'nvim-lua/plenary.nvim',
  }
}

Configuration

Make sure the Haskell parser for tree-sitter is installed, you can do so via nvim-treesitter like so:

require('nvim-treesitter.configs').setup {
  ensure_installed = {
    'haskell',
    --...,
  },
}

Add neotest-haskell to your neotest adapters:

require('neotest').setup {
  -- ...,
  adapters = {
    -- ...,
    require('neotest-haskell')
  },
}

You can also pass a config to the setup. The following are the defaults:

require('neotest').setup {
  adapters = {
    require('neotest-haskell') {
      -- Default: Use stack if possible and then try cabal
      build_tools = { 'stack', 'cabal' },
      -- Default: Check for tasty first and then try hspec
      frameworks = { 'tasty', 'hspec', 'sydtest' },
    },
  },
}

Note

If you were to use build_tools = { 'cabal', 'stack' }, then cabal will almost always be chosen, because almost all stack projects can be built with cabal.

Alternately, you can pair each test framework with a list of modules, used to identify the respective framework in a test file:

require('neotest').setup {
  adapters = {
    require('neotest-haskell') {
      frameworks = {
        { framework = 'tasty', modules = { 'Test.Tasty', 'MyTestModule' }, },
        'hspec',
        'sydtest',
      },
    },
  },
}

This can be useful if you have test files that do not import one of the default modules used for framework identification:

  • tasty: modules = { 'Test.Tasty' }
  • hspec: modules = { 'Test.Hspec' }
  • sydtest: modules = { 'Test.Syd' }

Advanced configuration

This plugin uses tree-sitter queries in files that match <runtimepath>/queries/haskell/<framework>-positions.scm

For example, to add position queries for this plugin for tasty, without having to fork this plugin, you can add them to $XDG_CONFIG_HOME/nvim/after/queries/haskell/tasty-positions.scm.

Note

Examples

module FixtureSpec ( spec ) where
import Test.Hspec
import Test.Hspec.QuickCheck
import Control.Exception ( evaluate )

spec :: Spec
spec = describe "Prelude.head" $ do
  it "returns the first element of a list" $ head [23 ..] `shouldBe` (23 :: Int)

  prop "returns the first element of an *arbitrary* list" $ \x xs ->
    head (x : xs) `shouldBe` (x :: Int)

  describe "Empty list" $
    it "throws an exception if used with an empty list"
      $             evaluate (head [])
      `shouldThrow` anyException

In the above listing, calling :lua require('neotest').run.run() with the cursor on the line...

  describe "Empty list" $

...will run the tests with the following Cabal command:

# Assuming a Cabal package called "my_package"
cabal test my_package --test-option -m --test-option "/Prelude.head/Empty list/"

...or with the following Stack command:

# Assuming a Stack package called "my_package"
stack test my_package --ta "--match \"/Prelude.head/Empty list/\""

...which will run the "throws an exception if used with an empty list" test.

Calling :lua require('neotest').run.run() with the cursor on the line...

spec = describe "Prelude.head" $ do

...will run the tests with the following Cabal command:

# Assuming a Cabal package called "my_package"
cabal test my_package --test-option -m --test-option "/Prelude.head/"

...or with the following Stack command:

# Assuming a Stack package called "my_package"
stack test my_package --ta "--match \"/Prelude.head/\""

...which will run all tests in the module.

TODO

See issues.

Troubleshooting

To run a health check, run :checkhealth neotest-haskell in Neovim.

Limitations

  • To run sydtest tests of type 'file', sydtest >= 0.13.0.4 is required, if the file has more than one top-level namespace (describe, context, ..).

Recommendations

Here are some other plugins I recommend for Haskell development:

Contributors ✨

Thanks goes to these wonderful people (emoji key):

Perigord
Perigord

πŸ’»
Sebastian Witte
Sebastian Witte

πŸ’» πŸš‡ πŸ“–
Andy Bell
Andy Bell

πŸ’»
Tom Sydney Kerckhove
Tom Sydney Kerckhove

πŸ§‘β€πŸ«
Nadeem Bitar
Nadeem Bitar

πŸ›
Mango The Fourth
Mango The Fourth

πŸ›
HΓ©cate Moonlight
HΓ©cate Moonlight

πŸ›
Amaan Qureshi
Amaan Qureshi

πŸ’»
Brad Sherman
Brad Sherman

πŸ’»

This project follows the all-contributors specification. Contributions of any kind welcome!

About

Neotest adapter for Haskell (cabal or stack) with support for Sydtest, Hspec and Tasty

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 8