Files
roux/test/Roux/NYTimesSpec.hs
T
2026-05-19 20:21:43 -04:00

106 lines
5.3 KiB
Haskell

module Roux.NYTimesSpec (spec) where
import qualified Data.Text.IO as TIO
import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)
import Data.CookLang
import Roux.NYTimes
spec :: Spec
spec = do
describe "extractNextData" $ do
it "extracts JSON from fried-rice.html" $ do
html <- TIO.readFile "test-data/fried-rice.html"
let result = extractNextData html
result `shouldSatisfy` isJust
it "extracts JSON from carrot-risotto.html" $ do
html <- TIO.readFile "test-data/carrot-risotto.html"
let result = extractNextData html
result `shouldSatisfy` isJust
describe "parseNYTRecipe" $ do
it "parses fried-rice.html recipe correctly" $ do
html <- TIO.readFile "test-data/fried-rice.html"
let result = do
val <- extractNextData html
parseNYTRecipe val
case result of
Nothing -> error "failed to parse fried-rice recipe"
Just recipe -> do
nytTitle recipe `shouldBe` "Fried Rice"
nytUrl recipe `shouldBe` Just "https://cooking.nytimes.com/recipes/12177-fried-rice"
nytTotalTime recipe `shouldBe` Just "20 minutes"
nytRecipeYield recipe `shouldBe` Just "4 to 6 servings"
nytTopnote recipe `shouldSatisfy` isJust
length (nytIngredientGroups recipe) `shouldBe` 1
case nytIngredientGroups recipe of
[group] -> do
length (nytIngredients group) `shouldBe` 14
case nytIngredients group of
(firstIng : _) -> do
nytIngredientText firstIng `shouldBe` "tablespoons neutral oil, like canola or grapeseed"
nytIngredientQuantity firstIng `shouldBe` "3"
[] -> error "empty ingredient group"
_ -> error "expected 1 ingredient group"
case nytStepGroups recipe of
[stepGroup] -> do
length (nytSteps stepGroup) `shouldBe` 4
case nytSteps stepGroup of
(firstStep : _) -> nytStepNumber firstStep `shouldBe` 1
[] -> error "empty step group"
_ -> error "expected 1 step group"
it "parses carrot-risotto.html recipe correctly" $ do
html <- TIO.readFile "test-data/carrot-risotto.html"
let result = do
val <- extractNextData html
parseNYTRecipe val
case result of
Nothing -> error "failed to parse carrot-risotto recipe"
Just recipe -> do
nytTitle recipe `shouldBe` "Carrot Risotto With Chile Crisp"
nytUrl recipe `shouldBe` Just "https://cooking.nytimes.com/recipes/1024086-carrot-risotto-with-chile-crisp"
nytTotalTime recipe `shouldBe` Just "30 minutes"
nytRecipeYield recipe `shouldBe` Just "4 servings"
length (nytIngredientGroups recipe) `shouldBe` 1
case nytIngredientGroups recipe of
[group] -> length (nytIngredients group) `shouldBe` 11
_ -> error "expected 1 ingredient group"
case nytStepGroups recipe of
[stepGroup] -> length (nytSteps stepGroup) `shouldBe` 7
_ -> error "expected 1 step group"
describe "nytToCooklang" $ do
it "converts fried-rice NYTRecipe to Cooklang Recipe" $ do
html <- TIO.readFile "test-data/fried-rice.html"
let result = do
val <- extractNextData html
nyt <- parseNYTRecipe val
pure (nytToCooklang nyt)
case result of
Nothing -> error "failed to parse/convert fried-rice"
Just recipe -> do
metaTitle (recipeMetadata recipe) `shouldBe` Just "Fried Rice"
metaSource (recipeMetadata recipe) `shouldBe` Just "https://cooking.nytimes.com/recipes/12177-fried-rice"
metaTotalTime (recipeMetadata recipe) `shouldBe` Just (Duration 20 (Just "minutes"))
length (recipeSections recipe) `shouldSatisfy` (> 0)
it "converts carrot-risotto NYTRecipe to Cooklang Recipe" $ do
html <- TIO.readFile "test-data/carrot-risotto.html"
let result = do
val <- extractNextData html
nyt <- parseNYTRecipe val
pure (nytToCooklang nyt)
case result of
Nothing -> error "failed to parse/convert carrot-risotto"
Just recipe -> do
metaTitle (recipeMetadata recipe) `shouldBe` Just "Carrot Risotto With Chile Crisp"
metaTotalTime (recipeMetadata recipe) `shouldBe` Just (Duration 30 (Just "minutes"))
length (recipeSections recipe) `shouldSatisfy` (> 0)
-- | Check if a Maybe value is Just.
isJust :: Maybe a -> Bool
isJust (Just _) = True
isJust Nothing = False