Packages

Playwright is an Elixir library to automate Chromium, Firefox and WebKit browsers with a single API. Playwright delivers automation that is ever-green, capable, reliable and fast.

Current section

Files

Jump to
playwrightais lib playwright channel.ex
Raw

lib/playwright/channel.ex

defmodule Playwright.Channel do
@moduledoc false
import Playwright.Helpers.ErrorHandling
alias Playwright.Channel.{Catalog, Connection, Error, Event, Message, Response, Session}
# API
# ---------------------------------------------------------------------------
def bind(session, {:guid, guid}, event_type, callback) when is_binary(guid) do
Session.bind(session, {guid, event_type}, callback)
end
def find(session, {:guid, guid}, options \\ %{}) when is_binary(guid) do
Session.catalog(session) |> Catalog.get(guid, options)
end
def list(session, {:guid, guid}, type) do
Catalog.list(Session.catalog(session), %{
parent: guid,
type: type
})
end
def patch(session, {:guid, guid}, data) when is_binary(guid) do
catalog = Session.catalog(session)
owner = Catalog.get(catalog, guid)
Catalog.put(catalog, Map.merge(owner, data))
end
def post(session, {:guid, guid}, message, params \\ %{}) when is_binary(guid) when is_pid(session) do
connection = Session.connection(session)
message = Message.new(guid, message, params)
with_timeout(params, fn timeout ->
case Connection.post(connection, message, timeout) do
{:ok, %{id: _}} -> :ok
{:ok, resource} -> resource
{:error, error} -> {:error, error}
end
end)
end
def recv(session, {nil, message}) when is_map(message) do
Response.recv(session, message)
end
def recv(session, {from, message}) when is_map(message) do
Response.recv(session, message)
|> reply(from)
end
# or, "expect"?
def wait(session, owner, event_type, options \\ %{}, trigger \\ nil)
def wait(session, {:guid, guid}, event_type, options, trigger) when is_map(options) do
connection = Session.connection(session)
with_timeout(options, fn timeout ->
{:ok, event} = Connection.wait(connection, {:guid, guid}, event_type, timeout, trigger)
evaluate(event, options)
end)
end
def wait(session, {:guid, guid}, event, trigger, _) when is_function(trigger) do
wait(session, {:guid, guid}, event, %{}, trigger)
end
# private
# ---------------------------------------------------------------------------
defp evaluate(%Event{} = event, options) do
predicate = Map.get(options, :predicate)
if predicate do
with_timeout(options, fn timeout ->
task =
Task.async(fn ->
evaluate(predicate, event.target, event)
end)
Task.await(task, timeout)
end)
else
event
end
end
defp evaluate(predicate, resource, event) do
case predicate.(resource, event) do
false ->
:timer.sleep(5)
evaluate(predicate, resource, event)
_ ->
event
end
end
defp load_preview(handle, timeout \\ DateTime.utc_now() |> DateTime.add(5, :second))
defp load_preview(items, timeout) when is_list(items) do
result =
Enum.map(items, fn item ->
load_preview(item, timeout)
end)
result
end
defp load_preview(%Playwright.ElementHandle{session: session} = handle, timeout) do
if DateTime.compare(DateTime.utc_now(), timeout) == :gt do
{:error, :timeout}
else
case handle.preview do
"JSHandle@node" ->
:timer.sleep(5)
find(session, {:guid, handle.guid}) |> load_preview(timeout)
_hydrated ->
handle
end
end
end
defp load_preview(item, _timeout) do
item
end
defp reply(%Error{} = error, from) do
Task.start_link(fn ->
GenServer.reply(from, {:error, error})
end)
end
defp reply(%Response{} = response, from) do
Task.start_link(fn ->
GenServer.reply(from, {:ok, load_preview(response.parsed)})
end)
end
defp reply(%Event{} = event, from) do
Task.start_link(fn ->
GenServer.reply(from, {:ok, event})
end)
end
end