diff --git a/lib/playwright/browser.ex b/lib/playwright/browser.ex index 0367ca2..09588b0 100644 --- a/lib/playwright/browser.ex +++ b/lib/playwright/browser.ex @@ -420,6 +420,13 @@ defmodule Playwright.Browser do required(:value) => String.t() } + @typedoc "Options for tracing API." + @type opts_tracing :: %{ + optional(:categories) => [String.t()], + optional(:path) => String.t(), + optional(:screenshots) => boolean() + } + @typedoc "Network proxy settings." @type proxy_settings :: %{ required(:server) => String.t(), @@ -482,9 +489,6 @@ defmodule Playwright.Browser do """ @type worker_settings :: String.t() - @typedoc "Options for tracing API." - @type opts_tracing :: map() - # callbacks # --------------------------------------------------------------------------- @@ -506,7 +510,7 @@ defmodule Playwright.Browser do Returns - - `Playwright.BrowserType.t()` + - `Playwright.BrowserType.t()` """ @spec browser_type(t()) :: BrowserType.t() def browser_type(%Browser{} = browser) do @@ -553,8 +557,7 @@ defmodule Playwright.Browser do ## Returns - - `:ok` - + - `:ok` """ @spec close(t(), opts_close()) :: :ok def close(%Browser{session: session} = browser, options \\ %{}) do @@ -588,11 +591,9 @@ defmodule Playwright.Browser do | --------- | ---------- | ----------------------- | | `browser` | | The "subject" `Browser` | - ## Returns - `[Playwright.BrowserContext.t()]` - """ @spec contexts(t()) :: [BrowserContext.t()] def contexts(%Browser{} = browser) do @@ -621,6 +622,7 @@ defmodule Playwright.Browser do - `[Playwright.CDPSession.t()]` - `{:error, %Error{}}` """ + @pipe {:new_browser_cdp_session, [:browser]} @spec new_browser_cdp_session(t()) :: CDPSession.t() | {:error, Error.t()} def new_browser_cdp_session(browser) do Channel.post({browser, "newBrowserCDPSession"}) @@ -664,9 +666,11 @@ defmodule Playwright.Browser do ## Returns - - `Playwright.BrowserContext.t()` - - `{:error, Error.t()}` + - `Playwright.BrowserContext.t()` + - `{:error, Error.t()}` """ + @pipe {:new_context, [:browser]} + @pipe {:new_context, [:browser, :options]} @spec new_context(t(), opts_new()) :: BrowserContext.t() | {:error, Error.t()} def new_context(%Browser{} = browser, options \\ %{}) do Channel.post({browser, :new_context}, prepare(options)) @@ -705,8 +709,8 @@ defmodule Playwright.Browser do ## Returns - - `Playwright.Page.t()` - - `{:error, Error.t()}` + - `Playwright.Page.t()` + - `{:error, Error.t()}` """ @spec new_page(t(), opts_new()) :: {Page.t() | {:error, Error.t()}} def new_page(browser, options \\ %{}) @@ -725,8 +729,55 @@ defmodule Playwright.Browser do end end - # --- + @doc """ + `Playwright.Browser.start_tracing/3` initiates a Chromium Tracing session. + + `start_tracing/3` may be used in conjunction with `Playwright.Browser.stop_tracing/1` + to create a trace file that can be opened in the Chrome DevTools performance + panel. + + > #### NOTE {: .info} + > + > This API controls [Chromium Tracing](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool) + > which is a low-level Chromium-specific debugging tool. Details on the API + > used to work with [Playwright Tracing](https://playwright.dev/docs/trace-viewer) + > are found in the `Playwright.Tracing` API documentation. + + ## Usage + + browser = Browser.start_tracing(browser) + browser = Browser.start_tracing(browser, %{path: "trace.json"}) + browser = Browser.start_tracing(browser, page) + browser = Browser.start_tracing(browser, page, %{path: "trace.json"}) + Page.goto(page, "https://example.com") + + Browser.stop_tracing(browser) + + ## Arguments + + | name | | description | + | --------- | ---------- | ------------------------ | + | `browser` | | The "subject" `Browser` | + | `page` | (optional) | If specified, tracing includes screenshots of the given page. | + | `options` | (optional) | `Browser.opts_tracing()` | + + ## Options + + | name | | description | + | -------------- | ---------- | --------------------------------- | + | `:categories` | (optional) | Specifies custom categories to use instead of defaults. | + | `:path` | (optional) | Provides a path to write the trace file. | + | `:screenshots` | (optional) | Indicates whether to capture screenshots in the trace. | + + ## Returns + + - `Playwright.Browser.t()` + - `{:error, Error.t()}` + """ + @pipe {:start_tracing, [:browser]} + @pipe {:start_tracing, [:browser, :page]} + @pipe {:start_tracing, [:browser, :page, :options]} @spec start_tracing(t(), Page.t(), opts_tracing()) :: t() | {:error, Error.t()} def start_tracing(browser, page \\ nil, options \\ %{}) @@ -734,18 +785,37 @@ defmodule Playwright.Browser do Channel.post({browser, :start_tracing}) end - @spec stop_tracing(t()) :: binary() + @doc """ + `Playwright.Browser.stop_tracing/3` terminates a Chromium Tracing session. + + > #### NOTE {: .info} + > + > This API controls [Chromium Tracing](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool) + > which is a low-level Chromium-specific debugging tool. Details on the API + > used to work with [Playwright Tracing](https://playwright.dev/docs/trace-viewer) + > are found in the `Playwright.Tracing` API documentation. + + ## Usage + + Browser.stop_tracing(browser) + + ## Arguments + + | name | | description | + | --------- | ---------- | ------------------------ | + | `browser` | | The "subject" `Browser` | + + ## Returns + + - `Playwright.Artifact.t()` + - `{:error, Error.t()}` + """ + @pipe {:stop_tracing, [:browser]} + @spec stop_tracing(t()) :: Playwright.Artifact.t() | {:error, Error.t()} def stop_tracing(%Browser{} = browser) do Channel.post({browser, :stop_tracing}) end - # events - # ---------------------------------------------------------------------------- - - # test_browsertype_connect.py - # @spec on(t(), event(), function()) :: Browser.t() - # def on(browser, event, callback) - # private # ---------------------------------------------------------------------------- diff --git a/test/api/browser_test.exs b/test/api/browser_test.exs index fdae0f1..b0e250f 100644 --- a/test/api/browser_test.exs +++ b/test/api/browser_test.exs @@ -79,10 +79,28 @@ defmodule Playwright.BrowserTest do end end - describe "Browser.new_cdp_session_/1" do + describe "Browser.new_browser_cdp_session/1" do test "on success, returns a new `CDPSession`", %{browser: browser} do assert %CDPSession{} = Browser.new_browser_cdp_session(browser) end + + test "on failure, returns `{:error, error}`", %{browser: browser} do + browser = %{browser | guid: "bogus"} + assert {:error, %Error{type: "TargetClosedError"}} = Browser.new_browser_cdp_session(browser) + end + end + + describe "Browser.new_browser_cdp_session!/1" do + test "on success, returns a new `CDPSession`", %{browser: browser} do + assert %CDPSession{} = Browser.new_browser_cdp_session!(browser) + end + + test "on failure, raises", %{browser: browser} do + assert_raise RuntimeError, fn -> + browser = %{browser | guid: "bogus"} + Browser.new_browser_cdp_session!(browser) + end + end end describe "Browser.new_context/1" do @@ -142,6 +160,32 @@ defmodule Playwright.BrowserTest do # test_should_authenticate_with_empty_password end + describe "Browser.new_context!/1" do + test "on success, returns a new `BrowserContext`", %{browser: browser} do + assert %BrowserContext{} = Browser.new_context!(browser) + end + + test "on failure, raises", %{browser: browser} do + assert_raise RuntimeError, fn -> + browser = %{browser | guid: "bogus"} + Browser.new_context!(browser) + end + end + end + + describe "Browser.new_context!/2" do + test "on success, returns a new `BrowserContext`", %{browser: browser} do + assert %BrowserContext{} = Browser.new_context!(browser, %{base_url: "https://example.com"}) + end + + test "on failure, raises", %{browser: browser} do + assert_raise RuntimeError, fn -> + browser = %{browser | guid: "bogus"} + Browser.new_context!(browser, %{base_url: "https://example.com"}) + end + end + end + describe "Browser.new_page/1" do @tag exclude: [:page] test "creates and binds a new context", %{transport: transport} do @@ -190,6 +234,26 @@ defmodule Playwright.BrowserTest do end end + # skip: the `:disconnected` event is meant to be emitted from the client-side, + # upon `Browser.close/1`; we don't yet have a good mechanism for that. + @tag :skip + describe "Browser.on/3" do + # test "on success, returns the 'subject' `Browser`", %{transport: transport} do + # {_session, browser} = setup_browser(transport) + # assert %Browser{} = Browser.on(browser, :disconnected, fn -> nil end) + # end + + # test "on `:disconnected`, ...", %{transport: transport} do + # {_session, browser} = setup_browser(transport) + + # Browser.on(browser, :disconnected, fn data -> + # IO.inspect(data, label: "on(:disconnected) data ->") + # end) + + # Browser.close(browser) + # end + end + describe "Browser.start_tracing/3" do test "on success, returns the 'subject' `Browser`", %{browser: browser} do assert %Browser{} = Browser.start_tracing(browser) @@ -202,6 +266,20 @@ defmodule Playwright.BrowserTest do end end + describe "Browser.start_tracing!/3" do + test "on success, returns the 'subject' `Browser`", %{browser: browser} do + assert %Browser{} = Browser.start_tracing!(browser) + Browser.stop_tracing(browser) + end + + test "on failure, raises", %{browser: browser} do + assert_raise RuntimeError, fn -> + browser = %{browser | guid: "bogus"} + Browser.start_tracing!(browser) + end + end + end + describe "Browser.stop_tracing/1" do test "on success, returns the resultant `Artifact`", %{browser: browser} do Browser.start_tracing(browser) @@ -214,4 +292,19 @@ defmodule Playwright.BrowserTest do assert {:error, %Error{type: "TargetClosedError"}} = Browser.start_tracing(browser) end end + + describe "Browser.stop_tracing!/3" do + test "on success, returns the resultant `Artifact`", %{browser: browser} do + Browser.start_tracing(browser) + assert %Playwright.Artifact{} = Browser.stop_tracing!(browser) + end + + test "on failure, raises", %{browser: browser} do + assert_raise RuntimeError, fn -> + Browser.start_tracing(browser) + browser = %{browser | guid: "bogus"} + Browser.stop_tracing!(browser) + end + end + end end