chore: fmt, event tests

This commit is contained in:
orion 2023-09-29 13:23:27 -05:00
parent 252bbd1b1a
commit ac1b2227d0
Signed by: orion
GPG Key ID: 6D4165AE4C928719
17 changed files with 164 additions and 71 deletions

View File

@ -1,4 +0,0 @@
/** @template T */
export class Maybe {}
export class Milliseconds {}

View File

@ -41,7 +41,9 @@ to generate this file without the comments in this block.
, "prelude" , "prelude"
, "simple-json" , "simple-json"
, "spec" , "spec"
, "st"
, "strings" , "strings"
, "tailrec"
, "transformers" , "transformers"
, "tuples" , "tuples"
, "unsafe-coerce" , "unsafe-coerce"

View File

@ -51,14 +51,14 @@ type Viewport =
prepareViewport :: Viewport -> Foreign prepareViewport :: Viewport -> Foreign
prepareViewport { deviceScaleFactor, hasTouch, height, width, isLandscape, isMobile } = prepareViewport { deviceScaleFactor, hasTouch, height, width, isLandscape, isMobile } =
writeImpl writeImpl
{ deviceScaleFactor: FFI.maybeToUndefined deviceScaleFactor { deviceScaleFactor: FFI.maybeToUndefined deviceScaleFactor
, hasTouch: FFI.maybeToUndefined hasTouch , hasTouch: FFI.maybeToUndefined hasTouch
, isLandscape: FFI.maybeToUndefined isLandscape , isLandscape: FFI.maybeToUndefined isLandscape
, isMobile: FFI.maybeToUndefined isMobile , isMobile: FFI.maybeToUndefined isMobile
, height , height
, width , width
} }
--| [`PuppeteerNode`](https://pptr.dev/api/puppeteer.puppeteernode) --| [`PuppeteerNode`](https://pptr.dev/api/puppeteer.puppeteernode)
foreign import data Puppeteer :: Row Type -> Type foreign import data Puppeteer :: Row Type -> Type

View File

@ -1,8 +1,8 @@
import {Page, JSHandle} from 'puppeteer' import { Page, JSHandle } from 'puppeteer'
/** /**
* @type {(_: string) => (_: Page | JSHandle<unknown>) => (_: Array<unknown>) => Promise<unknown>} * @type {(_: string) => (_: Page | JSHandle<unknown>) => (_: Array<unknown>) => Promise<unknown>}
*/ */
export const _run = s => h => a => { export const _run = s => h => a => {
/** @type {any} */ /** @type {any} */
const f = new Function(`return (${s})(...arguments)`) const f = new Function(`return (${s})(...arguments)`)
@ -12,8 +12,8 @@ export const _run = s => h => a => {
} }
/** /**
* @type {(_: string) => (_: Page | JSHandle<unknown>) => (_: Array<unknown>) => Promise<JSHandle<unknown>>} * @type {(_: string) => (_: Page | JSHandle<unknown>) => (_: Array<unknown>) => Promise<JSHandle<unknown>>}
*/ */
export const _runh = s => h => a => { export const _runh = s => h => a => {
/** @type {any} */ /** @type {any} */
const f = new Function(`return (${s})(...arguments)`) const f = new Function(`return (${s})(...arguments)`)

View File

@ -27,19 +27,19 @@ unsafeRunJsHandle0 :: forall e @r. EvalTarget e => String -> e -> Aff (Handle r)
unsafeRunJsHandle0 js h = Promise.toAff $ _runh js (unsafeToForeign h) [] unsafeRunJsHandle0 js h = Promise.toAff $ _runh js (unsafeToForeign h) []
unsafeRunJs1 :: forall a e @r. EvalTarget e => String -> a -> e -> Aff r unsafeRunJs1 :: forall a e @r. EvalTarget e => String -> a -> e -> Aff r
unsafeRunJs1 js a h = Promise.toAff $ _run js (unsafeToForeign h) [unsafeToForeign a] unsafeRunJs1 js a h = Promise.toAff $ _run js (unsafeToForeign h) [ unsafeToForeign a ]
unsafeRunJsHandle1 :: forall a e @r. EvalTarget e => String -> a -> e -> Aff (Handle r) unsafeRunJsHandle1 :: forall a e @r. EvalTarget e => String -> a -> e -> Aff (Handle r)
unsafeRunJsHandle1 js a h = Promise.toAff $ _runh js (unsafeToForeign h) [unsafeToForeign a] unsafeRunJsHandle1 js a h = Promise.toAff $ _runh js (unsafeToForeign h) [ unsafeToForeign a ]
unsafeRunJs2 :: forall a b e @r. EvalTarget e => String -> a -> b-> e -> Aff r unsafeRunJs2 :: forall a b e @r. EvalTarget e => String -> a -> b -> e -> Aff r
unsafeRunJs2 js a b h = Promise.toAff $ _run js (unsafeToForeign h) [unsafeToForeign a, unsafeToForeign b] unsafeRunJs2 js a b h = Promise.toAff $ _run js (unsafeToForeign h) [ unsafeToForeign a, unsafeToForeign b ]
unsafeRunJsHandle2 :: forall a b e @r. EvalTarget e => String -> a -> b -> e -> Aff (Handle r) unsafeRunJsHandle2 :: forall a b e @r. EvalTarget e => String -> a -> b -> e -> Aff (Handle r)
unsafeRunJsHandle2 js a b h = Promise.toAff $ _runh js (unsafeToForeign h) [unsafeToForeign a, unsafeToForeign b] unsafeRunJsHandle2 js a b h = Promise.toAff $ _runh js (unsafeToForeign h) [ unsafeToForeign a, unsafeToForeign b ]
unsafeRunJs3 :: forall a b c e @r. EvalTarget e => String -> a -> b -> c -> e -> Aff r unsafeRunJs3 :: forall a b c e @r. EvalTarget e => String -> a -> b -> c -> e -> Aff r
unsafeRunJs3 js a b c h = Promise.toAff $ _run js (unsafeToForeign h) [unsafeToForeign a, unsafeToForeign b, unsafeToForeign c] unsafeRunJs3 js a b c h = Promise.toAff $ _run js (unsafeToForeign h) [ unsafeToForeign a, unsafeToForeign b, unsafeToForeign c ]
unsafeRunJsHandle3 :: forall a b c e @r. EvalTarget e => String -> a -> b -> c -> e -> Aff (Handle r) unsafeRunJsHandle3 :: forall a b c e @r. EvalTarget e => String -> a -> b -> c -> e -> Aff (Handle r)
unsafeRunJsHandle3 js a b c h = Promise.toAff $ _runh js (unsafeToForeign h) [unsafeToForeign a, unsafeToForeign b, unsafeToForeign c] unsafeRunJsHandle3 js a b c h = Promise.toAff $ _runh js (unsafeToForeign h) [ unsafeToForeign a, unsafeToForeign b, unsafeToForeign c ]

View File

@ -10,7 +10,7 @@ export const mergeRecords = rs =>
/** @type {(m: Array<{k: string, v: any}>) => Record<string, any>} */ /** @type {(m: Array<{k: string, v: any}>) => Record<string, any>} */
export const _mapToRecord = map => export const _mapToRecord = map =>
map.reduce((r, {k, v}) => { map.reduce((r, { k, v }) => {
r[k] = v r[k] = v
return r return r
}, emptyRecord()) }, emptyRecord())

View File

@ -15,14 +15,14 @@ import Foreign (Foreign)
import Simple.JSON (class WriteForeign) import Simple.JSON (class WriteForeign)
foreign import mergeRecords :: Array Foreign -> Foreign foreign import mergeRecords :: Array Foreign -> Foreign
foreign import _mapToRecord :: forall a. Array {k :: String, v :: a} -> Foreign foreign import _mapToRecord :: forall a. Array { k :: String, v :: a } -> Foreign
foreign import _maybeToUndefined :: forall a. (Maybe a -> Nullable a) -> Maybe a -> Foreign foreign import _maybeToUndefined :: forall a. (Maybe a -> Nullable a) -> Maybe a -> Foreign
makeMap :: forall k v. Ord k => Array { k :: k, v :: v } -> Map k v makeMap :: forall k v. Ord k => Array { k :: k, v :: v } -> Map k v
makeMap = Map.fromFoldable <<< map (\{ k, v } -> Tuple k v) makeMap = Map.fromFoldable <<< map (\{ k, v } -> Tuple k v)
mapToRecord :: forall a. WriteForeign a => Map String a -> Foreign mapToRecord :: forall a. WriteForeign a => Map String a -> Foreign
mapToRecord = _mapToRecord <<< foldlWithIndex (\k a v -> Array.cons {k, v} a) [] mapToRecord = _mapToRecord <<< foldlWithIndex (\k a v -> Array.cons { k, v } a) []
maybeToUndefined :: forall a. WriteForeign a => Maybe a -> Foreign maybeToUndefined :: forall a. WriteForeign a => Maybe a -> Foreign
maybeToUndefined = _maybeToUndefined Nullable.toNullable maybeToUndefined = _maybeToUndefined Nullable.toNullable

View File

@ -81,35 +81,37 @@ offsetHeight :: forall a. IsElement a => Handle a -> Aff (Array Number)
offsetHeight = Eval.unsafeRunJs0 "e => e.offsetHeight" offsetHeight = Eval.unsafeRunJs0 "e => e.offsetHeight"
attrs :: forall a. IsElement a => Handle a -> Aff (Map String String) attrs :: forall a. IsElement a => Handle a -> Aff (Map String String)
attrs = let attrs =
js = String.joinWith "\n" let
[ "e => Array.from(e.attributes)" js = String.joinWith "\n"
, " .reduce(" [ "e => Array.from(e.attributes)"
, " (m, a) => [...m, {k: a.name, v: a.value}]," , " .reduce("
, " []," , " (m, a) => [...m, {k: a.name, v: a.value}],"
, " )" , " [],"
, " .filter(({k}) => k)" , " )"
] , " .filter(({k}) => k)"
]
in in
map FFI.makeMap <<< Eval.unsafeRunJs0 @(Array {k :: String, v :: String}) js map FFI.makeMap <<< Eval.unsafeRunJs0 @(Array { k :: String, v :: String }) js
computedStyle :: forall a. IsElement a => Handle a -> Aff (Map String String) computedStyle :: forall a. IsElement a => Handle a -> Aff (Map String String)
computedStyle = let computedStyle =
let
js = String.joinWith "\n" js = String.joinWith "\n"
[ "e => {" [ "e => {"
, " const s = window.getComputedStyle(e)" , " const s = window.getComputedStyle(e)"
, " const a = []" , " const a = []"
, " for (let i = 0; i < s.length; i++) {" , " for (let i = 0; i < s.length; i++) {"
, " const k = s.item(i)" , " const k = s.item(i)"
, " const v = s.getPropertyValue(k)" , " const v = s.getPropertyValue(k)"
, " a.push({k, v})" , " a.push({k, v})"
, " }" , " }"
, "" , ""
, " return a" , " return a"
, "}" , "}"
] ]
in in
map FFI.makeMap <<< Eval.unsafeRunJs0 @(Array {k :: String, v :: String}) js map FFI.makeMap <<< Eval.unsafeRunJs0 @(Array { k :: String, v :: String }) js
value :: Handle HTML.HTMLInputElement -> Aff String value :: Handle HTML.HTMLInputElement -> Aff String
value = Eval.unsafeRunJs0 "e => e.value" value = Eval.unsafeRunJs0 "e => e.value"

View File

@ -4,14 +4,17 @@ import { ElementHandle } from 'puppeteer'
import { JSHandle } from 'puppeteer' import { JSHandle } from 'puppeteer'
/** @type {<T>(_: { remoteObject: (_0: string) => T, primitive: (_0: unknown) => T }) => (_: JSHandle<unknown>) => () => T} */ /** @type {<T>(_: { remoteObject: (_0: string) => T, primitive: (_0: unknown) => T }) => (_: JSHandle<unknown>) => () => T} */
export const _id = ({remoteObject, primitive}) => h => () => { export const _id =
const oid = h.remoteObject().objectId ({ remoteObject, primitive }) =>
if (oid) { h =>
return remoteObject(oid) () => {
} else { const oid = h.remoteObject().objectId
return primitive(h.remoteObject().value) if (oid) {
return remoteObject(oid)
} else {
return primitive(h.remoteObject().value)
}
} }
}
/** @type {(_: string) => (_: ElementHandle<HTMLElement>) => Promise<Array<ElementHandle<Node>>>} */ /** @type {(_: string) => (_: ElementHandle<HTMLElement>) => Promise<Array<ElementHandle<Node>>>} */
export const _find = s => h => h.$$(s) export const _find = s => h => h.$$(s)

View File

@ -60,7 +60,7 @@ import Web.HTML (HTMLElement)
import Web.HTML as HTML import Web.HTML as HTML
id :: forall a. Handle a -> Effect HandleId id :: forall a. Handle a -> Effect HandleId
id = _id {remoteObject: HandleObject, primitive: HandlePrimitive} id = _id { remoteObject: HandleObject, primitive: HandlePrimitive }
data HandleId data HandleId
= HandleObject String = HandleObject String

View File

@ -14,7 +14,9 @@ import Prelude
import Control.Monad.Except (runExcept) import Control.Monad.Except (runExcept)
import Data.Array as Array import Data.Array as Array
import Data.Either (hush) import Data.Either (hush)
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe) import Data.Maybe (Maybe)
import Data.Show.Generic (genericShow)
import Foreign (Foreign, unsafeFromForeign) import Foreign (Foreign, unsafeFromForeign)
import Puppeteer.Base (Handle) import Puppeteer.Base (Handle)
import Puppeteer.FFI as FFI import Puppeteer.FFI as FFI
@ -54,6 +56,10 @@ data MessageType
| TimeEnd | TimeEnd
| Verbose | Verbose
derive instance eqMessageType :: Eq MessageType
derive instance genericMessageType :: Generic MessageType _
instance showMessageType :: Show MessageType where show = genericShow
messageTypeOfString :: String -> MessageType messageTypeOfString :: String -> MessageType
messageTypeOfString "debug" = Debug messageTypeOfString "debug" = Debug
messageTypeOfString "info" = Info messageTypeOfString "info" = Info

View File

@ -41,7 +41,8 @@ import Puppeteer.Page.Event.Dialog (Dialog)
import Simple.JSON (class ReadForeign, readImpl) import Simple.JSON (class ReadForeign, readImpl)
connectPageConsole :: Page -> Aff Unit connectPageConsole :: Page -> Aff Unit
connectPageConsole p = let connectPageConsole p =
let
onmsg m = do onmsg m = do
title <- Page.title p title <- Page.title p
let t = ConsoleMessage.messageType m let t = ConsoleMessage.messageType m

View File

@ -138,7 +138,7 @@ close = Promise.toAff <<< _close
content :: Page -> Aff String content :: Page -> Aff String
content = Promise.toAff <<< _content content = Promise.toAff <<< _content
setContent :: String -> LifecycleEvent -> Page -> Aff Unit setContent :: String -> LifecycleEvent -> Page -> Aff Unit
setContent s ev = Promise.toAff <<< _setContent s (prepareLifecycleEvent ev) setContent s ev = Promise.toAff <<< _setContent s (prepareLifecycleEvent ev)
setViewport :: Viewport -> Page -> Aff Unit setViewport :: Viewport -> Page -> Aff Unit

View File

@ -0,0 +1,78 @@
module Puppeteer.Page.Event.Spec where
import Prelude
import Control.Monad.Error.Class (liftMaybe)
import Control.Monad.Rec.Class (untilJust)
import Control.Monad.ST.Class (liftST)
import Control.Monad.ST.Global as ST
import Control.Monad.ST.Ref as ST.Ref
import Data.Array as Array
import Data.Array.NonEmpty as NonEmptyArray
import Data.Map as Map
import Data.Maybe (Maybe(..))
import Data.Newtype (wrap)
import Data.Time.Duration (Milliseconds(..))
import Effect (Effect)
import Effect.Aff (Aff, forkAff, joinFiber, makeAff)
import Effect.Class (liftEffect)
import Effect.Exception (error)
import Effect.Exception as Error
import Puppeteer as Pup
import Puppeteer.Base (timeoutThrow)
import Puppeteer.Handle as Pup.Handle
import Puppeteer.Handle.HTML as Pup.Handle.HTML
import Puppeteer.Keyboard as Pup.Keyboard
import Puppeteer.Page as Pup.Page
import Puppeteer.Page.Event (connectPageConsole)
import Puppeteer.Page.Event as Pup.Page.Event
import Puppeteer.Page.Event.ConsoleMessage as ConsoleMessage
import Puppeteer.Page.WaitFor as Pup.Page.WaitFor
import Test.Spec (SpecT, afterAll, beforeAll, describe)
import Test.Spec.Assertions (shouldEqual)
import Test.Util (failOnPageError, test)
scriptError :: String
scriptError = "throw new Error('eek!')"
scriptLog :: String
scriptLog = "console.log('beak')"
listenIntoSTArray :: forall e ed. Pup.Page.Event.Event e ed => e -> Pup.Page -> Aff ({ st :: ST.Ref.STRef ST.Global (Array ed), cleanup :: Aff Unit })
listenIntoSTArray e p = do
st <- liftST $ ST.Ref.new []
let
handle ed = do
eds <- liftST $ ST.Ref.read st
_ <- liftST $ ST.Ref.write (eds <> [ ed ]) st
pure unit
t <- Pup.Page.Event.listen e handle p
pure { st, cleanup: Pup.closeContext t }
spec :: SpecT Aff Unit Effect Unit
spec =
beforeAll (Pup.Page.new =<< Pup.launch_ =<< Pup.puppeteer unit)
$ afterAll Pup.Page.close
$ describe "Page" do
test "listen, PageError" \p -> do
{ st: errsST, cleanup } <- listenIntoSTArray Pup.Page.Event.PageError p
_ <- Pup.Page.addScriptTag (Pup.Page.AddScriptInline Pup.Page.Script scriptError) p
err <- timeoutThrow (wrap 1000.0)
$ untilJust do
errs <- liftST $ ST.Ref.read errsST
pure $ Array.head errs
Error.message err `shouldEqual` "eek!"
cleanup
test "once" \p -> do
errF <- forkAff $ Pup.Page.Event.once Pup.Page.Event.PageError p
_ <- Pup.Page.addScriptTag (Pup.Page.AddScriptInline Pup.Page.Script scriptError) p
err <- joinFiber errF
Error.message err `shouldEqual` "eek!"
test "Console" \p -> do
logF <- forkAff $ Pup.Page.Event.once Pup.Page.Event.Console p
_ <- Pup.Page.addScriptTag (Pup.Page.AddScriptInline Pup.Page.Script scriptLog) p
log <- joinFiber logF
ConsoleMessage.text log `shouldEqual` "beak"
ConsoleMessage.messageType log `shouldEqual` ConsoleMessage.Log

View File

@ -105,13 +105,15 @@ spec = beforeAll (Pup.launch_ =<< Pup.puppeteer unit)
test "setViewport, viewport" \b -> do test "setViewport, viewport" \b -> do
p <- Pup.Page.new b p <- Pup.Page.new b
let vp = { deviceScaleFactor: Nothing let
, hasTouch: Nothing vp =
, height: 1200 { deviceScaleFactor: Nothing
, width: 800 , hasTouch: Nothing
, isLandscape: Nothing , height: 1200
, isMobile: Nothing , width: 800
} , isLandscape: Nothing
, isMobile: Nothing
}
Pup.Page.setViewport vp p Pup.Page.setViewport vp p
vp' <- liftMaybe (error "no viewport!") $ Pup.Page.viewport p vp' <- liftMaybe (error "no viewport!") $ Pup.Page.viewport p

View File

@ -18,6 +18,7 @@ import Node.Process as Process
import Node.Stream as Writable import Node.Stream as Writable
import Puppeteer.Browser.Spec as Spec.Browser import Puppeteer.Browser.Spec as Spec.Browser
import Puppeteer.Page.Spec as Spec.Page import Puppeteer.Page.Spec as Spec.Page
import Puppeteer.Page.Event.Spec as Spec.Page.Event
import Puppeteer.Spec as Spec import Puppeteer.Spec as Spec
import Test.Spec (SpecT) import Test.Spec (SpecT)
import Test.Spec.Config (defaultConfig) import Test.Spec.Config (defaultConfig)
@ -32,6 +33,7 @@ specs = do
Spec.spec Spec.spec
Spec.Browser.spec Spec.Browser.spec
Spec.Page.spec Spec.Page.spec
Spec.Page.Event.spec
main :: Effect Unit main :: Effect Unit
main = launchAff_ do main = launchAff_ do

View File

@ -27,7 +27,8 @@ testA :: forall m t arg g. MonadAff g => Monad m => Example t arg Aff => String
testA = test_ liftAff testA = test_ liftAff
failOnPageError :: forall a. Pup.Page -> Aff a -> Aff a failOnPageError :: forall a. Pup.Page -> Aff a -> Aff a
failOnPageError p a = let failOnPageError p a =
let
ok = parallel $ try a ok = parallel $ try a
err = parallel $ Left <$> Pup.Page.Event.once Pup.Page.Event.PageError p err = parallel $ Left <$> Pup.Page.Event.once Pup.Page.Event.PageError p
in in