rspec-interactive 0.3.1 → 0.7.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: e1f9390c00756ace39f74e3af9d78410cf2890000285035537c2ec6ce6b9e861
4
+ data.tar.gz: 8d07aec8a3fb5bc78849dbf403a3d30aeb1fec9bdbb38cef2204672e84ba3e9d
5
5
  SHA512:
6
- metadata.gz: 5e8c797fc2481ce1380d4f4056883b39479d6519be4f40af235979fd63dd23040eb7b62e1e80234156b805dead002837afb09ca4fb569f30c134cc97a6f5c6e3
7
- data.tar.gz: a49843eff84cb74c5a3de6da1758de16a947b9ce16e741253354d69b4082c871184ce7e8dd346cb51576e2484e44ca3950d5079d581cc211915d3f600e7b01fd
6
+ metadata.gz: 8f585f27c12cc58f2ccb1f8a9d1baf5c05139b58244cba1daf0228c7a9ff8bff71bc0ad79bc0d87ae27ac7580138cb3607ae51c84f3a11d2443fe03f8eaff183
7
+ data.tar.gz: d8bd001d9bd1be1b3cfa21ec69bcd70b9cb55f3d684bcc336f71e458aa20483a30ced6977c40e4055e9871698246e6e494f805a3fd210a3ec0310dfe72ef25e4
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rspec-interactive (0.3.1)
4
+ rspec-interactive (0.6.1)
5
5
  listen
6
6
  pry
7
7
  rspec-core
@@ -11,7 +11,7 @@ GEM
11
11
  specs:
12
12
  coderay (1.1.3)
13
13
  diff-lcs (1.4.4)
14
- ffi (1.15.0)
14
+ ffi (1.15.3)
15
15
  listen (3.5.1)
16
16
  rb-fsevent (~> 0.10, >= 0.10.3)
17
17
  rb-inotify (~> 0.9, >= 0.9.10)
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
@@ -12,23 +10,23 @@ Install:
12
10
  gem 'rspec-interactive'
13
11
  ```
14
12
 
15
- Add a config file named `.rspec_interactive_config`:
16
-
17
- ```json
18
- {
19
- "configs": [
20
- {
21
- "name": "spec",
22
- "watch_dirs": ["app"],
23
- "init_script": "spec/spec_helper.rb"
24
- },
25
- {
26
- "name": "spec_integration",
27
- "watch_dirs": ["app"],
28
- "init_script": "spec_integration/integration_helper.rb"
29
- }
30
- ]
31
- }
13
+ Add a config file which configures RSpec and RSpec::Interactive, for example `spec/rspec_interactive.rb`:
14
+
15
+ ```ruby
16
+ RSpec::Interactive.configure do |config|
17
+ # Directories to watch for file changes. When a file changes, it will be reloaded like `load 'path/to/file'`.
18
+ config.watch_dirs += ["app", "lib", "config"]
19
+
20
+ # This block is invoked on startup. RSpec configuration must happen here so that it can be reloaded before each test run.
21
+ config.configure_rspec do
22
+ require './spec/spec_helper.rb'
23
+ end
24
+
25
+ # Invoked whenever a class is loaded due to a file change in one of the watch_dirs.
26
+ config.on_class_load do |clazz|
27
+ clazz.clear_validators! if clazz < ApplicationRecord
28
+ end
29
+ end
32
30
  ```
33
31
 
34
32
  Update `.gitignore`
@@ -39,10 +37,10 @@ echo '.rspec_interactive_history' >> .gitignore
39
37
 
40
38
  ## Usage
41
39
 
42
- See more examples below.
40
+ Optionally, specify a config file with `--config <config-file>`. Optionally, specify arguments to an initial RSpec invocation with `--initial-rspec-args <initial-rspec-args>`.
43
41
 
44
42
  ```shell
45
- bundle exec rspec-interactive [spec name]
43
+ bundle exec rspec-interactive [--config <config-file>] [--initial-rspec-args <initial-rspec-args>]
46
44
  ```
47
45
 
48
46
  ## Example Usage In This Repo
@@ -53,6 +51,12 @@ Start:
53
51
  bundle exec rspec-interactive
54
52
  ```
55
53
 
54
+ Start with an initial RSpec invocation:
55
+
56
+ ```shell
57
+ bundle exec rspec-interactive --initial-rspec-args examples/passing_spec.rb
58
+ ```
59
+
56
60
  Run a passing spec:
57
61
 
58
62
  ```shell
@@ -100,3 +104,9 @@ Exit:
100
104
  ```shell
101
105
  bundle exec bin/test
102
106
  ```
107
+
108
+ ## Releasing
109
+
110
+ ```shell
111
+ ./scripts/release.sh <version>
112
+ ```
@@ -1,5 +1,20 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'optparse'
3
4
  require 'rspec-interactive'
4
5
 
5
- RSpec::Interactive.start(ARGV)
6
+ @options = {}
7
+ parser = OptionParser.new do |opts|
8
+ opts.banner = "Starts an interactive RSpec shell.\n\n"\
9
+ "Usage: bundle exec rspec-interactive [-c config-file] <initial-rspec-args>"
10
+
11
+ opts.on("-c", "--config <config-file>", String, "Optional. Path to the RSpec Interactive config file.") do |config_file|
12
+ @options[:config_file] = config_file
13
+ end
14
+
15
+ opts.on("-r", "--initial-rspec-args <initial-rspec-args>", String, "Optional. Arguments to pass to an initial invocation of RSpec.") do |initial_rspec_args|
16
+ @options[:initial_rspec_args] = initial_rspec_args
17
+ end
18
+ end.parse!
19
+
20
+ RSpec::Interactive.start(config_file: @options[:config_file], initial_rspec_args: @options[:initial_rspec_args])
@@ -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
@@ -3,9 +3,11 @@ require 'listen'
3
3
  require 'pry'
4
4
  require 'readline'
5
5
  require 'rspec/core'
6
+ require 'shellwords'
6
7
 
7
8
  require 'rspec-interactive/runner'
8
- require 'rspec-interactive/config_cache'
9
+ require 'rspec-interactive/config'
10
+ require 'rspec-interactive/rspec_config_cache'
9
11
  require 'rspec-interactive/input_completer'
10
12
  require 'rspec-interactive/rspec_command'
11
13
 
@@ -13,23 +15,18 @@ module RSpec
13
15
  module Interactive
14
16
 
15
17
  DEFAULT_HISTORY_FILE = '.rspec_interactive_history'.freeze
16
- DEFAULT_CONFIG_FILE = '.rspec_interactive_config'.freeze
17
18
 
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
19
+ class << self
20
+ attr_accessor :configuration
21
21
  end
22
22
 
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
23
+ def self.configure(&block)
24
+ block.call(@configuration)
25
+ end
28
26
 
29
- @config_file = config_file
27
+ def self.start(config_file: nil, initial_rspec_args: nil, history_file: DEFAULT_HISTORY_FILE, input_stream: STDIN, output_stream: STDOUT, error_stream: STDERR)
30
28
  @history_file = history_file
31
29
  @updated_files = []
32
- @results = []
33
30
  @stty_save = %x`stty -g`.chomp
34
31
  @mutex = Mutex.new
35
32
  @output_stream = output_stream
@@ -37,16 +34,25 @@ module RSpec
37
34
  @error_stream = error_stream
38
35
  @config_cache = RSpec::Interactive::ConfigCache.new
39
36
 
40
- @config = get_config(args[0])
41
- return 1 unless @config
37
+ @configuration = Configuration.new
38
+ load config_file if config_file
42
39
 
43
- load_rspec_config
44
40
  check_rails
45
41
  start_file_watcher
46
42
  trap_interrupt
47
43
  configure_pry
48
44
 
45
+ @init_thread = Thread.start {
46
+ @config_cache.record_configuration { @configuration.configure_rspec.call }
47
+ }
48
+
49
+ if initial_rspec_args
50
+ open(@history_file, 'a') { |f| f.puts "rspec #{initial_rspec_args.strip}" }
51
+ rspec Shellwords.split(initial_rspec_args)
52
+ end
53
+
49
54
  Pry.start
55
+ @listener.stop if @listener
50
56
  0
51
57
  end
52
58
 
@@ -58,10 +64,6 @@ module RSpec
58
64
  end
59
65
  end
60
66
 
61
- def self.load_rspec_config
62
- @config_cache.record_configuration(&rspec_configuration)
63
- end
64
-
65
67
  def self.configure_rspec
66
68
  RSpec.configure do |config|
67
69
  config.error_stream = @error_stream
@@ -69,61 +71,6 @@ module RSpec
69
71
  end
70
72
  end
71
73
 
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
74
  def self.trap_interrupt
128
75
  trap('INT') do
129
76
  if @runner
@@ -138,15 +85,15 @@ module RSpec
138
85
  end
139
86
 
140
87
  def self.start_file_watcher
141
- return unless @config["watch_dirs"]
88
+ return if @configuration.watch_dirs.empty?
142
89
 
143
90
  # Only polling seems to work in Docker.
144
- listener = Listen.to(*@config["watch_dirs"], only: /\.rb$/, force_polling: true) do |modified, added, removed|
91
+ @listener = Listen.to(*@configuration.watch_dirs, only: /\.rb$/, force_polling: true) do |modified, added, removed|
145
92
  @mutex.synchronize do
146
93
  @updated_files.concat(added + modified)
147
94
  end
148
95
  end
149
- listener.start
96
+ @listener.start
150
97
  end
151
98
 
152
99
  def self.configure_pry
@@ -164,5 +111,55 @@ module RSpec
164
111
 
165
112
  Pry.config.history_file = @history_file
166
113
  end
114
+
115
+ def self.rspec(args)
116
+ if @init_thread&.alive?
117
+ @init_thread.join
118
+ @init_thread = nil
119
+ end
120
+
121
+ parsed_args = args.flat_map do |arg|
122
+ if arg.match(/[\*\?\[]/)
123
+ glob = Dir.glob(arg)
124
+ glob.empty? ? [arg] : glob
125
+ else
126
+ [arg]
127
+ end
128
+ end
129
+
130
+ @mutex.synchronize do
131
+ @updated_files.uniq.each do |filename|
132
+ @output_stream.puts "modified: #{filename}"
133
+ trace = TracePoint.new(:class) do |tp|
134
+ @configuration.on_class_load.call(tp.self)
135
+ end
136
+ trace.enable
137
+ load filename
138
+ trace.disable
139
+ @output_stream.puts
140
+ end
141
+ @updated_files.clear
142
+ end
143
+
144
+ @runner = RSpec::Interactive::Runner.new(parsed_args)
145
+
146
+ # Stop saving history in case a new Pry session is started for debugging.
147
+ Pry.config.history_save = false
148
+
149
+ # RSpec::Interactive-specific RSpec configuration
150
+ configure_rspec
151
+
152
+ # Run.
153
+ exit_code = @runner.run
154
+ @runner = nil
155
+
156
+ # Reenable history
157
+ Pry.config.history_save = true
158
+
159
+ # Reset
160
+ RSpec.clear_examples
161
+ RSpec.reset
162
+ @config_cache.replay_configuration
163
+ end
167
164
  end
168
165
  end
@@ -0,0 +1,23 @@
1
+ module RSpec
2
+ module Interactive
3
+ class Configuration
4
+ attr_accessor :watch_dirs, :configure_rspec, :on_class_load
5
+
6
+ def initialize
7
+ @watch_dirs = []
8
+ @configure_rspec = proc {}
9
+ @on_class_load = proc {}
10
+ end
11
+
12
+ def configure_rspec(&block)
13
+ return @configure_rspec unless block
14
+ @configure_rspec = block
15
+ end
16
+
17
+ def on_class_load(&block)
18
+ return @on_class_load unless block
19
+ @on_class_load = block
20
+ end
21
+ end
22
+ end
23
+ 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.7.0"
6
6
  end
7
7
  end
@@ -0,0 +1,25 @@
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ if [ $# -ne 1 ]; then
6
+ echo "usage: $0 <version>" >&2
7
+ exit 1
8
+ fi
9
+
10
+ if [ -n "$(git status --porcelain)" ]; then
11
+ echo "error: stage or commit your changes." >&2
12
+ exit 1;
13
+ fi
14
+
15
+ NEW_VERSION=$1
16
+ CURRENT_VERSION=$(grep VERSION lib/rspec-interactive/version.rb | cut -d'"' -f 2)
17
+
18
+ echo "Updating from v$CURRENT_VERSION to v$NEW_VERSION. Press enter to continue."
19
+ read
20
+
21
+ sed -E -i '' "s/VERSION = \"[^\"]+\"/VERSION = \"$NEW_VERSION\"/g" lib/rspec-interactive/version.rb
22
+ gem build
23
+ gem push rspec-interactive-$NEW_VERSION.gem
24
+ bundle install
25
+ git commit -a -m "v$NEW_VERSION Release"
@@ -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.7.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-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec-core
@@ -72,18 +72,28 @@ 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
+ - scripts/release.sh
87
+ - scripts/run-with-local-dep.sh
83
88
  - tests/debugged_spec_test.rb
89
+ - tests/eof_test.rb
90
+ - tests/example_file_test.rb
84
91
  - tests/failing_spec_test.rb
85
- - tests/invalid_config_test.rb
92
+ - tests/glob_test.rb
93
+ - tests/line_number_test.rb
86
94
  - tests/passing_spec_test.rb
95
+ - tests/rerun_failed_specs_test.rb
96
+ - tests/spec_with_syntax_error_test.rb
87
97
  - tests/support/ansi.rb
88
98
  - tests/support/test_helper.rb
89
99
  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