{"id":13879506,"url":"https://github.com/lewagon/foot_traffic","last_synced_at":"2025-07-16T15:32:29.092Z","repository":{"id":47636311,"uuid":"263914028","full_name":"lewagon/foot_traffic","owner":"lewagon","description":"[NOT MAINTAINED] Pure Ruby DSL for Chrome scripting based on Ferrum. No Selenium required. Works from any script. Simulate web app usage scenarios in production or locally.","archived":true,"fork":false,"pushed_at":"2021-08-20T10:24:08.000Z","size":2745,"stargazers_count":133,"open_issues_count":0,"forks_count":6,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-11-18T00:59:27.619Z","etag":null,"topics":["automation","browser","chrome","gem","load-testing","qa","ruby","testing"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/foot_traffic","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lewagon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-14T12:51:37.000Z","updated_at":"2024-07-11T16:01:48.000Z","dependencies_parsed_at":"2022-09-12T11:20:18.710Z","dependency_job_id":null,"html_url":"https://github.com/lewagon/foot_traffic","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewagon%2Ffoot_traffic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewagon%2Ffoot_traffic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewagon%2Ffoot_traffic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewagon%2Ffoot_traffic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lewagon","download_url":"https://codeload.github.com/lewagon/foot_traffic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226143895,"owners_count":17580245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","browser","chrome","gem","load-testing","qa","ruby","testing"],"created_at":"2024-08-06T08:02:23.219Z","updated_at":"2024-11-24T08:31:25.155Z","avatar_url":"https://github.com/lewagon.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"[![Gem Version](https://badge.fury.io/rb/foot_traffic.svg)](https://badge.fury.io/rb/foot_traffic)\n\n# Foot Traffic :dancers: :dancing_men:\n\nA natural companion to an amazing [Ferrum](https://github.com/rubycdp/ferrum) gem that controls a fleet of Chrome windows and tabs and simulates real user interaction with your web applications from any Ruby scripts. Works naturally with your system Chrome or Chromium, no extra magic like Selenium or WebDrivers needed.\n\n```rb\nrequire \"foot_traffic\"\nusing FootTraffic\n\nFootTraffic::Session.start do |window|\n  window.tab_thread { |tab| tab.goto \"https://www.lewagon.com\" }\n  window.tab_thread { |tab| tab.goto \"https://www.lewagon.com/berlin\" }\n  window.tab_thread { |tab| tab.goto \"https://www.lewagon.com/paris\" }\nend\n```\n\n![FootTraffic in action](docs/in_action.gif)\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'foot_traffic'\n```\n\nAnd then execute:\n\n    $ bundle install\n\nOr install it yourself as:\n\n    $ gem install foot_traffic\n    \n## Can I use it in my Rails system tests?\n\nTake a look at [Cuprite](https://github.com/rubycdp/cuprite) that allows Capybara to work with Ferrum instead of Selenium/ChromeDriver. The goal of Foot Traffic is not Rspec integration, but to create simple and reproducible Ruby scripts that automate common usage scenarios for moderate load testing of production applications or as a visual aid in development.\n\n\n\u003e — Do you want to write integration tests without Selenium/ChromeDriver dependency?  \n\u003e — Use Cuprite and write specs with Capybara.\n\n\u003e — Do you want to make sure that your app handles Action Cable properly for multiple users and see the interaction play out before your eyes?  \n\u003e — Use Foot Traffic and create a script that can be commited to the repo and run from Rake task.\n\n## Powered by Ferrum :heart:\n\nAt [Le Wagon](https://www.lewagon.com) we love Ferrum and use it as a Selenium replacement to run system tests for our learning platforms. We highly recommend you do the same, and here's why\n\n\u003e Ferrum connects to the browser by CDP protocol and there's no Selenium/WebDriver/ChromeDriver dependency. The emphasis was made on a raw CDP protocol because Chrome allows you to do so many things that are barely supported by WebDriver because it should have consistent design with other browsers.—[Ferrum on GitHub](https://github.com/rubycdp/ferrum)\n\nPure Ruby + pure Chrome—what's not to like?\n\n## Tutorial\n\n### Single thread\n\nIn a simplest case, all you need is to `require \"foot_traffic\"`, put in the `using FootTraffic` to enable Ferrum [refinements](https://docs.ruby-lang.org/en/master/syntax/refinements_rdoc.html) and proceed with opening a session block. It yields a `window` object that is an instance of `Ferrum::Context` ([source](https://github.com/rubycdp/ferrum/blob/master/lib/ferrum/context.rb)). You can create a \"tab\" instance with a `new_tab` method and control it through Ferrum [methods](https://github.com/rubycdp/ferrum#examples) that are designed to be close to [Puppeteer](https://github.com/puppeteer/puppeteer/).\n\n```rb\nrequire \"foot_traffic\"\nusing FootTraffic\n\nFootTraffic::Session.start do |window|\n  window.new_tab.goto \"https://www.lewagon.com\"\n  window.new_tab.goto \"https://www.lewagon.com/berlin\"\n\n  paris = window.new_tab\n  paris.goto \"https://www.lewagon.com/paris\"\n  paris.at_css('[href=\"/paris/apply\"]').click\n  paris.at_css(\"#apply_first_name\").focus.type(\"Alan\")\n  paris.at_css(\"#apply_last_name\").focus.type(\"Turing\", :Tab)\nend\n```\n\nIn this case, all the instructions to the browser will run in a _single thread_ of execution, so you will see a browser performing actions consequetively.\n\n### Multiple threads\n\nAs Ferrum is thread-safe by design, you can execute the same scenario in parallel. `tab_thread` method opens a block that yields the instance of `Ferrum::Page` ([source](https://github.com/rubycdp/ferrum/blob/master/lib/ferrum/page.rb)).\n\n```rb\nrequire \"foot_traffic\"\nusing FootTraffic\n\nFootTraffic::Session.start do |window|\n  window.tab_thread { |tab| tab.goto \"https://www.lewagon.com\" }\n  window.tab_thread { |tab| tab.goto \"https://www.lewagon.com/berlin\" }\n  window.tab_thread do |paris|\n    paris.goto \"https://www.lewagon.com/paris\"\n    paris.at_css('[href=\"/paris/apply\"]').click\n    paris.at_css(\"#apply_first_name\").focus.type(\"Alan\")\n    paris.at_css(\"#apply_last_name\").focus.type(\"Turing\", :Tab)\n  end\nend\n```\n\nNow, all the tabs will run **in parallel** (with limits to Ruby concurrency model, of course). After the session block finishes execution, browser will stay open indefinitely—until you `Ctrl-C` the original script. That might be useful if you want to use Chrome Developer Tools on open pages.\n\n### Setting duration\n\nIf your script does not end with a session block and you want to continue running your code—set the duration time for the session.\n\n```rb\nrequire \"foot_traffic\"\nusing FootTraffic\n\nFootTraffic::Session.start(duration: 10) do |window|\n  window.tab_thread { |tab| tab.goto \"https://www.lewagon.com\" }\n  window.tab_thread { |tab| tab.goto \"https://www.lewagon.com/berlin\" }\n  window.tab_thread do |paris|\n    paris.goto \"https://www.lewagon.com/paris\"\n    paris.at_css('[href=\"/paris/apply\"]').click\n    paris.at_css(\"#apply_first_name\").focus.type(\"Alan\")\n    paris.at_css(\"#apply_last_name\").focus.type(\"Turing\", :Tab)\n  end\nend\n```\n\nNow the block will exit after 10 seconds.\n\n### Quit when all threads quit\n\nIf you don't want to guess the time for pages to stay open—you can use the `quit` parameter of session. Note that in that case, you need to wait for all your threads to exit. As a convenience, `session` block yields a second argument that is a primitive implementation of a thread pool.\n\n```rb\nrequire \"foot_traffic\"\nusing FootTraffic\n\nFootTraffic::Session.start(quit: true) do |window, pool|\n  pool \u003c\u003c window.tab_thread { |tab| tab.goto \"https://www.lewagon.com\" }\n  pool \u003c\u003c window.tab_thread { |tab| tab.goto \"https://www.lewagon.com/berlin\" }\n  pool \u003c\u003c window.tab_thread do |paris|\n    paris.goto \"https://www.lewagon.com/paris\"\n    paris.at_css('[href=\"/paris/apply\"]').click\n    paris.at_css(\"#apply_first_name\").focus.type(\"Alan\")\n    paris.at_css(\"#apply_last_name\").focus.type(\"Turing\", :Tab)\n  end\n  pool.wait\nend\n```\n\nNow, the session block will exit as soon as the last action in the last tab completes—your script can run further!\n\nIf you want to see how your website handles multiple concurrent visits—you can use the `clone` parameter that will open as many Chrome windows as you want and run the tab scenario in each of them.\n\n### Customizing\n\nAs this puts the strain on your system's resources, it makes sense to also use some of the Ferrum's [options](https://github.com/rubycdp/ferrum#customization) to set higher timeouts for Chrome startup and page loads. `slowmo` parameter might be particularly useful for simulating real user behavior, as it will add a small wait before executing each action, including sending keyboard keys.\n\n```rb\nrequire \"foot_traffic\"\nusing FootTraffic\n\nopts = {\n  process_timeout: 10,\n  timeout: 100,\n  slowmo: 0.1,\n  window_size: [1024, 768]\n}\n\nFootTraffic::Session.start(options: opts, quit: true, clones: 10) do |window, pool|\n  pool \u003c\u003c window.tab_thread { |tab| tab.goto \"https://www.lewagon.com\" }\n  pool \u003c\u003c window.tab_thread { |tab| tab.goto \"https://www.lewagon.com/berlin\" }\n  pool \u003c\u003c window.tab_thread { |paris|\n    paris.goto \"https://www.lewagon.com/paris\"\n    paris.at_css('[href=\"/paris/apply\"]').click\n    paris.at_css(\"#apply_first_name\").focus.type(\"Alan\")\n    paris.at_css(\"#apply_last_name\").focus.type(\"Turing\", :Tab)\n  }\n  pool.wait\nend\n```\n\nYou can also set the `headless` option to `true` to perform script in headless mode. If you open too many concurrent tabs, or the number of clones becomes too high—your system will run out of memory. To prevent that, Foot Traffic will raise the\n`FootTraffic::ResourceOverloadError` once `ThreadError`, `RuntimeError`, `Errno::EMFILE`, or `Errno::ECONNRESET` start propagating.\n\n```rb\nrequire \"foot_traffic\"\nusing FootTraffic\n\nopts = {\n  headless: true,\n  process_timeout: 10,\n  timeout: 100,\n  slowmo: 0.1,\n  window_size: [1024, 768]\n}\n\nbegin\n  FootTraffic::Session.start(options: opts, quit: true, clones: 10) do |window, pool|\n    pool \u003c\u003c window.tab_thread { |tab| tab.goto \"https://www.lewagon.com\" }\n    pool \u003c\u003c window.tab_thread { |tab| tab.goto \"https://www.lewagon.com/berlin\" }\n    pool \u003c\u003c window.tab_thread { |paris|\n      paris.goto \"https://www.lewagon.com/paris\"\n      paris.at_css('[href=\"/paris/apply\"]').click\n      paris.at_css(\"#apply_first_name\").focus.type(\"Alan\")\n      paris.at_css(\"#apply_last_name\").focus.type(\"Turing\", :Tab)\n    }\n    pool.wait\n  end\nrescue FootTraffic::ResourceOverloadError\n  puts \"Oops...\"\n  exit(1)\nend\n```\n\n### Cookies\n\nYou can also control cookies for each tab. Keep in mind that in this case you don't want all your actions to run entirely concurrently, as the values of cookies may leak between tabs. Here's an example on how to avoid it:\n\n```rb\nrequire \"concurrent\" # concurrent-ruby\n\ntokens = [] # imaginary array of auth tokens\n\ncookies = Concurrent::Hash.new\n\nopts = {\n  headless: false, # Headless or not\n  timeout: 300, # How long to wait for new tab to open, set for high value\n  slowmo: 0.1, # How fast do you want bots to type\n  window_size: [1200, 800]\n}\n\nFootTraffic::Session.start(options: opts, quit: true) do |window, pool|\n  tokens.each do |token|\n    sleep(1) # Need to sleep so we can propely save cookies\n    pool \u003c\u003c window.with_tab { |tab|\n      tab.goto(\"https://example.com/sign_in/#{token}\")\n      cookies[token] = tab.cookies[\"_example_session\"].value\n    }\n  end\n  pool.wait\nend\n\nFootTraffic::Session.start(options: opts) do |window|\n  tokens.each do |token|\n    sleep(1) # Wait to properly load cookies\n    window.with_tab do |tab|\n      tab.cookies.clear\n      tab.cookies.set(\n        name: \"_example_session\",\n        domain: \"example.com\",\n        value: cookies[token]\n      )\n      tab.goto(\"https://example.com/protected_route\")\n    end\n  end\nend\n```\n\nCheck out the [examples](https://github.com/lewagon/foot_traffic/tree/master/examples) folder to study some of the scripts above.\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/lewagon/foot_traffic.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flewagon%2Ffoot_traffic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flewagon%2Ffoot_traffic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flewagon%2Ffoot_traffic/lists"}