rspec-interactive 0.3.0 → 0.6.1
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 +4 -4
- data/.gitignore +0 -1
- data/Gemfile.lock +2 -2
- data/README.md +31 -22
- data/bin/rspec-interactive +16 -1
- data/examples/other_passing_spec.rb +11 -0
- data/examples/spec_with_syntax_error.rb +5 -0
- data/lib/rspec-interactive.rb +72 -71
- data/lib/rspec-interactive/config.rb +23 -0
- data/lib/rspec-interactive/rspec_command.rb +1 -46
- data/lib/rspec-interactive/{config_cache.rb → rspec_config_cache.rb} +0 -0
- data/lib/rspec-interactive/runner.rb +12 -30
- data/lib/rspec-interactive/version.rb +1 -1
- data/scripts/release.sh +25 -0
- data/scripts/run-with-local-dep.sh +36 -0
- data/tests/debugged_spec_test.rb +41 -1
- data/tests/eof_test.rb +10 -0
- data/tests/example_file_test.rb +54 -0
- data/tests/failing_spec_test.rb +0 -3
- data/tests/glob_test.rb +18 -0
- data/tests/line_number_test.rb +19 -0
- data/tests/passing_spec_test.rb +0 -1
- data/tests/rerun_failed_specs_test.rb +90 -0
- data/tests/spec_with_syntax_error_test.rb +30 -0
- data/tests/support/test_helper.rb +76 -11
- metadata +14 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 858197f05a88cbac9b4acf36c6220a79c15bc008945fa87cef7c008e20ca172d
|
4
|
+
data.tar.gz: b9a34852edc5bc544e9117ebfef1c6190e7ecae73cb7a29e2929f82743e72ed5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec6835e7baeb24d4126edb542629529e308ab9ecd79a28697c03f8290a8c6b5d15bbe6fd645338e870df124a073638c45bab0f790f8bb09becfd4a613d995cc0
|
7
|
+
data.tar.gz: cbf961a6c0a60cfc3cced32778f34ebbf7ae3e97399c017148cbe88e1229f5d96b2ab6f374ad4bc68e6eaaf9e7f18013e5510cab76521f4d70c0e90cb485b126
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rspec-interactive (0.
|
4
|
+
rspec-interactive (0.6.0)
|
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.
|
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,38 +10,37 @@ Install:
|
|
12
10
|
gem 'rspec-interactive'
|
13
11
|
```
|
14
12
|
|
15
|
-
Add a config file
|
16
|
-
|
17
|
-
```
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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`
|
35
33
|
|
36
34
|
```shell
|
37
35
|
echo '.rspec_interactive_history' >> .gitignore
|
38
|
-
echo '.rspec_interactive_results' >> .gitignore
|
39
36
|
```
|
40
37
|
|
41
38
|
## Usage
|
42
39
|
|
43
|
-
|
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>`.
|
44
41
|
|
45
42
|
```shell
|
46
|
-
bundle exec rspec-interactive [
|
43
|
+
bundle exec rspec-interactive [--config <config-file>] [--initial-rspec-args <initial-rspec-args>]
|
47
44
|
```
|
48
45
|
|
49
46
|
## Example Usage In This Repo
|
@@ -54,6 +51,12 @@ Start:
|
|
54
51
|
bundle exec rspec-interactive
|
55
52
|
```
|
56
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
|
+
|
57
60
|
Run a passing spec:
|
58
61
|
|
59
62
|
```shell
|
@@ -101,3 +104,9 @@ Exit:
|
|
101
104
|
```shell
|
102
105
|
bundle exec bin/test
|
103
106
|
```
|
107
|
+
|
108
|
+
## Releasing
|
109
|
+
|
110
|
+
```shell
|
111
|
+
./scripts/release.sh <version>
|
112
|
+
```
|
data/bin/rspec-interactive
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
require 'optparse'
|
3
4
|
require 'rspec-interactive'
|
4
5
|
|
5
|
-
|
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])
|
data/lib/rspec-interactive.rb
CHANGED
@@ -3,32 +3,30 @@ 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/
|
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
|
|
12
14
|
module RSpec
|
13
15
|
module Interactive
|
14
16
|
|
15
|
-
|
16
|
-
CONFIG_FILE = '.rspec_interactive_config'.freeze
|
17
|
+
DEFAULT_HISTORY_FILE = '.rspec_interactive_history'.freeze
|
17
18
|
|
18
|
-
class <<self
|
19
|
-
attr_accessor :
|
20
|
-
attr_accessor :config, :stty_save, :mutex, :config_cache, :runner, :results, :result, :updated_files
|
19
|
+
class << self
|
20
|
+
attr_accessor :configuration
|
21
21
|
end
|
22
22
|
|
23
|
-
def self.
|
24
|
-
|
25
|
-
|
26
|
-
exit!(1)
|
27
|
-
end
|
23
|
+
def self.configure(&block)
|
24
|
+
block.call(@configuration)
|
25
|
+
end
|
28
26
|
|
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)
|
28
|
+
@history_file = history_file
|
29
29
|
@updated_files = []
|
30
|
-
@results = []
|
31
|
-
@config = get_config(args[0])
|
32
30
|
@stty_save = %x`stty -g`.chomp
|
33
31
|
@mutex = Mutex.new
|
34
32
|
@output_stream = output_stream
|
@@ -36,13 +34,24 @@ module RSpec
|
|
36
34
|
@error_stream = error_stream
|
37
35
|
@config_cache = RSpec::Interactive::ConfigCache.new
|
38
36
|
|
39
|
-
|
37
|
+
@configuration = Configuration.new
|
38
|
+
load config_file if config_file
|
39
|
+
|
40
|
+
@config_cache.record_configuration { @configuration.configure_rspec.call }
|
41
|
+
|
40
42
|
check_rails
|
41
43
|
start_file_watcher
|
42
44
|
trap_interrupt
|
43
45
|
configure_pry
|
44
46
|
|
47
|
+
if initial_rspec_args
|
48
|
+
open(@history_file, 'a') { |f| f.puts "rspec #{initial_rspec_args.strip}" }
|
49
|
+
rspec Shellwords.split(initial_rspec_args)
|
50
|
+
end
|
51
|
+
|
45
52
|
Pry.start
|
53
|
+
@listener.stop if @listener
|
54
|
+
0
|
46
55
|
end
|
47
56
|
|
48
57
|
def self.check_rails
|
@@ -53,10 +62,6 @@ module RSpec
|
|
53
62
|
end
|
54
63
|
end
|
55
64
|
|
56
|
-
def self.load_rspec_config
|
57
|
-
@config_cache.record_configuration(&rspec_configuration)
|
58
|
-
end
|
59
|
-
|
60
65
|
def self.configure_rspec
|
61
66
|
RSpec.configure do |config|
|
62
67
|
config.error_stream = @error_stream
|
@@ -64,55 +69,6 @@ module RSpec
|
|
64
69
|
end
|
65
70
|
end
|
66
71
|
|
67
|
-
def self.rspec_configuration
|
68
|
-
proc do
|
69
|
-
if @config["init_script"]
|
70
|
-
$LOAD_PATH << '.'
|
71
|
-
require @config["init_script"]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.get_config(name = nil)
|
77
|
-
unless File.exists? CONFIG_FILE
|
78
|
-
@error_stream.puts "warning: #{CONFIG_FILE} not found, using default config"
|
79
|
-
return {}
|
80
|
-
end
|
81
|
-
|
82
|
-
configs = JSON.parse(File.read(CONFIG_FILE))["configs"] || []
|
83
|
-
if configs.empty?
|
84
|
-
@error_stream.puts "no configs found in: #{CONFIG_FILE}"
|
85
|
-
exit!(1)
|
86
|
-
end
|
87
|
-
|
88
|
-
# If a specific config was specified, use it.
|
89
|
-
if name
|
90
|
-
config = configs.find { |e| e["name"] == name }
|
91
|
-
return config if config
|
92
|
-
@error_stream.puts "invalid config: #{name}"
|
93
|
-
exit!(1)
|
94
|
-
end
|
95
|
-
|
96
|
-
# If there is only one, use it.
|
97
|
-
if configs.size == 1
|
98
|
-
return configs[0]
|
99
|
-
end
|
100
|
-
|
101
|
-
# Ask the user which to use.
|
102
|
-
loop do
|
103
|
-
names = configs.map { |e| e["name"] }
|
104
|
-
names[0] = "#{names[0]} (default)"
|
105
|
-
print "Multiple simultaneous configs not yet supported. Please choose a config. #{names.join(', ')}: "
|
106
|
-
answer = @input_stream.gets.chomp
|
107
|
-
if answer.strip.empty?
|
108
|
-
return configs[0]
|
109
|
-
end
|
110
|
-
config = configs.find { |e| e["name"] == answer }
|
111
|
-
return config if config
|
112
|
-
@error_stream.puts "invalid config: #{answer}"
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
72
|
def self.trap_interrupt
|
117
73
|
trap('INT') do
|
118
74
|
if @runner
|
@@ -127,15 +83,15 @@ module RSpec
|
|
127
83
|
end
|
128
84
|
|
129
85
|
def self.start_file_watcher
|
130
|
-
return
|
86
|
+
return if @configuration.watch_dirs.empty?
|
131
87
|
|
132
88
|
# Only polling seems to work in Docker.
|
133
|
-
listener = Listen.to(*@
|
89
|
+
@listener = Listen.to(*@configuration.watch_dirs, only: /\.rb$/, force_polling: true) do |modified, added, removed|
|
134
90
|
@mutex.synchronize do
|
135
91
|
@updated_files.concat(added + modified)
|
136
92
|
end
|
137
93
|
end
|
138
|
-
listener.start
|
94
|
+
@listener.start
|
139
95
|
end
|
140
96
|
|
141
97
|
def self.configure_pry
|
@@ -151,7 +107,52 @@ module RSpec
|
|
151
107
|
# Use custom completer to get file completion.
|
152
108
|
Pry.config.completer = RSpec::Interactive::InputCompleter
|
153
109
|
|
154
|
-
Pry.config.history_file =
|
110
|
+
Pry.config.history_file = @history_file
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.rspec(args)
|
114
|
+
parsed_args = args.flat_map do |arg|
|
115
|
+
if arg.match(/[\*\?\[]/)
|
116
|
+
glob = Dir.glob(arg)
|
117
|
+
glob.empty? ? [arg] : glob
|
118
|
+
else
|
119
|
+
[arg]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
@mutex.synchronize do
|
124
|
+
@updated_files.uniq.each do |filename|
|
125
|
+
@output_stream.puts "modified: #{filename}"
|
126
|
+
trace = TracePoint.new(:class) do |tp|
|
127
|
+
@configuration.on_class_load.call(tp.self)
|
128
|
+
end
|
129
|
+
trace.enable
|
130
|
+
load filename
|
131
|
+
trace.disable
|
132
|
+
@output_stream.puts
|
133
|
+
end
|
134
|
+
@updated_files.clear
|
135
|
+
end
|
136
|
+
|
137
|
+
@runner = RSpec::Interactive::Runner.new(parsed_args)
|
138
|
+
|
139
|
+
# Stop saving history in case a new Pry session is started for debugging.
|
140
|
+
Pry.config.history_save = false
|
141
|
+
|
142
|
+
# RSpec::Interactive-specific RSpec configuration
|
143
|
+
configure_rspec
|
144
|
+
|
145
|
+
# Run.
|
146
|
+
exit_code = @runner.run
|
147
|
+
@runner = nil
|
148
|
+
|
149
|
+
# Reenable history
|
150
|
+
Pry.config.history_save = true
|
151
|
+
|
152
|
+
# Reset
|
153
|
+
RSpec.clear_examples
|
154
|
+
RSpec.reset
|
155
|
+
@config_cache.replay_configuration
|
155
156
|
end
|
156
157
|
end
|
157
158
|
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
|
-
|
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)
|
File without changes
|
@@ -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
|
-
|
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
|
-
|
57
|
-
ExampleGroupResult.new(example_group, group_success)
|
33
|
+
example_group.run(reporter)
|
58
34
|
end
|
59
35
|
|
60
|
-
success = group_results.all?
|
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
|
-
|
43
|
+
exit_code
|
68
44
|
end
|
69
45
|
end
|
70
|
-
|
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
|
65
|
+
::RSpec.configuration.error_stream.puts "warning: failed to write results to #{path}"
|
84
66
|
end
|
85
67
|
end
|
86
68
|
end
|
data/scripts/release.sh
ADDED
@@ -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
|
data/tests/debugged_spec_test.rb
CHANGED
@@ -29,7 +29,47 @@ Test.test "debugged spec" do
|
|
29
29
|
Finished in 0 seconds (files took 0 seconds to load)
|
30
30
|
1 example, 0 failures
|
31
31
|
|
32
|
-
=> <RSpec::Interactive::Result @success=true, @group_results=[...]>
|
33
32
|
[2] pry(main)> exit
|
34
33
|
EOF
|
35
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
|
71
|
+
|
72
|
+
expect_history <<~EOF
|
73
|
+
rspec examples/debugged_spec.rb
|
74
|
+
EOF
|
75
|
+
end
|
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
|
data/tests/failing_spec_test.rb
CHANGED
@@ -36,9 +36,6 @@ Test.test "failing spec" do
|
|
36
36
|
|
37
37
|
rspec ./examples/failing_spec.rb:4 # example spec fails
|
38
38
|
|
39
|
-
Rerun failures by executing the previous command with --only-failures or --next-failure.
|
40
|
-
|
41
|
-
=> <RSpec::Interactive::Result @success=false, @group_results=[...]>
|
42
39
|
[2] pry(main)> exit
|
43
40
|
EOF
|
44
41
|
end
|
data/tests/glob_test.rb
ADDED
@@ -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
|
data/tests/passing_spec_test.rb
CHANGED
@@ -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
|
-
|
114
|
-
|
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
|
|
@@ -156,39 +163,67 @@ end
|
|
156
163
|
|
157
164
|
class Test
|
158
165
|
|
159
|
-
def self.test(name, &block)
|
160
|
-
Test.new.run(name, &block)
|
166
|
+
def self.test(name, config_path: nil, &block)
|
167
|
+
Test.new.run(name, config_path, &block)
|
161
168
|
end
|
162
169
|
|
163
|
-
def run(name, &block)
|
170
|
+
def run(name, config_path, &block)
|
171
|
+
puts "running: #{name}"
|
172
|
+
|
164
173
|
@output_temp_file = Tempfile.new('output')
|
165
174
|
@output_write = File.open(@output_temp_file.path, 'w')
|
166
175
|
|
176
|
+
@error_temp_file = Tempfile.new('error')
|
177
|
+
@error_write = File.open(@error_temp_file.path, 'w')
|
178
|
+
|
179
|
+
@history_temp_file = Tempfile.new('history')
|
180
|
+
|
167
181
|
@interactive_thread = Thread.start do
|
168
|
-
|
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
|
169
193
|
end
|
170
194
|
|
171
195
|
begin
|
172
196
|
instance_eval &block
|
173
197
|
rescue Exception => e
|
174
198
|
failed = true
|
175
|
-
|
199
|
+
STDERR.puts e.message
|
200
|
+
e.backtrace[0..5].each { |line| STDERR.puts " #{line}" }
|
176
201
|
end
|
177
202
|
|
178
203
|
await_termination
|
179
204
|
|
180
205
|
if Readline.error
|
181
206
|
failed = true
|
182
|
-
|
207
|
+
STDOUT.puts Readline.error
|
183
208
|
end
|
184
209
|
|
185
|
-
if
|
210
|
+
if failed
|
211
|
+
Ansi.puts :red, "failed: #{name}"
|
212
|
+
else
|
186
213
|
Ansi.puts :green, "passed: #{name}"
|
187
214
|
end
|
215
|
+
puts
|
188
216
|
ensure
|
189
217
|
@output_write.close
|
190
218
|
@output_temp_file.close
|
219
|
+
|
220
|
+
@error_write.close
|
221
|
+
@error_temp_file.close
|
222
|
+
|
223
|
+
@history_temp_file.close
|
224
|
+
|
191
225
|
Readline.reset
|
226
|
+
Pry.reset_defaults
|
192
227
|
end
|
193
228
|
|
194
229
|
def await_termination
|
@@ -208,14 +243,44 @@ class Test
|
|
208
243
|
Readline.puts(string)
|
209
244
|
end
|
210
245
|
|
246
|
+
def ctrl_d
|
247
|
+
Readline.ctrl_d
|
248
|
+
end
|
249
|
+
|
211
250
|
def output
|
212
251
|
@output_temp_file.rewind
|
213
252
|
File.read(@output_temp_file.path).gsub("\e[0G", "")
|
214
253
|
end
|
215
254
|
|
255
|
+
def error_output
|
256
|
+
@error_write.flush
|
257
|
+
@error_temp_file.rewind
|
258
|
+
File.read(@error_temp_file.path)
|
259
|
+
end
|
260
|
+
|
261
|
+
def expect_history(expected)
|
262
|
+
@history_temp_file.rewind
|
263
|
+
history = File.read(@history_temp_file.path)
|
264
|
+
if expected != history
|
265
|
+
raise "unexpected history:\n expected: #{expected.inspect}\n actual: #{history.inspect}"
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
216
269
|
def expect_output(expected)
|
217
|
-
|
218
|
-
|
270
|
+
expect_equal("output", output, expected)
|
271
|
+
end
|
272
|
+
|
273
|
+
def expect_error_output(expected)
|
274
|
+
expect_equal("error output", error_output, expected)
|
275
|
+
end
|
276
|
+
|
277
|
+
def expect_result(expected)
|
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}"
|
219
284
|
end
|
220
285
|
end
|
221
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.
|
4
|
+
version: 0.6.1
|
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-
|
11
|
+
date: 2021-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec-core
|
@@ -72,17 +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/
|
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
|
92
|
+
- tests/glob_test.rb
|
93
|
+
- tests/line_number_test.rb
|
85
94
|
- tests/passing_spec_test.rb
|
95
|
+
- tests/rerun_failed_specs_test.rb
|
96
|
+
- tests/spec_with_syntax_error_test.rb
|
86
97
|
- tests/support/ansi.rb
|
87
98
|
- tests/support/test_helper.rb
|
88
99
|
homepage: https://github.com/nicholasdower/rspec-interactive
|