From e0e7cf965d591debbbd6de572dbb75459aaf2e8b Mon Sep 17 00:00:00 2001 From: Hadley Wickham <hadley@posit.co> Date: Tue, 30 Jan 2024 16:39:06 -0600 Subject: [PATCH 1/5] Drop the --disable-gpu flag (#141) It is no longer needed as the underlying bugs have been fixed in chromium (for multiple years). This flag was dropped in puppeteer in https://github.com/puppeteer/puppeteer/pull/2908 and https://github.com/puppeteer/puppeteer/pull/4523. --- NEWS.md | 2 ++ R/chromote.R | 7 +------ man/default_chrome_args.Rd | 6 +----- tests/testthat/test-default_chromote_args.R | 2 +- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/NEWS.md b/NEWS.md index d2e9f17..671e9e0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # chromote (development version) +* `--disable-gpu` is no longer included in the default Chrome arguments. + * `ChromoteSession` now records the `targetId`. This eliminates one round-trip to the browser when viewing or closing a session, and will make it possible to re-start a closed session (#94). * `ChromoteSession$screenshot()` gains an `options` argument that accepts a list of additional options to be passed to the Chrome Devtools Protocol's [`Page.captureScreenshot` method](https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-captureScreenshot). (#129) diff --git a/R/chromote.R b/R/chromote.R index cbc19e4..76cb060 100644 --- a/R/chromote.R +++ b/R/chromote.R @@ -556,8 +556,6 @@ is_missing_linux_user <- cache_value(function() { #' Default chromote arguments are composed of the following values (when #' appropriate): #' -#' * [`"--disable-gpu"`](https://peter.sh/experiments/chromium-command-line-switches/#disable-gpu) -#' * \verb{Disables GPU hardware acceleration. If software renderer is not in place, then the GPU process won't launch.} #' * [`"--no-sandbox"`](https://peter.sh/experiments/chromium-command-line-switches/#no-sandbox) #' * Only added when `CI` system environment variable is set, when the #' user on a Linux system is not set, or when executing inside a Docker container. @@ -584,9 +582,6 @@ is_missing_linux_user <- cache_value(function() { #' @export default_chrome_args <- function() { c( - # Better cross platform support - "--disable-gpu", - # > Note: --no-sandbox is not needed if you properly setup a user in the container. # https://developers.google.com/web/updates/2017/04/headless-chrome if (is_inside_ci() || is_missing_linux_user() || is_inside_docker()) { @@ -638,7 +633,7 @@ reset_chrome_args <- function() { #' @examples #' old_chrome_args <- get_chrome_args() #' -#' # Only disable the gpu and using `/dev/shm` +#' # Disable the gpu and use `/dev/shm` #' set_chrome_args(c("--disable-gpu", "--disable-dev-shm-usage")) #' #' #... Make new `Chrome` or `ChromoteSession` instance diff --git a/man/default_chrome_args.Rd b/man/default_chrome_args.Rd index 241d803..a50c451 100644 --- a/man/default_chrome_args.Rd +++ b/man/default_chrome_args.Rd @@ -32,10 +32,6 @@ list of possible arguments. Default chromote arguments are composed of the following values (when appropriate): \itemize{ -\item \href{https://peter.sh/experiments/chromium-command-line-switches/#disable-gpu}{\code{"--disable-gpu"}} -\itemize{ -\item \verb{Disables GPU hardware acceleration. If software renderer is not in place, then the GPU process won't launch.} -} \item \href{https://peter.sh/experiments/chromium-command-line-switches/#no-sandbox}{\code{"--no-sandbox"}} \itemize{ \item Only added when \code{CI} system environment variable is set, when the @@ -82,7 +78,7 @@ passed when initializing. Returns the updated defaults. \examples{ old_chrome_args <- get_chrome_args() -# Only disable the gpu and using `/dev/shm` +# Disable the gpu and use `/dev/shm` set_chrome_args(c("--disable-gpu", "--disable-dev-shm-usage")) #... Make new `Chrome` or `ChromoteSession` instance diff --git a/tests/testthat/test-default_chromote_args.R b/tests/testthat/test-default_chromote_args.R index b8e1cb9..0ac879a 100644 --- a/tests/testthat/test-default_chromote_args.R +++ b/tests/testthat/test-default_chromote_args.R @@ -1,5 +1,5 @@ -min_chrome_arg_length <- if (is_inside_ci()) 5 else 4 +min_chrome_arg_length <- if (is_inside_ci()) 4 else 3 test_that("default args are retrieved", { expect_gte(length(default_chrome_args()), min_chrome_arg_length) From ff76fde5b637e6036a10e30b2417c7d340d07984 Mon Sep 17 00:00:00 2001 From: Hadley Wickham <hadley@posit.co> Date: Tue, 30 Jan 2024 16:40:01 -0600 Subject: [PATCH 2/5] Minor documentation improvements (#138) --- R/chromote_session.R | 10 +--------- man/ChromoteSession.Rd | 6 +----- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/R/chromote_session.R b/R/chromote_session.R index f6b8391..0a1b52b 100644 --- a/R/chromote_session.R +++ b/R/chromote_session.R @@ -9,15 +9,6 @@ #' but this is not currently supported by chromote. #' #' @export -#' @param timeout_ Number of seconds for \pkg{chromote} to wait for a Chrome -#' DevTools Protocol response. If `timeout_` is [`rlang::missing_arg()`] and -#' `timeout` is provided, `timeout_` will be set to `2 * timeout / 1000`. -#' @param timeout Number of milliseconds for Chrome DevTools Protocol execute a -#' method. -#' @param width Width, in pixels, of the `Target` to create if `targetId` is -#' `NULL` -#' @param height Height, in pixels, of the `Target` to create if `targetId` is -#' `NULL` #' @param targetId #' [Target](https://chromedevtools.github.io/devtools-protocol/tot/Target/) #' ID of an existing target to attach to. When a `targetId` is provided, the @@ -53,6 +44,7 @@ ChromoteSession <- R6Class( #' from the parent `Chromote` object. If `TRUE`, enable automatic #' event enabling/disabling; if `FALSE`, disable automatic event #' enabling/disabling. + #' @param width,height Width and height of the new window. #' @param wait_ If `FALSE`, return a [promises::promise()] of a new #' `ChromoteSession` object. Otherwise, block during initialization, and #' return a `ChromoteSession` object directly. diff --git a/man/ChromoteSession.Rd b/man/ChromoteSession.Rd index ba50da8..84ab906 100644 --- a/man/ChromoteSession.Rd +++ b/man/ChromoteSession.Rd @@ -82,11 +82,7 @@ if (interactive()) b$view() \item{\code{parent}}{\code{\link{Chromote}} object to use; defaults to \code{\link[=default_chromote_object]{default_chromote_object()}}} -\item{\code{width}}{Width, in pixels, of the \code{Target} to create if \code{targetId} is -\code{NULL}} - -\item{\code{height}}{Height, in pixels, of the \code{Target} to create if \code{targetId} is -\code{NULL}} +\item{\code{width, height}}{Width and height of the new window.} \item{\code{targetId}}{\href{https://chromedevtools.github.io/devtools-protocol/tot/Target/}{Target} ID of an existing target to attach to. When a \code{targetId} is provided, the From c4415ff477a2e436b69e38ee96888f0e594f17e2 Mon Sep 17 00:00:00 2001 From: Hadley Wickham <hadley@posit.co> Date: Wed, 31 Jan 2024 07:12:40 -0600 Subject: [PATCH 3/5] Extract out connection code into own method (#137) Part of #94 --- R/chromote.R | 57 +++++++++++++++++++++++++++++++------------------ man/Chromote.Rd | 23 ++++++++++++++++++++ 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/R/chromote.R b/R/chromote.R index 76cb060..a076108 100644 --- a/R/chromote.R +++ b/R/chromote.R @@ -38,17 +38,42 @@ Chromote <- R6Class( private$auto_events <- auto_events private$multi_session <- multi_session + private$command_callbacks <- fastmap() + + # Use a private event loop to drive the websocket + private$child_loop <- create_loop(parent = current_loop()) + + p <- self$connect(multi_session = multi_session, wait_ = FALSE) + + # Populate methods while the connection is being established. + protocol_spec <- jsonlite::fromJSON(self$url("/json/protocol"), simplifyVector = FALSE) + self$protocol <- process_protocol(protocol_spec, self$.__enclos_env__) + lockBinding("protocol", self) + # self$protocol is a list of domains, each of which is a list of + # methods. Graft the entries from self$protocol onto self + list2env(self$protocol, self) + + private$event_manager <- EventManager$new(self) + private$is_active_ <- TRUE + + self$wait_for(p) + + private$register_default_event_listeners() + }, + + #' @description Re-connect the websocket to the browser. The Chrome browser + #' automatically closes websockets when your computer goes to sleep; + #' you can use this to bring it back to life with a new connection. + #' @param multi_session Should multiple sessions be allowed? + #' @param wait_ If `FALSE`, return a promise; if `TRUE` wait until + #' connection is complete. + connect = function(multi_session = TRUE, wait_ = TRUE) { if (multi_session) { chrome_info <- fromJSON(self$url("/json/version")) } else { chrome_info <- fromJSON(self$url("/json")) } - private$command_callbacks <- fastmap() - - # Use a private event loop to drive the websocket - private$child_loop <- create_loop(parent = current_loop()) - with_loop(private$child_loop, { private$ws <- WebSocket$new( chrome_info$webSocketDebuggerUrl, @@ -81,23 +106,13 @@ Chromote <- R6Class( }) private$ws$connect() - - # Populate methods while the connection is being established. - protocol_spec <- jsonlite::fromJSON(self$url("/json/protocol"), simplifyVector = FALSE) - self$protocol <- process_protocol(protocol_spec, self$.__enclos_env__) - lockBinding("protocol", self) - - # self$protocol is a list of domains, each of which is a list of - # methods. Graft the entries from self$protocol onto self - list2env(self$protocol, self) - - private$event_manager <- EventManager$new(self) - private$is_active_ <- TRUE - - self$wait_for(p) - - private$register_default_event_listeners() }) + + if (wait_) { + invisible(self$wait_for(p)) + } else { + p + } }, #' @description Display the current session in the `browser` diff --git a/man/Chromote.Rd b/man/Chromote.Rd index 9594cdc..cd6e31f 100644 --- a/man/Chromote.Rd +++ b/man/Chromote.Rd @@ -44,6 +44,7 @@ wait for a Chrome DevTools Protocol response.} \subsection{Public methods}{ \itemize{ \item \href{#method-Chromote-new}{\code{Chromote$new()}} +\item \href{#method-Chromote-connect}{\code{Chromote$connect()}} \item \href{#method-Chromote-view}{\code{Chromote$view()}} \item \href{#method-Chromote-get_auto_events}{\code{Chromote$get_auto_events()}} \item \href{#method-Chromote-get_child_loop}{\code{Chromote$get_child_loop()}} @@ -83,6 +84,28 @@ if \code{FALSE}, disable automatic event enabling/disabling.} } } \if{html}{\out{<hr>}} +\if{html}{\out{<a id="method-Chromote-connect"></a>}} +\if{latex}{\out{\hypertarget{method-Chromote-connect}{}}} +\subsection{Method \code{connect()}}{ +Re-connect the websocket to the browser. The Chrome browser +automatically closes websockets when your computer goes to sleep; +you can use this to bring it back to life with a new connection. +\subsection{Usage}{ +\if{html}{\out{<div class="r">}}\preformatted{Chromote$connect(multi_session = TRUE, wait_ = TRUE)}\if{html}{\out{</div>}} +} + +\subsection{Arguments}{ +\if{html}{\out{<div class="arguments">}} +\describe{ +\item{\code{multi_session}}{Should multiple sessions be allowed?} + +\item{\code{wait_}}{If \code{FALSE}, return a promise; if \code{TRUE} wait until +connection is complete.} +} +\if{html}{\out{</div>}} +} +} +\if{html}{\out{<hr>}} \if{html}{\out{<a id="method-Chromote-view"></a>}} \if{latex}{\out{\hypertarget{method-Chromote-view}{}}} \subsection{Method \code{view()}}{ From af5dbe7d9561094e7cebc9259b37e13ac9f8d947 Mon Sep 17 00:00:00 2001 From: Hadley Wickham <hadley@posit.co> Date: Wed, 31 Jan 2024 07:24:15 -0600 Subject: [PATCH 4/5] Implement `ChromoteSession$respawn()` & refactor session creation (#139) Pull out separate `create_session()` function to make it more clear that this is a factory class method. Part of #94 --- NEWS.md | 2 +- R/chromote.R | 20 ++++------ R/chromote_session.R | 55 ++++++++++++++++++++++++-- man/ChromoteSession.Rd | 23 ++++++++--- tests/testthat/helper.R | 27 +++++++++++++ tests/testthat/test-chromote_session.R | 9 +++++ 6 files changed, 114 insertions(+), 22 deletions(-) create mode 100644 tests/testthat/helper.R create mode 100644 tests/testthat/test-chromote_session.R diff --git a/NEWS.md b/NEWS.md index 671e9e0..25a54d5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,7 +2,7 @@ * `--disable-gpu` is no longer included in the default Chrome arguments. -* `ChromoteSession` now records the `targetId`. This eliminates one round-trip to the browser when viewing or closing a session, and will make it possible to re-start a closed session (#94). +* `ChromoteSession` now records the `targetId`. This eliminates one round-trip to the browser when viewing or closing a session. You can now call the `$respawn()` method if a session terminates and you want to reconnect to the same target (#94). * `ChromoteSession$screenshot()` gains an `options` argument that accepts a list of additional options to be passed to the Chrome Devtools Protocol's [`Page.captureScreenshot` method](https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-captureScreenshot). (#129) diff --git a/R/chromote.R b/R/chromote.R index a076108..5b19392 100644 --- a/R/chromote.R +++ b/R/chromote.R @@ -175,19 +175,13 @@ Chromote <- R6Class( #' `ChromoteSession` object. Otherwise, block during initialization, and #' return a `ChromoteSession` object directly. new_session = function(width = 992, height = 1323, targetId = NULL, wait_ = TRUE) { - session <- ChromoteSession$new(self, width, height, targetId, wait_ = FALSE) - - # ChromoteSession$new() always returns the object, but the - # initialization is async. To properly wait for initialization, we - # need to call b$init_promise() to get the promise; it resolves - # after initialization is complete. - p <- session$init_promise() - - if (wait_) { - self$wait_for(p) - } else { - p - } + create_session( + chromote = self, + width = width, + height = height, + targetId = targetId, + wait_ = wait_ + ) }, #' @description Retrieve all [`ChromoteSession`] objects diff --git a/R/chromote_session.R b/R/chromote_session.R index 0a1b52b..6ccbc4a 100644 --- a/R/chromote_session.R +++ b/R/chromote_session.R @@ -129,7 +129,7 @@ ChromoteSession <- R6Class( # returning p, because the call to ChromoteSession$new() always # returns the new object. Instead, we'll store it as # private$init_promise_, and the user can retrieve it with - # b$init_promise(). + # b$get_init_promise(). private$init_promise_ <- p$then(function(value) self) } @@ -409,7 +409,13 @@ ChromoteSession <- R6Class( #' when the `ChromoteSession` has created a new session. Otherwise, block #' until the `ChromoteSession` has created a new session. new_session = function(width = 992, height = 1323, targetId = NULL, wait_ = TRUE) { - self$parent$new_session(width = width, height = height, targetId = targetId, wait_ = wait_) + create_session( + chromote = self$parent, + width = width, + height = height, + targetId = targetId, + wait_ = wait_ + ) }, #' @description @@ -418,6 +424,22 @@ ChromoteSession <- R6Class( private$session_id }, + #' @description + #' Create a new session that connects to the same target (i.e. page) + #' as this session. This is useful if the session has been closed but the target still + #' exists. + respawn = function() { + if (!private$is_active_) { + stop("Can't respawn session; target has been closed.") + } + + create_session( + chromote = self$parent, + targetId = private$target_id, + auto_events = private$auto_events + ) + }, + #' @description #' Retrieve the target id get_target_id = function() { @@ -531,7 +553,7 @@ ChromoteSession <- R6Class( #' @description Initial promise #' #' For internal use only. - init_promise = function() { + get_init_promise = function() { private$init_promise_ }, @@ -561,3 +583,30 @@ ChromoteSession <- R6Class( } ) ) + + +# Wrapper around ChromoteSession$new() that can return a promise +create_session <- function(chromote = default_chromote_object(), + width = 992, + height = 1323, + targetId = NULL, + wait_ = TRUE, + auto_events = NULL) { + + session <- ChromoteSession$new( + parent = chromote, + width = width, + height = height, + targetId, + auto_events = auto_events, + wait_ = wait_ + ) + + if (wait_) { + session + } else { + # ChromoteSession$new() must return a ChromoteSession object so we need a + # side-channel to return a promise + session$get_init_promise() + } +} diff --git a/man/ChromoteSession.Rd b/man/ChromoteSession.Rd index 84ab906..a2081f2 100644 --- a/man/ChromoteSession.Rd +++ b/man/ChromoteSession.Rd @@ -33,6 +33,7 @@ wait for a Chrome DevTools Protocol response.} \item \href{#method-ChromoteSession-screenshot_pdf}{\code{ChromoteSession$screenshot_pdf()}} \item \href{#method-ChromoteSession-new_session}{\code{ChromoteSession$new_session()}} \item \href{#method-ChromoteSession-get_session_id}{\code{ChromoteSession$get_session_id()}} +\item \href{#method-ChromoteSession-respawn}{\code{ChromoteSession$respawn()}} \item \href{#method-ChromoteSession-get_target_id}{\code{ChromoteSession$get_target_id()}} \item \href{#method-ChromoteSession-wait_for}{\code{ChromoteSession$wait_for()}} \item \href{#method-ChromoteSession-debug_log}{\code{ChromoteSession$debug_log()}} @@ -42,7 +43,7 @@ wait for a Chrome DevTools Protocol response.} \item \href{#method-ChromoteSession-invoke_event_callbacks}{\code{ChromoteSession$invoke_event_callbacks()}} \item \href{#method-ChromoteSession-mark_closed}{\code{ChromoteSession$mark_closed()}} \item \href{#method-ChromoteSession-is_active}{\code{ChromoteSession$is_active()}} -\item \href{#method-ChromoteSession-init_promise}{\code{ChromoteSession$init_promise()}} +\item \href{#method-ChromoteSession-get_init_promise}{\code{ChromoteSession$get_init_promise()}} } } \if{html}{\out{<hr>}} @@ -412,6 +413,18 @@ Retrieve the session id \if{html}{\out{<div class="r">}}\preformatted{ChromoteSession$get_session_id()}\if{html}{\out{</div>}} } +} +\if{html}{\out{<hr>}} +\if{html}{\out{<a id="method-ChromoteSession-respawn"></a>}} +\if{latex}{\out{\hypertarget{method-ChromoteSession-respawn}{}}} +\subsection{Method \code{respawn()}}{ +Create a new session that connects to the same target (i.e. page) +as this session. This is useful if the session has been closed but the target still +exists. +\subsection{Usage}{ +\if{html}{\out{<div class="r">}}\preformatted{ChromoteSession$respawn()}\if{html}{\out{</div>}} +} + } \if{html}{\out{<hr>}} \if{html}{\out{<a id="method-ChromoteSession-get_target_id"></a>}} @@ -583,14 +596,14 @@ called, this value will be \code{FALSE}. } \if{html}{\out{<hr>}} -\if{html}{\out{<a id="method-ChromoteSession-init_promise"></a>}} -\if{latex}{\out{\hypertarget{method-ChromoteSession-init_promise}{}}} -\subsection{Method \code{init_promise()}}{ +\if{html}{\out{<a id="method-ChromoteSession-get_init_promise"></a>}} +\if{latex}{\out{\hypertarget{method-ChromoteSession-get_init_promise}{}}} +\subsection{Method \code{get_init_promise()}}{ Initial promise For internal use only. \subsection{Usage}{ -\if{html}{\out{<div class="r">}}\preformatted{ChromoteSession$init_promise()}\if{html}{\out{</div>}} +\if{html}{\out{<div class="r">}}\preformatted{ChromoteSession$get_init_promise()}\if{html}{\out{</div>}} } } diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R new file mode 100644 index 0000000..2381a31 --- /dev/null +++ b/tests/testthat/helper.R @@ -0,0 +1,27 @@ +skip_if_no_chromote <- function() { + skip_on_cran() + skip_on_os("windows") # currently hangs the test process + skip_if(lacks_chromote(), "chromote not available") +} + +lacks_chromote <- function() { + # We try twice because in particular Windows on GHA seems to need it, + # but it doesn't otherwise hurt. More details at + # https://github.com/rstudio/shinytest2/issues/209 + env_cache(globals, "lacks_chromote", !has_chromote() && !has_chromote()) +} + +has_chromote <- function() { + tryCatch( + { + default <- default_chromote_object() + local_bindings(default_timeout = 5, .env = default) + startup <- default$new_session(wait_ = FALSE) + default$wait_for(startup) + TRUE + }, + error = function(cnd) { + FALSE + } + ) +} diff --git a/tests/testthat/test-chromote_session.R b/tests/testthat/test-chromote_session.R new file mode 100644 index 0000000..a58ad78 --- /dev/null +++ b/tests/testthat/test-chromote_session.R @@ -0,0 +1,9 @@ +test_that("respawning preserves targetId and auto_events", { + skip_if_no_chromote() + + sess1 <- create_session(auto_events = FALSE) + sess2 <- sess1$respawn() + + expect_equal(sess1$get_target_id(), sess2$get_target_id()) + expect_equal(sess1$get_auto_events(), sess2$get_auto_events()) +}) From 454e1947a6d6387567ca4490022aa0de2c3c8125 Mon Sep 17 00:00:00 2001 From: olivroy <52606734+olivroy@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:23:11 -0500 Subject: [PATCH 5/5] Correct docs for R6 classes (#123) --- R/browser.R | 2 ++ R/chrome.R | 4 +++- R/chromote.R | 3 +-- man/Browser.Rd | 8 ++------ man/Chrome.Rd | 5 ----- man/ChromeRemote.Rd | 2 -- man/Chromote.Rd | 7 ------- 7 files changed, 8 insertions(+), 23 deletions(-) diff --git a/R/browser.R b/R/browser.R index c6a793c..a32a1c9 100644 --- a/R/browser.R +++ b/R/browser.R @@ -2,10 +2,12 @@ globals <- new.env() #' Browser base class #' +#' @description #' Base class for browsers like Chrome, Chromium, etc. Defines the interface #' used by various browser implementations. It can represent a local browser #' process or one running remotely. #' +#' @details #' The \code{initialize()} method of an implementation should set private$host #' and private$port. If the process is local, the \code{initialize()} method #' should also set private$process. diff --git a/R/chrome.R b/R/chrome.R index f7a82fa..b7643a2 100644 --- a/R/chrome.R +++ b/R/chrome.R @@ -1,5 +1,6 @@ #' Local Chrome process #' +#' @description #' This is a subclass of [`Browser`] that represents a local browser. It extends #' the [`Browser`] class with a [`processx::process`] object, which represents #' the browser's system process. @@ -231,7 +232,8 @@ launch_chrome_impl <- function(path, args, port) { #' Remote Chrome process #' -#' +#' @description +#' Remote Chrome process #' #' @export ChromeRemote <- R6Class("ChromeRemote", diff --git a/R/chromote.R b/R/chromote.R index 5b19392..de2ac85 100644 --- a/R/chromote.R +++ b/R/chromote.R @@ -1,7 +1,6 @@ #' Chromote class #' -#' This class represents the browser as a whole. -#' +#' @description #' A `Chromote` object represents the browser as a whole, and it can have #' multiple _targets_, which each represent a browser tab. In the Chrome #' DevTools Protocol, each target can have one or more debugging _sessions_ to diff --git a/man/Browser.Rd b/man/Browser.Rd index 2354fbb..1f6338c 100644 --- a/man/Browser.Rd +++ b/man/Browser.Rd @@ -4,15 +4,11 @@ \alias{Browser} \title{Browser base class} \description{ -Browser base class - -Browser base class -} -\details{ Base class for browsers like Chrome, Chromium, etc. Defines the interface used by various browser implementations. It can represent a local browser process or one running remotely. - +} +\details{ The \code{initialize()} method of an implementation should set private$host and private$port. If the process is local, the \code{initialize()} method should also set private$process. diff --git a/man/Chrome.Rd b/man/Chrome.Rd index dc312b4..f3a5180 100644 --- a/man/Chrome.Rd +++ b/man/Chrome.Rd @@ -4,11 +4,6 @@ \alias{Chrome} \title{Local Chrome process} \description{ -Local Chrome process - -Local Chrome process -} -\details{ This is a subclass of \code{\link{Browser}} that represents a local browser. It extends the \code{\link{Browser}} class with a \code{\link[processx:process]{processx::process}} object, which represents the browser's system process. diff --git a/man/ChromeRemote.Rd b/man/ChromeRemote.Rd index 683ca01..0d5cc49 100644 --- a/man/ChromeRemote.Rd +++ b/man/ChromeRemote.Rd @@ -4,8 +4,6 @@ \alias{ChromeRemote} \title{Remote Chrome process} \description{ -Remote Chrome process - Remote Chrome process } \section{Super class}{ diff --git a/man/Chromote.Rd b/man/Chromote.Rd index cd6e31f..66b8a8a 100644 --- a/man/Chromote.Rd +++ b/man/Chromote.Rd @@ -4,13 +4,6 @@ \alias{Chromote} \title{Chromote class} \description{ -Chromote class - -Chromote class -} -\details{ -This class represents the browser as a whole. - A \code{Chromote} object represents the browser as a whole, and it can have multiple \emph{targets}, which each represent a browser tab. In the Chrome DevTools Protocol, each target can have one or more debugging \emph{sessions} to