rainforest_ruby_runtime 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +35 -0
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -6
- data/README.md +142 -2
- data/Rakefile +26 -5
- data/bin/rainforest_test +47 -2
- data/lib/rainforest_ruby_runtime.rb +4 -5
- data/lib/rainforest_ruby_runtime/drivers/sauce.rb +22 -11
- data/lib/rainforest_ruby_runtime/drivers/selenium.rb +34 -4
- data/lib/rainforest_ruby_runtime/dsl.rb +16 -2
- data/lib/rainforest_ruby_runtime/runner.rb +39 -67
- data/lib/rainforest_ruby_runtime/test.rb +1 -18
- data/lib/rainforest_ruby_runtime/variables/{registery.rb → registry.rb} +6 -6
- data/lib/rainforest_ruby_runtime/variables/scope.rb +1 -1
- data/lib/rainforest_ruby_runtime/version.rb +1 -1
- data/rainforest_ruby_runtime.gemspec +16 -5
- data/sample_tests/empty.rb +1 -1
- data/spec/rainforest_test_spec.rb +89 -0
- data/spec/runner_spec.rb +132 -0
- data/spec/spec_helper.rb +20 -0
- metadata +74 -26
- data/.travis.yml +0 -12
- data/lib/rainforest_ruby_runtime/drivers/browser_stack.rb +0 -42
- data/lib/rainforest_ruby_runtime/drivers/testing_bot.rb +0 -34
- data/test/runner_test.rb +0 -212
- data/test/test_helper.rb +0 -8
@@ -1,5 +1,8 @@
|
|
1
1
|
module RainforestRubyRuntime
|
2
2
|
class DSL
|
3
|
+
include RSpec::Matchers
|
4
|
+
include Capybara::DSL
|
5
|
+
|
3
6
|
def initialize(callback: )
|
4
7
|
@callback = callback
|
5
8
|
end
|
@@ -8,14 +11,25 @@ module RainforestRubyRuntime
|
|
8
11
|
RainforestRubyRuntime::Test.new(id: id, title: title, callback: @callback, &block)
|
9
12
|
end
|
10
13
|
|
14
|
+
def step(options, &block)
|
15
|
+
RainforestRubyRuntime::Step.new(options.merge(callback: @callback), &block).tap(&:run)
|
16
|
+
end
|
17
|
+
|
11
18
|
def define_variable_scope(name, &block)
|
12
19
|
scope = Variables::Scope.new(name, &block)
|
13
|
-
Variables.
|
20
|
+
Variables.scope_registry.register(scope)
|
14
21
|
end
|
15
22
|
|
16
23
|
def run_code(code)
|
17
24
|
eval(code)
|
18
25
|
end
|
26
|
+
|
27
|
+
def method_missing(name, *args, &block)
|
28
|
+
if Variables.scope_registry.has_variable?(name)
|
29
|
+
Variables.scope_registry[name]
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
19
34
|
end
|
20
35
|
end
|
21
|
-
|
@@ -1,12 +1,15 @@
|
|
1
1
|
module RainforestRubyRuntime
|
2
2
|
class Runner
|
3
3
|
attr_reader :config_options, :logger
|
4
|
+
attr_accessor :browser
|
4
5
|
|
5
6
|
FAILURE_EXCEPTIONS = [
|
6
7
|
RSpec::Expectations::ExpectationNotMetError,
|
7
8
|
Capybara::ElementNotFound,
|
8
9
|
].freeze
|
9
10
|
|
11
|
+
BROWSERS = %w(chrome firefox ie edge safari).freeze
|
12
|
+
|
10
13
|
def initialize(options = {})
|
11
14
|
@config_options = options.dup.freeze
|
12
15
|
@step_variables = options[:step_variables]
|
@@ -14,64 +17,55 @@ module RainforestRubyRuntime
|
|
14
17
|
@logger = options.fetch(:logger) { Logger.new(StringIO.new) }
|
15
18
|
end
|
16
19
|
|
17
|
-
def run(
|
18
|
-
logger.debug "Running code:\n#{
|
19
|
-
Capybara.default_driver = :"#{
|
20
|
+
def run(codes)
|
21
|
+
logger.debug "Running code:\n#{codes.join('\n')}\nDriver: #{driver_type}"
|
22
|
+
Capybara.default_driver = :"#{driver_type}"
|
20
23
|
Capybara.default_max_wait_time = wait_time
|
21
24
|
|
22
|
-
|
23
|
-
setup_scope_registery!
|
25
|
+
setup_scope_registry!
|
24
26
|
|
25
27
|
dsl = RainforestRubyRuntime::DSL.new(callback: @callback)
|
26
28
|
|
27
|
-
|
28
|
-
if
|
29
|
-
|
29
|
+
tests = codes.map { |code| dsl.run_code(code) }
|
30
|
+
if tests.all? { |test| test.is_a?(Test) }
|
31
|
+
describe = driver_klass.new(config_options).to_rspec(tests)
|
32
|
+
run_rspec(describe)
|
30
33
|
else
|
31
|
-
raise WrongReturnValueError, test
|
34
|
+
raise WrongReturnValueError, tests.reject { |test| test.is_a?(Test) }
|
32
35
|
end
|
33
|
-
|
36
|
+
tests
|
34
37
|
ensure
|
35
38
|
terminate_session!
|
36
39
|
end
|
37
40
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
def run_rspec(describe)
|
42
|
+
if ENV['RUNTIME_ENV'] == 'test' && ENV['SHOW_OUTPUT'] != 'true'
|
43
|
+
# if we're in tests, don't mix output from here with tests output
|
44
|
+
# and don't include this describe block in the test count
|
45
|
+
describe.run
|
46
|
+
RSpec.world.example_groups.pop
|
47
|
+
else
|
48
|
+
RSpec.configure do |config|
|
49
|
+
config.color = true
|
50
|
+
config.formatter = :documentation
|
51
|
+
end
|
52
|
+
RSpec.configuration.reporter.report(RSpec.world.example_count([describe])) do |reporter|
|
53
|
+
describe.run(reporter)
|
44
54
|
end
|
45
|
-
rescue *FAILURE_EXCEPTIONS => e
|
46
|
-
payload = exception_to_payload e, status: 'failed'
|
47
|
-
rescue StandardError => e
|
48
|
-
payload = exception_to_payload e, status: 'error'
|
49
|
-
rescue SyntaxError, Exception => e
|
50
|
-
payload = exception_to_payload e, status: 'fatal_error'
|
51
55
|
end
|
52
|
-
|
53
|
-
payload ||= { status: 'passed' }
|
54
|
-
|
55
|
-
sid = fake_session_id || session_id
|
56
|
-
|
57
|
-
payload = payload.merge({
|
58
|
-
stdout: stdout,
|
59
|
-
stderr: stderr,
|
60
|
-
session_id: sid,
|
61
|
-
driver: driver,
|
62
|
-
})
|
63
|
-
|
64
|
-
|
65
|
-
logger.debug("Payload")
|
66
|
-
logger.debug(payload.inspect)
|
67
|
-
|
68
|
-
payload
|
69
56
|
end
|
70
57
|
|
71
|
-
def
|
58
|
+
def driver_type
|
72
59
|
ENV.fetch("CAPYBARA_DRIVER") { "selenium" }
|
73
60
|
end
|
74
61
|
|
62
|
+
def driver_klass
|
63
|
+
{
|
64
|
+
'selenium' => Drivers::Selenium,
|
65
|
+
'sauce' => Drivers::Sauce,
|
66
|
+
}.fetch(driver_type)
|
67
|
+
end
|
68
|
+
|
75
69
|
def current_browser
|
76
70
|
current_driver.browser
|
77
71
|
end
|
@@ -93,17 +87,6 @@ module RainforestRubyRuntime
|
|
93
87
|
})
|
94
88
|
end
|
95
89
|
|
96
|
-
def apply_config!
|
97
|
-
config = {
|
98
|
-
"selenium" => Drivers::Selenium,
|
99
|
-
"sauce" => Drivers::Sauce,
|
100
|
-
"testingbot" => Drivers::TestingBot,
|
101
|
-
"browser_stack" => Drivers::BrowserStack,
|
102
|
-
}.fetch(driver)
|
103
|
-
|
104
|
-
config.new(config_options).call
|
105
|
-
end
|
106
|
-
|
107
90
|
def current_driver
|
108
91
|
Capybara.current_session.driver
|
109
92
|
end
|
@@ -115,12 +98,12 @@ module RainforestRubyRuntime
|
|
115
98
|
elsif current_driver.respond_to?(:quit)
|
116
99
|
current_driver.quit
|
117
100
|
else
|
118
|
-
logger.warn "Cannot terminate session. Driver #{
|
101
|
+
logger.warn "Cannot terminate session. Driver #{driver_type}" and return
|
119
102
|
end
|
120
103
|
logger.debug "Session successfuly terminated"
|
121
104
|
rescue Selenium::WebDriver::Error::WebDriverError => e
|
122
105
|
# Ignore
|
123
|
-
logger.warn "Exception while terminating session. Driver #{
|
106
|
+
logger.warn "Exception while terminating session. Driver #{driver_type}. Class: #{e.class}"
|
124
107
|
logger.warn "#{e.message}\n#{e.backtrace.join("\n")}"
|
125
108
|
end
|
126
109
|
|
@@ -128,23 +111,12 @@ module RainforestRubyRuntime
|
|
128
111
|
ENV.fetch("CAPYBARA_WAIT_TIME", 20).to_i
|
129
112
|
end
|
130
113
|
|
131
|
-
def
|
132
|
-
previous_stdout, $stdout = $stdout, StringIO.new
|
133
|
-
previous_stderr, $stderr = $stderr, StringIO.new
|
134
|
-
yield
|
135
|
-
[$stdout.string, $stderr.string]
|
136
|
-
ensure
|
137
|
-
# Restore the previous value of stdout (typically equal to STDERR).
|
138
|
-
$stdout = previous_stdout
|
139
|
-
$stderr = previous_stderr
|
140
|
-
end
|
141
|
-
|
142
|
-
def setup_scope_registery!
|
114
|
+
def setup_scope_registry!
|
143
115
|
# TODO this should not be set globally, but passed in the DSL
|
144
116
|
if @step_variables.nil?
|
145
|
-
Variables.
|
117
|
+
Variables.scope_registry = Variables::Registry.new
|
146
118
|
else
|
147
|
-
Variables.
|
119
|
+
Variables.scope_registry = Variables::StaticVariableRegistry.new(@step_variables)
|
148
120
|
end
|
149
121
|
end
|
150
122
|
end
|
@@ -10,28 +10,11 @@ module RainforestRubyRuntime
|
|
10
10
|
@callback = callback
|
11
11
|
end
|
12
12
|
|
13
|
-
def step(options, &block)
|
14
|
-
step = Step.new(options.merge(callback: @callback), &block)
|
15
|
-
@steps << step
|
16
|
-
step.run
|
17
|
-
step
|
18
|
-
end
|
19
|
-
|
20
13
|
def run
|
21
|
-
extend RSpec::Matchers
|
22
|
-
extend Capybara::DSL
|
23
14
|
@callback.before_test(self)
|
24
|
-
|
15
|
+
@block.call
|
25
16
|
@callback.after_test(self)
|
26
17
|
end
|
27
|
-
|
28
|
-
def method_missing(name, *args, &block)
|
29
|
-
if Variables.scope_registery.has_variable?(name)
|
30
|
-
Variables.scope_registery[name]
|
31
|
-
else
|
32
|
-
super
|
33
|
-
end
|
34
|
-
end
|
35
18
|
end
|
36
19
|
|
37
20
|
class Step
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RainforestRubyRuntime
|
2
2
|
module Variables
|
3
|
-
class
|
3
|
+
class Registry
|
4
4
|
def initialize(variables = {})
|
5
5
|
@variables = {}
|
6
6
|
end
|
@@ -22,7 +22,7 @@ module RainforestRubyRuntime
|
|
22
22
|
attr_reader :variables
|
23
23
|
end
|
24
24
|
|
25
|
-
class
|
25
|
+
class StaticVariableRegistry
|
26
26
|
def initialize(variables)
|
27
27
|
@variables = variables.inject({}) do |variables, (name, var_and_values)|
|
28
28
|
scope = Scope.new(name)
|
@@ -47,12 +47,12 @@ module RainforestRubyRuntime
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
def self.
|
51
|
-
@
|
50
|
+
def self.scope_registry
|
51
|
+
@scope_registry ||= Registry.new
|
52
52
|
end
|
53
53
|
|
54
|
-
def self.
|
55
|
-
@
|
54
|
+
def self.scope_registry=(registry)
|
55
|
+
@scope_registry = registry
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
@@ -13,19 +13,30 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.homepage = "https://www.rainforestqa.com/"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
|
-
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f =~ %r(^vendor/sauce/) }
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.
|
22
|
-
|
21
|
+
spec.post_install_message = <<-EOS
|
22
|
+
Thanks for installing!
|
23
|
+
If you plan to run scripts against Sauce Labs, please run
|
24
|
+
`rainforest_test --prepare-sauce`
|
25
|
+
and set the SAUCE_USERNAME, SAUCE_ACCESS_KEY, and CAPYBARA_DRIVER
|
26
|
+
environment variables.
|
27
|
+
EOS
|
28
|
+
|
29
|
+
spec.add_development_dependency "pry"
|
30
|
+
spec.add_development_dependency "byebug"
|
31
|
+
spec.add_development_dependency "awesome_print"
|
32
|
+
spec.add_development_dependency "rspec_junit_formatter"
|
23
33
|
spec.add_dependency "sauce", "~> 3.7"
|
24
34
|
spec.add_dependency "sauce-connect", "~> 3.6"
|
25
|
-
spec.add_dependency "rspec
|
35
|
+
spec.add_dependency "rspec", "3.5.0"
|
26
36
|
spec.add_dependency "capybara", "~> 2.7.1"
|
27
37
|
spec.add_dependency "selenium-client", "~> 1.2.0"
|
28
38
|
spec.add_dependency "selenium-webdriver", "~> 3.3"
|
29
39
|
spec.add_dependency "net-http-persistent", "~> 3.0"
|
30
|
-
spec.add_dependency "
|
40
|
+
spec.add_dependency "bundler", "~> 1.16"
|
41
|
+
spec.add_dependency "rake", "~> 12.3"
|
31
42
|
end
|
data/sample_tests/empty.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
test(id: 1, title: "") do
|
1
|
+
test(id: 1, title: "empty") do
|
2
2
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require_relative './spec_helper'
|
3
|
+
|
4
|
+
module RainforestRubyRuntime
|
5
|
+
describe 'rainforest_test', show_output: true do
|
6
|
+
subject do
|
7
|
+
if browsers
|
8
|
+
Open3.capture2e("ruby bin/rainforest_test #{browsers} sample_tests/empty.rb")
|
9
|
+
else
|
10
|
+
Open3.capture2e('ruby bin/rainforest_test sample_tests/empty.rb')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'with no browsers' do
|
15
|
+
let(:browsers) { nil }
|
16
|
+
|
17
|
+
it 'defaults to chrome' do
|
18
|
+
output, status = subject
|
19
|
+
|
20
|
+
expect(status).to be_success
|
21
|
+
expect(output).to match(/chrome/)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with a browser' do
|
26
|
+
context 'from the whitelist' do
|
27
|
+
let(:browser) { Runner::BROWSERS.sample }
|
28
|
+
let(:browsers) { "--browsers #{browser}" }
|
29
|
+
|
30
|
+
it 'passes it to Runner' do
|
31
|
+
output, status = subject
|
32
|
+
|
33
|
+
expect(status).to be_success
|
34
|
+
expect(output).to match(browser)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'that is unknown' do
|
39
|
+
let(:browsers) { "--browsers opera" }
|
40
|
+
|
41
|
+
it 'exits with status 1' do
|
42
|
+
output, status = subject
|
43
|
+
|
44
|
+
expect(status).to_not be_success
|
45
|
+
expect(output).to match(/invalid option: #{browsers}/)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'with multiple browsers' do
|
51
|
+
context 'from the whitelist' do
|
52
|
+
let(:browser_values) { Runner::BROWSERS.sample(2) }
|
53
|
+
let(:browsers) { "--browsers #{browser_values.join(',')}" }
|
54
|
+
|
55
|
+
it 'passes them to Runner' do
|
56
|
+
output, status = subject
|
57
|
+
|
58
|
+
expect(status).to be_success
|
59
|
+
browser_values.each { |b| expect(output).to match(b) }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'that is unknown' do
|
64
|
+
let(:browsers) { "--browsers #{Runner::BROWSERS.sample},opera" }
|
65
|
+
|
66
|
+
it 'exits with status 1' do
|
67
|
+
output, status = subject
|
68
|
+
|
69
|
+
expect(status).to_not be_success
|
70
|
+
expect(output).to match(/invalid option: --browsers opera/)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'with multiple files' do
|
76
|
+
subject do
|
77
|
+
Open3.capture2e('ruby bin/rainforest_test sample_tests/empty.rb sample_tests/simple.rb')
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should work' do
|
81
|
+
output, status = subject
|
82
|
+
|
83
|
+
expect(status).to be_success
|
84
|
+
expect(output).to match(/\[1\] empty/)
|
85
|
+
expect(output).to match(/\[1\] My Sample Test/)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/spec/runner_spec.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require_relative './spec_helper'
|
2
|
+
|
3
|
+
module RainforestRubyRuntime
|
4
|
+
describe Runner do
|
5
|
+
let(:codes) { [read_sample('empty')] }
|
6
|
+
|
7
|
+
subject { Runner.new(browsers: %i(chrome)) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
allow(subject).to receive(:driver).and_return('selenium')
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#session_id" do
|
14
|
+
before { allow(subject).to receive(:current_driver) { OpenStruct.new(browser: OpenStruct.new(session_id: 'session')) } }
|
15
|
+
|
16
|
+
it "returns a session id" do
|
17
|
+
expect(subject.session_id).to eq('session')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#run" do
|
22
|
+
describe "with a limited browser set" do
|
23
|
+
before do
|
24
|
+
allow(subject).to receive(:driver_type).and_return('sauce')
|
25
|
+
expect_any_instance_of(Drivers::Sauce).to receive(:to_rspec) do |driver|
|
26
|
+
driver.send(:apply_config)
|
27
|
+
double(run: nil)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "applies the correct configuration" do
|
32
|
+
subject.run(codes)
|
33
|
+
expect(Sauce.get_config.browsers).to eq([['Windows 7', 'Chrome', 'latest']])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "for a rainforest test" do
|
38
|
+
let(:codes) { [read_sample('simple')] }
|
39
|
+
|
40
|
+
it "runs the content of the step" do
|
41
|
+
tests = subject.run(codes)
|
42
|
+
expect(tests).to all be_instance_of(Test)
|
43
|
+
expect($simple_test_was).to eq(:run)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "for another type of test" do
|
48
|
+
it "raises an exception" do
|
49
|
+
expect { subject.run(['']) }.to raise_error(WrongReturnValueError)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "with custom step variables" do
|
54
|
+
let(:codes) { [read_sample('step_variables')] }
|
55
|
+
|
56
|
+
it "makes the variable accessible in the test" do
|
57
|
+
subject.run(codes)
|
58
|
+
expect($step_variable_1_was).to_not be_nil
|
59
|
+
expect($step_variable_2_was).to match(/time is: .*/)
|
60
|
+
expect($step_variable_3_was).to eq('1')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "callbacks" do
|
66
|
+
let(:callback) do
|
67
|
+
Class.new do
|
68
|
+
attr_reader :before_steps, :before_tests, :after_steps, :after_tests
|
69
|
+
|
70
|
+
def initialize
|
71
|
+
@before_steps = []
|
72
|
+
@after_steps = []
|
73
|
+
@after_tests = []
|
74
|
+
@before_tests = []
|
75
|
+
end
|
76
|
+
|
77
|
+
def before_step(step)
|
78
|
+
@before_steps << step
|
79
|
+
end
|
80
|
+
|
81
|
+
def after_step(step)
|
82
|
+
@after_steps << step
|
83
|
+
end
|
84
|
+
|
85
|
+
def after_test(test)
|
86
|
+
@after_tests << test
|
87
|
+
end
|
88
|
+
|
89
|
+
def before_test(test)
|
90
|
+
@before_tests << test
|
91
|
+
end
|
92
|
+
end.new
|
93
|
+
end
|
94
|
+
|
95
|
+
let(:codes) { [read_sample('two_steps')] }
|
96
|
+
|
97
|
+
subject { Runner.new(browsers: %i(chrome), callback: callback) }
|
98
|
+
|
99
|
+
it "calls the right method on the callback object" do
|
100
|
+
subject.run(codes)
|
101
|
+
expect(callback.before_tests.size).to eq(1)
|
102
|
+
expect(callback.after_tests.size).to eq(1)
|
103
|
+
expect(callback.before_steps.size).to eq(2)
|
104
|
+
expect(callback.after_steps.size).to eq(2)
|
105
|
+
|
106
|
+
expect(callback.before_steps.map(&:id)).to eq([1, 2])
|
107
|
+
expect(callback.after_steps.map(&:id)).to eq([1, 2])
|
108
|
+
|
109
|
+
expect(callback.before_steps.map(&:action)).to eq(["action 1", "action 2"])
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "a partially define callback object" do
|
113
|
+
let(:callback) do
|
114
|
+
Class.new do
|
115
|
+
end.new
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should not raise a method missing exception" do
|
119
|
+
subject.run(codes)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def read_sample(name)
|
125
|
+
File.read(File.expand_path("../sample_tests/#{name}.rb", __dir__))
|
126
|
+
end
|
127
|
+
|
128
|
+
def format_step(code)
|
129
|
+
read_sample("one_step").gsub("#REPLACE", code)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|