1
1
mirror of https://github.com/aelve/guide.git synced 2024-12-23 12:52:31 +03:00

[tests] General improvements

This commit is contained in:
Artyom 2016-09-01 01:25:46 +03:00
parent 14d61485a0
commit 002736831d

View File

@ -24,7 +24,8 @@ import qualified Data.Text.All as T
-- Files
import System.Directory
-- Testing
import Test.Hspec.WebDriver
import Test.Hspec.WebDriver hiding (shouldHaveAttr, shouldHaveText, click)
import qualified Test.Hspec.WebDriver as WD
import Test.WebDriver.Commands.Wait
import Test.WebDriver.Exceptions
import qualified Test.Hspec.Expectations as Hspec
@ -56,14 +57,14 @@ mainPageTests = session "main page" $ using Firefox $ do
checkPresent "#categories"
checkNotPresent "#categories > *"
wd "has a google-token" $ do
e <- select "meta[name=google-site-verification]"
e `shouldHaveAttr` ("content", "some-google-token")
"meta[name=google-site-verification]" `shouldHaveAttr`
("content", "some-google-token")
wd "has a title" $ do
e <- select "h1"; e `shouldHaveText` "Aelve Guide: Haskell"
"h1" `shouldHaveText` "Aelve Guide: Haskell"
describe "subtitle" $ do
wd "is present" $ do
e <- select ".subtitle"
fs <- fontSize e; fs `shouldBeInRange` (15,17)
sub <- select ".subtitle"
fs <- fontSize sub; fs `shouldBeInRange` (15,17)
wd "has a discuss link" $ do
checkPresent ".subtitle a[href='http://discuss.link']"
describe "footer" $ do
@ -71,15 +72,15 @@ mainPageTests = session "main page" $ using Firefox $ do
checkPresent "#footer"
wd "isn't overflowing" $ do
setWindowSize (900, 500) -- the footer is about 800px wide
e <- select "#footer"
(width, height) <- elemSize e
footer <- select "#footer"
(width, height) <- elemSize footer
width `shouldBeInRange` (750, 850)
height `shouldBeInRange` (60, 70)
-- and now it shall be overflowing
setWindowSize (700, 500)
waitUntil 2 (expect . inRange (90, 140) . snd =<< elemSize e)
waitUntil 2 (expect . inRange (90, 140) . snd =<< elemSize footer)
`catch` \(_::ExpectFailed) -> return ()
height2 <- snd <$> elemSize e
height2 <- snd <$> elemSize footer
height2 `shouldBeInRange` (90, 140)
categoryTests :: Spec
@ -93,9 +94,10 @@ categoryTests = session "categories" $ using Firefox $ do
slug `shouldBe` "some-category"
describe "created category" $ do
wd "has a link to the main page" $ do
e <- select "h1 > a"; e `shouldHaveText` "Aelve Guide: Haskell"
titleLink <- select "h1 > a"
titleLink `shouldHaveText` "Aelve Guide: Haskell"
getBackAfterwards $ do
changesURL $ click e
changesURL $ click titleLink
url <- getCurrentRelativeURL
uriPath url `shouldBe` "/haskell"
wd "has a subtitle" $ do
@ -105,8 +107,7 @@ categoryTests = session "categories" $ using Firefox $ do
wd "is present on the main page" $ do
catURL <- getCurrentURL
openGuidePage "/"
e <- select (ByLinkText "Some category")
changesURL $ click e
changesURL $ click (ByLinkText "Some category")
do u <- getCurrentURL
u `shouldBe` catURL
wd "is initially empty" $ do
@ -122,8 +123,8 @@ categoryTests = session "categories" $ using Firefox $ do
do inp <- select (form :// "input[name=title]")
clearInput inp
sendKeys ("Cat 1" <> _enter) inp
waitWhile 2 (expectNotStale inp)
e <- select categoryTitle; e `shouldHaveText` "Cat 1"
checkNotPresent (form :& Displayed)
categoryTitle `shouldHaveText` "Cat 1"
wd "changes page slug when changed" $ do
changesURL $ refresh
do (slug, _) <- parseCategoryURL . uriPath =<< getCurrentRelativeURL
@ -132,7 +133,7 @@ categoryTests = session "categories" $ using Firefox $ do
do inp <- select (form :// "input[name=title]")
clearInput inp
sendKeys ("Cat 2" <> _enter) inp
waitWhile 2 (expectNotStale inp)
checkNotPresent (form :& Displayed)
changesURL $ refresh
do (slug, _) <- parseCategoryURL . uriPath =<< getCurrentRelativeURL
slug `shouldBe` "cat-2"
@ -141,22 +142,21 @@ categoryTests = session "categories" $ using Firefox $ do
openGuidePage "/"
checkNotPresent (ByLinkText "Some category")
checkNotPresent (ByLinkText "Cat 1")
e <- select (ByLinkText "Cat 2")
changesURL $ click e
changesURL $ click (ByLinkText "Cat 2")
(slug2, id2) <- parseCategoryURL . uriPath =<< getCurrentRelativeURL
id1 `shouldBe` id2; slug2 `shouldBe` "cat-2"
describe "group" $ do
wd "is present" $ do
e <- select categoryGroup; e `shouldHaveText` "Miscellaneous"
fs <- fontSize e; fs `shouldBeInRange` (12, 15)
group_ <- select categoryGroup
group_ `shouldHaveText` "Miscellaneous"
fs <- fontSize group_; fs `shouldBeInRange` (12, 15)
wd "can be changed" $ do
form <- openCategoryEditForm
do inp <- select (form :// "input[name=group]")
clearInput inp
sendKeys ("Basics" <> _enter) inp
waitWhile 2 (expectNotStale inp)
e <- select categoryGroup
e `shouldHaveText` "Basics"
checkNotPresent (form :& Displayed)
categoryGroup `shouldHaveText` "Basics"
wd "is changed on the front page too" $ do
onAnotherPage "/" $ do
catLink <- select (ByLinkText "Cat 2")
@ -165,84 +165,80 @@ categoryTests = session "categories" $ using Firefox $ do
describe "status" $ do
wd "is “stub” by default" $ do
form <- openCategoryEditForm
chosen <- select (form :// "select[name=status] option:checked")
chosen `shouldHaveText` "Stub"
chosenOption <- select (form :// "select[name=status] option:checked")
chosenOption `shouldHaveText` "Stub"
onAnotherPage "/" $ do
catLink <- select (ByLinkText "Cat 2")
catLink `shouldHaveAttr` ("class", "status-stub")
ByLinkText "Cat 2" `shouldHaveAttr` ("class", "status-stub")
wd "can be changed" $ do
form <- openCategoryEditForm
sel <- select (form :// "select[name=status]")
opt <- select (sel :// HasText "Complete")
selectDropdown sel opt
click =<< select (form :// ".save")
click (form :// ".save")
onAnotherPage "/" $ do
catLink <- select (ByLinkText "Cat 2")
catLink `shouldHaveAttr` ("class", "status-finished")
ByLinkText "Cat 2" `shouldHaveAttr` ("class", "status-finished")
wd "create two items for further tests" $ do
createItem "some item"
createItem "another item"
describe "pros/cons enabled" $ do
wd "checkbox enabled by default" $ do
form <- openCategoryEditForm
check <- select (form :// "[name=pros-cons-enabled]")
shouldBeSelected check
click =<< select (form :// ".cancel")
checkbox <- select (form :// "[name=pros-cons-enabled]")
shouldBeSelected checkbox
click (form :// ".cancel")
wd "section is shown in an item" $ do
mapM_ shouldBeDisplayed =<< selectAll ".item-traits"
wd "section isn't shown after unchecking the checkbox" $ do
form <- openCategoryEditForm
click =<< select (form :// "[name=pros-cons-enabled]")
click =<< select (form :// ".save")
click (form :// "[name=pros-cons-enabled]")
click (form :// ".save")
waitUntil 2 $
expect . not =<< anyM isDisplayed =<< selectAll ".item-traits"
wd "section is shown again after checking the checkbox" $ do
form <- openCategoryEditForm
click =<< select (form :// "[name=pros-cons-enabled]")
click =<< select (form :// ".save")
click (form :// "[name=pros-cons-enabled]")
click (form :// ".save")
waitUntil 2 $
expect =<< allM isDisplayed =<< selectAll ".item-traits"
describe "ecosystem enabled" $ do
wd "checkbox enabled by default" $ do
form <- openCategoryEditForm
check <- select (form :// "[name=ecosystem-enabled]")
shouldBeSelected check
click =<< select (form :// ".cancel")
checkbox <- select (form :// "[name=ecosystem-enabled]")
shouldBeSelected checkbox
click (form :// ".cancel")
wd "section is shown in an item" $ do
mapM_ shouldBeDisplayed =<< selectAll ".item-ecosystem"
wd "section isn't shown after unchecking the checkbox" $ do
form <- openCategoryEditForm
click =<< select (form :// "[name=ecosystem-enabled]")
click =<< select (form :// ".save")
click (form :// "[name=ecosystem-enabled]")
click (form :// ".save")
waitUntil 2 $
expect . not =<< anyM isDisplayed =<< selectAll ".item-ecosystem"
wd "section is shown again after checking the checkbox" $ do
form <- openCategoryEditForm
click =<< select (form :// "[name=ecosystem-enabled]")
click =<< select (form :// ".save")
click (form :// "[name=ecosystem-enabled]")
click (form :// ".save")
waitUntil 2 $
expect =<< allM isDisplayed =<< selectAll ".item-ecosystem"
describe "deleting a category" $ do
wd "dismissing the alert doesn't do anything" $ do
click =<< select (".category h2" :// ByLinkText "delete")
click (".category h2" :// ByLinkText "delete")
dismissAlert
catURL <- getCurrentURL
openGuidePage "/"
e <- select (ByLinkText "Cat 2")
changesURL $ click e
changesURL $ click (ByLinkText "Cat 2")
do u <- getCurrentURL
u `shouldBe` catURL
wd "accepting the alert deletes the category" $ do
catURL <- getCurrentURL
changesURL $ do
click =<< select (".category h2" :// ByLinkText "delete")
click (".category h2" :// ByLinkText "delete")
acceptAlert
url <- getCurrentRelativeURL
uriPath url `shouldBe` "/haskell"
checkNotPresent (ByLinkText "Cat 2")
openPage catURL
body <- select "body"
body `shouldHaveText` "Something went wrong"
"body" `shouldHaveText` "Something went wrong"
-- Feed button works
-- Description editing works
@ -252,14 +248,14 @@ markdownTests = session "markdown" $ using Firefox $ do
describe "Markdown isn't allowed in category names" $ do
wd "when creating a category" $ do
createCategory "*foo*"
e <- select categoryTitle; e `shouldHaveText` "*foo*"
categoryTitle `shouldHaveText` "*foo*"
wd "when changing existing category's name" $ do
form <- openCategoryEditForm
do inp <- select (form :// "input[name=title]")
clearInput inp
sendKeys ("foo `bar`" <> _enter) inp
waitWhile 2 (expectNotStale inp)
e <- select categoryTitle; e `shouldHaveText` "foo `bar`"
checkNotPresent (form :& Displayed)
categoryTitle `shouldHaveText` "foo `bar`"
-----------------------------------------------------------------------------
-- Helpers dealing with guide specifically
@ -313,13 +309,33 @@ categoryGroup = ByCSS ".category .group"
openCategoryEditForm :: WD Element
openCategoryEditForm = do
click =<< select (".category h2" :// ByLinkText "edit")
selectWait ".category-info form"
click (".category h2" :// ByLinkText "edit")
select ".category-info form"
-----------------------------------------------------------------------------
-- Utilities for webdriver
-----------------------------------------------------------------------------
isAlive :: Element -> WD Bool
isAlive e = do
let handler ex@(FailedCommand t _)
| t `elem` [NoSuchElement, StaleElementReference] = return False
| otherwise = throw ex
(isEnabled e >> return True) `catch` handler
click :: CanSelect a => a -> WD ()
click s = WD.click =<< select s
shouldHaveAttr :: CanSelect a => a -> (Text, Text) -> WD ()
s `shouldHaveAttr` (a, txt) = do
e <- select s
e `WD.shouldHaveAttr` (a, txt)
shouldHaveText :: CanSelect a => a -> Text -> WD ()
s `shouldHaveText` txt = do
e <- select s
e `WD.shouldHaveText` txt
highlight :: Element -> WD ()
highlight e = do
html <- executeJS [JSArg e]
@ -391,9 +407,14 @@ class Show a => CanSelect a where
anyElem :: a -> [Element] -> WD Bool
anyElem = defAnyElem
instance CanSelect Element where
selectAll e = return [e]
filterElems s es = return (filter (== s) es)
anyElem s es = return (s `elem` es)
-- We take care not to select an element if it's stale.
selectAll e = filterM isAlive [e]
filterElems s es = do
alive <- isAlive s
return $ if alive then filter (s ==) es else []
anyElem s es = do
alive <- isAlive s
return $ if alive then any (s ==) es else False
instance CanSelect Selector where
selectAll s = findElems s
instance (a ~ Text) => CanSelect a where
@ -443,13 +464,25 @@ instance ToSelector Text where
-- | Ensure that the element is the only element matching the selector.
select :: CanSelect a => a -> WD Element
select x = do
es <- selectAll x
case es of
[] -> expectationFailure
(printf "%s wasn't found on the page" (show x))
[e] -> return e
_ -> expectationFailure
(printf "%s isn't unique on the page" (show x))
-- True = found more than one element
-- False = found no elements
v <- liftIO $ newIORef False
let findOne = do
es <- selectAll x
case es of
[e] -> return e
[] -> do liftIO $ writeIORef v False
unexpected "select: no elements"
_ -> do liftIO $ writeIORef v True
unexpected "select: more than one element"
let handler = do
moreThanOne <- liftIO $ readIORef v
if moreThanOne
then expectationFailure $
printf "%s isn't unique on the page" (show x)
else expectationFailure $
printf "%s wasn't found on the page" (show x)
waitUntil 2 findOne `onTimeout` handler
-- | Select one of the elements matching the selector.
selectSome :: CanSelect a => a -> WD Element
@ -459,16 +492,10 @@ selectSome x = do
printf "%s wasn't found on the page" (show x)
return (head es)
selectWait :: CanSelect a => a -> WD Element
selectWait s = waitUntil 2 (select s)
`catch` \e@(FailedCommand ty _) ->
if ty == Timeout
then error (printf "Waiting for %s timed out" (show s))
else throwM e
-- | @font-size@ of an element, in pixels
fontSize :: Element -> WD Double
fontSize e = do
fontSize :: CanSelect a => a -> WD Double
fontSize s = do
e <- select s
mbProp <- cssProp e "font-size"
case mbProp of
Nothing -> expectationFailure $
@ -512,9 +539,9 @@ checkPresentSome :: CanSelect a => a -> WD ()
checkPresentSome x = void (selectSome x)
checkNotPresent :: CanSelect a => a -> WD ()
checkNotPresent x = do
checkNotPresent x = waitUntil 2 $ do
es <- selectAll x
when (not (null es)) $ expectationFailure $
when (not (null es)) $ unexpected $
printf "expected %s not to be present on the page" (show x)
getCurrentRelativeURL :: WD URI
@ -576,27 +603,31 @@ shouldBeInRange :: (Show a, Ord a, MonadIO m) => a -> (a, a) -> m ()
shouldBeInRange a (x, y) =
shouldSatisfy a ("be in range " ++ show (x,y), \n -> n >= x && n <= y)
shouldHaveProp :: Element -> (Text, Text) -> WD ()
e `shouldHaveProp` (a, txt) = do
shouldHaveProp :: CanSelect a => a -> (Text, Text) -> WD ()
s `shouldHaveProp` (a, txt) = do
e <- select s
t <- cssProp e a
unless (Just txt == t) $ expectationFailure $
printf "expected property %s of %s to be %s, got %s"
a (show e) (show txt) (show t)
shouldBeSelected :: Element -> WD ()
shouldBeSelected a = do
x <- isSelected a
a `shouldSatisfy` ("be checked/selected", const x)
shouldBeSelected :: CanSelect a => a -> WD ()
shouldBeSelected s = do
e <- select s
x <- isSelected e
e `shouldSatisfy` ("be checked/selected", const x)
shouldBeDisplayed :: Element -> WD ()
shouldBeDisplayed a = do
x <- isDisplayed a
a `shouldSatisfy` ("be displayed", const x)
shouldBeDisplayed :: CanSelect a => a -> WD ()
shouldBeDisplayed s = do
e <- select s
x <- isDisplayed e
e `shouldSatisfy` ("be displayed", const x)
shouldBeHidden :: Element -> WD ()
shouldBeHidden a = do
x <- isDisplayed a
a `shouldSatisfy` ("be hidden", const (not x))
shouldBeHidden :: CanSelect a => a -> WD ()
shouldBeHidden s = do
e <- select s
x <- isDisplayed e
e `shouldSatisfy` ("be hidden", const (not x))
_backspace, _enter, _esc :: Text
(_backspace, _enter, _esc) = ("\xE003", "\xE007", "\xE00C")