module ApiCoverageTest where
import Data.Set as S (Set, difference, fromList, null)
import Data.Text as T (Text, intercalate, lines, null, pack, replace, strip, unwords, words)
import GHC.Utils.Misc (filterOut)
import Test.Tasty.HUnit as HUnit (Assertion, assertBool)
import Text.RawString.QQ (r)
import Utils (UrlPath(..))
import WebDriverPreCore.Http
import WebDriverPreCore.HTTP.Protocol
( Actions (..),
Cookie (..),
ElementId (..),
FrameReference (..),
Handle (..),
Script (..),
Selector (..),
Session (..),
ShadowRootElementId (..),
Timeouts (..),
URL (..),
WindowRect (..),
minFirefoxCapabilities
)
{-
!! Replace this the endepoints from the spec with every release
https://www.w3.org/TR/2025/WD-webdriver2-20251028/#endpoints- W3C Working Draft 28 October 2025
-}
endPointsCopiedFromSpc :: Text
endPointsCopiedFromSpc =
pack
[r|POST /session New Session
DELETE /session/{session id} Delete Session
GET /status Status
GET /session/{session id}/timeouts Get Timeouts
POST /session/{session id}/timeouts Set Timeouts
POST /session/{session id}/url Navigate To
GET /session/{session id}/url Get Current URL
POST /session/{session id}/back Back
POST /session/{session id}/forward Forward
POST /session/{session id}/refresh Refresh
GET /session/{session id}/title Get Title
GET /session/{session id}/window Get Window Handle
DELETE /session/{session id}/window Close Window
POST /session/{session id}/window Switch To Window
GET /session/{session id}/window/handles Get Window Handles
POST /session/{session id}/window/new New Window
POST /session/{session id}/frame Switch To Frame
POST /session/{session id}/frame/parent Switch To Parent Frame
GET /session/{session id}/window/rect Get Window Rect
POST /session/{session id}/window/rect Set Window Rect
POST /session/{session id}/window/maximize Maximize Window
POST /session/{session id}/window/minimize Minimize Window
POST /session/{session id}/window/fullscreen Fullscreen Window
GET /session/{session id}/element/active Get Active Element
GET /session/{session id}/element/{element id}/shadow Get Element Shadow Root
POST /session/{session id}/element Find Element
POST /session/{session id}/elements Find Elements
POST /session/{session id}/element/{element id}/element Find Element From Element
POST /session/{session id}/element/{element id}/elements Find Elements From Element
POST /session/{session id}/shadow/{shadow id}/element Find Element From Shadow Root
POST /session/{session id}/shadow/{shadow id}/elements Find Elements From Shadow Root
GET /session/{session id}/element/{element id}/selected Is Element Selected
GET /session/{session id}/element/{element id}/attribute/{name} Get Element Attribute
GET /session/{session id}/element/{element id}/property/{name} Get Element Property
GET /session/{session id}/element/{element id}/css/{property name} Get Element CSS Value
GET /session/{session id}/element/{element id}/text Get Element Text
GET /session/{session id}/element/{element id}/name Get Element Tag Name
GET /session/{session id}/element/{element id}/rect Get Element Rect
GET /session/{session id}/element/{element id}/enabled Is Element Enabled
GET /session/{session id}/element/{element id}/computedrole Get Computed Role
GET /session/{session id}/element/{element id}/computedlabel Get Computed Label
POST /session/{session id}/element/{element id}/click Element Click
POST /session/{session id}/element/{element id}/clear Element Clear
POST /session/{session id}/element/{element id}/value Element Send Keys
GET /session/{session id}/source Get Page Source
POST /session/{session id}/execute/sync Execute Script
POST /session/{session id}/execute/async Execute Async Script
GET /session/{session id}/cookie Get All Cookies
GET /session/{session id}/cookie/{name} Get Named Cookie
POST /session/{session id}/cookie Add Cookie
DELETE /session/{session id}/cookie/{name} Delete Cookie
DELETE /session/{session id}/cookie Delete All Cookies
POST /session/{session id}/actions Perform Actions
DELETE /session/{session id}/actions Release Actions
POST /session/{session id}/alert/dismiss Dismiss Alert
POST /session/{session id}/alert/accept Accept Alert
GET /session/{session id}/alert/text Get Alert Text
POST /session/{session id}/alert/text Send Alert Text
GET /session/{session id}/screenshot Take Screenshot
GET /session/{session id}/element/{element id}/screenshot Take Element Screenshot
POST /session/{session id}/print Print Page
|]
parseLine :: Text -> SpecLine
parseLine line = MkSpecLine method uriTemplate command
where
segments = filterOut T.null $ T.words $ replaceTemplateTxt line
method = case segments of
[] -> "PARSER ERROR NO METHOD IN LINE" <> line
x : _ -> x
uriTemplate = segments !! 1
command = T.unwords $ drop 2 segments
specLinesFromSpec :: Set SpecLine
specLinesFromSpec = fromList $ parseLine <$> filterOut T.null (strip <$> T.lines endPointsCopiedFromSpc)
sessionId :: Text
sessionId = "session_id"
session :: Session
session = MkSession sessionId
elementId :: Text
elementId = "element_id"
element :: ElementId
element = MkElement elementId
shadowDOMElement :: ShadowRootElementId
shadowDOMElement = MkShadowRootElementId elementId
windowHandle :: Handle
windowHandle = MkHandle "window-handle"
selector :: Selector
selector = CSS "Blahh"
name :: Text
name = "name"
data SpecLine = MkSpecLine
{ method :: Text,
uriTemplate :: Text,
command :: Text
}
deriving (Show, Eq, Ord)
replaceTemplateTxt :: Text -> Text
replaceTemplateTxt =
replace "{property name}" name
. replace "{name}" name
. replace "{session id}" sessionId
. replace "{element id}" elementId
. replace "{shadow id}" elementId
toSpecLine :: HttpSpec a -> SpecLine
toSpecLine w3 = case w3 of
Get {} -> MkSpecLine "GET" path command
Post {} -> MkSpecLine "POST" path command
PostEmpty {} -> MkSpecLine "POST" path command
Delete {} -> MkSpecLine "DELETE" path command
where
command = w3.description
path = replaceTemplateTxt $ "/" <> intercalate "/" w3.path.segments
allSpecsSample :: Set SpecLine
allSpecsSample =
fromList $
[ toSpecLine $ newSession minFirefoxCapabilities,
toSpecLine status,
toSpecLine $ maximizeWindow session,
toSpecLine $ minimizeWindow session,
toSpecLine $ fullscreenWindow session,
toSpecLine $ getTimeouts session,
toSpecLine $ setTimeouts session $ MkTimeouts Nothing Nothing Nothing,
toSpecLine $ switchToFrame session TopLevelFrame,
toSpecLine $ getCurrentUrl session,
toSpecLine $ findElementFromElement session element selector,
toSpecLine $ findElementsFromElement session element selector,
toSpecLine $ findElements session selector,
toSpecLine $ getTitle session,
toSpecLine $ getWindowHandle session,
toSpecLine $ isElementSelected session element,
toSpecLine $ closeWindow session,
toSpecLine $ back session,
toSpecLine $ forward session,
toSpecLine $ refresh session,
toSpecLine $ newSession minFirefoxCapabilities,
toSpecLine $ deleteSession session,
toSpecLine $ getActiveElement session,
toSpecLine $ getWindowHandles session,
toSpecLine $ newWindow session,
toSpecLine $ switchToWindow session windowHandle,
toSpecLine $ navigateTo session $ MkUrl "url",
toSpecLine $ findElement session selector,
toSpecLine $ getWindowRect session,
toSpecLine $ elementClick session element,
toSpecLine $ getElementText session element,
toSpecLine $ switchToParentFrame session,
toSpecLine $ getElementProperty session element name,
toSpecLine $ getElementAttribute session element name,
toSpecLine $ getElementCssValue session element name,
toSpecLine $ setWindowRect session (Rect 0 0 1280 720),
toSpecLine $ findElementsFromShadowRoot session shadowDOMElement selector,
toSpecLine $ getElementShadowRoot session element,
toSpecLine $ findElementFromShadowRoot session shadowDOMElement selector,
toSpecLine $ getElementTagName session element,
toSpecLine $ getElementRect session element,
toSpecLine $ isElementEnabled session element,
toSpecLine $ getElementComputedRole session element,
toSpecLine $ getElementComputedLabel session element,
toSpecLine $ elementClear session element,
toSpecLine $ elementSendKeys session element "Some keys",
toSpecLine $ getPageSource session,
toSpecLine $ takeScreenshot session,
toSpecLine $ takeElementScreenshot session element,
toSpecLine $ printPage session,
toSpecLine $ executeScript session $ MkScript "console.log('test');" [],
toSpecLine $ executeScriptAsync session $ MkScript "console.log('test');" [],
toSpecLine $ getAllCookies session,
toSpecLine $ getNamedCookie session name,
toSpecLine $ addCookie session $ MkCookie "testCookie" "testValue" Nothing Nothing Nothing Nothing Nothing Nothing,
toSpecLine $ deleteCookie session name,
toSpecLine $ deleteAllCookies session,
toSpecLine $ dismissAlert session,
toSpecLine $ acceptAlert session,
toSpecLine $ getAlertText session,
toSpecLine $ sendAlertText session "Test alert",
toSpecLine $ performActions session $ MkActions [],
toSpecLine $ releaseActions session
]
-- >>> unit_test_all_endpoints_covered
unit_test_all_endpoints_covered :: Assertion
unit_test_all_endpoints_covered = do
-- print allSpecsSample
-- putStrLn ""
assertBool ("Missing specs:\n " <> show missing) (S.null missing)
assertBool ("Extra specs:\n " <> show extra) (S.null extra)
where
missing = specLinesFromSpec `difference` allSpecsSample
extra = allSpecsSample `difference` specLinesFromSpec