• This repository has been archived on 28/May/2023
  • Stars
    star
    133
  • Rank 272,600 (Top 6 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 4 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

[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.

Gem Version

Foot Traffic 👯 👯‍♂️

A natural companion to an amazing 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.

require "foot_traffic"
using FootTraffic

FootTraffic::Session.start do |window|
  window.tab_thread { |tab| tab.goto "https://www.lewagon.com" }
  window.tab_thread { |tab| tab.goto "https://www.lewagon.com/berlin" }
  window.tab_thread { |tab| tab.goto "https://www.lewagon.com/paris" }
end

FootTraffic in action

Installation

Add this line to your application's Gemfile:

gem 'foot_traffic'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install foot_traffic

Can I use it in my Rails system tests?

Take a look at 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.

— Do you want to write integration tests without Selenium/ChromeDriver dependency?
— Use Cuprite and write specs with Capybara.

— 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?
— Use Foot Traffic and create a script that can be commited to the repo and run from Rake task.

Powered by Ferrum ❤️

At Le Wagon 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

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

Pure Ruby + pure Chrome—what's not to like?

Tutorial

Single thread

In a simplest case, all you need is to require "foot_traffic", put in the using FootTraffic to enable Ferrum refinements and proceed with opening a session block. It yields a window object that is an instance of Ferrum::Context (source). You can create a "tab" instance with a new_tab method and control it through Ferrum methods that are designed to be close to Puppeteer.

require "foot_traffic"
using FootTraffic

FootTraffic::Session.start do |window|
  window.new_tab.goto "https://www.lewagon.com"
  window.new_tab.goto "https://www.lewagon.com/berlin"

  paris = window.new_tab
  paris.goto "https://www.lewagon.com/paris"
  paris.at_css('[href="/paris/apply"]').click
  paris.at_css("#apply_first_name").focus.type("Alan")
  paris.at_css("#apply_last_name").focus.type("Turing", :Tab)
end

In 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.

Multiple threads

As 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).

require "foot_traffic"
using FootTraffic

FootTraffic::Session.start do |window|
  window.tab_thread { |tab| tab.goto "https://www.lewagon.com" }
  window.tab_thread { |tab| tab.goto "https://www.lewagon.com/berlin" }
  window.tab_thread do |paris|
    paris.goto "https://www.lewagon.com/paris"
    paris.at_css('[href="/paris/apply"]').click
    paris.at_css("#apply_first_name").focus.type("Alan")
    paris.at_css("#apply_last_name").focus.type("Turing", :Tab)
  end
end

Now, 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.

Setting duration

If your script does not end with a session block and you want to continue running your code—set the duration time for the session.

require "foot_traffic"
using FootTraffic

FootTraffic::Session.start(duration: 10) do |window|
  window.tab_thread { |tab| tab.goto "https://www.lewagon.com" }
  window.tab_thread { |tab| tab.goto "https://www.lewagon.com/berlin" }
  window.tab_thread do |paris|
    paris.goto "https://www.lewagon.com/paris"
    paris.at_css('[href="/paris/apply"]').click
    paris.at_css("#apply_first_name").focus.type("Alan")
    paris.at_css("#apply_last_name").focus.type("Turing", :Tab)
  end
end

Now the block will exit after 10 seconds.

Quit when all threads quit

If 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.

require "foot_traffic"
using FootTraffic

FootTraffic::Session.start(quit: true) do |window, pool|
  pool << window.tab_thread { |tab| tab.goto "https://www.lewagon.com" }
  pool << window.tab_thread { |tab| tab.goto "https://www.lewagon.com/berlin" }
  pool << window.tab_thread do |paris|
    paris.goto "https://www.lewagon.com/paris"
    paris.at_css('[href="/paris/apply"]').click
    paris.at_css("#apply_first_name").focus.type("Alan")
    paris.at_css("#apply_last_name").focus.type("Turing", :Tab)
  end
  pool.wait
end

Now, the session block will exit as soon as the last action in the last tab completes—your script can run further!

If 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.

Customizing

As this puts the strain on your system's resources, it makes sense to also use some of the Ferrum's options 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.

require "foot_traffic"
using FootTraffic

opts = {
  process_timeout: 10,
  timeout: 100,
  slowmo: 0.1,
  window_size: [1024, 768]
}

FootTraffic::Session.start(options: opts, quit: true, clones: 10) do |window, pool|
  pool << window.tab_thread { |tab| tab.goto "https://www.lewagon.com" }
  pool << window.tab_thread { |tab| tab.goto "https://www.lewagon.com/berlin" }
  pool << window.tab_thread { |paris|
    paris.goto "https://www.lewagon.com/paris"
    paris.at_css('[href="/paris/apply"]').click
    paris.at_css("#apply_first_name").focus.type("Alan")
    paris.at_css("#apply_last_name").focus.type("Turing", :Tab)
  }
  pool.wait
end

You 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 FootTraffic::ResourceOverloadError once ThreadError, RuntimeError, Errno::EMFILE, or Errno::ECONNRESET start propagating.

require "foot_traffic"
using FootTraffic

opts = {
  headless: true,
  process_timeout: 10,
  timeout: 100,
  slowmo: 0.1,
  window_size: [1024, 768]
}

begin
  FootTraffic::Session.start(options: opts, quit: true, clones: 10) do |window, pool|
    pool << window.tab_thread { |tab| tab.goto "https://www.lewagon.com" }
    pool << window.tab_thread { |tab| tab.goto "https://www.lewagon.com/berlin" }
    pool << window.tab_thread { |paris|
      paris.goto "https://www.lewagon.com/paris"
      paris.at_css('[href="/paris/apply"]').click
      paris.at_css("#apply_first_name").focus.type("Alan")
      paris.at_css("#apply_last_name").focus.type("Turing", :Tab)
    }
    pool.wait
  end
rescue FootTraffic::ResourceOverloadError
  puts "Oops..."
  exit(1)
end

Cookies

You 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:

require "concurrent" # concurrent-ruby

tokens = [] # imaginary array of auth tokens

cookies = Concurrent::Hash.new

opts = {
  headless: false, # Headless or not
  timeout: 300, # How long to wait for new tab to open, set for high value
  slowmo: 0.1, # How fast do you want bots to type
  window_size: [1200, 800]
}

FootTraffic::Session.start(options: opts, quit: true) do |window, pool|
  tokens.each do |token|
    sleep(1) # Need to sleep so we can propely save cookies
    pool << window.with_tab { |tab|
      tab.goto("https://example.com/sign_in/#{token}")
      cookies[token] = tab.cookies["_example_session"].value
    }
  end
  pool.wait
end

FootTraffic::Session.start(options: opts) do |window|
  tokens.each do |token|
    sleep(1) # Wait to properly load cookies
    window.with_tab do |tab|
      tab.cookies.clear
      tab.cookies.set(
        name: "_example_session",
        domain: "example.com",
        value: cookies[token]
      )
      tab.goto("https://example.com/protected_route")
    end
  end
end

Check out the examples folder to study some of the scripts above.

Development

After 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.

To 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.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/lewagon/foot_traffic.

License

The gem is available as open source under the terms of the MIT License.

More Repositories

1

dotfiles

Default configuration for Le Wagon's students
Shell
18,480
star
2

setup

Setup instructions for Le Wagon's students on their first day of Web Development Bootcamp
Ruby
17,095
star
3

data-setup

Setup instructions for Le Wagon's students on their first day of Data Science Bootcamp
Ruby
1,798
star
4

rails-templates

Jump start your Rails development with Le Wagon best practices
Ruby
658
star
5

wait-on-check-action

This action can be used to halt any workflow until required checks for a given ref (e.g., in a sibling workflow) pass successfully.
Ruby
332
star
6

rails-k8s-demo

[ABANDONED] Easy Rails on Kubernetes approach for Digital Ocean and a classic Rails stack: Puma, Redis, Sidekiq, Postgres, Action Cable, Webpacker. Helm 3 in production and docker-compose + dip (https://github.com/bibendi/dip) in development. Issues and PRs welcome.
Ruby
314
star
7

data-kit

Devenez Data-Scientist sur Le Wagon On Demand
Jupyter Notebook
201
star
8

rails-stylesheets

Stylesheets starting kit @LeWagon
SCSS
173
star
9

html-css-challenges

HTML / CSS challenges @LeWagon
CSS
110
star
10

bootstrap-boilerplate

A nice Bootstrap HTML boilerplate using official Bootstrap CDN to start coding right away!
HTML
109
star
11

awesome-navbars

navbar HTML/SCSS templates for Le Wagon's students
HTML
60
star
12

react-boilerplate

JavaScript
47
star
13

webpack-boilerplate

JavaScript
43
star
14

ruby-101

43
star
15

data-templates

Curated templates for data analysis / science
Jupyter Notebook
41
star
16

google-place-autocomplete

Exemple of Google Place Autocomplete Javascript API
HTML
40
star
17

ruby-101-challenges

Le Wagon Ruby Workshop
Ruby
37
star
18

wagon_rails

[DEPRECATED] Please use this 👉
Ruby
37
star
19

goodbye-jquery

IE lost the Browser war, time to move on. Thank you for your service jQuery 🙏
27
star
20

middleman-template

A Middleman template following @lewagon's best practices
Ruby
26
star
21

layouts-101

HTML
22
star
22

google-maps-autocomplete

Demo of Google Maps Autocomplete
Ruby
20
star
23

flats-boilerplate

17
star
24

rails-google-maps

Demo app integrating gmaps on a Flat model for Le Wagon's students.
Ruby
16
star
25

middleman-boilerplate

Middleman Boilerplate for @LeWagon Bootcamp
CSS
16
star
26

data-analytics-sprint

Jupyter Notebook
15
star
27

frontend-advanced-boilerplate

Advanced Middleman boilerplate for Le Wagon fullstack students
Ruby
14
star
28

www-sinatra

Old version of www.lewagon.com - Retired on Oct 22nd, 2015
CSS
13
star
29

rails-kickoff

[DEPRECATED] See lewagon/rails-templates 👉
12
star
30

surfcamp

Code & Surf Camp - Septembre 2014 - France
CSS
12
star
31

nightmare-boilerplate

JavaScript
11
star
32

seatrain

[ABANDONED] Developer-friendly DevOps/GitOps boilerplate generator for Rails applications. Sets up local Docker dev environment and generates Helm chart to deploy to Digital Ocean Kubernetes. No admin black-belt required!
Ruby
10
star
33

data-engineering-setup

Ruby
9
star
34

wagon-chat-api

Wagon chat API for challenge @LeWagon
Ruby
9
star
35

redux-boilerplate

JavaScript
9
star
36

nbresult

Testing Library for Jupyter Notebooks
Python
8
star
37

ux-ui-lectures

8
star
38

install-rails

🇫🇷 Installer Rails 5 (OSX => natif, Windows => Cloud 9)
8
star
39

product-design

7
star
40

recommendation-graphdb

Python
7
star
41

quay-github-actions-dispatch

A missing *secure* link between Quay.io build triggers and Github Action's repository_dispatch events
Go
7
star
42

ui-components

[DEPRECATED] Replaced by Le Wagon UI Kit
HTML
6
star
43

taxi-fare-interface

JavaScript
6
star
44

omniauth-kitt

OAuth Strategy for Kitt
Ruby
6
star
45

components-demo

HTML
6
star
46

garage-api

API for (repair shop) and cars 🚗
Ruby
6
star
47

python-scraping-workshop

Jupyter Notebook
6
star
48

chat-redux

JavaScript
5
star
49

recipes

Stable website to be scraped by @lewagon students
Ruby
5
star
50

google-maps-markers-static

Static example of Google Maps markers (with infowindows)
HTML
5
star
51

xbar

Ruby
5
star
52

google-maps-snazzy-themes

Snazzy Maps theme for Gmaps
5
star
53

redux-router-boilerplate

React + Redux + Router boilerplate
JavaScript
5
star
54

wagon-hunt

Ruby
5
star
55

opengraph

Moved to
Ruby
5
star
56

tips

Sharing tips with your classmates and future alumni
5
star
57

dictionary-api

Dictionary API for Web Dev Bootcamp
Ruby
5
star
58

conduct

Le Wagon's code of conduct for the Alumni Slack & Events
4
star
59

static-airbnb-redux

JavaScript
4
star
60

pg_bucket_import

[ABANDONED]
Ruby
4
star
61

python-101

Python
4
star
62

dribbble-cards

HTML
4
star
63

fullstack-images

Images for Le Wagon fullstack challenges
4
star
64

rails-watch-list

Ruby
4
star
65

amsterdam-drive-in

Le Wagon Amsterdam - Drive-in (students project)
HTML
4
star
66

install-middleman

🇫🇷 Comment installer Middleman sur Mac ou Windows
3
star
67

wikinimous

Simple anonymous Wiki with Rails
Ruby
3
star
68

html-css-sprint

Simple HTML/CSS Boilerplate for Le Wagon's course
HTML
3
star
69

blog-redux

JavaScript
3
star
70

chat-rails-redux

Ruby
3
star
71

matplotlib

Matplotlib examples for Le Wagon's Data Science bootcamp
Jupyter Notebook
3
star
72

html-demo

HTML
3
star
73

jekyll-boilerplate

The simplest Jekyll boilerplate possible with Bootstrap + FontAwesome CDN
Shell
3
star
74

git-101-boilerplate

Simple boilerplate to show how to use git with Github on @lewagon setup day.
HTML
3
star
75

amsterdam

Le Wagon Amsterdam - BSSA
CSS
3
star
76

react-giphy

JavaScript
3
star
77

cetetejecode-videos

Code présenté pendant les vidéos du MOOC
CSS
2
star
78

active-record-advanced

Ruby
2
star
79

animation-challenges

CSS and jQuery animation challenges for on-demand
CSS
2
star
80

trello-dashboard

Starter code for a JavaScript Trello Dashboard
CSS
2
star
81

rails-base-chrome-imagemagick

Shell
2
star
82

product-design-figma

2
star
83

rails-blog

Ruby
2
star
84

bookstore

Ruby
2
star
85

garage-redux

JavaScript
2
star
86

gosu-pong

Ruby
2
star
87

jekyll-iceme

Exemple of using Jekyll. Check out the branches for steps
CSS
2
star
88

stylus

Styl.us middleman project @LeWagon
HTML
2
star
89

restaurants_ajaxified_with_stimulus

Ruby
2
star
90

ml-api

Python
2
star
91

watchlist

Sampe rails app demonstrating Devise, S3, Mandrill & Sidekiq usage
Ruby
2
star
92

ecommerce-template

HTML
2
star
93

krails

[ABANDONED]
Ruby
2
star
94

taxi-fare-deep

Packaged neural network-based predictor for the Kaggle's NY Taxi Fare challenge
Jupyter Notebook
2
star
95

react-flats

JavaScript
2
star
96

fullstack-challenges-04-Rails-watch-list-specs

Ruby
2
star
97

intro-to-data-science-env

Setup environment for Introduction to Data Science challenges
Python
2
star
98

alfred-coworker

Automatically check-in people on Cobot as they connect to the Unifi Wifi
Ruby
2
star
99

taxi-fare

Python
1
star
100

sass-challenges

SASS challenges @LeWagon
1
star