marionette-1.0.0: src/Test/Marionette/Commands.hs
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE UndecidableInstances #-}
module Test.Marionette.Commands where
import Data.Aeson
( FromJSON
, KeyValue (..)
, ToJSON (toJSON)
, Value (..)
)
import Data.Aeson qualified as Aeson
import Data.Aeson.KeyMap qualified as Object
import Data.ByteString (ByteString)
import Data.ByteString.Base64 qualified as Base64
import Data.Foldable qualified as Foldable
import Data.Text
import Data.Text.Encoding qualified as Text
import GHC.Generics (Generic)
import GHC.Stack (HasCallStack)
import Test.Marionette.AccessibilityProperties (AccessibilityProperties)
import Test.Marionette.Class
import Test.Marionette.Context (Context)
import Test.Marionette.Cookie (Cookie)
import Test.Marionette.Element (Element (..), Shadow)
import Test.Marionette.Frame (Frame)
import Test.Marionette.Orientation (Orientation)
import Test.Marionette.Protocol
import Test.Marionette.Rect (Rect)
import Test.Marionette.Registry (RegistryEntry)
import Test.Marionette.Selector
( Selector
, SelectorFrom (..)
, SelectorFromShadowRoot (..)
)
import Test.Marionette.Timeouts (Timeouts)
import Test.Marionette.WebAuthn
( AuthenticatorId (..)
, Credential
, CredentialId (..)
, VirtualAuthenticator
)
import Test.Marionette.Window
( NewWindowResult
, WindowHandle (..)
, WindowType (..)
)
import Prelude hiding (log)
newtype ValueObject a = ValueObject {value :: a}
deriving stock (Generic)
deriving anyclass (FromJSON, ToJSON)
type role ValueObject representational
-- | Enable or disable accepting new socket connections.
-- This has no effect on existing connections.
acceptConnections :: (HasCallStack, Marionette m) => Bool -> m ()
acceptConnections value =
sendCommand_
Command
{ command = "Marionette:AcceptConnections"
, parameters = Aeson.object ["value" .= value]
}
-- | Look up accessibility properties of a node in the platform accessibility tree,
-- rather than by a web element reference.
getAccessibilityPropertiesForAccessibilityNode
:: (HasCallStack, Marionette m)
=> Text
-- ^ Node identifier @nodeId@
-> m AccessibilityProperties
getAccessibilityPropertiesForAccessibilityNode nodeId =
sendCommand
Command
{ command = "Marionette:GetAccessibilityPropertiesForAccessibilityNode"
, parameters = Aeson.object ["nodeId" .= nodeId]
}
-- | Look up the accessibility properties exposed to assistive technology
-- (such as screen readers) for a given element.
getAccessibilityPropertiesForElement
:: (HasCallStack, Marionette m)
=> Element
-> m AccessibilityProperties
getAccessibilityPropertiesForElement Element{..} =
sendCommand
Command
{ command = "Marionette:GetAccessibilityPropertiesForElement"
, parameters = Aeson.object ["id" .= elementId]
}
-- | Return whether subsequent browsing-context-scoped commands (such as
-- 'navigate' or 'findElement') target privileged browser chrome or ordinary
-- web content.
-- New sessions start in the 'Content' context; use 'setContext' to switch,
-- for example when driving browser UI rather than a web page.
getContext :: (HasCallStack, Marionette m) => m Context
getContext = value <$> sendCommand "Marionette:GetContext"
-- | Return the current orientation of the browser window.
getScreenOrientation :: (HasCallStack, Marionette m) => m Orientation
getScreenOrientation = value <$> sendCommand "Marionette:GetScreenOrientation"
-- | Return the chrome window's @windowtype@ attribute, for example
-- @navigator:browser@ for a normal browser window.
getWindowType :: (HasCallStack, Marionette m) => m Text
getWindowType = value <$> sendCommand "Marionette:GetWindowType"
-- | Shut the browser down: Marionette first stops accepting new
-- connections, then ends the current session, and finally causes the
-- application itself to quit.
quit :: (HasCallStack, Marionette m) => m ()
quit = sendCommand_ "Marionette:Quit"
-- | Register a chrome protocol handler for a directory containing XHTML or
-- XUL files, allowing them to be loaded via the @chrome://@ protocol.
-- Return the identifier for the registered handler which can be unregistered
-- with 'unregisterChromeHandler'.
registerChromeHandler :: (HasCallStack, Marionette m) => Text -> [RegistryEntry] -> m Text
registerChromeHandler manifestPath entries =
sendCommand
Command
{ command = "Marionette:RegisterChromeHandler"
, parameters =
Aeson.object
[ "manifestPath" .= manifestPath
, "entries" .= entries
]
}
-- | Set the context of the subsequent commands. All subsequent requests to
-- commands that in some way involve interaction with a browsing context
-- will target the chosen context.
setContext :: (HasCallStack, Marionette m) => Context -> m ()
setContext value =
sendCommand_
Command
{ command = "Marionette:SetContext"
, parameters = Aeson.object ["value" .= value]
}
-- | Set the current browser orientation.
setScreenOrientation :: (HasCallStack, Marionette m) => Orientation -> m ()
setScreenOrientation orientation =
sendCommand_
Command
{ command = "Marionette:SetScreenOrientation"
, parameters = Aeson.object ["orientation" .= orientation]
}
-- | Unregister a previously registered chrome protocol handler, given an
-- identifier returned by 'registerChromeHandler'.
unregisterChromeHandler :: (HasCallStack, Marionette m) => Text -> m ()
unregisterChromeHandler handlerId =
sendCommand_
Command
{ command = "Marionette:UnregisterChromeHandler"
, parameters = Aeson.object ["id" .= handlerId]
}
-- | Accept a currently displayed dialog modal, or throw if no modal is
-- displayed.
--
-- See <https://w3c.github.io/webdriver/#accept-alert>
acceptAlert :: (HasCallStack, Marionette m) => m ()
acceptAlert = sendCommand_ "WebDriver:AcceptAlert"
-- | Add a single cookie to the cookie store associated with the active
-- document's address.
--
-- See <https://w3c.github.io/webdriver/#add-cookie>
addCookie :: (HasCallStack, Marionette m) => Cookie -> m ()
addCookie cookie =
sendCommand_
Command
{ command = "WebDriver:AddCookie"
, parameters = Aeson.object ["cookie" .= cookie]
}
-- | Cause the browser to traverse one step backward in the joint history
-- of the current browsing context.
--
-- See <https://w3c.github.io/webdriver/#back>
back :: (HasCallStack, Marionette m) => m ()
back = sendCommand_ "WebDriver:Back"
-- | Close the currently selected chrome window. If it is the last window
-- currently open, the chrome window is not closed, to prevent an
-- application shutdown.
closeChromeWindow :: (HasCallStack, Marionette m) => m ()
closeChromeWindow = sendCommand_ "WebDriver:CloseChromeWindow"
-- | Close the currently selected tab or window. With multiple open tabs,
-- only the selected tab is closed; if it is the last window currently
-- open, the window is not closed, to prevent an application shutdown.
--
-- See <https://w3c.github.io/webdriver/#close-window>
closeWindow :: (HasCallStack, Marionette m) => m ()
closeWindow = sendCommand_ "WebDriver:CloseWindow"
-- | Delete all cookies that are visible to a document.
--
-- See <https://w3c.github.io/webdriver/#delete-all-cookies>
deleteAllCookies :: (HasCallStack, Marionette m) => m ()
deleteAllCookies = sendCommand_ "WebDriver:DeleteAllCookies"
-- | Delete a cookie by name.
--
-- See <https://w3c.github.io/webdriver/#delete-cookie>
deleteCookie :: (HasCallStack, Marionette m) => Text -> m ()
deleteCookie name =
sendCommand_
Command
{ command = "WebDriver:DeleteCookie"
, parameters = Aeson.object ["name" .= name]
}
-- | Delete the current WebDriver session.
--
-- See <https://w3c.github.io/webdriver/#delete-session>
deleteSession :: (HasCallStack, Marionette m) => m ()
deleteSession = sendCommand_ "WebDriver:DeleteSession"
-- | Dismiss a currently displayed modal dialog, or throw if no modal is
-- displayed.
--
-- See <https://w3c.github.io/webdriver/#dismiss-alert>
dismissAlert :: (HasCallStack, Marionette m) => m ()
dismissAlert = sendCommand_ "WebDriver:DismissAlert"
-- | Clear the text of an element.
--
-- See <https://w3c.github.io/webdriver/#element-clear>
elementClear :: (HasCallStack, Marionette m) => Element -> m ()
elementClear Element{..} =
sendCommand_
Command
{ command = "WebDriver:ElementClear"
, parameters = Aeson.object ["id" .= elementId]
}
-- | Send a click event to an element.
--
-- See <https://w3c.github.io/webdriver/#element-click>
elementClick :: (HasCallStack, Marionette m) => Element -> m ()
elementClick Element{..} =
sendCommand_
Command
{ command = "WebDriver:ElementClick"
, parameters = Aeson.object ["id" .= elementId]
}
-- | Send key presses to an element after focusing on it.
--
-- See <https://w3c.github.io/webdriver/#element-send-keys>
elementSendKeys :: (HasCallStack, Marionette m) => Element -> Text -> m ()
elementSendKeys Element{..} text =
sendCommand_
Command
{ command = "WebDriver:ElementSendKeys"
, parameters =
Aeson.object
[ "id" .= elementId
, "text" .= text
]
}
-- | Execute a JavaScript function asynchronously in the context of the
-- current browsing context, and return the value passed to the callback,
-- which is always the last argument exposed to the script.
--
-- See <https://w3c.github.io/webdriver/#execute-async-script>
executeAsyncScript
:: (HasCallStack, Marionette m, Foldable f, FromJSON a)
=> Text
-> f Value
-> m (Maybe a)
executeAsyncScript script args =
fmap value . sendCommand $
Command
{ command = "WebDriver:ExecuteAsyncScript"
, parameters =
Aeson.object
[ "script" .= script
, "args" .= Foldable.toList args
]
}
-- | Execute a JavaScript function synchronously in the context of the
-- current browsing context, and return its return value.
--
-- See <https://w3c.github.io/webdriver/#execute-script>
executeScript :: (HasCallStack, Marionette m, Foldable f, FromJSON a) => Text -> f Value -> m a
executeScript script args =
fmap value . sendCommand $
Command
{ command = "WebDriver:ExecuteScript"
, parameters =
Aeson.object
[ "script" .= script
, "args" .= Foldable.toList args
]
}
-- | Find an element using the given search strategy.
--
-- See <https://w3c.github.io/webdriver/#find-element>
findElement :: (HasCallStack, Marionette m) => Selector -> m Element
findElement selector =
value
<$> sendCommand
Command
{ command = "WebDriver:FindElement"
, parameters = toJSON selector
}
-- | Find an element using the given search strategy, relative to the
-- given element.
--
-- See <https://w3c.github.io/webdriver/#find-element>
findElementFrom :: (HasCallStack, Marionette m) => Element -> Selector -> m Element
findElementFrom element selector =
value
<$> sendCommand
Command
{ command = "WebDriver:FindElement"
, parameters = toJSON $ SelectorFrom element selector
}
-- | Find an element within a shadow root using the given search strategy.
--
-- See <https://w3c.github.io/webdriver/#find-element-from-shadow-root>
findElementFromShadowRoot :: (HasCallStack, Marionette m) => Shadow -> Selector -> m Element
findElementFromShadowRoot shadowRoot selector =
value
<$> sendCommand
Command
{ command = "WebDriver:FindElementFromShadowRoot"
, parameters = toJSON $ SelectorFromShadowRoot shadowRoot selector
}
-- | Find elements using the given search strategy.
--
-- See <https://w3c.github.io/webdriver/#find-elements>
findElements :: (HasCallStack, Marionette m) => Selector -> m [Element]
findElements selector =
sendCommand
Command
{ command = "WebDriver:FindElements"
, parameters = toJSON selector
}
-- | Find elements using the given search strategy, relative to the given
-- element.
--
-- See <https://w3c.github.io/webdriver/#find-elements>
findElementsFrom :: (HasCallStack, Marionette m) => Element -> Selector -> m [Element]
findElementsFrom element selector =
sendCommand
Command
{ command = "WebDriver:FindElements"
, parameters = toJSON (SelectorFrom element selector)
}
-- | Find elements within a shadow root using the given search strategy.
--
-- See <https://w3c.github.io/webdriver/#find-elements-from-shadow-root>
findElementsFromShadowRoot :: (HasCallStack, Marionette m) => Shadow -> Selector -> m [Element]
findElementsFromShadowRoot shadowRoot selector =
sendCommand
Command
{ command = "WebDriver:FindElementsFromShadowRoot"
, parameters = toJSON $ SelectorFromShadowRoot shadowRoot selector
}
-- | Cause the browser to traverse one step forward in the joint history
-- of the current browsing context.
--
-- See <https://w3c.github.io/webdriver/#forward>
forward :: (HasCallStack, Marionette m) => m ()
forward = sendCommand_ "WebDriver:Forward"
-- | Set the window to full screen, as if the user had chosen
-- View -> Enter Full Screen. Not supported on Android.
--
-- See <https://w3c.github.io/webdriver/#fullscreen-window>
fullscreenWindow :: (HasCallStack, Marionette m) => m ()
fullscreenWindow = sendCommand_ "WebDriver:FullscreenWindow"
-- | Return the active element in the document.
--
-- See <https://w3c.github.io/webdriver/#get-active-element>
getActiveElement :: (HasCallStack, Marionette m) => m Element
getActiveElement = value <$> sendCommand "WebDriver:GetActiveElement"
-- | Return the message shown in a currently displayed modal, or throw if
-- no modal is displayed.
--
-- See <https://w3c.github.io/webdriver/#get-alert-text>
getAlertText :: (HasCallStack, Marionette m) => m Text
getAlertText = value <$> sendCommand "WebDriver:GetAlertText"
-- | Determine the accessibility label for an element.
--
-- See <https://w3c.github.io/webdriver/#get-computed-label>
getComputedLabel :: (HasCallStack, Marionette m) => Element -> m Text
getComputedLabel Element{..} =
value
<$> sendCommand
Command
{ command = "WebDriver:GetComputedLabel"
, parameters = Aeson.object ["id" .= elementId]
}
-- | Determine the accessibility role for an element.
--
-- See <https://w3c.github.io/webdriver/#get-computed-role>
getComputedRole :: (HasCallStack, Marionette m) => Element -> m Text
getComputedRole Element{..} =
value
<$> sendCommand
Command
{ command = "WebDriver:GetComputedRole"
, parameters = Aeson.object ["id" .= elementId]
}
-- | Get all the cookies for the current domain. Equivalent to calling
-- @document.cookie@ and parsing the result.
--
-- See <https://w3c.github.io/webdriver/#get-all-cookies>
getCookies :: (HasCallStack, Marionette m) => m [Cookie]
getCookies = sendCommand "WebDriver:GetCookies"
-- | Get a string representing the current URL, equivalent to
-- @document.location.href@. When in the chrome context, return the
-- canonical URL of the current resource.
--
-- See <https://w3c.github.io/webdriver/#get-current-url>
getCurrentURL :: (HasCallStack, Marionette m) => m Text
getCurrentURL = value <$> sendCommand "WebDriver:GetCurrentURL"
-- | Get the value of the given attribute of an element.
--
-- See <https://w3c.github.io/webdriver/#get-element-attribute>
getElementAttribute :: (HasCallStack, Marionette m) => Text -> Element -> m (Maybe Text)
getElementAttribute attr Element{..} =
value
<$> sendCommand
Command
{ command = "WebDriver:GetElementAttribute"
, parameters =
Aeson.object
[ "id" .= elementId
, "name" .= attr
]
}
-- | Get the given CSS property of the computed style of an element.
--
-- See <https://w3c.github.io/webdriver/#get-element-css-value>
getElementCSSValue :: (HasCallStack, Marionette m) => Element -> Text -> m (Maybe Text)
getElementCSSValue Element{..} propertyName =
value
<$> sendCommand
Command
{ command = "WebDriver:GetElementCSSValue"
, parameters =
Aeson.object
[ "id" .= elementId
, "propertyName" .= propertyName
]
}
-- | Get the value of the given property of an element.
--
-- See <https://w3c.github.io/webdriver/#get-element-property>
getElementProperty :: (HasCallStack, Marionette m) => Element -> Text -> m (Maybe Text)
getElementProperty Element{..} name =
value
<$> sendCommand
Command
{ command = "WebDriver:GetElementProperty"
, parameters =
Aeson.object
[ "id" .= elementId
, "name" .= name
]
}
-- | Get the dimensions and coordinates of an element.
--
-- See <https://w3c.github.io/webdriver/#get-element-rect>
getElementRect :: (HasCallStack, Marionette m) => Element -> m Rect
getElementRect Element{..} =
sendCommand
Command
{ command = "WebDriver:GetElementRect"
, parameters = Aeson.object ["id" .= elementId]
}
-- | Get the local tag name of an element.
--
-- See <https://w3c.github.io/webdriver/#get-element-tag-name>
getElementTagName :: (HasCallStack, Marionette m) => Element -> m Text
getElementTagName Element{..} =
value
<$> sendCommand
Command
{ command = "WebDriver:GetElementTagName"
, parameters = Aeson.object ["id" .= elementId]
}
-- | Get the rendered text of an element, including the text of all its
-- child elements.
--
-- See <https://w3c.github.io/webdriver/#get-element-text>
getElementText :: (HasCallStack, Marionette m) => Element -> m Text
getElementText Element{..} =
value
<$> sendCommand
Command
{ command = "WebDriver:GetElementText"
, parameters = Aeson.object ["id" .= elementId]
}
-- | Get the page source of the content document, serialised as a string.
--
-- See <https://w3c.github.io/webdriver/#get-page-source>
getPageSource :: (HasCallStack, Marionette m) => m Text
getPageSource = value <$> sendCommand "WebDriver:GetPageSource"
-- | Get the shadow root of an element.
--
-- See <https://w3c.github.io/webdriver/#get-element-shadow-root>
getShadowRoot :: (HasCallStack, Marionette m) => Element -> m Shadow
getShadowRoot Element{..} =
value
<$> sendCommand
Command
{ command = "WebDriver:GetShadowRoot"
, parameters = Aeson.object ["id" .= elementId]
}
-- | Get the timeouts for page loading, searching, and scripts.
--
-- See <https://w3c.github.io/webdriver/#get-timeouts>
getTimeouts :: (HasCallStack, Marionette m) => m Timeouts
getTimeouts = sendCommand "WebDriver:GetTimeouts"
-- | Get the current title of the window.
--
-- See <https://w3c.github.io/webdriver/#get-title>
getTitle :: (HasCallStack, Marionette m) => m Text
getTitle = value <$> sendCommand "WebDriver:GetTitle"
-- | Get the current window's handle: an opaque, server-assigned
-- identifier that can be used to switch back to this window later with
-- 'switchToWindow'.
--
-- See <https://w3c.github.io/webdriver/#get-window-handle>
getWindowHandle :: (HasCallStack, Marionette m) => m WindowHandle
getWindowHandle = value <$> sendCommand "WebDriver:GetWindowHandle"
-- | Get the unordered list of window handles of every open top-level
-- browsing context.
--
-- See <https://w3c.github.io/webdriver/#get-window-handles>
getWindowHandles :: (HasCallStack, Marionette m) => m [WindowHandle]
getWindowHandles = sendCommand "WebDriver:GetWindowHandles"
-- | Get the position and size of the browser window currently in focus.
-- The width and height refer to the window's @outerWidth@ and
-- @outerHeight@, which include scroll bars, title bars, and so on.
--
-- See <https://w3c.github.io/webdriver/#get-window-rect>
getWindowRect :: (HasCallStack, Marionette m) => m Rect
getWindowRect = sendCommand "WebDriver:GetWindowRect"
-- | Check whether an element is displayed.
--
-- See <https://w3c.github.io/webdriver/#element-displayedness>
isElementDisplayed :: (HasCallStack, Marionette m) => Element -> m Bool
isElementDisplayed Element{..} =
value
<$> sendCommand
Command
{ command = "WebDriver:IsElementDisplayed"
, parameters = Aeson.object ["id" .= elementId]
}
-- | Check whether an element is enabled.
--
-- See <https://w3c.github.io/webdriver/#is-element-enabled>
isElementEnabled :: (HasCallStack, Marionette m) => Element -> m Bool
isElementEnabled Element{..} =
value
<$> sendCommand
Command
{ command = "WebDriver:IsElementEnabled"
, parameters = Aeson.object ["id" .= elementId]
}
-- | Check whether an element is selected.
--
-- See <https://w3c.github.io/webdriver/#is-element-selected>
isElementSelected :: (HasCallStack, Marionette m) => Element -> m Bool
isElementSelected Element{..} =
value
<$> sendCommand
Command
{ command = "WebDriver:IsElementSelected"
, parameters = Aeson.object ["id" .= elementId]
}
-- | Maximise the window, as if the user had pressed the maximise button.
-- Not supported on Android.
--
-- See <https://w3c.github.io/webdriver/#maximize-window>
maximizeWindow :: (HasCallStack, Marionette m) => m ()
maximizeWindow = sendCommand_ "WebDriver:MaximizeWindow"
-- | Minimise the window, as if the user had pressed the minimise button.
-- Not supported on Android.
--
-- See <https://w3c.github.io/webdriver/#minimize-window>
minimizeWindow :: (HasCallStack, Marionette m) => m ()
minimizeWindow = sendCommand_ "WebDriver:MinimizeWindow"
-- | Navigate to the given URL, waiting for the document to load or the
-- session's page load timeout to elapse before returning.
--
-- See <https://w3c.github.io/webdriver/#navigate-to>
navigate :: (HasCallStack, Marionette m) => Text -> m ()
navigate url =
sendCommand_
Command
{ command = "WebDriver:Navigate"
, parameters = Aeson.object ["url" .= url]
}
-- | Create a new WebDriver session. Must be called before performing any
-- other command.
--
-- See <https://w3c.github.io/webdriver/#new-session>
newSession :: (HasCallStack, Marionette m) => m ()
newSession = sendCommand_ "WebDriver:NewSession"
-- | Open a new top-level browsing context of type window.
--
-- See <https://w3c.github.io/webdriver/#new-window>
newWindow :: (HasCallStack, Marionette m) => m NewWindowResult
newWindow =
sendCommand
Command
{ command = "WebDriver:NewWindow"
, parameters = Aeson.object ["type" .= Window]
}
-- | Open a new top-level browsing context of type tab.
--
-- See <https://w3c.github.io/webdriver/#new-window>
newTab :: (HasCallStack, Marionette m) => m NewWindowResult
newTab =
sendCommand
Command
{ command = "WebDriver:NewWindow"
, parameters = Aeson.object ["type" .= Tab]
}
-- | Perform a series of grouped input actions at the specified points in
-- time.
--
-- See <https://w3c.github.io/webdriver/#perform-actions>
performActions :: (HasCallStack, Marionette m) => m ()
performActions = sendCommand_ "WebDriver:PerformActions"
-- | Print the current page, returning it as a base64-encoded PDF.
--
-- See <https://w3c.github.io/webdriver/#print-page>
print :: (HasCallStack, Marionette m) => m ()
print = sendCommand_ "WebDriver:Print"
-- | Reload the page in the current top-level browsing context.
--
-- See <https://w3c.github.io/webdriver/#refresh>
refresh :: (HasCallStack, Marionette m) => m ()
refresh = sendCommand_ "WebDriver:Refresh"
-- | Release all the keys and pointer buttons that are currently
-- depressed.
--
-- See <https://w3c.github.io/webdriver/#release-actions>
releaseActions :: (HasCallStack, Marionette m) => m ()
releaseActions = sendCommand_ "WebDriver:ReleaseActions"
-- | Send keys to the input field of a currently displayed modal, or
-- throw if no modal is displayed, or the modal has no means for text
-- input.
--
-- See <https://w3c.github.io/webdriver/#send-alert-text>
sendAlertText :: (HasCallStack, Marionette m) => Text -> m ()
sendAlertText text =
sendCommand_
Command
{ command = "WebDriver:SendAlertText"
, parameters = Aeson.object ["text" .= text]
}
-- | Simulate user modification of a permission descriptor's permission
-- state.
--
-- See <https://www.w3.org/TR/permissions/#webdriver-command-set-permission>
setPermission :: (HasCallStack, Marionette m) => m ()
setPermission = sendCommand_ "WebDriver:SetPermission"
-- | Set the timeouts for page loading, searching, and scripts.
--
-- See <https://w3c.github.io/webdriver/#set-timeouts>
setTimeouts :: (HasCallStack, Marionette m) => Timeouts -> m ()
setTimeouts timeouts =
sendCommand_
Command
{ command = "WebDriver:SetTimeouts"
, parameters = toJSON timeouts
}
-- | Set the position and size of the window on the operating system's
-- window manager. The width and height refer to the window's
-- @outerWidth@ and @outerHeight@, which include browser chrome and
-- OS-level window borders.
--
-- See <https://w3c.github.io/webdriver/#set-window-rect>
setWindowRect :: (HasCallStack, Marionette m) => Rect -> m ()
setWindowRect rect =
sendCommand_
Command
{ command = "WebDriver:SetWindowRect"
, parameters = toJSON rect
}
-- | Switch to the given frame within the current window.
--
-- See <https://w3c.github.io/webdriver/#switch-to-frame>
switchToFrame :: (HasCallStack, Marionette m) => Frame -> m ()
switchToFrame frame =
sendCommand_
Command
{ command = "WebDriver:SwitchToFrame"
, parameters = toJSON frame
}
-- | Set the current browsing context for future commands to the parent
-- of the current browsing context.
--
-- See <https://w3c.github.io/webdriver/#switch-to-parent-frame>
switchToParentFrame :: (HasCallStack, Marionette m) => m ()
switchToParentFrame = sendCommand_ "WebDriver:SwitchToParentFrame"
-- | Switch to the top-level browsing context identified by the given
-- window handle.
--
-- See <https://w3c.github.io/webdriver/#switch-to-window>
switchToWindow :: (HasCallStack, Marionette m) => WindowHandle -> m ()
switchToWindow window =
sendCommand_
Command
{ command = "WebDriver:SwitchToWindow"
, parameters = toJSON window
}
-- | Take a screenshot of the current frame, returned as a lossless PNG
-- image.
--
-- See <https://w3c.github.io/webdriver/#take-screenshot>
takeScreenshot :: (HasCallStack, Marionette m) => m ByteString
takeScreenshot =
Base64.decodeLenient
. Text.encodeUtf8
. value
<$> sendCommand
Command
{ command = "WebDriver:TakeScreenshot"
, parameters = Aeson.object []
}
-- | Add a credential to a virtual authenticator.
--
-- See <https://www.w3.org/TR/webauthn-3/#sctn-automation-add-credential>
addCredential :: (HasCallStack, Marionette m) => AuthenticatorId -> Credential -> m ()
addCredential authenticatorId credential =
sendCommand_
Command
{ command = "WebAuthn:AddCredential"
, parameters =
Aeson.Object . mconcat $
[ Object.fromList ["authenticatorId" .= authenticatorId]
, case toJSON credential of
Aeson.Object o -> o
_ -> mempty
]
}
-- | Add a virtual authenticator, returning its identifier.
--
-- See <https://www.w3.org/TR/webauthn-3/#sctn-automation-add-virtual-authenticator>
addVirtualAuthenticator :: (HasCallStack, Marionette m) => VirtualAuthenticator -> m AuthenticatorId
addVirtualAuthenticator authenticator =
value
<$> sendCommand
Command
{ command = "WebAuthn:AddVirtualAuthenticator"
, parameters = toJSON authenticator
}
-- | Get the credentials stored in a virtual authenticator.
--
-- See <https://www.w3.org/TR/webauthn-3/#sctn-automation-get-credentials>
getCredentials :: (HasCallStack, Marionette m) => AuthenticatorId -> m [Credential]
getCredentials authenticatorId =
value
<$> sendCommand
Command
{ command = "WebAuthn:GetCredentials"
, parameters = Aeson.object ["authenticatorId" .= authenticatorId]
}
-- | Remove all credentials from a virtual authenticator.
--
-- See <https://www.w3.org/TR/webauthn-3/#sctn-automation-remove-all-credentials>
removeAllCredentials :: (HasCallStack, Marionette m) => AuthenticatorId -> m ()
removeAllCredentials authenticatorId =
sendCommand_
Command
{ command = "WebAuthn:RemoveAllCredentials"
, parameters = Aeson.object ["authenticatorId" .= authenticatorId]
}
-- | Remove a credential from a virtual authenticator.
--
-- See <https://www.w3.org/TR/webauthn-3/#sctn-automation-remove-credential>
removeCredential :: (HasCallStack, Marionette m) => AuthenticatorId -> CredentialId -> m ()
removeCredential authenticatorId credentialId =
sendCommand_
Command
{ command = "WebAuthn:RemoveCredential"
, parameters =
Aeson.object
[ "authenticatorId" .= authenticatorId
, "credentialId" .= credentialId
]
}
-- | Remove a virtual authenticator.
--
-- See <https://www.w3.org/TR/webauthn-3/#sctn-automation-remove-virtual-authenticator>
removeVirtualAuthenticator :: (HasCallStack, Marionette m) => AuthenticatorId -> m ()
removeVirtualAuthenticator authenticatorId =
sendCommand_
Command
{ command = "WebAuthn:RemoveVirtualAuthenticator"
, parameters = Aeson.object ["authenticatorId" .= authenticatorId]
}
-- | Set the user-verified flag on a virtual authenticator.
--
-- See <https://www.w3.org/TR/webauthn-3/#sctn-automation-set-user-verified>
setUserVerified :: (HasCallStack, Marionette m) => AuthenticatorId -> Bool -> m ()
setUserVerified authenticatorId verified =
sendCommand_
Command
{ command = "WebAuthn:SetUserVerified"
, parameters =
Aeson.object
[ "authenticatorId" .= authenticatorId
, "isUserVerified" .= verified
]
}