From bbbef41334df9e584d60908deafacc66d10eea81 Mon Sep 17 00:00:00 2001 From: Corey Innis Date: Wed, 9 Oct 2024 09:23:50 -0700 Subject: [PATCH] API: impl `BrowserContext.set_geolocation` Warning: this function has not yet been successfully tested. > So far, the test runs have failed to receive location data and instead > experiences "error code 2", which [reportedly](https://developer.mozilla.org/en-US/docs/Web/API/GeolocationPositionError/code) > represents `POSITION_UNAVAILABLE` - "The acquisition of the geolocation > failed because one or several internal sources of position returned an internal error." --- .envrc | 2 +- lib/playwright/browser_context.ex | 56 +++++++++++++++++++++++++++++++ test/api/browser_context_test.exs | 51 ++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/.envrc b/.envrc index 5cabccec..4b8fc554 100644 --- a/.envrc +++ b/.envrc @@ -5,7 +5,7 @@ export REPO="$(expand_path .)" export ERL_AFLAGS="-kernel shell_history enabled" # persistent iex history # default: true -export PLAYWRIGHT_HEADLESS=false +# export PLAYWRIGHT_HEADLESS=false # default transport: driver (websocket is the one alternative) # export PLAYWRIGHT_TRANSPORT=websocket diff --git a/lib/playwright/browser_context.ex b/lib/playwright/browser_context.ex index ec7609b6..5bc3245b 100644 --- a/lib/playwright/browser_context.ex +++ b/lib/playwright/browser_context.ex @@ -1030,6 +1030,62 @@ defmodule Playwright.BrowserContext do Channel.post({context, "setExtraHTTPHeaders"}, %{headers: serialize_headers(headers)}) end + @doc """ + Sets the context's geolocation. + + Passing `nil` emulates position unavailable. + + > #### NOTE {: .info} + > + > Consider using `Playwright.BrowserContext.grant_permissions/3` to grant + > permissions for the browser context pages to read geolocation. + + > #### WARNING! {: .warning} + > + > As of 2024-10-09, this function has not yet been successfully tested. + > So far, the test runs have failed to receive location data and instead + > experiences "error code 2", which [reportedly](https://developer.mozilla.org/en-US/docs/Web/API/GeolocationPositionError/code) + > represents `POSITION_UNAVAILABLE` - "The acquisition of the geolocation + > failed because one or several internal sources of position returned an internal error." + + ## Usage + + BrowserContext.set_geolocation(context, %{ + latitude: 59.95, + longitude: 30.31667 + }) + + ## Arguments + + | name | | description | + | ------------- | ---------- | ------------------------------- | + | `context` | | The "subject" `BrowserContext`. | + | `geolocation` | | `BrowserContext.geolocation()`. | + + ### Geolocation settings + + | name | | description | + | ----------- | ---------- | ----------------------------------- | + | `latitude` | | Latitude between `-90` and `90`. | + | `lingitude` | | Longitude between `-180` and `180`. | + | `accuracy` | (optional) | Non-negative accuracy value. Defaults to `0`. | + + ## Returns + + - `BrowserContext.t()` + - `{:error, Error. t()}` + """ + @pipe {:set_geolocation, [:context, :geolocation]} + @spec set_geolocation(t(), geolocation() | nil) :: t() | {:error, Error.t()} + def set_geolocation(context, params \\ nil) + + def set_geolocation(%BrowserContext{} = context, params) when is_map(params) do + Channel.post({context, :set_geolocation}, params) + end + + def set_geolocation(%BrowserContext{} = context, nil) do + Channel.post({context, :set_geolocation}) + end @spec set_offline(t(), boolean()) :: t() | {:error, Error.t()} def set_offline(%BrowserContext{} = context, offline) do diff --git a/test/api/browser_context_test.exs b/test/api/browser_context_test.exs index 61befe20..6f49b5f6 100644 --- a/test/api/browser_context_test.exs +++ b/test/api/browser_context_test.exs @@ -936,6 +936,57 @@ defmodule Playwright.BrowserContextTest do end end + # skip: See documentation comment for `BrowserContext.set_geolocation/2` + @tag :skip + describe "BrowserContext.set_geolocation/2" do + test "on success, returns the 'subject' `BrowserContext`", %{page: page} do + context = Page.context(page) + assert %BrowserContext{} = BrowserContext.set_geolocation(context, nil) + end + + test "on failure, returns `{:error, error}`", %{page: page} do + context = Page.context(page) + context = %{context | guid: "bogus"} + + assert {:error, %Error{message: "Target page, context or browser has been closed"}} = + BrowserContext.set_geolocation(context, %{}) + end + + test "...", %{assets: assets, page: page} do + context = Page.context(page) + BrowserContext.grant_permissions(context, ["geolocation"]) + + BrowserContext.set_geolocation(context, %{latitude: 10, longitude: 10}) + + Page.goto(page, assets.empty) + + geolocation = + Page.evaluate(page, """ + async() => new Promise(resolve => navigator.geolocation.getCurrentPosition(position => { + resolve({latitude: position.coords.latitude, longitude: position.coords.longitude}); + })) + """) + |> IO.inspect(label: "geolocation") + + assert %{latitude: 10, longitude: 10} = geolocation + end + end + + describe "BrowserContext.set_geolocation!/2" do + test "on success, returns the 'subject' `BrowserContext`", %{page: page} do + context = Page.context(page) + assert %BrowserContext{} = BrowserContext.set_geolocation!(context, %{latitude: 0, longitude: 0}) + end + + test "on failure, raises `RuntimeError`", %{page: page} do + assert_raise RuntimeError, "Target page, context or browser has been closed", fn -> + context = Page.context(page) + context = %{context | guid: "bogus"} + BrowserContext.set_geolocation!(context, %{latitude: 0, longitude: 0}) + end + end + end + describe "BrowserContext.set_offline/2" do test "returns 'subject'", %{page: page} do context = Page.context(page)