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"
, "simple-json"
, "spec"
, "st"
, "strings"
, "tailrec"
, "transformers"
, "tuples"
, "unsafe-coerce"

View File

@ -51,14 +51,14 @@ type Viewport =
prepareViewport :: Viewport -> Foreign
prepareViewport { deviceScaleFactor, hasTouch, height, width, isLandscape, isMobile } =
writeImpl
{ deviceScaleFactor: FFI.maybeToUndefined deviceScaleFactor
, hasTouch: FFI.maybeToUndefined hasTouch
, isLandscape: FFI.maybeToUndefined isLandscape
, isMobile: FFI.maybeToUndefined isMobile
, height
, width
}
writeImpl
{ deviceScaleFactor: FFI.maybeToUndefined deviceScaleFactor
, hasTouch: FFI.maybeToUndefined hasTouch
, isLandscape: FFI.maybeToUndefined isLandscape
, isMobile: FFI.maybeToUndefined isMobile
, height
, width
}
--| [`PuppeteerNode`](https://pptr.dev/api/puppeteer.puppeteernode)
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 => {
/** @type {any} */
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 => {
/** @type {any} */
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) []
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 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 js a b h = Promise.toAff $ _run js (unsafeToForeign h) [unsafeToForeign a, unsafeToForeign b]
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 ]
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 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 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>} */
export const _mapToRecord = map =>
map.reduce((r, {k, v}) => {
map.reduce((r, { k, v }) => {
r[k] = v
return r
}, emptyRecord())

View File

@ -15,14 +15,14 @@ import Foreign (Foreign)
import Simple.JSON (class WriteForeign)
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
makeMap :: forall k v. Ord k => Array { k :: k, v :: v } -> Map k v
makeMap = Map.fromFoldable <<< map (\{ k, v } -> Tuple k v)
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 = _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"
attrs :: forall a. IsElement a => Handle a -> Aff (Map String String)
attrs = let
js = String.joinWith "\n"
[ "e => Array.from(e.attributes)"
, " .reduce("
, " (m, a) => [...m, {k: a.name, v: a.value}],"
, " [],"
, " )"
, " .filter(({k}) => k)"
]
attrs =
let
js = String.joinWith "\n"
[ "e => Array.from(e.attributes)"
, " .reduce("
, " (m, a) => [...m, {k: a.name, v: a.value}],"
, " [],"
, " )"
, " .filter(({k}) => k)"
]
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 = let
computedStyle =
let
js = String.joinWith "\n"
[ "e => {"
, " const s = window.getComputedStyle(e)"
, " const a = []"
, " for (let i = 0; i < s.length; i++) {"
, " const k = s.item(i)"
, " const v = s.getPropertyValue(k)"
, " a.push({k, v})"
, " }"
, ""
, " return a"
, "}"
]
[ "e => {"
, " const s = window.getComputedStyle(e)"
, " const a = []"
, " for (let i = 0; i < s.length; i++) {"
, " const k = s.item(i)"
, " const v = s.getPropertyValue(k)"
, " a.push({k, v})"
, " }"
, ""
, " return a"
, "}"
]
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 = Eval.unsafeRunJs0 "e => e.value"

View File

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

View File

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

View File

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

View File

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

View File

@ -138,7 +138,7 @@ close = Promise.toAff <<< _close
content :: Page -> Aff String
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)
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
p <- Pup.Page.new b
let vp = { deviceScaleFactor: Nothing
, hasTouch: Nothing
, height: 1200
, width: 800
, isLandscape: Nothing
, isMobile: Nothing
}
let
vp =
{ deviceScaleFactor: Nothing
, hasTouch: Nothing
, height: 1200
, width: 800
, isLandscape: Nothing
, isMobile: Nothing
}
Pup.Page.setViewport vp 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 Puppeteer.Browser.Spec as Spec.Browser
import Puppeteer.Page.Spec as Spec.Page
import Puppeteer.Page.Event.Spec as Spec.Page.Event
import Puppeteer.Spec as Spec
import Test.Spec (SpecT)
import Test.Spec.Config (defaultConfig)
@ -32,6 +33,7 @@ specs = do
Spec.spec
Spec.Browser.spec
Spec.Page.spec
Spec.Page.Event.spec
main :: Effect Unit
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
failOnPageError :: forall a. Pup.Page -> Aff a -> Aff a
failOnPageError p a = let
failOnPageError p a =
let
ok = parallel $ try a
err = parallel $ Left <$> Pup.Page.Event.once Pup.Page.Event.PageError p
in