Skip to content

Instantly share code, notes, and snippets.

@thiagoa
Last active March 14, 2025 16:03
Show Gist options
  • Save thiagoa/5e8287f8a863a3bc60293005c6c00785 to your computer and use it in GitHub Desktop.
Save thiagoa/5e8287f8a863a3bc60293005c6c00785 to your computer and use it in GitHub Desktop.
### Using TestOptions
#
# TestOptions is a Minitest extension that enables setup functionality
# at the test declaration level. This allows you to declaratively
# control test behavior through options passed at the class or
# individual test level.
#
# Use TestOptions for contextual/generic behavior that is not
# essential for understanding the test's purpose, such as VCR,
# freezing time, environment variables, etc.
#
# For example, if you've registered a VCR test helper with
# TestOptions, you can enable VCR for all tests in a Minitest file
# like this:
#
# include TestOptions.new(vcr: true)
#
# With `vcr: true`, VCR will run for all tests with the default
# options.
#
# You can also provide default VCR options that apply to all tests:
#
# include TestOptions.new(vcr: {match_requests_on: [:uri, :body]})
#
# Or override those options on a per-test basis:
#
# test "my test", vcr: {match_requests_on: [:uri, :method]} do
# # ...
# end
#
# If no options are provided for a test, the default options (if any)
# will be used.
#
# You can also opt out of VCR for an individual test if it was
# enabled for all tests:
#
# include TestOptions.new(vcr: true)
#
# test "my test", vcr: false do
# # ...
# end
#
# Or even, you can opt out of VCR for the entire file but enable it on
# a per-test basis:
#
# include TestOptions.new
#
# test "my test 1" do
# # ...
# end
#
# test "my test 2", vcr: true do
# # ...
# end
#
### Registering Helper Extensions
#
# You can extend TestOptions by registering custom helper extensions.
# A helper is a module or class that responds to the following
# methods:
#
# Note: `test_options` refers to either the test-specific options or
# the default options if no specific ones are provided. It includes
# configuration for all registered helper extensions.
#
# - `configure_extension(test_class, test_options)` — A hook that runs
# before each test's setup. Use it to include modules, extend the
# test class, or perform other setup actions. Check whether the
# relevant options for your extension are present in `test_options`
# before applying any configuration.
#
# - `setup(test_object, test_options)` — Runs during the Minitest
# `setup` phase, before each test. `test_object` is the current test
# instance.
#
# - `teardown(test_object, test_options)` — Runs during the Minitest
# `teardown` phase, after each test. Works similarly to
# `setup`.
class TestOptions < Module
module Core
def test(test_name, **options, &block)
test_name = test_name.gsub(/\s+/, "_")
if options.any?
test_options << [test_name, options.freeze]
end
super(test_name, &block)
end
def test_options_for(current_test_name)
current_test_name = current_test_name.sub(/^test_/, "")
test_options.find do |test_name, test_options|
if test_name == current_test_name
break test_options
end
end
end
def test_options
@test_options ||= []
end
end
class_attribute :helpers, default: []
def self.register_helper(helper)
helpers << helper
end
def initialize(**default_options)
default_options = default_options.freeze
define_singleton_method :included do |test_class|
test_class.extend Core
get_options = ->(test_object) do
test_name = test_object.name
test_options = test_object.class.test_options_for(test_name)
test_options || default_options || {}
end
self.class.helpers.each do |helper|
helper.configure_extension(test_class, default_options)
test_class.setup do
options = get_options.call(self)
helper.configure_extension(test_class, options)
helper.setup(self, options)
end
test_class.teardown do
options = get_options.call(self)
helper.teardown(self, options)
end
end
end
end
end
TestOptions.register_helper VcrTestOptionsExtension
TestOptions.register_helper FreezeTimeTestOptionsExtension
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment