Skip to content

Instantly share code, notes, and snippets.

@adenta
Created May 4, 2025 15:53
Show Gist options
  • Save adenta/5b243ea51138774f5afc91a521b564dc to your computer and use it in GitHub Desktop.
Save adenta/5b243ea51138774f5afc91a521b564dc to your computer and use it in GitHub Desktop.
https://magnitude.run / ruby minitest integration
# lib/generators/magnitude_generator.rb
class MagnitudeGenerator < Rails::Generators::Base
source_root File.expand_path('templates', __dir__)
desc "Installs Magnitude.run integration with Minitest DSL, helper, and example test"
def create_script_builder
template "script_builder.rb", "lib/magnitude/script_builder.rb"
end
def create_magnitude_helper
template "magnitude_helper.rb", "test/support/magnitude_helper.rb"
end
def inject_magnitude_helper
inject_into_file "test/test_helper.rb", after: /class ActionDispatch::SystemTestCase\n/ do
" include MagnitudeHelper\n"
end
end
def create_example_test
template "todo_test.rb", "test/system/todo_test.rb"
end
end
# lib/generators/templates/script_builder.rb
module Magnitude
class ScriptBuilder
def initialize(name)
@name = name
@steps = []
end
def step(description, &block)
builder = StepBuilder.new(description)
builder.instance_eval(&block) if block
@steps << builder
end
def to_script
lines = [
"import { test } from 'magnitude-test';",
"",
"test('#{@name}')"
]
@steps.each { |s| lines.concat(s.to_js) }
lines.join("\n")
end
end
class StepBuilder
def initialize(desc)
@desc = desc
@actions = []
end
def visit(url = nil)
target = url ? url.inspect : "process.env.BASE_URL!"
@actions << ".visit(\#{target})"
end
def fill(selector, text)
@actions << ".fill('\#{selector}', '\#{text}')"
end
def click(selector)
@actions << ".click('\#{selector}')"
end
def check(text)
@actions << ".check('\#{text}')"
end
def to_js
[" .step('\#{@desc}')"] + @actions.map { |a| " \#{a}" }
end
end
end
# lib/generators/templates/magnitude_helper.rb
require 'open3'
require 'json'
require 'tempfile'
require_relative '../../../lib/magnitude/script_builder'
module MagnitudeHelper
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def magnitude_test(name, &block)
test(name) do
result = MagnitudeHelper.run_magnitude(name, &block)
assert_equal "success", result["status"]
end
end
end
def self.run_magnitude(name, &block)
builder = Magnitude::ScriptBuilder.new(name)
builder.instance_eval(&block)
script = builder.to_script
file = Tempfile.new(["magnitude", ".mag.ts"], binmode: true)
file.write(script)
file.flush
server = Capybara.current_session.server
raise "Capybara server not running" unless server
base_url = "http://\#{server.host}:\#{server.port}"
cmd = %W[npx magnitude run \#{file.path} --base-url \#{base_url} --json]
stdout, stderr, status = Open3.capture3(*cmd)
file.close!
raise "Magnitude failed:\n\#{stderr}" unless status.success?
JSON.parse(stdout)
end
end
# lib/generators/templates/todo_test.rb
require "application_system_test_case"
class TodoTest < ApplicationSystemTestCase
magnitude_test "create and complete a todo" do
step "visit home page" do
visit
end
step "add a new todo" do
fill 'What needs to be done?', 'Buy milk'
click 'Add'
end
step "mark it complete" do
click 'input[type=checkbox]'
end
step "verify completion" do
check 'Buy milk is marked completed'
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment