rspec-interactive 0.3.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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