hspec-junit-formatter 1.0.2.1 → 1.0.2.2
raw patch · 7 files changed
+122/−17 lines, 7 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Test.HSpec.JUnit.Schema: [testCaseLocation] :: TestCase -> Maybe Location
+ Test.Hspec.JUnit.Schema: Location :: FilePath -> Natural -> Location
+ Test.Hspec.JUnit.Schema: [locationFile] :: Location -> FilePath
+ Test.Hspec.JUnit.Schema: [locationLine] :: Location -> Natural
+ Test.Hspec.JUnit.Schema: [testCaseLocation] :: TestCase -> Maybe Location
+ Test.Hspec.JUnit.Schema: data Location
+ Test.Hspec.JUnit.Schema: instance GHC.Show.Show Test.Hspec.JUnit.Schema.Location
- Test.HSpec.JUnit.Schema: TestCase :: Text -> Text -> Double -> Maybe Result -> TestCase
+ Test.HSpec.JUnit.Schema: TestCase :: Maybe Location -> Text -> Text -> Double -> Maybe Result -> TestCase
- Test.Hspec.JUnit.Schema: TestCase :: Text -> Text -> Double -> Maybe Result -> TestCase
+ Test.Hspec.JUnit.Schema: TestCase :: Maybe Location -> Text -> Text -> Double -> Maybe Result -> TestCase
Files
- CHANGELOG.md +5/−1
- hspec-junit-formatter.cabal +1/−1
- library/Test/Hspec/JUnit.hs +16/−1
- library/Test/Hspec/JUnit/Render.hs +13/−9
- library/Test/Hspec/JUnit/Schema.hs +10/−1
- tests/Main.hs +19/−1
- tests/golden.xml +58/−3
CHANGELOG.md view
@@ -1,6 +1,10 @@-## [_Unreleased_](https://github.com/freckle/hspec-junit-formatter/compare/v1.0.2.1...main)+## [_Unreleased_](https://github.com/freckle/hspec-junit-formatter/compare/v1.0.2.2...main) None++## [v1.0.2.2](https://github.com/freckle/hspec-junit-formatter/compare/v1.0.2.1...v1.0.2.2)++- Add `file` and `line` attributes in `testcase` nodes ## [v1.0.2.1](https://github.com/freckle/hspec-junit-formatter/compare/v1.0.2.0...v1.0.2.1)
hspec-junit-formatter.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.12 name: hspec-junit-formatter-version: 1.0.2.1+version: 1.0.2.2 license: MIT license-file: LICENSE copyright: 2021 Renaissance Learning Inc
library/Test/Hspec/JUnit.hs view
@@ -8,6 +8,7 @@ import Prelude +import Control.Applicative ((<|>)) import Data.Conduit (runConduitRes, (.|)) import Data.Conduit.Combinators (sinkFile) import Data.Conduit.List (sourceList)@@ -79,7 +80,9 @@ itemToTestCase :: (FilePath -> FilePath) -> Text -> Text -> Item -> Schema.TestCase itemToTestCase applyPrefix group name item = Schema.TestCase- { testCaseClassName = group+ { testCaseLocation =+ toSchemaLocation <$> (itemResultLocation item <|> itemLocation item)+ , testCaseClassName = group , testCaseName = name , testCaseDuration = unSeconds $ itemDuration item , testCaseResult = case itemResult item of@@ -123,6 +126,18 @@ prefixInfo str | T.null $ T.strip $ pack $ itemInfo item = str | otherwise = pack (itemInfo item) <> "\n\n" <> str++itemResultLocation :: Item -> Maybe Location+itemResultLocation item = case itemResult item of+ Success -> Nothing+ Pending mLocation _ -> mLocation+ Failure mLocation _ -> mLocation++toSchemaLocation :: Location -> Schema.Location+toSchemaLocation Location {..} = Schema.Location+ { Schema.locationFile = locationFile+ , Schema.locationLine = fromIntegral $ max 0 locationLine+ } unSeconds :: Seconds -> Double unSeconds (Seconds x) = x
library/Test/Hspec/JUnit/Render.hs view
@@ -11,7 +11,8 @@ import Data.Text (Text, pack) import Data.Time.Format.ISO8601 (iso8601Show) import Data.XML.Types (Event)-import Test.Hspec.JUnit.Schema (Result(..), Suite(..), Suites(..), TestCase(..))+import Test.Hspec.JUnit.Schema+ (Location(..), Result(..), Suite(..), Suites(..), TestCase(..)) import Text.Printf import Text.XML.Stream.Render (attr, content, tag) @@ -55,15 +56,18 @@ tshow = pack . show testCase :: MonadThrow m => ConduitT TestCase Event m ()-testCase = awaitForever $ \(TestCase className name duration mResult) ->- tag "testcase" (attributes className name duration)- $ traverse_ yield mResult- .| result+testCase =+ awaitForever $ \(TestCase mLocation className name duration mResult) ->+ tag "testcase" (attributes mLocation className name duration)+ $ traverse_ yield mResult+ .| result where- attributes className name duration =- attr "name" name <> attr "classname" className <> attr- "time"- (roundToStr duration)+ attributes mLocation className name duration =+ maybe mempty (attr "file" . pack . locationFile) mLocation+ <> maybe mempty (attr "line" . pack . show . locationLine) mLocation+ <> attr "name" name+ <> attr "classname" className+ <> attr "time" (roundToStr duration) result :: MonadThrow m => ConduitT Result Event m () result = awaitForever go
library/Test/Hspec/JUnit/Schema.hs view
@@ -2,6 +2,7 @@ ( Suites(..) , Suite(..) , TestCase(..)+ , Location(..) , Result(..) ) where @@ -9,6 +10,7 @@ import Data.Text (Text) import Data.Time (UTCTime)+import Numeric.Natural data Suites = Suites { suitesName :: Text@@ -24,10 +26,17 @@ deriving stock Show data TestCase = TestCase- { testCaseClassName :: Text+ { testCaseLocation :: Maybe Location+ , testCaseClassName :: Text , testCaseName :: Text , testCaseDuration :: Double , testCaseResult :: Maybe Result+ }+ deriving stock Show++data Location = Location+ { locationFile :: FilePath+ , locationLine :: Natural } deriving stock Show
tests/Main.hs view
@@ -6,6 +6,7 @@ import Prelude import Control.Monad (void)+import Data.Char (isSpace) import qualified Data.Map.Strict as Map import Data.Text (Text) import qualified Data.Text as T@@ -23,7 +24,7 @@ it "matches golden file" $ do withJUnitReport ExampleSpec.spec $ \doc -> do golden <- XML.readFile XML.def "tests/golden.xml"- removeTimeAttributes doc `shouldBe` removeTimeAttributes golden+ normalizeDoc doc `shouldBe` normalizeDoc golden it "can prefix source paths" $ do let modify = setJUnitConfigSourcePathPrefix "lol/monorepo"@@ -52,6 +53,23 @@ hspecConfig = configWithJUnit junitConfig defaultConfig void $ runSpec spec hspecConfig f =<< XML.readFile XML.def path++normalizeDoc :: XML.Document -> XML.Document+normalizeDoc = removeWhitespaceNodes . removeTimeAttributes++removeWhitespaceNodes :: XML.Document -> XML.Document+removeWhitespaceNodes doc = doc+ { XML.documentRoot = go $ XML.documentRoot doc+ }+ where+ go el =+ el { XML.elementNodes = concatMap filterWhitespace $ XML.elementNodes el }++ filterWhitespace :: XML.Node -> [XML.Node]+ filterWhitespace = \case+ XML.NodeElement el -> [XML.NodeElement $ go el]+ XML.NodeContent c | T.all isSpace c -> []+ n -> [n] -- | Remove volatile attributes so they don't invalidate comparison removeTimeAttributes :: XML.Document -> XML.Document
tests/golden.xml view
@@ -1,6 +1,61 @@-<testsuites name="hspec-junit-format"><testsuite name="Some section" package="Some section" id="0" time="0.000032355" timestamp="2021-05-17T15:36:10.205608409Z" hostname="localhost" tests="2" failures="1" errors="0" skipped="0"><properties/><testcase name="has a failure" classname="Some section" time="0.000015537"><failure type="error">tests/ExampleSpec.hs:18:7+<testsuites name="hspec-junit-format">+ <testsuite+ name="Some section"+ package="Some section"+ id="0"+ hostname="localhost"+ time="0.000032355"+ timestamp="2021-05-17T15:36:10.205608409Z"+ tests="2" failures="1" errors="0" skipped="0">+ <properties/>+ <testcase+ file="tests/ExampleSpec.hs"+ line="18"+ name="has a failure"+ classname="Some section"+ time="0.000015537">+ <failure type="error">tests/ExampleSpec.hs:18:7 expected: "False" but got: "True"-</failure></testcase><testcase name="has an expectation" classname="Some section" time="0.000016818"/></testsuite><testsuite name="Some section/A grouped context" package="Some section/A grouped context" id="1" time="0.000021009" timestamp="2021-05-17T15:36:10.205608409Z" hostname="localhost" tests="3" failures="0" errors="0" skipped="1"><properties/><testcase name="gets skipped" classname="Some section/A grouped context" time="0.000006765"><skipped>tests/ExampleSpec.hs:26:9-some reason</skipped></testcase><testcase name="also happens in a group" classname="Some section/A grouped context" time="0.000007421"/><testcase name="happens in a group" classname="Some section/A grouped context" time="0.000006823"/></testsuite></testsuites>+</failure>+ </testcase>+ <testcase+ file="tests/ExampleSpec.hs"+ line="15"+ name="has an expectation"+ classname="Some section"+ time="0.000016818"/>+ </testsuite>+ <testsuite+ name="Some section/A grouped context"+ package="Some section/A grouped context"+ id="1"+ time="0.000021009"+ timestamp="2021-05-17T15:36:10.205608409Z"+ hostname="localhost"+ tests="3" failures="0" errors="0" skipped="1">+ <properties/>+ <testcase+ file="tests/ExampleSpec.hs"+ line="26"+ name="gets skipped"+ classname="Some section/A grouped context"+ time="0.000006765">+ <skipped>tests/ExampleSpec.hs:26:9+some reason</skipped>+ </testcase>+ <testcase+ file="tests/ExampleSpec.hs"+ line="23"+ name="also happens in a group"+ classname="Some section/A grouped context"+ time="0.000007421"/>+ <testcase+ file="tests/ExampleSpec.hs"+ line="21"+ name="happens in a group"+ classname="Some section/A grouped context"+ time="0.000006823"/>+ </testsuite>+</testsuites>