test: add step count preservation tests for SchemaOrg → Cooklang conversion
Build and Deploy / build-and-deploy (push) Successful in 1m14s

Adds checkStepCount helper that verifies the number of instructions in
the parsed schema.org recipe matches the number of SecStep items in
the Method section of the resulting Cooklang Recipe. Tests both
fried-rice (4 steps) and carrot-risotto (7 steps).
This commit is contained in:
2026-05-20 15:57:14 -04:00
parent 6081534c10
commit c33a51d80b
+65 -31
View File
@@ -1,7 +1,7 @@
module Roux.SchemaOrgSpec (spec) where module Roux.SchemaOrgSpec (spec) where
import Data.Aeson (Value, decodeStrict) import Data.Aeson (Value, decodeStrict)
import Data.CookLang (Duration (..), Metadata (..), Recipe (..)) import Data.CookLang (Duration (..), Metadata (..), Recipe (..), Section (..), SectionBodyItem (..))
import Data.List.NonEmpty (toList) import Data.List.NonEmpty (toList)
import Data.Maybe (fromJust, isJust) import Data.Maybe (fromJust, isJust)
import Data.Text (Text) import Data.Text (Text)
@@ -66,34 +66,68 @@ spec = describe "SchemaOrg" $ do
it "human-readable -> Nothing" $ chk "20 minutes" Nothing it "human-readable -> Nothing" $ chk "20 minutes" Nothing
describe "schemaOrgToCooklang" $ do describe "schemaOrgToCooklang" $ do
it "converts fried-rice schema.org recipe to Cooklang" $ do let loadRecipeFile :: FilePath -> IO (Maybe SchemaOrgRecipe)
html <- readFile "test-data/fried-rice.html" loadRecipeFile path = do
let decoded = tryDecode (T.pack html) html <- readFile path
recipe = parseSchemaOrgRecipe (fromJust decoded) let decoded = tryDecode (T.pack html)
case recipe of pure (parseSchemaOrgRecipe =<< decoded)
Just r -> case schemaOrgToCooklang r of
Right cook -> do
metaTitle (recipeMetadata cook) `shouldBe` Just "Fried Rice"
metaSource (recipeMetadata cook) `shouldBe` Just "https://cooking.nytimes.com/recipes/12177-fried-rice"
metaCourse (recipeMetadata cook) `shouldBe` Just "one pot, side dish"
metaCuisine (recipeMetadata cook) `shouldBe` Just "asian"
metaTotalTime (recipeMetadata cook) `shouldBe` Just (Duration 20 (Just "minutes"))
metaTags (recipeMetadata cook) `shouldBe` ["egg", "rice", "vegetarian"]
metaDescription (recipeMetadata cook) `shouldSatisfy` isJust
let sections = toList (recipeSections cook)
length sections `shouldBe` 2
Left err -> fail err
Nothing -> fail "Failed to parse schema.org recipe"
it "converts carrot-risotto schema.org recipe to Cooklang" $ do let countMethodSteps :: Recipe -> Int
html <- readFile "test-data/carrot-risotto.html" countMethodSteps recipe =
let decoded = tryDecode (T.pack html) let sections = toList (recipeSections recipe)
recipe = parseSchemaOrgRecipe (fromJust decoded) in case filter (\s -> sectionName s == Just "Method") sections of
case recipe of [s] ->
Just r -> case schemaOrgToCooklang r of let bodyItems = toList (sectionBody s)
Right cook -> do in length [() | SecStep _ <- bodyItems]
metaTitle (recipeMetadata cook) `shouldBe` Just "Carrot Risotto With Chile Crisp" _ -> 0
metaAuthor (recipeMetadata cook) `shouldBe` Just "Alexa Weibel"
metaTags (recipeMetadata cook) `shouldSatisfy` (not . null) let checkStepCount :: FilePath -> String -> Int -> Spec
Left err -> fail err checkStepCount path label expectedSteps = it ("preserves " <> label <> " step count in Cooklang conversion") $ do
Nothing -> fail "Failed to parse schema.org recipe" mRecipe <- loadRecipeFile path
case mRecipe of
Nothing -> fail "Failed to parse schema.org recipe"
Just r -> do
let rawInstructions = soRecipeInstructions r
length rawInstructions `shouldBe` expectedSteps
case schemaOrgToCooklang r of
Left err -> fail err
Right cook -> do
let cookSteps = countMethodSteps cook
cookSteps `shouldBe` expectedSteps
let checkMetadata :: FilePath -> String -> (SchemaOrgRecipe -> IO ()) -> Spec
checkMetadata path label checks = it ("converts " <> label <> " schema.org recipe to Cooklang") $ do
mRecipe <- loadRecipeFile path
case mRecipe of
Nothing -> fail "Failed to parse schema.org recipe"
Just r -> do
checks r
case schemaOrgToCooklang r of
Left err -> fail err
Right _ -> pure ()
checkStepCount "test-data/fried-rice.html" "fried-rice" 4
checkStepCount "test-data/carrot-risotto.html" "carrot-risotto" 7
checkMetadata "test-data/fried-rice.html" "fried-rice" $ \r ->
case schemaOrgToCooklang r of
Left err -> fail err
Right cook -> do
metaTitle (recipeMetadata cook) `shouldBe` Just "Fried Rice"
metaSource (recipeMetadata cook) `shouldBe` Just "https://cooking.nytimes.com/recipes/12177-fried-rice"
metaCourse (recipeMetadata cook) `shouldBe` Just "one pot, side dish"
metaCuisine (recipeMetadata cook) `shouldBe` Just "asian"
metaTotalTime (recipeMetadata cook) `shouldBe` Just (Duration 20 (Just "minutes"))
metaTags (recipeMetadata cook) `shouldBe` ["egg", "rice", "vegetarian"]
metaDescription (recipeMetadata cook) `shouldSatisfy` isJust
let sections = toList (recipeSections cook)
length sections `shouldBe` 2
checkMetadata "test-data/carrot-risotto.html" "carrot-risotto" $ \r ->
case schemaOrgToCooklang r of
Left err -> fail err
Right cook -> do
metaTitle (recipeMetadata cook) `shouldBe` Just "Carrot Risotto With Chile Crisp"
metaAuthor (recipeMetadata cook) `shouldBe` Just "Alexa Weibel"
metaTags (recipeMetadata cook) `shouldSatisfy` (not . null)