From ca1b06f1681192ed33399c8d7d16bc316a9b003e Mon Sep 17 00:00:00 2001 From: ashbythorpe <61390103+ashbythorpe@users.noreply.github.com> Date: Sat, 25 Nov 2023 18:22:23 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20@=20ashbytho?= =?UTF-8?q?rpe/selenider@2bc85ca27d4f6a5a78907626b9cc3b2a92af96f2=20?= =?UTF-8?q?=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dev/articles/unit-testing.html | 8 ++++---- dev/pkgdown.yml | 2 +- dev/search.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/articles/unit-testing.html b/dev/articles/unit-testing.html index 71e401a0..aab6b479 100644 --- a/dev/articles/unit-testing.html +++ b/dev/articles/unit-testing.html @@ -198,16 +198,16 @@

Using selenider with shinytest2}) #> Can't compare snapshot to reference when testing interactively. #> i Run `devtools::test()` or `testthat::test_file()` to see changes. -#> New path: /tmp/Rtmpj6ON6k/st2-1d607d7578b/001_.png +#> New path: /tmp/RtmpEbfBjc/st2-1cfa2bdcfe2d/001_.png #> Can't compare snapshot to reference when testing interactively. #> i Run `devtools::test()` or `testthat::test_file()` to see changes. -#> New path: /tmp/Rtmpj6ON6k/st2-1d607d7578b/001.json +#> New path: /tmp/RtmpEbfBjc/st2-1cfa2bdcfe2d/001.json #> Can't compare snapshot to reference when testing interactively. #> i Run `devtools::test()` or `testthat::test_file()` to see changes. -#> New path: /tmp/Rtmpj6ON6k/st2-1d607d7578b/002_.png +#> New path: /tmp/RtmpEbfBjc/st2-1cfa2bdcfe2d/002_.png #> Can't compare snapshot to reference when testing interactively. #> i Run `devtools::test()` or `testthat::test_file()` to see changes. -#> New path: /tmp/Rtmpj6ON6k/st2-1d607d7578b/002.json +#> New path: /tmp/RtmpEbfBjc/st2-1cfa2bdcfe2d/002.json #> Test passed

Note the difference in styles: while in selenider you must specify tests explicitly, shinytest2 uses a snapshot-based approach (specifying diff --git a/dev/pkgdown.yml b/dev/pkgdown.yml index bc7a0ca3..5dcd725d 100644 --- a/dev/pkgdown.yml +++ b/dev/pkgdown.yml @@ -6,7 +6,7 @@ articles: selenider: selenider.html unit-testing: unit-testing.html with-rvest: with-rvest.html -last_built: 2023-11-25T18:17Z +last_built: 2023-11-25T18:21Z urls: reference: https://ashbythorpe.github.io/selenider/reference article: https://ashbythorpe.github.io/selenider/articles diff --git a/dev/search.json b/dev/search.json index 5c2753b8..14118be4 100644 --- a/dev/search.json +++ b/dev/search.json @@ -1 +1 @@ -[{"path":"https://ashbythorpe.github.io/selenider/dev/LICENSE.html","id":null,"dir":"","previous_headings":"","what":"MIT License","title":"MIT License","text":"Copyright (c) 2023 selenider authors Permission hereby granted, free charge, person obtaining copy software associated documentation files (“Software”), deal Software without restriction, including without limitation rights use, copy, modify, merge, publish, distribute, sublicense, /sell copies Software, permit persons Software furnished , subject following conditions: copyright notice permission notice shall included copies substantial portions Software. SOFTWARE PROVIDED “”, WITHOUT WARRANTY KIND, EXPRESS IMPLIED, INCLUDING LIMITED WARRANTIES MERCHANTABILITY, FITNESS PARTICULAR PURPOSE NONINFRINGEMENT. EVENT SHALL AUTHORS COPYRIGHT HOLDERS LIABLE CLAIM, DAMAGES LIABILITY, WHETHER ACTION CONTRACT, TORT OTHERWISE, ARISING , CONNECTION SOFTWARE USE DEALINGS SOFTWARE.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/articles/selenider.html","id":"starting-the-session","dir":"Articles","previous_headings":"","what":"Starting the session","title":"Getting started with selenider","text":"use selenider, must first start session selenider_session(). don’t , done automatically , may want change options defaults (backend, example). , use chromote backend (default), set timeout 10 seconds (default 4). session, created, set local session inside current environment, meaning case, can accessed anywhere script, closed automatically script finishes running. One thing remember start session inside function, closed automatically function finishes running. want use session outside function, need use .env argument. example, let’s say want wrapper function around selenider_session() always uses selenium: Use open_url() navigate website. selenider also provides back() forward() functions easily navigate search history, reload() function reload current page.","code":"session <- selenider_session( \"chromote\", timeout = 10 ) # Bad (unless you only need to use the session inside the function) my_selenider_session <- function(...) { selenider_session(\"selenium\", ...) # The session will be closed here } # Good - the session will be open in the caller environment/function my_selenider_session <- function(..., .env = rlang::caller_env()) { selenider_session(\"selenium\", ..., .env = .env) } open_url(\"https://www.r-project.org/\") open_url(\"https://www.tidyverse.org/\") back() forward() reload()"},{"path":"https://ashbythorpe.github.io/selenider/dev/articles/selenider.html","id":"selecting-elements","dir":"Articles","previous_headings":"","what":"Selecting elements","title":"Getting started with selenider","text":"Use s() select element. default, CSS selectors used, options available. example, XPath can used instead. XPaths can useful complex selectors, limited selecting ancestors current element. However, can difficult read. Use ss() select multiple elements. Use find_element() find_elements() find child elements existing element. can chained pipe operator (|>) specify paths elements. Just like s() ss(), variety selector types available, CSS selectors used default. Use elem_children() friends find elements using relative position another. can use elem_filter() elem_find() filter collections elements using custom function. elem_find() returns first matching element, elem_filter() returns matching elements. functions use interface elem_expect(): see “Expectations” section .","code":"header <- s(\"#rStudioHeader\") header #> { selenider_element } #>

#> \\n
\\n
<\/div> s(xpath = \"//div/a\") #> { selenider_element } #> #> Tidyverse #> <\/a> all_links <- ss(\"a\") all_links #> { selenider_elements (24) } #> [1] Tidyverse<\/a> #> [2] Packages<\/a> #> [3] Blog<\/a> #> [4] Learn<\/a> #> [5] Help<\/a> #> [6] Contribute<\/a> #> [7] [8] [9] [10] [11] [12] [13] [14] [15] collection of R packages<\/a> #> [16] online<\/a> #> [17] the book<\/a> #> [18] resource<\/a> #> [19] [20] reprex<\/a> #> ... tidyverse_title <- s(\"#rStudioHeader\") |> find_element(\"div\") |> find_element(\".productName\") tidyverse_title #> { selenider_element } #> #> Tidyverse #> <\/a> menu_items <- s(\"#rStudioHeader\") |> find_element(\"#menu\") |> find_elements(\".menuItem\") menu_items #> { selenider_elements (5) } #> [1] Packages<\/a> #> [2] Blog<\/a> #> [3] Learn<\/a> #> [4] Help<\/a> #> [5] Contribute<\/a> s(\"#menuItems\") |> elem_children() #> { selenider_elements (5) } #> [1] Packages<\/a> #> [2] Blog<\/a> #> [3] Learn<\/a> #> [4] Help<\/a> #> [5] Contribute<\/a> s(\"#menuItems\") |> elem_ancestors() #> { selenider_elements (8) } #> [1] \\n\\n\\n\\n\\n\\n [2] \\n
\\n
\\n \\n ... #> [3]
\\n
\\n \\n
[4]
\\n \\n
\\n
[5]
\\n
\\n
[6]
\\n
\\n ... #> [7]
\\n
\\n [8]
\\n
<\/div>\\n
elem_find(has_text(\"Blog\")) #> { selenider_element } #> #> Blog #> <\/a> # Find the hex badges on the second row s(\".hexBadges\") |> find_elements(\"img\") |> elem_filter( \\(x) substring(elem_attr(x, \"class\"), 1, 2) == \"r2\" ) #> { selenider_elements (3) } #> [1] \"ggplot2 #> [2] \"forcats #> [3] \"tibble"},{"path":"https://ashbythorpe.github.io/selenider/dev/articles/selenider.html","id":"interacting-with-an-element","dir":"Articles","previous_headings":"","what":"Interacting with an element","title":"Getting started with selenider","text":"selenider elements lazy, meaning specify path element group elements, actually located DOM something . three types functions force element collected: actions (e.g. elem_click()) properties (e.g. elem_text()) conditions (e.g. is_visible()) functions act elements use elem_ prefix.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/articles/selenider.html","id":"actions","dir":"Articles","previous_headings":"","what":"Actions","title":"Getting started with selenider","text":"various ways interact HTML element. Use elem_click(), elem_right_click(), elem_double_click() click element, elem_hover() hover element. Use elem_scroll_to() scroll element clicking , useful element currently view. links work clicked , since open content new tab. Use open_url() manually solve . approach recommended using elem_click(), reliable. Use elem_set_value() set value input element, elem_clear_value() clear value. selenider also provides elem_submit() function, allowing submit HTML form using element inside form.","code":"s(\".blurb\") |> find_element(\"a\") |> # List of packages elem_scroll_to() |> elem_click() s(\".packages\") |> find_elements(\"a\") |> elem_find(has_text(\"dplyr\")) |> # Find the link to the dplyr documentation elem_attr(\"href\") |> # Get the URL open_url() s(\"input[type='search']\") |> elem_set_value(\"filter\") # Go back to the main page back() back()"},{"path":"https://ashbythorpe.github.io/selenider/dev/articles/selenider.html","id":"properties","dir":"Articles","previous_headings":"","what":"Properties","title":"Getting started with selenider","text":"HTML elements number accessible properties.","code":"# Get the tag name s(\"#appTidyverseSite\") |> elem_name() #> [1] \"div\" # Get the text inside the element s(\".tagline\") |> elem_text() #> [1] \"\\n R packages for data science\\n \" # Get an attribute s(\".hexBadges\") |> find_element(\"img\") |> elem_attr(\"alt\") #> [1] \"dplyr hex sticker\" # Get every attribute s(\".hexBadges\") |> find_element(\"img\") |> elem_attrs() #> $src #> [1] \"/css/images/hex/dplyr.png\" #> #> $alt #> [1] \"dplyr hex sticker\" #> #> $class #> [1] \"r1 c0\" # Get the 'value' attribute (`NULL` in this case) s(\"#homeContent\") |> elem_value() #> NULL # Get a CSS property s(\".tagline\") |> elem_css_property(\"font-size\") #> [1] \"36px\""},{"path":"https://ashbythorpe.github.io/selenider/dev/articles/selenider.html","id":"conditions","dir":"Articles","previous_headings":"","what":"Conditions","title":"Getting started with selenider","text":"Conditions predicate functions HTML elements. Unlike functions selenider, wait element exist condition met: return TRUE FALSE (throw error) instantly. reason, designed used elem_expect() elem_wait_until(), automatically wait conditions met. wide range conditions, many thing. HTML property corresponding condition, selenider also provides conditions basic checks like is_present(), is_visible() is_enabled(). documentation condition, can find conditions “See Also” section.","code":"s(\".hexBadges\") |> is_present() #> [1] TRUE"},{"path":"https://ashbythorpe.github.io/selenider/dev/articles/selenider.html","id":"expectations","dir":"Articles","previous_headings":"","what":"Expectations","title":"Getting started with selenider","text":"selenider provides concise testing interface using elem_expect() function. Provide element, one conditions, function wait conditions met. Conditions can functions simple calls (e.g. has_text(\"text\") turned has_text(, \"text\")). elem_expect() tends work well R’s lambda function syntax. Errors try give much information possible. Since know condition going fail, ’ll set timeout lower value don’t wait long. (&&), (||) (!) can used conditions logical values. Additionally, can omit first argument elem_expect() (case, conditions must calls). Use elem_wait_until() don’t want error thrown condition met. elem_wait_until() exact thing elem_expect() always returns TRUE FALSE. syntax used elem_expect() elem_wait_until() can also used elem_filter() elem_find() filter element collections. Additionally, selenider provides elem_expect_all() elem_wait_until_all() test condition every element collection. done, need close session; closed us automatically!","code":"s(\".tagline\") |> elem_expect(is_present) |> elem_expect(has_text(\"data science\")) s(\".hexBadges\") |> find_element(\"a\") |> elem_expect(is_visible, is_enabled) s(\"#menu\") |> find_element(\"#menuItems\") |> elem_children() |> elem_expect(has_at_least(4)) s(\".productName\") |> elem_expect( \\(x) substring(elem_text(x), 1, 1) == \"T\" # Tidyverse starts with T ) s(\".band.first\") |> find_element(\".blurb\") |> find_element(\"code\") |> elem_expect(has_text('install.packages(\"selenider\")'), timeout = 1) #> Error in `elem_expect()`: #> ! Condition failed after waiting for 1 seconds: #> `has_text(\"install.packages(\\\"selenider\\\")\")` #> ℹ `x` does not have text \"install.packages(\\\"selenider\\\")\". #> ℹ Actual text: \"install.packages(\\\"tidyverse\\\")\". s(\".random-class\") |> elem_expect(!is_present) s(\".innards\") |> elem_expect(is_visible || is_enabled) elem_1 <- s(\".random-class\") elem_2 <- s(\"#main\") # Test that either the first or second element exists elem_expect(is_present(elem_1) || is_present(elem_2)) elem_wait_until(is_present(elem_1) || is_present(elem_2)) #> [1] TRUE s(\".hexBadges\") |> find_elements(\"a\") |> elem_expect_all(is_visible)"},{"path":"https://ashbythorpe.github.io/selenider/dev/articles/unit-testing.html","id":"using-selenider-with-testthat","dir":"Articles","previous_headings":"","what":"Using selenider with testthat","title":"Unit testing","text":"Tests contained within testthat::test_that() self-contained, impact tests. selenider exception: selenider sessions, created inside testthat::test_that() block, closed automatically test finishes running. Remember, always, use .env argument wrapping selenider_session() another function. elem_expect() also additional features inside testhat::test_that(). succeeds, call testthat::succeed(), fails, use testthat::fail() instead throwing error. allows tests continue running even elem_expect() fails.","code":"test_that(\"My test\", { # session will be opened here... open_url(\"https://www.r-project.org/\") s(\".random-class\") |> elem_expect(is_present) }) # and closed here! #> -- Failure: My test ------------------------------------------------------------ #> Condition failed after waiting for 4 seconds: #> `is_present` #> i `x` is not present. #> #> Where `x` is: #> A selenider element selecting: #> The first element with css selector \".random-class\". #> Error: #> ! Test failed"},{"path":"https://ashbythorpe.github.io/selenider/dev/articles/unit-testing.html","id":"using-selenider-with-shinytest2","dir":"Articles","previous_headings":"","what":"Using selenider with shinytest2","title":"Unit testing","text":"Since shinytest2 uses chromote backend, can used selenider. selenider can used add robust UI testing shinytest2, replacing unreliable uses AppDriver$expect_screenshot(). shinytest2 UI expectations (AppDriver$expect_text(), AppDriver$expect_html() AppDriver$expect_js()), include laziness implicit waiting selenider provides, making bit less reliable. Let’s create simple shiny app, consisting shiny::actionButton() shiny:: conditionalPanel(). panel shown button clicked odd number times, hidden otherwise. like test server-side processing button input done correctly, can using shinytest2. However, also like check panel visible correct times, shinytest2, use selenider instead. start selenider session using existing shinytest2::AppDriver object, supply driver argument selenider_session(): session <- selenider_session(driver = ) Note difference styles: selenider must specify tests explicitly, shinytest2 uses snapshot-based approach (specifying value want test omitting value expect ). advantages disadvantages approach: tests generally easier create update, little harder debug. want use snapshot-based style, can manually, e.g.: However, note tests longer wait certain period time value correct, since test unaware correct value .","code":"library(shiny) library(shinytest2) shiny_app <- shinyApp( ui = fluidPage( actionButton(\"button\", label = \"Click me!\"), conditionalPanel( condition = \"(input.button % 2) == 1\", p(\"Button has been clicked an odd number of times.\") ) |> tagAppendAttributes(id = \"condpanel\") ), server = function(input, output) { even <- reactive((input$button %% 2) == 0) exportTestValues(even = { even() }) } ) test_that(\"App works\", { app <- AppDriver$new(shiny_app) session <- selenider_session(driver = app) s(\"#condpanel\") |> elem_expect(is_invisible) app$click(\"button\") app$expect_values(export = \"even\") s(\"#condpanel\") |> elem_expect(is_visible) app$click(\"button\") app$expect_values(export = \"even\") s(\"#condpanel\") |> elem_expect(is_invisible) }) #> Can't compare snapshot to reference when testing interactively. #> i Run `devtools::test()` or `testthat::test_file()` to see changes. #> New path: /tmp/Rtmpj6ON6k/st2-1d607d7578b/001_.png #> Can't compare snapshot to reference when testing interactively. #> i Run `devtools::test()` or `testthat::test_file()` to see changes. #> New path: /tmp/Rtmpj6ON6k/st2-1d607d7578b/001.json #> Can't compare snapshot to reference when testing interactively. #> i Run `devtools::test()` or `testthat::test_file()` to see changes. #> New path: /tmp/Rtmpj6ON6k/st2-1d607d7578b/002_.png #> Can't compare snapshot to reference when testing interactively. #> i Run `devtools::test()` or `testthat::test_file()` to see changes. #> New path: /tmp/Rtmpj6ON6k/st2-1d607d7578b/002.json #> Test passed expect_snapshot(is_visible(s(\"#condpanel\")))"},{"path":"https://ashbythorpe.github.io/selenider/dev/articles/unit-testing.html","id":"using-selenider-with-github-actions","dir":"Articles","previous_headings":"","what":"Using selenider with Github Actions","title":"Unit testing","text":"complexity using selenider Github Actions depends backend use. like use chromote backend, shouldn’t need make special additions workflow files, can safely use something like r-lib’s R CMD CHECK action. chromote requires chrome installed, already case Github’s machines. want use selenium Github Actions, recommended make use docker. See https://github.com/SeleniumHQ/docker-selenium information. example, following lines Github Actions yaml file start selenium server (version 4.15.0), supporting Firefox, port 4444. recommend using “shm-size” argument make sure don’t run memory. download Firefox start Selenium server port 4444. Automating browser Selenium consists two parts: server client. default, selenider_session() tries setup , can stop happening using create_selenium_client() function, passing result driver argument selenider_session(). session can used usual. selenider longer able close selenium server, done automatically Github Action. information, see setup Github Actions workflow selenium: https://github.com/ashbythorpe/selenider/blob/main/.github/workflows/R-CMD-check-selenium.yaml https://github.com/ashbythorpe/selenider/blob/main/tests/testthat/helper-session.R","code":"services: selenium: image: selenium/standalone-firefox:4.15.0-20231108 ports: - 4444:4444 options: >- --shm-size=\"2g\" session <- selenider_session( \"selenium\", browser = \"firefox\" driver = create_selenium_client( browser = \"firefox\", port = 4444 ) )"},{"path":"https://ashbythorpe.github.io/selenider/dev/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Ashby Thorpe. Author, maintainer, copyright holder.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Thorpe (2023). selenider: Concise, Lazy Reliable Wrapper 'chromote' 'RSelenium'. R package version 0.1.2.9000, https://ashbythorpe.github.io/selenider/, https://github.com/ashbythorpe/selenider.","code":"@Manual{, title = {selenider: Concise, Lazy and Reliable Wrapper for 'chromote' and 'RSelenium'}, author = {Ashby Thorpe}, year = {2023}, note = {R package version 0.1.2.9000, https://ashbythorpe.github.io/selenider/}, url = {https://github.com/ashbythorpe/selenider}, }"},{"path":"https://ashbythorpe.github.io/selenider/dev/index.html","id":"selenider","dir":"","previous_headings":"","what":"Concise, Lazy and Reliable Wrapper for chromote and RSelenium","title":"Concise, Lazy and Reliable Wrapper for chromote and RSelenium","text":"Traditionally, automating web browser often unreliable, especially using R. Programmers forced write verbose code, utilising inconsistent workarounds (using Sys.sleep() wait something happen). selenider aims make web testing scraping R much simpler, providing wrapper either chromote selenium. inspired Java’s Selenide Python’s Selene. Code reliability reproducibility essential writing R code. selenider provides features make scripts work every time run, without extra code: Lazy elements: selenider try find element page absolutely necessary. definitions HTML elements separated existence page, allowing two converge absolutely necessary. selenider, HTML elements stored directions element page, rather element . much reliable alternative since webpage can constantly change, resulting elements becoming invalid creation use (e.g. dreaded StaleElementReferenceException Selenium). Automatic waiting: selenider automatically wait code work (e.g. waiting input exist clickable actually clicking ), allowing write scripts website always responds instantly interactions. selenider’s main focus API. design choices result concise yet expressive code easy read easy write: global session object results shorter, declarative code. also allows session created beginning script test, closed end. functions designed use pipe operator (|> %>%); elements can selected, tested operated single pipeline. elem_expect() powerful way specify test expectations, simple extensible syntax informative error messages. selenider compatible automated testing frameworks like testthat shinytest2.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/index.html","id":"installation","dir":"","previous_headings":"","what":"Installation","title":"Concise, Lazy and Reliable Wrapper for chromote and RSelenium","text":"Additionally, must install chromote selenium. recommend chromote, quicker easier get running. using selenium, must also Java installed. Finally, must web browser installed. chromote, Google Chrome required. selenium, browser can used, Firefox recommended.","code":"# Install selenider from CRAN install.packages(\"selenider\") # Or the development version from Github # install.packages(\"remotes\") remotes::install_github(\"ashbythorpe/selenider\") # Either: install.packages(\"chromote\") # Or: install.packages(\"selenium\")"},{"path":"https://ashbythorpe.github.io/selenider/dev/index.html","id":"usage","dir":"","previous_headings":"","what":"Usage","title":"Concise, Lazy and Reliable Wrapper for chromote and RSelenium","text":"following code navigates R project website, finds link CRAN mirror list, checks link correct, clicks link element. Now ’re mirror list page, let’s find link every CRAN mirror UK.","code":"library(selenider) open_url(\"https://www.r-project.org/\") s(\".row\") |> find_element(\"div\") |> find_elements(\"a\") |> elem_find(has_text(\"CRAN\")) |> elem_expect(attr_contains(\"href\", \"cran.r-project.org\")) |> elem_click() s(\"dl\") |> find_elements(\"dt\") |> elem_find(has_text(\"UK\")) |> find_element(xpath = \"./following-sibling::dd\") |> find_elements(\"tr\") |> elem_expect(has_at_least(1)) |> as.list() |> lapply( \\(x) x |> find_element(\"a\") |> elem_attr(\"href\") ) #> [[1]] #> [1] \"https://www.stats.bris.ac.uk/R/\" #> #> [[2]] #> [1] \"https://cran.ma.imperial.ac.uk/\""},{"path":"https://ashbythorpe.github.io/selenider/dev/index.html","id":"vignettes","dir":"","previous_headings":"","what":"Vignettes","title":"Concise, Lazy and Reliable Wrapper for chromote and RSelenium","text":"Get started selenider, learn basics: vignette(\"selenider\"). Use selenider testthat, shinytest2 Github Actions: vignette(\"unit-testing\", package = \"selenider\"). Use selenider rvest: vignette(\"-rvest\", package = \"selenider\")","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/as.list.selenider_elements.html","id":null,"dir":"Reference","previous_headings":"","what":"Iterate over an element collection — as.list.selenider_elements","title":"Iterate over an element collection — as.list.selenider_elements","text":".list() transforms selenider_elements object list selenider_element objects. result can used loops higher order functions like lapply()/purrr::map() (whereas selenider_element object ). function stable. element_list() underlying function called element_list(). Use elem_flatmap() want select sub-elements element collection. elem_flatmap() allows apply function element selenider_elements object, provided function returns selenider_element/selenider_elements object . result flattened single selenider_elements object. benefit traditional iteration techniques laziness elements maintained, nothing fetched DOM. function experimental, work .f uses elem_flatten() (nested elem_flatmap()). elem_flatmap() works executing .f mock element, recording results x. means matter length x, .f evaluated , elem_flatmap() call. reason, .f invoke side effects anything selecting sub-elements. elem_flatmap() can essentially viewed map operation (e.g. lapply(), purrr::map()) followed flattening operation (elem_flatmap()). means : essentially equivalent : However, second approach done lazily. .list()/element_list() essentially turns x : list(x[[1]], x[[2]], ...) However, , length x must computed. means element inside list still lazy, list considered lazy, since number elements DOM may change. avoid problems, recommended use element list just created, make sure list accurate representation DOM used.","code":"x |> elem_flatmap(.f) x |> as.list() |> lapply(.f) |> elem_flatten()"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/as.list.selenider_elements.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Iterate over an element collection — as.list.selenider_elements","text":"","code":"# S3 method for selenider_elements as.list(x, timeout = NULL, ...) element_list(x, timeout = NULL) elem_flatmap(x, .f, ...)"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/as.list.selenider_elements.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Iterate over an element collection — as.list.selenider_elements","text":"x selenider_elements object. timeout long wait x exist computing length. ... Passed .f. .f function apply element x.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/as.list.selenider_elements.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Iterate over an element collection — as.list.selenider_elements","text":"elem_flatmap() returns selenider_element object. .list()/element_list() returns list selenider_element objects.","code":""},{"path":[]},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/as.list.selenider_elements.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Iterate over an element collection — as.list.selenider_elements","text":"","code":"html <- \"

Text 1<\/p> <\/div>

Text 2<\/p> <\/div>

Text 3<\/p> <\/div>

Text 4<\/p> <\/div> \" session <- minimal_selenider_session(html) divs <- ss(\"div\") # Get the

tag inside each div. divs |> elem_flatmap(\\(x) x |> find_element(\"p\")) # Or: p_tags <- divs |> elem_flatmap(find_element, \"p\") # To get the text in each tag, we can't use elem_flatmap() for (elem in as.list(p_tags)) { print(elem_text(elem)) } # Or: lapply(as.list(p_tags), elem_text) # \\dontshow{ # Clean up all connections and invalidate default chromote object selenider_cleanup() # }"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/as_pretty_dt.html","id":null,"dir":"Reference","previous_headings":"","what":"Format a difftime — as_pretty_dt","title":"Format a difftime — as_pretty_dt","text":"Internal method used print selenider_session() object. Designed used prettyunits::pretty_dt(), prettyunits::pretty_ms() prettyunits::pretty_sec().","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/as_pretty_dt.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Format a difftime — as_pretty_dt","text":"","code":"as_pretty_dt(x) # S3 method for pretty_dt cli_format(x, style = NULL, ...)"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/as_pretty_dt.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Format a difftime — as_pretty_dt","text":"x string representing difftime. style, ... used.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/as_pretty_dt.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Format a difftime — as_pretty_dt","text":"object class pretty_dt.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/as_pretty_dt.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Format a difftime — as_pretty_dt","text":"","code":"x <- as_pretty_dt(prettyunits::pretty_sec(10)) cli::cli_text(\"{.val x}\")"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/back.html","id":null,"dir":"Reference","previous_headings":"","what":"Move back or forward in browsing history — back","title":"Move back or forward in browsing history — back","text":"back() navigates previously opened URL, previously opened page browsing history. forward() reverses action back(), going next page browsing history.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/back.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Move back or forward in browsing history — back","text":"","code":"back(session = NULL) forward(session = NULL)"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/back.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Move back or forward in browsing history — back","text":"session selenider_session object. specified, global session object (result get_session()) used.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/back.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Move back or forward in browsing history — back","text":"session object, invisibly.","code":""},{"path":[]},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/back.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Move back or forward in browsing history — back","text":"","code":"session <- selenider_session() open_url(\"https://r-project.org\") open_url(\"https://www.tidyverse.org/\") back() forward() # \\dontshow{ # Clean up all connections and invalidate default chromote object selenider_cleanup() # }"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/close_session.html","id":null,"dir":"Reference","previous_headings":"","what":"Close a session object — close_session","title":"Close a session object — close_session","text":"Shut session object, closing browser stopping server. done automatically session set local session (happens default).","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/close_session.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Close a session object — close_session","text":"","code":"close_session(x = NULL)"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/close_session.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Close a session object — close_session","text":"x selenider_session object. omitted, local session object closed.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/close_session.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Close a session object — close_session","text":"Nothing.","code":""},{"path":[]},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/close_session.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Close a session object — close_session","text":"","code":"session <- selenider_session(local = FALSE) close_session(session) # \\dontshow{ # Clean up all connections and invalidate default chromote object selenider_cleanup(FALSE) # }"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/create_rselenium_client.html","id":null,"dir":"Reference","previous_headings":"","what":"Start a Selenium session using RSelenium — create_rselenium_client","title":"Start a Selenium session using RSelenium — create_rselenium_client","text":"recommend using create_selenium_client() instead function, RSelenium compatible newer versions Selenium.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/create_rselenium_client.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Start a Selenium session using RSelenium — create_rselenium_client","text":"","code":"create_rselenium_client(browser, port = 4444L, ...)"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/create_rselenium_client.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Start a Selenium session using RSelenium — create_rselenium_client","text":"browser browser use. port port run RSelenium . ... arguments pass RSelenium.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/create_rselenium_client.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Start a Selenium session using RSelenium — create_rselenium_client","text":"RSelenium::remoteDriver object. can passed selenider_session() place selenium::SeleniumSession object.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/current_url.html","id":null,"dir":"Reference","previous_headings":"","what":"Get the URL of the current page — current_url","title":"Get the URL of the current page — current_url","text":"Get full URL current page.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/current_url.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Get the URL of the current page — current_url","text":"","code":"current_url(session = NULL)"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/current_url.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Get the URL of the current page — current_url","text":"session Optionally, selenider_session object.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/current_url.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Get the URL of the current page — current_url","text":"string: current URL.","code":""},{"path":[]},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/current_url.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Get the URL of the current page — current_url","text":"","code":"session <- selenider_session() open_url(\"https://r-project.org\") current_url() # \\dontshow{ # Clean up all connections and invalidate default chromote object selenider_cleanup() # }"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_ancestors.html","id":null,"dir":"Reference","previous_headings":"","what":"Get the DOM family of an element — elem_ancestors","title":"Get the DOM family of an element — elem_ancestors","text":"Find elements certain relative position HTML element. elem_ancestors() selects every element contains current element (children, grand-children, etc.). elem_parent() selects element contains current element. elem_siblings() selects every element parent current element. elem_children() selects every element connected directly current element. elem_descendants() selects every element contained current element. current element direct parent, must type ancestor.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_ancestors.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Get the DOM family of an element — elem_ancestors","text":"","code":"elem_ancestors(x) elem_parent(x) elem_siblings(x) elem_children(x) elem_descendants(x)"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_ancestors.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Get the DOM family of an element — elem_ancestors","text":"x selenider_element object.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_ancestors.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Get the DOM family of an element — elem_ancestors","text":"functions return selenider_elements object, except elem_parent(), returns selenider_element object (since element can one parent).","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_ancestors.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Get the DOM family of an element — elem_ancestors","text":"functions except elem_children() elem_descendants() use XPath selectors, may slow, especially using chromote backend.","code":""},{"path":[]},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_ancestors.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Get the DOM family of an element — elem_ancestors","text":"","code":"html <- \"

<\/p>

<\/p>
<\/div> <\/div>

<\/div>

<\/p> <\/div> <\/body> <\/html> \" session <- minimal_selenider_session(html) current <- s(\"#current\") # Get all the names of an element collection elem_names <- function(x) { x |> as.list() |> vapply(elem_name, FUN.VALUE = character(1)) } current |> elem_ancestors() |> elem_expect(has_length(3)) |> elem_names() # html, div, body current |> elem_parent() |> elem_name() # div current |> elem_siblings() |> elem_expect(has_length(2)) |> elem_names() # div, p current |> elem_children() |> elem_expect(has_length(2)) |> elem_names() # p, div current |> elem_descendants() |> elem_expect(has_length(4)) |> elem_names() # p, div, p, br # \\dontshow{ # Clean up all connections and invalidate default chromote object selenider_cleanup() # }"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_attr.html","id":null,"dir":"Reference","previous_headings":"","what":"Get attributes of an element — elem_attr","title":"Get attributes of an element — elem_attr","text":"Get attribute selenider_element object. elem_attr() returns single attribute value string. elem_attrs() returns named list containing every attribute. elem_value() returns 'value' attribute.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_attr.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Get attributes of an element — elem_attr","text":"","code":"elem_attr(x, name, default = NULL, timeout = NULL) elem_attrs(x, timeout = NULL) elem_value(x, ptype = character(), timeout = NULL)"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_attr.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Get attributes of an element — elem_attr","text":"x selenider_element object. name name attribute get; string. default default value use attribute exist element. timeout time wait x exist. ptype type cast value . Useful value integer decimal number. default, value returned string.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_attr.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Get attributes of an element — elem_attr","text":"elem_attr() returns character vector length 1. elem_attrs() returns named list strings. return value elem_value() type ptype length 1.","code":""},{"path":[]},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_attr.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Get attributes of an element — elem_attr","text":"","code":"html <- \" R<\/a> \" session <- minimal_selenider_session(html) s(\"a\") |> elem_attr(\"href\") s(\"a\") |> elem_attrs() s(\"input[type='number']\") |> elem_value(ptype = integer()) # \\dontshow{ # Clean up all connections and invalidate default chromote object selenider_cleanup() # }"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_cache.html","id":null,"dir":"Reference","previous_headings":"","what":"Force an element to be collected and stored — elem_cache","title":"Force an element to be collected and stored — elem_cache","text":"selenider_element/selenider_elements objects generally lazy, meaning collect actual element DOM absolutely necessary, forget immediately . avoid situations DOM changes element collected, resulting errors unreliable behaviour. elem_cache() forces element collection elements collected stored, making eager rather lazy. useful operating element multiple times, since collecting element improve performance. However, must sure element change page using .","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_cache.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Force an element to be collected and stored — elem_cache","text":"","code":"elem_cache(x, timeout = NULL)"},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_cache.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Force an element to be collected and stored — elem_cache","text":"x selenider_element/selenider_elements object. timeout long wait element(s) exist collecting .","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_cache.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Force an element to be collected and stored — elem_cache","text":"modified version x. result elem_cache() can used normal selenider_element/selenider_elements object.","code":""},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_cache.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Force an element to be collected and stored — elem_cache","text":"functions make selenider elements permanently eager. sub-elements cached unless specified. example, consider following code: example, parent element class \".class1\" cached, child element class \".class2\" .","code":"s(\".class1\") |> elem_parent() |> elem_cache() |> find_element(\".class2\")"},{"path":[]},{"path":"https://ashbythorpe.github.io/selenider/dev/reference/elem_cache.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Force an element to be collected and stored — elem_cache","text":"","code":"html <- \"

<\/p>