rspec-interactive 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44ae79866c1c58455a4c3002cd84f80b5a81ee65ff2256edee608179e8f0b4e1
4
- data.tar.gz: 189c67764a53a77ce517fbfe23f33a4a17fd368ce369a7ceb9bf423ce2cca3b1
3
+ metadata.gz: 04ebab7c57c976985c21b46ab99658f923f4c5b3550616db7c72f66d744b1e47
4
+ data.tar.gz: 56d0ca7636fa0efae3931708c88daaf226e766b098f743f7f888c6bb6d92f33b
5
5
  SHA512:
6
- metadata.gz: 5e8c797fc2481ce1380d4f4056883b39479d6519be4f40af235979fd63dd23040eb7b62e1e80234156b805dead002837afb09ca4fb569f30c134cc97a6f5c6e3
7
- data.tar.gz: a49843eff84cb74c5a3de6da1758de16a947b9ce16e741253354d69b4082c871184ce7e8dd346cb51576e2484e44ca3950d5079d581cc211915d3f600e7b01fd
6
+ metadata.gz: 0eea269e2f1a8f9a222baf3c707a8a7d418ddc6d2ea39c87da55c07490112e8909efd6f7c71d0ca01630cc6d894e397940c78406c3e206df0010ee90f52c8f75
7
+ data.tar.gz: d9080323163091dea28a8977d4b72c505e08e7f14b9c1f973ddf2086abb9d5f852f38e9760e20a6228e07480d99fac63508359a0f61d945452a93b063aa491ff
data/README.md CHANGED
@@ -1,7 +1,5 @@
1
1
  # RSpec Interactive
2
2
 
3
- **WARNING: New (or maybe old by now), experimental, untested and poorly documented. Use at your own risk.**
4
-
5
3
  An Pry console capable of running specs.
6
4
 
7
5
  ## Installation & Configuration
@@ -2,4 +2,13 @@
2
2
 
3
3
  require 'rspec-interactive'
4
4
 
5
- RSpec::Interactive.start(ARGV)
5
+ if ARGV.size == 0
6
+ RSpec::Interactive.start
7
+ elsif ARGV.size == 1
8
+ RSpec::Interactive.start(config_file: ARGV[0])
9
+ else
10
+ STDERR.puts "expected 0 or 1 argument, got: #{args.join(', ')}"
11
+ STDERR.puts ''
12
+ STDOUT.puts 'usage: rspec-interactive [config-file]'
13
+ exit 1
14
+ end
@@ -0,0 +1,11 @@
1
+ require 'rspec/core'
2
+
3
+ describe "other example spec" do
4
+ it "succeeds" do
5
+ expect(true).to eq(true)
6
+ end
7
+
8
+ it "succeeds again" do
9
+ expect(true).to eq(true)
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ require 'rspec/core'
2
+
3
+ describe "spec with syntax error" do
4
+ it "succeeds
5
+ end
@@ -5,7 +5,8 @@ require 'readline'
5
5
  require 'rspec/core'
6
6
 
7
7
  require 'rspec-interactive/runner'
8
- require 'rspec-interactive/config_cache'
8
+ require 'rspec-interactive/config'
9
+ require 'rspec-interactive/rspec_config_cache'
9
10
  require 'rspec-interactive/input_completer'
10
11
  require 'rspec-interactive/rspec_command'
11
12
 
@@ -13,23 +14,18 @@ module RSpec
13
14
  module Interactive
14
15
 
15
16
  DEFAULT_HISTORY_FILE = '.rspec_interactive_history'.freeze
16
- DEFAULT_CONFIG_FILE = '.rspec_interactive_config'.freeze
17
17
 
18
- class <<self
19
- attr_accessor :readline, :input_stream, :output_stream, :error_stream
20
- attr_accessor :config, :mutex, :config_cache, :runner, :results, :result, :updated_files
18
+ class << self
19
+ attr_accessor :configuration
21
20
  end
22
21
 
23
- def self.start(args, config_file: DEFAULT_CONFIG_FILE, history_file: DEFAULT_HISTORY_FILE, input_stream: STDIN, output_stream: STDOUT, error_stream: STDERR)
24
- if args.size > 1
25
- @error_stream.puts "expected 0 or 1 argument, got: #{args.join(', ')}"
26
- return 1
27
- end
22
+ def self.configure(&block)
23
+ block.call(@configuration)
24
+ end
28
25
 
29
- @config_file = config_file
26
+ def self.start(config_file: nil, history_file: DEFAULT_HISTORY_FILE, input_stream: STDIN, output_stream: STDOUT, error_stream: STDERR)
30
27
  @history_file = history_file
31
28
  @updated_files = []
32
- @results = []
33
29
  @stty_save = %x`stty -g`.chomp
34
30
  @mutex = Mutex.new
35
31
  @output_stream = output_stream
@@ -37,16 +33,16 @@ module RSpec
37
33
  @error_stream = error_stream
38
34
  @config_cache = RSpec::Interactive::ConfigCache.new
39
35
 
40
- @config = get_config(args[0])
41
- return 1 unless @config
36
+ @configuration = Configuration.new
37
+ @config_cache.record_configuration { load config_file if config_file }
42
38
 
43
- load_rspec_config
44
39
  check_rails
45
40
  start_file_watcher
46
41
  trap_interrupt
47
42
  configure_pry
48
43
 
49
44
  Pry.start
45
+ @listener.stop if @listener
50
46
  0
51
47
  end
52
48
 
@@ -58,10 +54,6 @@ module RSpec
58
54
  end
59
55
  end
60
56
 
61
- def self.load_rspec_config
62
- @config_cache.record_configuration(&rspec_configuration)
63
- end
64
-
65
57
  def self.configure_rspec
66
58
  RSpec.configure do |config|
67
59
  config.error_stream = @error_stream
@@ -69,61 +61,6 @@ module RSpec
69
61
  end
70
62
  end
71
63
 
72
- def self.rspec_configuration
73
- proc do
74
- if @config["init_script"]
75
- $LOAD_PATH << '.'
76
- require @config["init_script"]
77
- end
78
- end
79
- end
80
-
81
- def self.get_config(name = nil)
82
- unless @config_file && File.exists?(@config_file)
83
- @error_stream.puts "warning: config file not found, using default config" if @config_file
84
- return {}
85
- end
86
-
87
- begin
88
- configs = JSON.parse(File.read(@config_file))["configs"] || []
89
- rescue JSON::ParserError => e
90
- @error_stream.puts "failed to parse config file"
91
- return nil
92
- end
93
-
94
- if configs.empty?
95
- @error_stream.puts "no configs found in config file"
96
- return nil
97
- end
98
-
99
- # If a specific config was specified, use it.
100
- if name
101
- config = configs.find { |e| e["name"] == name }
102
- return config if config
103
- @error_stream.puts "invalid config: #{name}"
104
- return nil
105
- end
106
-
107
- # If there is only one, use it.
108
- if configs.size == 1
109
- return configs[0]
110
- end
111
-
112
- # Ask the user which to use.
113
- loop do
114
- names = configs.map { |e| e["name"] }
115
- names[0] = "#{names[0]} (default)"
116
- print "Multiple simultaneous configs not yet supported. Please choose a config. #{names.join(', ')}: "
117
- answer = @input_stream.gets.chomp
118
- if answer.strip.empty?
119
- return configs[0]
120
- end
121
- config = configs.find { |e| e["name"] == answer }
122
- return config if config
123
- @error_stream.puts "invalid config: #{answer}"
124
- end
125
- end
126
-
127
64
  def self.trap_interrupt
128
65
  trap('INT') do
129
66
  if @runner
@@ -138,15 +75,15 @@ module RSpec
138
75
  end
139
76
 
140
77
  def self.start_file_watcher
141
- return unless @config["watch_dirs"]
78
+ return if @configuration.watch_dirs.empty?
142
79
 
143
80
  # Only polling seems to work in Docker.
144
- listener = Listen.to(*@config["watch_dirs"], only: /\.rb$/, force_polling: true) do |modified, added, removed|
81
+ @listener = Listen.to(*@configuration.watch_dirs, only: /\.rb$/, force_polling: true) do |modified, added, removed|
145
82
  @mutex.synchronize do
146
83
  @updated_files.concat(added + modified)
147
84
  end
148
85
  end
149
- listener.start
86
+ @listener.start
150
87
  end
151
88
 
152
89
  def self.configure_pry
@@ -164,5 +101,50 @@ module RSpec
164
101
 
165
102
  Pry.config.history_file = @history_file
166
103
  end
104
+
105
+ def self.rspec(args)
106
+ parsed_args = args.flat_map do |arg|
107
+ if arg.match(/[\*\?\[]/)
108
+ glob = Dir.glob(arg)
109
+ glob.empty? ? [arg] : glob
110
+ else
111
+ [arg]
112
+ end
113
+ end
114
+
115
+ @mutex.synchronize do
116
+ @updated_files.uniq.each do |filename|
117
+ @output_stream.puts "modified: #{filename}"
118
+ trace = TracePoint.new(:class) do |tp|
119
+ @configuration.on_class_load.call(tp.self)
120
+ end
121
+ trace.enable
122
+ load filename
123
+ trace.disable
124
+ @output_stream.puts
125
+ end
126
+ @updated_files.clear
127
+ end
128
+
129
+ @runner = RSpec::Interactive::Runner.new(parsed_args)
130
+
131
+ # Stop saving history in case a new Pry session is started for debugging.
132
+ Pry.config.history_save = false
133
+
134
+ # RSpec::Interactive-specific RSpec configuration
135
+ configure_rspec
136
+
137
+ # Run.
138
+ exit_code = @runner.run
139
+ @runner = nil
140
+
141
+ # Reenable history
142
+ Pry.config.history_save = true
143
+
144
+ # Reset
145
+ RSpec.clear_examples
146
+ RSpec.reset
147
+ @config_cache.replay_configuration
148
+ end
167
149
  end
168
150
  end
@@ -0,0 +1,17 @@
1
+ module RSpec
2
+ module Interactive
3
+ class Configuration
4
+ attr_accessor :watch_dirs, :on_class_load
5
+
6
+ def initialize
7
+ @watch_dirs = []
8
+ @on_class_load = proc {}
9
+ end
10
+
11
+ def on_class_load(&block)
12
+ return @on_class_load unless block
13
+ @on_class_load = block
14
+ end
15
+ end
16
+ end
17
+ end
@@ -16,52 +16,7 @@ module RSpec::Interactive
16
16
  )
17
17
 
18
18
  def process
19
- parsed_args = args.flat_map do |arg|
20
- if arg.match(/[\*\?\[]/)
21
- glob = Dir.glob(arg)
22
- glob.empty? ? [arg] : glob
23
- else
24
- [arg]
25
- end
26
- end
27
-
28
- RSpec::Interactive.mutex.synchronize do
29
- RSpec::Interactive.updated_files.uniq.each do |filename|
30
- load filename
31
- end
32
- RSpec::Interactive.updated_files.clear
33
- end
34
-
35
- RSpec::Interactive.runner = RSpec::Interactive::Runner.new(parsed_args)
36
-
37
- # Stop saving history in case a new Pry session is started for debugging.
38
- Pry.config.history_save = false
39
-
40
- # RSpec::Interactive-specific RSpec configuration
41
- RSpec::Interactive.configure_rspec
42
-
43
- # Run.
44
- result = RSpec::Interactive.runner.run
45
- RSpec::Interactive.runner = nil
46
-
47
- # Save results
48
- RSpec::Interactive.results << result
49
- RSpec::Interactive.result = result
50
-
51
- # Reenable history
52
- Pry.config.history_save = true
53
-
54
- # Reset
55
- RSpec.clear_examples
56
- RSpec.reset
57
- RSpec::Interactive.config_cache.replay_configuration
58
-
59
- if !RSpec::Interactive.result.success && ::RSpec.configuration.example_status_persistence_file_path
60
- RSpec::Interactive.output_stream.puts "Rerun failures by executing the previous command with --only-failures or --next-failure."
61
- RSpec::Interactive.output_stream.puts
62
- end
63
-
64
- result
19
+ RSpec::Interactive.rspec(args)
65
20
  end
66
21
 
67
22
  Pry::Commands.add_command(::RSpec::Interactive::RSpecCommand)
@@ -2,29 +2,6 @@ require 'rspec/core'
2
2
 
3
3
  module RSpec
4
4
  module Interactive
5
- class ExampleGroupResult
6
- attr_accessor :group, :success
7
-
8
- def initialize(group, success)
9
- @group = group
10
- @success = success
11
- end
12
- end
13
-
14
- class Result
15
- attr_accessor :group_results, :success, :exit_code
16
-
17
- def initialize(group_results, success, exit_code)
18
- @group_results = group_results
19
- @success = success
20
- @exit_code = exit_code
21
- end
22
-
23
- def inspect(original = false)
24
- original ? super() : "<RSpec::Interactive::Result @success=#{@success}, @group_results=[...]>"
25
- end
26
- end
27
-
28
5
  class Runner
29
6
  def initialize(args)
30
7
  ::RSpec.world.wants_to_quit = false
@@ -46,28 +23,33 @@ module RSpec
46
23
  example_groups = ::RSpec.world.ordered_example_groups
47
24
  examples_count = ::RSpec.world.example_count(example_groups)
48
25
 
49
- result = ::RSpec.configuration.reporter.report(examples_count) do |reporter|
26
+ exit_code = ::RSpec.configuration.reporter.report(examples_count) do |reporter|
50
27
  ::RSpec.configuration.with_suite_hooks do
51
28
  if examples_count == 0 && ::RSpec.configuration.fail_if_no_examples
52
29
  return ::RSpec.configuration.failure_exit_code
53
30
  end
54
31
 
55
32
  group_results = example_groups.map do |example_group|
56
- group_success = example_group.run(reporter)
57
- ExampleGroupResult.new(example_group, group_success)
33
+ example_group.run(reporter)
58
34
  end
59
35
 
60
- success = group_results.all?(&:success)
36
+ success = group_results.all?
61
37
  exit_code = success ? 0 : 1
62
38
  if ::RSpec.world.non_example_failure
63
39
  success = false
64
40
  exit_code = ::RSpec.configuration.failure_exit_code
65
41
  end
66
42
  persist_example_statuses
67
- Result.new(group_results, success, exit_code)
43
+ exit_code
68
44
  end
69
45
  end
70
- result
46
+
47
+ if exit_code != 0 && ::RSpec.configuration.example_status_persistence_file_path
48
+ ::RSpec.configuration.output_stream.puts "Rerun failures by executing the previous command with --only-failures or --next-failure."
49
+ ::RSpec.configuration.output_stream.puts
50
+ end
51
+
52
+ exit_code
71
53
  end
72
54
 
73
55
  def quit
@@ -80,7 +62,7 @@ module RSpec
80
62
 
81
63
  ::RSpec::Core::ExampleStatusPersister.persist(::RSpec.world.all_examples, path)
82
64
  rescue SystemCallError => e
83
- RSpec::Interactive.error_stream.puts "warning: failed to write results to #{path}"
65
+ ::RSpec.configuration.error_stream.puts "warning: failed to write results to #{path}"
84
66
  end
85
67
  end
86
68
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module Interactive
5
- VERSION = "0.3.1"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Used to quickly test a development version of a gem in the current
4
+ # directory. Adds a local copy of the specified gem, at the specified
5
+ # path, to the current directory's Gemfile and executes the specified
6
+ # command. Upon completion, the Gemfile will be returned to its
7
+ # previous state.
8
+
9
+ if [ $# -ne 3 ]; then
10
+ echo "usage: $0 <gem-name> <path> <command>" >&2
11
+ exit 1
12
+ fi
13
+
14
+ GEM_NAME=$1
15
+ GEM_PATH=$2
16
+ COMMAND=$3
17
+
18
+ if [ -d $GEM_NAME ]; then
19
+ echo "directory exists: $GEM_NAME" >&2
20
+ exit 1
21
+ fi
22
+
23
+ OLD_DEP=$(grep "'$GEM_NAME'" Gemfile)
24
+ if [ $? -ne 0 ]; then
25
+ echo "$GEM_NAME not found in Gemfile" >&2
26
+ exit 1
27
+ fi
28
+
29
+ cp Gemfile Gemfile.save
30
+ cp Gemfile.lock Gemfile.lock.save
31
+ cp -R $GEM_PATH $GEM_NAME
32
+ sed -i '' -E "s/^( *gem '$GEM_NAME').*/\1, path: '$GEM_NAME'/g" Gemfile
33
+ $COMMAND
34
+ rm -rf $GEM_NAME
35
+ mv Gemfile.lock.save Gemfile.lock
36
+ mv Gemfile.save Gemfile
@@ -31,6 +31,43 @@ Test.test "debugged spec" do
31
31
 
32
32
  [2] pry(main)> exit
33
33
  EOF
34
+ end
35
+
36
+ Test.test "debugger does not add to history" do
37
+ await_prompt
38
+ input "rspec examples/debugged_spec.rb"
39
+ await_prompt
40
+ input '"this should not show up in history"'
41
+ await_prompt
42
+ input "exit"
43
+ await_prompt
44
+ input "exit"
45
+ await_termination
46
+ expect_output <<~EOF
47
+ [1] pry(main)> rspec examples/debugged_spec.rb
48
+
49
+ From: /Users/nickdower/Development/rspec-interactive/examples/debugged_spec.rb:6 :
50
+
51
+ 1: require 'rspec/core'
52
+ 2: require 'pry'
53
+ 3:
54
+ 4: describe "example spec" do
55
+ 5: it "gets debugged" do
56
+ => 6: binding.pry
57
+ 7: expect(true).to eq(true)
58
+ 8: end
59
+ 9: end
60
+
61
+ [1] pry(#<RSpec::ExampleGroups::ExampleSpec>)> "this should not show up in history"
62
+ => "this should not show up in history"
63
+ [2] pry(#<RSpec::ExampleGroups::ExampleSpec>)> exit
64
+ .
65
+
66
+ Finished in 0 seconds (files took 0 seconds to load)
67
+ 1 example, 0 failures
68
+
69
+ [2] pry(main)> exit
70
+ EOF
34
71
 
35
72
  expect_history <<~EOF
36
73
  rspec examples/debugged_spec.rb
data/tests/eof_test.rb ADDED
@@ -0,0 +1,10 @@
1
+ require_relative 'support/test_helper'
2
+
3
+ Test.test "exiting via ctrl-d" do
4
+ await_prompt
5
+ ctrl_d
6
+ await_termination
7
+ # No newlines in tests because we return false from tty? in test_helper.rb.
8
+ # In the real app, Pry will add a newline because tty? is true.
9
+ expect_output '[1] pry(main)> '
10
+ end
@@ -0,0 +1,54 @@
1
+ require_relative 'support/test_helper'
2
+
3
+ RSpec.configuration.backtrace_exclusion_patterns = [ /.*/ ]
4
+ RSpec.configuration.backtrace_inclusion_patterns = [ /examples\/failing_spec.rb/ ]
5
+
6
+ examples = Tempfile.new('examples')
7
+
8
+ config = Tempfile.new('config')
9
+ config.write <<~EOF
10
+ RSpec.configuration.example_status_persistence_file_path = "#{examples.path}"
11
+ EOF
12
+ config.rewind
13
+
14
+ Test.test "failing spec with example file", config_path: config.path do
15
+ await_prompt
16
+ input "rspec examples/failing_spec.rb"
17
+ await_prompt
18
+ input "exit"
19
+ await_termination
20
+ expect_output <<~EOF
21
+ [1] pry(main)> rspec examples/failing_spec.rb
22
+ F
23
+
24
+ Failures:
25
+
26
+ 1) example spec fails
27
+ Failure/Error: expect(true).to eq(false)
28
+
29
+ expected: false
30
+ got: true
31
+
32
+ (compared using ==)
33
+
34
+ Diff:
35
+ @@ -1 +1 @@
36
+ -false
37
+ +true
38
+ # ./examples/failing_spec.rb:5:in `block (2 levels) in <top (required)>'
39
+
40
+ Finished in 0 seconds (files took 0 seconds to load)
41
+ 1 example, 1 failure
42
+
43
+ Failed examples:
44
+
45
+ rspec ./examples/failing_spec.rb:4 # example spec fails
46
+
47
+ Rerun failures by executing the previous command with --only-failures or --next-failure.
48
+
49
+ [2] pry(main)> exit
50
+ EOF
51
+ end
52
+
53
+ config.close
54
+ examples.close
@@ -0,0 +1,18 @@
1
+ require_relative 'support/test_helper'
2
+
3
+ Test.test "passing spec" do
4
+ await_prompt
5
+ input "rspec examples/*passing*_spec.rb"
6
+ await_prompt
7
+ input "exit"
8
+ await_termination
9
+ expect_output <<~EOF
10
+ [1] pry(main)> rspec examples/*passing*_spec.rb
11
+ ....
12
+
13
+ Finished in 0 seconds (files took 0 seconds to load)
14
+ 4 examples, 0 failures
15
+
16
+ [2] pry(main)> exit
17
+ EOF
18
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'support/test_helper'
2
+
3
+ Test.test "running example group at line number" do
4
+ await_prompt
5
+ input "rspec examples/passing_spec.rb:8"
6
+ await_prompt
7
+ input "exit"
8
+ await_termination
9
+ expect_output <<~EOF
10
+ [1] pry(main)> rspec examples/passing_spec.rb:8
11
+ Run options: include {:locations=>{"./examples/passing_spec.rb"=>[8]}}
12
+ .
13
+
14
+ Finished in 0 seconds (files took 0 seconds to load)
15
+ 1 example, 0 failures
16
+
17
+ [2] pry(main)> exit
18
+ EOF
19
+ end
@@ -0,0 +1,90 @@
1
+ require_relative 'support/test_helper'
2
+
3
+ examples = Tempfile.new('examples')
4
+
5
+ config = Tempfile.new('config')
6
+ config.write <<~EOF
7
+ RSpec.configuration.example_status_persistence_file_path = "#{examples.path}"
8
+ EOF
9
+ config.rewind
10
+
11
+ Test.test "failing spec with example file", config_path: config.path do
12
+ await_prompt
13
+
14
+ RSpec.configuration.backtrace_exclusion_patterns = [ /.*/ ]
15
+ RSpec.configuration.backtrace_inclusion_patterns = [ /examples\/failing_spec.rb/ ]
16
+
17
+ input "rspec examples/failing_spec.rb examples/passing_spec.rb"
18
+ await_prompt
19
+
20
+ RSpec.configuration.backtrace_exclusion_patterns = [ /.*/ ]
21
+ RSpec.configuration.backtrace_inclusion_patterns = [ /examples\/failing_spec.rb/ ]
22
+
23
+ input "rspec examples/failing_spec.rb examples/passing_spec.rb --only-failures"
24
+ await_prompt
25
+ input "exit"
26
+ await_termination
27
+ expect_output <<~EOF
28
+ [1] pry(main)> rspec examples/failing_spec.rb examples/passing_spec.rb
29
+ F..
30
+
31
+ Failures:
32
+
33
+ 1) example spec fails
34
+ Failure/Error: expect(true).to eq(false)
35
+
36
+ expected: false
37
+ got: true
38
+
39
+ (compared using ==)
40
+
41
+ Diff:
42
+ @@ -1 +1 @@
43
+ -false
44
+ +true
45
+ # ./examples/failing_spec.rb:5:in `block (2 levels) in <top (required)>'
46
+
47
+ Finished in 0 seconds (files took 0 seconds to load)
48
+ 3 examples, 1 failure
49
+
50
+ Failed examples:
51
+
52
+ rspec ./examples/failing_spec.rb:4 # example spec fails
53
+
54
+ Rerun failures by executing the previous command with --only-failures or --next-failure.
55
+
56
+ [2] pry(main)> rspec examples/failing_spec.rb examples/passing_spec.rb --only-failures
57
+ Run options: include {:last_run_status=>"failed"}
58
+ F
59
+
60
+ Failures:
61
+
62
+ 1) example spec fails
63
+ Failure/Error: expect(true).to eq(false)
64
+
65
+ expected: false
66
+ got: true
67
+
68
+ (compared using ==)
69
+
70
+ Diff:
71
+ @@ -1 +1 @@
72
+ -false
73
+ +true
74
+ # ./examples/failing_spec.rb:5:in `block (2 levels) in <top (required)>'
75
+
76
+ Finished in 0 seconds (files took 0 seconds to load)
77
+ 1 example, 1 failure
78
+
79
+ Failed examples:
80
+
81
+ rspec ./examples/failing_spec.rb:4 # example spec fails
82
+
83
+ Rerun failures by executing the previous command with --only-failures or --next-failure.
84
+
85
+ [3] pry(main)> exit
86
+ EOF
87
+ end
88
+
89
+ config.close
90
+ examples.close
@@ -0,0 +1,30 @@
1
+ require_relative 'support/test_helper'
2
+
3
+ RSpec.configuration.backtrace_exclusion_patterns = [ /.*/ ]
4
+ RSpec.configuration.backtrace_inclusion_patterns = [ /`load_spec_files'/ ]
5
+
6
+ Test.test "spec with syntax error" do
7
+ await_prompt
8
+ input "rspec examples/spec_with_syntax_error.rb"
9
+ await_prompt
10
+ input "exit"
11
+ await_termination
12
+ expect_equal "output", output.gsub(/.+(?=(\\|\/)[a-z_-]+[.]rb:[0-9]+:.*)/, ' [...]'), <<~EOF
13
+ [1] pry(main)> rspec examples/spec_with_syntax_error.rb
14
+
15
+ An error occurred while loading ./examples/spec_with_syntax_error.rb.
16
+ Failure/Error: ::RSpec.configuration.load_spec_files
17
+
18
+ SyntaxError:
19
+ [...]/spec_with_syntax_error.rb:5: unterminated string meets end of file
20
+ [...]/spec_with_syntax_error.rb:5: syntax error, unexpected end-of-input, expecting `end'
21
+ [...]/configuration.rb:1607:in `load_spec_files'
22
+ No examples found.
23
+
24
+
25
+ Finished in 0 seconds (files took 0 seconds to load)
26
+ 0 examples, 0 failures, 1 error occurred outside of examples
27
+
28
+ [2] pry(main)> exit
29
+ EOF
30
+ end
@@ -109,9 +109,16 @@ module Readline
109
109
  Thread.current.kill
110
110
  end
111
111
 
112
+ response = @next_response[0]
113
+ @next_response.clear
114
+
112
115
  temp = Tempfile.new('input')
113
- temp.write("#{@next_response[0]}\n")
114
- temp.rewind
116
+
117
+ unless response.nil?
118
+ temp.write("#{response}\n")
119
+ temp.rewind
120
+ end
121
+
115
122
  input_read = File.new(temp.path, 'r')
116
123
  Readline.input = input_read
117
124
 
@@ -172,13 +179,17 @@ class Test
172
179
  @history_temp_file = Tempfile.new('history')
173
180
 
174
181
  @interactive_thread = Thread.start do
175
- @result = RSpec::Interactive.start(
176
- ARGV,
177
- config_file: config_path,
178
- history_file: @history_temp_file.path,
179
- input_stream: STDIN,
180
- output_stream: @output_write,
181
- error_stream: @error_write)
182
+ begin
183
+ @result = RSpec::Interactive.start(
184
+ config_file: config_path,
185
+ history_file: @history_temp_file.path,
186
+ input_stream: STDIN,
187
+ output_stream: @output_write,
188
+ error_stream: @error_write)
189
+ ensure
190
+ RSpec.clear_examples
191
+ RSpec.reset
192
+ end
182
193
  end
183
194
 
184
195
  begin
@@ -212,6 +223,7 @@ class Test
212
223
  @history_temp_file.close
213
224
 
214
225
  Readline.reset
226
+ Pry.reset_defaults
215
227
  end
216
228
 
217
229
  def await_termination
@@ -231,6 +243,10 @@ class Test
231
243
  Readline.puts(string)
232
244
  end
233
245
 
246
+ def ctrl_d
247
+ Readline.ctrl_d
248
+ end
249
+
234
250
  def output
235
251
  @output_temp_file.rewind
236
252
  File.read(@output_temp_file.path).gsub("\e[0G", "")
@@ -251,20 +267,20 @@ class Test
251
267
  end
252
268
 
253
269
  def expect_output(expected)
254
- if expected != output
255
- raise "unexpected output:\n expected: #{expected.inspect}\n actual: #{output.inspect}"
256
- end
270
+ expect_equal("output", output, expected)
257
271
  end
258
272
 
259
273
  def expect_error_output(expected)
260
- if expected != error_output
261
- raise "unexpected error output:\n expected: #{expected.inspect}\n actual: #{error_output.inspect}"
262
- end
274
+ expect_equal("error output", error_output, expected)
263
275
  end
264
276
 
265
277
  def expect_result(expected)
266
- if expected != @result
267
- raise "unexpected result:\n expected: #{expected.inspect}\n actual: #{@result.inspect}"
278
+ expect_equal("result", @result, expected)
279
+ end
280
+
281
+ def expect_equal(name, actual, expected)
282
+ if expected != actual
283
+ raise "unexpected #{name}:\n expected: #{expected.inspect}\n actual: #{actual.inspect}"
268
284
  end
269
285
  end
270
286
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-interactive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Dower
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-18 00:00:00.000000000 Z
11
+ date: 2021-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec-core
@@ -72,18 +72,27 @@ files:
72
72
  - bin/test
73
73
  - examples/debugged_spec.rb
74
74
  - examples/failing_spec.rb
75
+ - examples/other_passing_spec.rb
75
76
  - examples/passing_spec.rb
77
+ - examples/spec_with_syntax_error.rb
76
78
  - lib/rspec-interactive.rb
77
- - lib/rspec-interactive/config_cache.rb
79
+ - lib/rspec-interactive/config.rb
78
80
  - lib/rspec-interactive/input_completer.rb
79
81
  - lib/rspec-interactive/rspec_command.rb
82
+ - lib/rspec-interactive/rspec_config_cache.rb
80
83
  - lib/rspec-interactive/runner.rb
81
84
  - lib/rspec-interactive/version.rb
82
85
  - rspec-interactive.gemspec
86
+ - run-with-local-dep.sh
83
87
  - tests/debugged_spec_test.rb
88
+ - tests/eof_test.rb
89
+ - tests/example_file_test.rb
84
90
  - tests/failing_spec_test.rb
85
- - tests/invalid_config_test.rb
91
+ - tests/glob_test.rb
92
+ - tests/line_number_test.rb
86
93
  - tests/passing_spec_test.rb
94
+ - tests/rerun_failed_specs_test.rb
95
+ - tests/spec_with_syntax_error_test.rb
87
96
  - tests/support/ansi.rb
88
97
  - tests/support/test_helper.rb
89
98
  homepage: https://github.com/nicholasdower/rspec-interactive
@@ -1,26 +0,0 @@
1
- require_relative 'support/test_helper'
2
-
3
- config = Tempfile.new('config')
4
- config.write '{'
5
- config.rewind
6
-
7
- Test.test "invalid config", config_path: config.path do
8
- await_termination
9
- expect_error_output <<~EOF
10
- failed to parse config file
11
- EOF
12
- expect_result 1
13
- end
14
- config.close
15
-
16
- config = Tempfile.new('config')
17
- config.write '{}'
18
- config.rewind
19
-
20
- Test.test "empty config", config_path: config.path do
21
- await_termination
22
- expect_error_output <<~EOF
23
- no configs found in config file
24
- EOF
25
- expect_result 1
26
- end