cyperful 0.1.9 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/cyperful/driver.rb +68 -32
- data/lib/cyperful/framework_helper.rb +7 -0
- data/lib/cyperful/framework_injections.rb +0 -38
- data/lib/cyperful/logger.rb +14 -0
- data/lib/cyperful/minitest.rb +30 -0
- data/lib/cyperful/railtie.rb +9 -0
- data/lib/cyperful/rspec.rb +24 -0
- data/lib/cyperful/test_parser.rb +78 -14
- data/lib/cyperful.rb +29 -1
- data/public/assets/{index--K1anXib.js → index-Bcd7GDsE.js} +2 -2
- data/public/assets/{index-Uj6YFMhM.css → index-D7cO27Pa.css} +1 -1
- data/public/assets/{syntax-highlighter-worker-BSRAN01e.js → syntax-highlighter-worker-Cumko8SL.js} +1 -1
- data/public/index.html +2 -2
- metadata +24 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f85e5c56fa2637a6533a9fb13e8afd07278704d03f5703ec1c25c30b13a9ae31
|
4
|
+
data.tar.gz: 8c96954f38fb306b73b5a3c0423a277aef1d4911e5ca854d47067499e87ab6e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f39bbdf382d5f93cb7a85ebbcfbb78e3921b9ee7ad156e98320a2beb77c2be8c6247ff78b4bfef8d0be0fecaadfab24f28584a288cc3a5b6aef35e40d50be79e
|
7
|
+
data.tar.gz: 5cdb29c74f89f38024aad8ab9cf4d345285bbeacd22a3bc353ee3baf044fdbb1c08684572565deb10b2e380ddb6a0c65a204252fa3370ab86a9f25c7f199a972
|
data/lib/cyperful/driver.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
class Cyperful::Driver
|
2
2
|
attr_reader :steps, :pausing
|
3
3
|
|
4
|
+
# delegate
|
5
|
+
private def logger
|
6
|
+
Cyperful.logger
|
7
|
+
end
|
8
|
+
private def config
|
9
|
+
Cyperful.config
|
10
|
+
end
|
11
|
+
|
4
12
|
SCREENSHOTS_DIR = File.join(Cyperful::ROOT_DIR, "public/screenshots")
|
5
13
|
|
6
14
|
def initialize
|
@@ -8,6 +16,12 @@ class Cyperful::Driver
|
|
8
16
|
|
9
17
|
@session = Capybara.current_session
|
10
18
|
raise "Could not find Capybara session" unless @session
|
19
|
+
unless @session.driver.is_a?(Capybara::Selenium::Driver)
|
20
|
+
raise "Cyperful only supports Selenium, got: #{@session.driver}"
|
21
|
+
end
|
22
|
+
unless @session.driver.browser.browser == :chrome
|
23
|
+
raise "Cyperful only supports Chrome, got: #{@session.driver.browser.browser}"
|
24
|
+
end
|
11
25
|
|
12
26
|
setup_api_server
|
13
27
|
end
|
@@ -17,8 +31,11 @@ class Cyperful::Driver
|
|
17
31
|
@test_name = test_name.to_sym
|
18
32
|
|
19
33
|
@source_filepath =
|
20
|
-
|
21
|
-
|
34
|
+
if Cyperful.rspec?
|
35
|
+
test_class.metadata.fetch(:absolute_file_path)
|
36
|
+
else
|
37
|
+
Object.const_source_location(test_class.name).first
|
38
|
+
end || raise("Could not find source file for #{test_class.name}")
|
22
39
|
|
23
40
|
reset_steps
|
24
41
|
|
@@ -61,7 +78,9 @@ class Cyperful::Driver
|
|
61
78
|
@steps =
|
62
79
|
Cyperful::TestParser.new(@test_class).steps_per_test.fetch(@test_name)
|
63
80
|
|
64
|
-
|
81
|
+
raise "No steps found in #{@test_class}:#{@test_name}" if @steps.blank?
|
82
|
+
|
83
|
+
editor_scheme = config.editor_scheme
|
65
84
|
|
66
85
|
@steps.each_with_index do |step, i|
|
67
86
|
step.merge!(
|
@@ -115,19 +134,29 @@ class Cyperful::Driver
|
|
115
134
|
Object.const_get(class_name)
|
116
135
|
end
|
117
136
|
|
118
|
-
def
|
137
|
+
def enqueue_reset
|
119
138
|
at_exit do
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
139
|
+
case Cyperful.test_framework
|
140
|
+
when :rspec
|
141
|
+
RSpec.configuration.reset # private API. this resets the test reporter
|
142
|
+
RSpec.configuration.start_time = RSpec::Core::Time.now # this needs to be reset
|
143
|
+
RSpec.world.reset # private API. this unloads constants and clears examples
|
144
|
+
RSpec::Core::Runner.invoke # this reloads and starts the test suite
|
145
|
+
when :minitest
|
146
|
+
# reload test-suite code on reset (for `setup_file_listener`)
|
147
|
+
# TODO: also reload dependent files
|
148
|
+
# NOTE: run_on_method will fail if test_name also changed
|
149
|
+
@test_class = reload_const(@test_class.name, @source_filepath)
|
150
|
+
|
151
|
+
# TODO
|
152
|
+
# if Cyperful.config.reload_source_files && defined?(Rails)
|
153
|
+
# Rails.application.reloader.reload!
|
154
|
+
# end
|
155
|
+
|
156
|
+
Minitest.run_one_method(@test_class, @test_name)
|
157
|
+
else
|
158
|
+
raise "Unsupported test framework: #{Cyperful.test_framework}"
|
159
|
+
end
|
131
160
|
end
|
132
161
|
end
|
133
162
|
|
@@ -161,11 +190,11 @@ class Cyperful::Driver
|
|
161
190
|
# @source_file_listener = Listen.to(rails_directory) ...
|
162
191
|
# end
|
163
192
|
|
164
|
-
if
|
193
|
+
if config.reload_test_files
|
165
194
|
@file_listener&.stop
|
166
195
|
@file_listener =
|
167
196
|
Listen.to(test_directory) do |_modified, _added, _removed|
|
168
|
-
puts "Test files changed, resetting test..."
|
197
|
+
logger.puts "Test files changed, resetting test..."
|
169
198
|
|
170
199
|
# keep the same pause state after the reload
|
171
200
|
self.class.next_run_options = { pause_at_step: @pause_at_step }
|
@@ -178,13 +207,15 @@ class Cyperful::Driver
|
|
178
207
|
end
|
179
208
|
|
180
209
|
def print_steps
|
181
|
-
|
210
|
+
logger.plain("Found #{@steps.length} steps:")
|
182
211
|
@steps.each_with_index do |step, i|
|
183
|
-
|
184
|
-
|
185
|
-
|
212
|
+
logger.plain(
|
213
|
+
" #{
|
214
|
+
(i + 1).to_s.rjust(2)
|
215
|
+
}. #{step[:method]}: #{step[:line]}:#{step[:column]}",
|
216
|
+
)
|
186
217
|
end
|
187
|
-
|
218
|
+
logger.plain
|
188
219
|
end
|
189
220
|
|
190
221
|
# pending (i.e. test hasn't started), paused, running, passed, failed
|
@@ -267,7 +298,7 @@ class Cyperful::Driver
|
|
267
298
|
@current_step[:end_at] = (Time.now.to_f * 1000.0).to_i
|
268
299
|
@current_step[:status] = !error ? "passed" : "failed"
|
269
300
|
|
270
|
-
|
301
|
+
logger.plain(
|
271
302
|
" (#{@current_step[:end_at] - @current_step[:start_at]}ms)#{
|
272
303
|
error ? " FAILED" : ""
|
273
304
|
}",
|
@@ -293,7 +324,7 @@ class Cyperful::Driver
|
|
293
324
|
end
|
294
325
|
|
295
326
|
def drive_iframe
|
296
|
-
puts "Driving iframe..."
|
327
|
+
logger.puts "Driving iframe..."
|
297
328
|
|
298
329
|
# make sure a `within` block doesn't affect these commands
|
299
330
|
without_finder_scopes do
|
@@ -353,8 +384,13 @@ class Cyperful::Driver
|
|
353
384
|
end
|
354
385
|
|
355
386
|
private def skip_multi_sessions
|
356
|
-
|
357
|
-
warn "Skipped
|
387
|
+
if Capybara.current_session != @session
|
388
|
+
logger.warn "Skipped setup in non-default session"
|
389
|
+
# for debugging: {
|
390
|
+
# "current_session.mode": Capybara.current_session.mode,
|
391
|
+
# "session.mode": @session.mode,
|
392
|
+
# current_driver: Capybara.current_driver,
|
393
|
+
# }.to_json
|
358
394
|
return true
|
359
395
|
end
|
360
396
|
false
|
@@ -390,7 +426,7 @@ class Cyperful::Driver
|
|
390
426
|
end
|
391
427
|
|
392
428
|
def setup_api_server
|
393
|
-
@ui_server = Cyperful::UiServer.new(port:
|
429
|
+
@ui_server = Cyperful::UiServer.new(port: config.port)
|
394
430
|
|
395
431
|
@cyperful_origin = @ui_server.url_origin
|
396
432
|
|
@@ -422,7 +458,7 @@ class Cyperful::Driver
|
|
422
458
|
# The server appears to always stop on it's own,
|
423
459
|
# so we don't need to stop it within an `at_exit` or `Minitest.after_run`
|
424
460
|
|
425
|
-
puts "
|
461
|
+
logger.puts "server started: #{@cyperful_origin}"
|
426
462
|
end
|
427
463
|
|
428
464
|
def teardown(error = nil)
|
@@ -430,11 +466,11 @@ class Cyperful::Driver
|
|
430
466
|
@tracepoint = nil
|
431
467
|
|
432
468
|
if error&.is_a?(Cyperful::ResetCommand)
|
433
|
-
puts "
|
469
|
+
logger.puts "Resetting test (ignore any error logs)..."
|
434
470
|
|
435
471
|
@ui_server.notify(nil) # `break` out of the `loop` (see `UiServer#socket_open`)
|
436
472
|
|
437
|
-
|
473
|
+
enqueue_reset
|
438
474
|
return
|
439
475
|
end
|
440
476
|
|
@@ -461,10 +497,10 @@ class Cyperful::Driver
|
|
461
497
|
|
462
498
|
@ui_server.notify(nil) # `break` out of the `loop` (see `UiServer#socket_open`)
|
463
499
|
|
464
|
-
puts "
|
500
|
+
logger.puts "teardown complete. Waiting for command..."
|
465
501
|
# NOTE: this will raise an `Interrupt` if the user Ctrl+C's here
|
466
502
|
command = @step_pausing_queue.deq
|
467
|
-
|
503
|
+
enqueue_reset if command == :reset
|
468
504
|
ensure
|
469
505
|
@file_listener&.stop
|
470
506
|
@file_listener = nil
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module Cyperful::FrameworkHelper
|
2
|
+
# Disable default screenshot on failure b/c we handle them ourselves.
|
3
|
+
# https://github.com/rails/rails/blob/v7.0.1/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb#L156
|
4
|
+
def take_failed_screenshot
|
5
|
+
nil
|
6
|
+
end
|
7
|
+
end
|
@@ -1,29 +1,5 @@
|
|
1
1
|
require "action_dispatch/system_testing/driver"
|
2
2
|
|
3
|
-
# The Minitest test helper.
|
4
|
-
# TODO: support other test frameworks like RSpec
|
5
|
-
module Cyperful::SystemTestHelper
|
6
|
-
def setup
|
7
|
-
Cyperful.setup(self.class, self.method_name)
|
8
|
-
super
|
9
|
-
end
|
10
|
-
|
11
|
-
def teardown
|
12
|
-
error = passed? ? nil : failure
|
13
|
-
|
14
|
-
error = error.error if error.is_a?(Minitest::UnexpectedError)
|
15
|
-
|
16
|
-
Cyperful.teardown(error)
|
17
|
-
super
|
18
|
-
end
|
19
|
-
|
20
|
-
# Disable default screenshot on failure b/c we handle them ourselves.
|
21
|
-
# https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb#L156
|
22
|
-
def take_failed_screenshot
|
23
|
-
nil
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
3
|
# we need to override the some Capybara::Session methods because they
|
28
4
|
# control the top-level browser window, but we want them
|
29
5
|
# to control the iframe instead
|
@@ -94,19 +70,5 @@ module PrependSystemTestingDriver
|
|
94
70
|
end
|
95
71
|
ActionDispatch::SystemTesting::Driver.prepend(PrependSystemTestingDriver)
|
96
72
|
|
97
|
-
# if defined?(Minitest::Test)
|
98
|
-
# Minitest::Test::PASSTHROUGH_EXCEPTIONS << Cyperful::AbstractCommand
|
99
|
-
# end
|
100
|
-
|
101
|
-
# we need to allow the iframe to be embedded in the cyperful server
|
102
|
-
# TODO: use Rack middleware instead to support non-Rails apps
|
103
|
-
if defined?(Rails)
|
104
|
-
Rails.application.config.content_security_policy do |policy|
|
105
|
-
policy.frame_ancestors(:self, "localhost:#{Cyperful.config.port}")
|
106
|
-
end
|
107
|
-
else
|
108
|
-
warn "Cyperful: Rails not detected, skipping content_security_policy fix.\nThe Cyperful UI may not work correctly."
|
109
|
-
end
|
110
|
-
|
111
73
|
# fix for: Set-Cookie (SameSite=Lax) doesn't work when within an iframe with host 127.0.0.1
|
112
74
|
Capybara.server_host = "localhost"
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Cyperful::Logger
|
2
|
+
def puts(message = nil)
|
3
|
+
# call puts method from Kernel module
|
4
|
+
Kernel.puts("[cyperful] #{message}")
|
5
|
+
end
|
6
|
+
|
7
|
+
def warn(message = nil)
|
8
|
+
Kernel.warn("[cyperful] #{message}")
|
9
|
+
end
|
10
|
+
|
11
|
+
def plain(message = nil)
|
12
|
+
Kernel.puts(message)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "cyperful"
|
2
|
+
require "capybara/minitest"
|
3
|
+
|
4
|
+
module Cyperful::Minitest # rubocop:disable Style/ClassAndModuleChildren
|
5
|
+
module SystemTestHelper
|
6
|
+
include Cyperful::FrameworkHelper
|
7
|
+
|
8
|
+
def setup
|
9
|
+
Cyperful.setup(self.class, self.method_name)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
error = passed? ? nil : failure
|
15
|
+
|
16
|
+
error = error.error if error.is_a?(Minitest::UnexpectedError)
|
17
|
+
|
18
|
+
Cyperful.teardown(error)
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Cyperful.add_step_at_methods(
|
25
|
+
Capybara::Minitest::Assertions.instance_methods(false),
|
26
|
+
)
|
27
|
+
|
28
|
+
# if defined?(Minitest::Test)
|
29
|
+
# Minitest::Test::PASSTHROUGH_EXCEPTIONS << Cyperful::AbstractCommand
|
30
|
+
# end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# we need to allow the iframe to be embedded in the cyperful server
|
2
|
+
# TODO: consider Rack middleware instead to support non-Rails apps?
|
3
|
+
class Cyperful::Railtie < Rails::Railtie
|
4
|
+
config.after_initialize do |app|
|
5
|
+
app.config.content_security_policy do |policy|
|
6
|
+
policy.frame_ancestors(:self, "localhost:#{Cyperful.config.port}")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "cyperful"
|
2
|
+
|
3
|
+
RSpec.configure do |rspec_conf|
|
4
|
+
rspec_conf.include(Cyperful::FrameworkHelper)
|
5
|
+
|
6
|
+
rspec_conf.before(:example, type: :system) do
|
7
|
+
# e.g. class = `RSpec::ExampleGroups::MyTest`
|
8
|
+
# e.g. full_description = "my_test can visit root"
|
9
|
+
example = RSpec.current_example
|
10
|
+
Cyperful.setup(self.class, example.full_description)
|
11
|
+
end
|
12
|
+
|
13
|
+
rspec_conf.after(:example, type: :system) do
|
14
|
+
example = RSpec.current_example
|
15
|
+
error = example.exception # RSpec::Expectations::ExpectationNotMetError | nil
|
16
|
+
|
17
|
+
Cyperful.teardown(error)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Cyperful.add_step_at_methods(
|
22
|
+
Capybara::RSpecMatchers.instance_methods(false),
|
23
|
+
# Capybara::RSpecMatcherProxies.instance_methods(false),
|
24
|
+
)
|
data/lib/cyperful/test_parser.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
require "parser/current"
|
2
|
-
require "capybara/minitest"
|
1
|
+
require "parser/current" # TODO: switch to Prism?
|
3
2
|
|
4
3
|
class Cyperful::TestParser
|
5
4
|
# see docs for methods: https://www.rubydoc.info/github/jnicklas/capybara/Capybara/Session
|
6
5
|
@step_at_methods =
|
7
|
-
Capybara::Session::DSL_METHODS
|
8
|
-
Capybara::Minitest::Assertions.instance_methods(false) -
|
6
|
+
Capybara::Session::DSL_METHODS -
|
9
7
|
# exclude methods that don't have side-effects i.e. don't modify the page:
|
10
8
|
%i[
|
11
9
|
body
|
@@ -25,7 +23,7 @@ class Cyperful::TestParser
|
|
25
23
|
@step_at_methods_set ||= @step_at_methods.to_set
|
26
24
|
end
|
27
25
|
def self.add_step_at_methods(*mods_or_methods)
|
28
|
-
mods_or_methods.each do |mod_or_method|
|
26
|
+
mods_or_methods.flatten.each do |mod_or_method|
|
29
27
|
case mod_or_method
|
30
28
|
when Module
|
31
29
|
@step_at_methods +=
|
@@ -33,17 +31,81 @@ class Cyperful::TestParser
|
|
33
31
|
when String, Symbol
|
34
32
|
@step_at_methods << mod_or_method.to_sym
|
35
33
|
else
|
36
|
-
raise "Expected Module or
|
34
|
+
raise "Expected Module or string/symbol, got: #{mod_or_method.class.name}"
|
37
35
|
end
|
38
36
|
end
|
39
37
|
end
|
40
38
|
|
41
39
|
def initialize(test_class)
|
42
40
|
@test_class = test_class
|
43
|
-
|
41
|
+
|
42
|
+
@source_filepath =
|
43
|
+
if Cyperful.rspec?
|
44
|
+
test_class.metadata.fetch(:absolute_file_path)
|
45
|
+
else
|
46
|
+
Object.const_source_location(test_class.name).first
|
47
|
+
end
|
44
48
|
end
|
45
49
|
|
46
50
|
def steps_per_test
|
51
|
+
case Cyperful.test_framework
|
52
|
+
when :rspec
|
53
|
+
rspec_steps_per_test
|
54
|
+
when :minitest
|
55
|
+
minitest_steps_per_test
|
56
|
+
else
|
57
|
+
raise "Unsupported test framework: #{Cyperful.test_framework}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private def rspec_steps_per_test
|
62
|
+
ast = Parser::CurrentRuby.parse(File.read(@source_filepath))
|
63
|
+
|
64
|
+
example_per_line =
|
65
|
+
@test_class.examples.to_h do |example|
|
66
|
+
# file_path = example.metadata.fetch(:absolute_file_path)
|
67
|
+
[example.metadata.fetch(:line_number) || -1, example]
|
68
|
+
end
|
69
|
+
|
70
|
+
example_asts =
|
71
|
+
search_nodes(ast) do |node|
|
72
|
+
next nil unless node.type == :block
|
73
|
+
|
74
|
+
# assumption: the block is on the same line as the example, and there's at most one example per line
|
75
|
+
example = example_per_line[node.loc.begin.line]
|
76
|
+
next nil unless example
|
77
|
+
|
78
|
+
# "#{@test_class.name} #{example.description} #{}"
|
79
|
+
|
80
|
+
[example, node]
|
81
|
+
end
|
82
|
+
|
83
|
+
example_asts.to_h do |(example, block_node)|
|
84
|
+
out = []
|
85
|
+
block_node.children.each { |child| find_test_steps(child, out) }
|
86
|
+
|
87
|
+
# de-duplicate steps by line number
|
88
|
+
# TODO: support multiple steps on the same line. `step_per_line = ...` needs to be refactored
|
89
|
+
out = out.reverse.uniq { |step| step[:line] }.reverse
|
90
|
+
|
91
|
+
[example.full_description.to_sym, out]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private def search_nodes(parent, out = [], &block)
|
96
|
+
parent.children.each do |node|
|
97
|
+
next unless node.is_a?(Parser::AST::Node)
|
98
|
+
if (ret = block.call(node))
|
99
|
+
#
|
100
|
+
out << ret
|
101
|
+
else
|
102
|
+
search_nodes(node, out, &block)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
out
|
106
|
+
end
|
107
|
+
|
108
|
+
private def minitest_steps_per_test
|
47
109
|
ast = Parser::CurrentRuby.parse(File.read(@source_filepath))
|
48
110
|
|
49
111
|
test_class_name = @test_class.name.to_sym
|
@@ -57,7 +119,7 @@ class Cyperful::TestParser
|
|
57
119
|
end
|
58
120
|
end
|
59
121
|
unless system_test_class
|
60
|
-
raise "Could not find class #{test_class.name} in #{@source_filepath}"
|
122
|
+
raise "Could not find class #{@test_class.name} in #{@source_filepath}"
|
61
123
|
end
|
62
124
|
|
63
125
|
(
|
@@ -76,21 +138,21 @@ class Cyperful::TestParser
|
|
76
138
|
test_string = node.children[0].children[2].children[0]
|
77
139
|
|
78
140
|
# https://github.com/rails/rails/blob/66676ce499a32e4c62220bd05f8ee2cdf0e15f0c/activesupport/lib/active_support/testing/declarative.rb#L14C23-L14C61
|
79
|
-
|
141
|
+
test_name = :"test_#{test_string.gsub(/\s+/, "_")}"
|
80
142
|
|
81
143
|
block_node = node.children[2]
|
82
|
-
[
|
144
|
+
[test_name, block_node]
|
83
145
|
|
84
146
|
# e.g. `def test_my_test; ... end`
|
85
147
|
elsif node.type == :def && node.children[0].to_s.start_with?("test_")
|
86
|
-
|
148
|
+
test_name = node.children[0]
|
87
149
|
|
88
150
|
block_node = node.children[2]
|
89
|
-
[
|
151
|
+
[test_name, block_node]
|
90
152
|
end
|
91
153
|
end
|
92
154
|
.compact
|
93
|
-
.to_h do |
|
155
|
+
.to_h do |test_name, block_node|
|
94
156
|
out = []
|
95
157
|
block_node.children.each { |child| find_test_steps(child, out) }
|
96
158
|
|
@@ -98,7 +160,7 @@ class Cyperful::TestParser
|
|
98
160
|
# TODO: support multiple steps on the same line. `step_per_line = ...` needs to be refactored
|
99
161
|
out = out.reverse.uniq { |step| step[:line] }.reverse
|
100
162
|
|
101
|
-
[
|
163
|
+
[test_name, out]
|
102
164
|
end
|
103
165
|
end
|
104
166
|
|
@@ -122,6 +184,8 @@ class Cyperful::TestParser
|
|
122
184
|
end
|
123
185
|
|
124
186
|
children.each { |child| find_test_steps(child, out, depth) }
|
187
|
+
elsif ast.type == :begin || ast.type == :kwbegin || ast.type == :ensure
|
188
|
+
ast.children.each { |child| find_test_steps(child, out, depth) }
|
125
189
|
end
|
126
190
|
|
127
191
|
out
|
data/lib/cyperful.rb
CHANGED
@@ -33,11 +33,36 @@ module Cyperful
|
|
33
33
|
@config ||= Config.new
|
34
34
|
end
|
35
35
|
|
36
|
+
def self.logger
|
37
|
+
@logger ||= Cyperful::Logger.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.test_framework
|
41
|
+
@test_framework || raise("Cyperful not set up yet")
|
42
|
+
end
|
43
|
+
def self.rspec?
|
44
|
+
@test_framework == :rspec
|
45
|
+
end
|
46
|
+
def self.minitest?
|
47
|
+
@test_framework == :minitest
|
48
|
+
end
|
49
|
+
|
36
50
|
def self.current
|
37
51
|
@current
|
38
52
|
end
|
39
53
|
def self.setup(test_class, test_name)
|
40
|
-
|
54
|
+
@test_framework =
|
55
|
+
if defined?(RSpec::Core::ExampleGroup) &&
|
56
|
+
test_class < RSpec::Core::ExampleGroup
|
57
|
+
:rspec
|
58
|
+
elsif defined?(ActiveSupport::TestCase) &&
|
59
|
+
test_class < ActiveSupport::TestCase
|
60
|
+
:minitest
|
61
|
+
else
|
62
|
+
raise "Unsupported test framework for class: #{test_class.name}"
|
63
|
+
end
|
64
|
+
|
65
|
+
logger.puts "init test: \"#{rspec? ? test_name : "#{test_class}##{test_name}"}\""
|
41
66
|
|
42
67
|
# must set `Cyperful.current` before calling `async_setup`
|
43
68
|
@current ||= Cyperful::Driver.new
|
@@ -62,7 +87,10 @@ module Cyperful
|
|
62
87
|
end
|
63
88
|
|
64
89
|
require "cyperful/commands"
|
90
|
+
require "cyperful/logger"
|
65
91
|
require "cyperful/test_parser"
|
66
92
|
require "cyperful/ui_server"
|
67
93
|
require "cyperful/driver"
|
94
|
+
require "cyperful/framework_helper"
|
68
95
|
require "cyperful/framework_injections"
|
96
|
+
require "cyperful/railtie" if defined?(Rails::Railtie)
|