Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save antonfefilov/e2d4725de127916ed6689503ca5bd16c to your computer and use it in GitHub Desktop.
Save antonfefilov/e2d4725de127916ed6689503ca5bd16c to your computer and use it in GitHub Desktop.
Saving and restoring Capybara sessions
module CapybaraSessionFactory
class SessionAlreadyDefined < StandardError; end
class SessionNotDefined < StandardError; end
# Parse a capybara session mode, which has the form
# "[driver]:[session_name]:[application_id]"
#
class CapybaraModeParser
attr_reader :driver, :session_name, :application_id
def initialize(mode)
@mode = mode
parse
end
private
def parse
@driver, @session_name, @application_id = @mode.split(':')
end
end
class Session
include Capybara::DSL
def initialize(name, setup_proc)
@name, @setup_proc = name, setup_proc
@is_setup = false
end
def setup?
@is_setup
end
def run_setup
return if setup?
instance_eval(&@setup_proc)
@is_setup = true
end
def capybara_session_name
"capybara_session_factory_#{@name}"
end
end
class << self
# Defines a new session and its setup code.
#
def define_session(name, &setup_proc)
raise SessionAlreadyDefined if sessions.key?(name)
sessions[name] = Session.new(name, setup_proc)
end
# Loads a session by name.
# The setup code is only run on the first load.
#
def load_session(name)
raise SessionNotDefined unless sessions.key?(name)
session = sessions[name]
Capybara.using_session(name) do
session.run_setup unless session.setup?
yield
end
end
private
def sessions
@sessions ||= {}
end
# Returns true if the capybara mode string corresponds to a
# CapybaraSessionFactory session.
#
def managed_session_mode?(mode)
parser = CapybaraModeParser.new(mode)
sessions.key?(parser.session_name)
end
end
end
class << Capybara
# Force capybara not to reset sessions that are managed by CapybaraSessionFactory.
# This let's sessions persist between tests.
#
# TODO: Capybara doesn't allow management of its "session_pool", so we need to monkey-path.
# Capybara should be updated with a session manager strategy so this is not required.
#
def reset_sessions!
session_pool.each do |mode, session|
session.reset! unless CapybaraSessionFactory.managed_session_mode?(mode)
end
end
alias_method :reset!, :reset_sessions!
end
# spec/features/dashboard_spec.rb
require 'spec_helper'
describe 'the dashboard' do
it 'has a welcome message' do
CapybaraSessionFactory.load_session('signed in') do
click_link 'Dashboard'
expect(page).to have_content 'Welcome to your dashboard'
end
end
end
# spec/sessions/signed_in.rb
CapybaraSessionFactory.define_session 'signed in' do
visit '/signup'
fill_in 'First name', with: 'Bob'
fill_in 'Email', with: '[email protected]'
fill_in 'Password', with: 'password'
click_button 'Sign Up'
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment