From 072f6fec596869b6cc5f58e86ef1ffd4d40135c4 Mon Sep 17 00:00:00 2001 From: Marc Jakobi Date: Sun, 12 Mar 2023 02:03:29 +0100 Subject: [PATCH] feat: support for skipped tests - xdescribe xit xprop (#67) Fixes #64. --- CHANGELOG.md | 3 ++ lua/neotest-haskell/hspec.lua | 31 +++++------ .../subpackage1/test/Fix1/FixtureSpec.hs | 6 +++ .../subpackage2/test/Fix2/FixtureSpec.hs | 7 +++ .../subpackage1/test/Fix1/FixtureSpec.hs | 2 +- tests/fixtures/results/test_file_fail.txt | 3 +- tests/hspec_spec.lua | 52 ++++++++----------- 7 files changed, 54 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa257fe..a036505 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [0.5.0] - 2023-03-12 ### Added - Health checks (`:help checkhealth`). +- Hspec: Support for skipped tests (`xdescribe` `xit`, `xprop`). ## [0.4.0] - 2023-03-10 ### Added diff --git a/lua/neotest-haskell/hspec.lua b/lua/neotest-haskell/hspec.lua index 94bf5c9..b9ac731 100644 --- a/lua/neotest-haskell/hspec.lua +++ b/lua/neotest-haskell/hspec.lua @@ -8,13 +8,13 @@ local describe_query = [[ (_ (_ (exp_apply (exp_name (variable) @func_name) (exp_literal) @namespace.name - ) (#eq? @func_name "describe"))) @namespace.definition + ) (#any-of? @func_name "describe" "xdescribe"))) @namespace.definition ;; describe (qualified) (_ (_ (exp_apply (exp_name (qualified_variable (variable) @func_name)) (exp_literal) @namespace.name - ) (#eq? @func_name "describe"))) @namespace.definition + ) (#any-of? @func_name "describe" "xdescribe"))) @namespace.definition ]] ---Parse the positions in a test file. @@ -24,29 +24,17 @@ local describe_query = [[ function hspec.parse_positions(path) local tests_query = describe_query .. [[ - ;; it (unqualified) + ;; unqualified ((exp_apply (exp_name (variable) @func_name) (exp_literal) @test.name - ) (#eq? @func_name "it")) @test.definition + ) (#any-of? @func_name "it" "xit" "prop" "xprop")) @test.definition - ;; it (qualified) + ;; qualified ((exp_apply (exp_name (qualified_variable (variable) @func_name)) (exp_literal) @test.name - ) (#eq? @func_name "it")) @test.definition - - ;; prop (unqualified) - ((exp_apply - (exp_name (variable) @func_name) - (exp_literal) @test.name - ) (#eq? @func_name "prop")) @test.definition - - ;; prop (qualified) - ((exp_apply - (exp_name (qualified_variable (variable) @func_name)) - (exp_literal) @test.name - ) (#eq? @func_name "prop")) @test.definition + ) (#any-of? @func_name "it" "xit" "prop" "xprop")) @test.definition ]] return util.parse_positions(path, tests_query) end @@ -243,13 +231,17 @@ function hspec.parse_results(context, out_path, tree) local lines = vim.split(data, '\n') local failure_positions = {} local success_positions = {} + local skipped_positions = {} for _, line in ipairs(lines) do local failed = line:match('%s*(.*)%s.✘') local succeeded = line:match('%s*(.*)%s.✔') + local skipped = line:match('%s*(.*)%s%[‐%]') if failed then failure_positions[#failure_positions + 1] = failed elseif succeeded then success_positions[#success_positions + 1] = succeeded + elseif skipped then + skipped_positions[#skipped_positions + 1] = skipped end end @@ -261,6 +253,9 @@ function hspec.parse_results(context, out_path, tree) for _, test_name in ipairs(success_positions) do set_test_status(test_name, 'passed') end + for _, test_name in ipairs(skipped_positions) do + set_test_status(test_name, 'skipped') + end for _, test_name in ipairs(failure_positions) do local errors = get_hspec_errors(lines, test_name) set_test_status(test_name, 'failed', errors) diff --git a/tests/fixtures/hspec/cabal/multi-package/subpackage1/test/Fix1/FixtureSpec.hs b/tests/fixtures/hspec/cabal/multi-package/subpackage1/test/Fix1/FixtureSpec.hs index e269c74..7c47f2f 100644 --- a/tests/fixtures/hspec/cabal/multi-package/subpackage1/test/Fix1/FixtureSpec.hs +++ b/tests/fixtures/hspec/cabal/multi-package/subpackage1/test/Fix1/FixtureSpec.hs @@ -18,3 +18,9 @@ spec = describe "oneOf successful tests" $ do it "returns two of the thing" $ oneOf (3 :: Integer) `shouldBe` [3, 3] + xit "skipped it" pending + + xprop "skipped prop" pending + + xdescribe "skipped describe" $ + it "implicitly skipped it" pending diff --git a/tests/fixtures/hspec/cabal/multi-package/subpackage2/test/Fix2/FixtureSpec.hs b/tests/fixtures/hspec/cabal/multi-package/subpackage2/test/Fix2/FixtureSpec.hs index 3a0b41b..aaa50c5 100644 --- a/tests/fixtures/hspec/cabal/multi-package/subpackage2/test/Fix2/FixtureSpec.hs +++ b/tests/fixtures/hspec/cabal/multi-package/subpackage2/test/Fix2/FixtureSpec.hs @@ -15,3 +15,10 @@ spec = H.describe "twoOf successful tests" $ do H.describe "twoOf failing tests" $ H.it "returns one of the thing" $ twoOf (3 :: Integer) `H.shouldBe` [3] + + H.xit "skipped it" H.pending + + Q.xprop "skipped prop" H.pending + + H.xdescribe "skipped describe" $ + H.it "implicitly skipped it" H.pending diff --git a/tests/fixtures/hspec/stack/multi-package/subpackage1/test/Fix1/FixtureSpec.hs b/tests/fixtures/hspec/stack/multi-package/subpackage1/test/Fix1/FixtureSpec.hs index affdb31..a2e6805 100644 --- a/tests/fixtures/hspec/stack/multi-package/subpackage1/test/Fix1/FixtureSpec.hs +++ b/tests/fixtures/hspec/stack/multi-package/subpackage1/test/Fix1/FixtureSpec.hs @@ -12,7 +12,7 @@ spec = spec1 >> spec2 spec1 :: Spec spec1 = describe "Prelude.head" $ do - it "Returns the first element of a list" $ head [23 ..] `shouldBe` (23 :: Int) + xit "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` (5 :: Int) diff --git a/tests/fixtures/results/test_file_fail.txt b/tests/fixtures/results/test_file_fail.txt index ac04859..1ba916e 100644 --- a/tests/fixtures/results/test_file_fail.txt +++ b/tests/fixtures/results/test_file_fail.txt @@ -8,7 +8,8 @@ Running 1 test suites... Test suite subpackage1-spec: RUNNING... Prelude.head - Returns the first element of a list [✔] + Returns the first element of a list [‐] + # PENDING: No reason given Returns the first element of an arbitrary list [✘] Empty list Throws on empty list [✔] diff --git a/tests/hspec_spec.lua b/tests/hspec_spec.lua index 185b980..d3b1f0e 100644 --- a/tests/hspec_spec.lua +++ b/tests/hspec_spec.lua @@ -35,14 +35,11 @@ describe('hspec', function() assert_has_position(result, filename_pos_id) local ns_1_pos_id = filename_pos_id .. '::"section 1"' assert_has_position(result, ns_1_pos_id) - local test_1_1_pos_id = ns_1_pos_id .. '::"is a tautology"' - assert_has_position(result, test_1_1_pos_id) - local test_1_2_pos_id = ns_1_pos_id .. '::"assumes that 2 is 1"' - assert_has_position(result, test_1_2_pos_id) + assert_has_position(result, ns_1_pos_id .. '::"is a tautology"') + assert_has_position(result, ns_1_pos_id .. '::"assumes that 2 is 1"') local ns_2_pos_id = filename_pos_id .. '::"section 2"' assert_has_position(result, ns_2_pos_id) - local test_2_1_pos_id = ns_2_pos_id .. '::"only contains one test"' - assert_has_position(result, test_2_1_pos_id) + assert_has_position(result, ns_2_pos_id .. '::"only contains one test"') end) end) async.it('unqualified imports 1', function() @@ -53,14 +50,15 @@ describe('hspec', function() assert_has_position(result, filename_pos_id) local ns_1_pos_id = filename_pos_id .. '::"oneOf successful tests"' assert_has_position(result, ns_1_pos_id) - local test_1_1_pos_id = ns_1_pos_id .. '::"returns one of the thing"' - assert_has_position(result, test_1_1_pos_id) - local test_1_2_pos_id = ns_1_pos_id .. '::"always has length 1"' - assert_has_position(result, test_1_2_pos_id) + assert_has_position(result, ns_1_pos_id .. '::"returns one of the thing"') + assert_has_position(result, ns_1_pos_id .. '::"always has length 1"') local ns_2_pos_id = ns_1_pos_id .. '::"oneOf failing tests"' assert_has_position(result, ns_2_pos_id) - local test_2_1_pos_id = ns_2_pos_id .. '::"returns two of the thing"' - assert_has_position(result, test_2_1_pos_id) + assert_has_position(result, ns_2_pos_id .. '::"returns two of the thing"') + assert_has_position(result, ns_1_pos_id .. '::"skipped it"') + assert_has_position(result, ns_1_pos_id .. '::"skipped prop"') + local ns_3_pos_id = ns_1_pos_id .. '::"skipped describe"' + assert_has_position(result, ns_3_pos_id .. '::"implicitly skipped it"') end) async.it('unqualified imports 2', function() local test_file = Path:new(test_cwd .. '/fixtures/hspec/stack/multi-package/subpackage1/test/Fix1/FixtureSpec.hs') @@ -70,20 +68,16 @@ describe('hspec', function() assert_has_position(result, filename_pos_id) local ns_1_pos_id = filename_pos_id .. '::"Prelude.head"' assert_has_position(result, ns_1_pos_id) - local test_1_1_pos_id = ns_1_pos_id .. '::"Returns the first element of a list"' - assert_has_position(result, test_1_1_pos_id) - local test_1_2_pos_id = ns_1_pos_id .. '::"Returns the first element of an arbitrary list"' - assert_has_position(result, test_1_2_pos_id) + assert_has_position(result, ns_1_pos_id .. '::"Returns the first element of a list"') + assert_has_position(result, ns_1_pos_id .. '::"Returns the first element of an arbitrary list"') local ns_2_pos_id = ns_1_pos_id .. '::"Empty list"' assert_has_position(result, ns_2_pos_id) - local test_2_1_pos_id = ns_2_pos_id .. '::"Throws on empty list"' - assert_has_position(result, test_2_1_pos_id) + assert_has_position(result, ns_2_pos_id .. '::"Throws on empty list"') local ns_3_pos_id = filename_pos_id .. '::"Prelude.tail"' assert_has_position(result, ns_3_pos_id) local ns_4_pos_id = ns_3_pos_id .. '::"Single element list"' assert_has_position(result, ns_4_pos_id) - local test_4_1_pos_id = ns_4_pos_id .. '::"Returns the empty list"' - assert_has_position(result, test_4_1_pos_id) + assert_has_position(result, ns_4_pos_id .. '::"Returns the empty list"') end) async.it('qualified imports', function() local test_file = Path:new(test_cwd .. '/fixtures/hspec/cabal/multi-package/subpackage2/test/Fix2/FixtureSpec.hs') @@ -93,14 +87,15 @@ describe('hspec', function() assert_has_position(result, filename_pos_id) local ns_1_pos_id = filename_pos_id .. '::"twoOf successful tests"' assert_has_position(result, ns_1_pos_id) - local test_1_1_pos_id = ns_1_pos_id .. '::"returns two of the thing"' - assert_has_position(result, test_1_1_pos_id) - local test_1_2_pos_id = ns_1_pos_id .. '::"always has length 2"' - assert_has_position(result, test_1_2_pos_id) + assert_has_position(result, ns_1_pos_id .. '::"returns two of the thing"') + assert_has_position(result, ns_1_pos_id .. '::"always has length 2"') local ns_2_pos_id = ns_1_pos_id .. '::"twoOf failing tests"' assert_has_position(result, ns_2_pos_id) - local test_2_1_pos_id = ns_2_pos_id .. '::"returns one of the thing"' - assert_has_position(result, test_2_1_pos_id) + assert_has_position(result, ns_2_pos_id .. '::"returns one of the thing"') + assert_has_position(result, ns_1_pos_id .. '::"skipped it"') + assert_has_position(result, ns_1_pos_id .. '::"skipped prop"') + local ns_3_pos_id = ns_1_pos_id .. '::"skipped describe"' + assert_has_position(result, ns_3_pos_id .. '::"implicitly skipped it"') end) describe('parse results', function() @@ -135,10 +130,7 @@ describe('hspec', function() status = 'passed', }, results[filename .. '::"Prelude.head"::"Empty list"::"Throws on empty list"']) assert.same({ - status = 'passed', - }, results[filename .. '::"Prelude.head"::"Returns the first element of a list"']) - assert.same({ - status = 'passed', + status = 'skipped', }, results[filename .. '::"Prelude.head"::"Returns the first element of a list"']) assert.same(failure, results[filename .. '::"Prelude.head"::"Returns the first element of an arbitrary list"']) assert.same({