rainforest-cli 1.6.5 → 1.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +8 -0
  4. data/README.md +42 -7
  5. data/bin/rainforest +1 -1
  6. data/lib/{rainforest/cli.rb → rainforest_cli.rb} +23 -15
  7. data/lib/{rainforest/cli → rainforest_cli}/constants.rb +0 -0
  8. data/lib/{rainforest/cli → rainforest_cli}/csv_importer.rb +0 -0
  9. data/lib/{rainforest/cli → rainforest_cli}/deleter.rb +0 -0
  10. data/lib/{rainforest/cli → rainforest_cli}/exporter.rb +0 -0
  11. data/lib/{rainforest/cli → rainforest_cli}/git_trigger.rb +0 -0
  12. data/lib/{rainforest/cli → rainforest_cli}/http_client.rb +5 -4
  13. data/lib/rainforest_cli/junit_outputter.rb +69 -0
  14. data/lib/{rainforest/cli → rainforest_cli}/options.rb +40 -1
  15. data/lib/{rainforest/cli → rainforest_cli}/remote_tests.rb +0 -0
  16. data/lib/rainforest_cli/reporter.rb +64 -0
  17. data/lib/{rainforest/cli → rainforest_cli}/resources.rb +0 -0
  18. data/lib/{rainforest/cli → rainforest_cli}/runner.rb +20 -6
  19. data/lib/{rainforest/cli → rainforest_cli}/test_files.rb +0 -0
  20. data/lib/{rainforest/cli → rainforest_cli}/test_parser.rb +4 -65
  21. data/lib/rainforest_cli/test_parser/embedded_test.rb +14 -0
  22. data/lib/rainforest_cli/test_parser/step.rb +24 -0
  23. data/lib/rainforest_cli/test_parser/test.rb +40 -0
  24. data/lib/{rainforest/cli → rainforest_cli}/uploader.rb +32 -27
  25. data/lib/rainforest_cli/uploader/multi_form_post_request.rb +50 -0
  26. data/lib/rainforest_cli/uploader/uploadable_parser.rb +143 -0
  27. data/lib/{rainforest/cli → rainforest_cli}/validator.rb +0 -0
  28. data/lib/{rainforest/cli → rainforest_cli}/version.rb +1 -1
  29. data/rainforest-cli.gemspec +3 -1
  30. data/spec/fixtures/failed_test_response.json +29 -0
  31. data/spec/fixtures/runs_response.json +275 -0
  32. data/spec/fixtures/tests_response.json +130 -0
  33. data/spec/{csv_importer_spec.rb → rainforest_cli/csv_importer_spec.rb} +7 -14
  34. data/spec/{deleter_spec.rb → rainforest_cli/deleter_spec.rb} +0 -0
  35. data/spec/{exporter_spec.rb → rainforest_cli/exporter_spec.rb} +0 -0
  36. data/spec/{git_trigger_spec.rb → rainforest_cli/git_trigger_spec.rb} +0 -0
  37. data/spec/{http_client_spec.rb → rainforest_cli/http_client_spec.rb} +23 -0
  38. data/spec/rainforest_cli/junit_outputter_spec.rb +32 -0
  39. data/spec/{options_spec.rb → rainforest_cli/options_spec.rb} +33 -0
  40. data/spec/{remote_tests_spec.rb → rainforest_cli/remote_tests_spec.rb} +0 -0
  41. data/spec/rainforest_cli/reporter_spec.rb +51 -0
  42. data/spec/{resources_spec.rb → rainforest_cli/resources_spec.rb} +0 -0
  43. data/spec/{runner_spec.rb → rainforest_cli/runner_spec.rb} +0 -0
  44. data/spec/{test_files_spec.rb → rainforest_cli/test_files_spec.rb} +1 -1
  45. data/spec/rainforest_cli/test_parser/step_spec.rb +53 -0
  46. data/spec/rainforest_cli/test_parser_spec.rb +15 -0
  47. data/spec/rainforest_cli/uploader/uploadable_parser_spec.rb +84 -0
  48. data/spec/{uploader_spec.rb → rainforest_cli/uploader_spec.rb} +2 -2
  49. data/spec/{validator_spec.rb → rainforest_cli/validator_spec.rb} +6 -7
  50. data/spec/{cli_spec.rb → rainforest_cli_spec.rb} +5 -5
  51. data/spec/spec_helper.rb +4 -1
  52. metadata +95 -47
  53. data/.rvmrc +0 -1
  54. data/spec/test_parser_spec.rb +0 -95
@@ -1,22 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
  describe RainforestCli::CSVImporter do
3
- let(:csv_file) { "#{File.dirname(__FILE__)}/fixtures/variables.txt" }
3
+ let(:csv_file) { "#{File.dirname(__FILE__)}/../fixtures/variables.txt" }
4
4
 
5
5
  describe '.import' do
6
6
  subject { described_class.new('variables', csv_file, 'abc123') }
7
-
8
- before do
9
- # suppress output in terminal
10
- allow_any_instance_of(described_class).to receive(:print)
11
- allow_any_instance_of(described_class).to receive(:puts)
12
- end
13
-
14
7
  let(:columns) { %w(email pass) }
15
8
 
16
9
  let(:success_response) do
17
10
  {
18
11
  'id' => 12345,
19
- 'columns' => columns.each_with_index.map { |col, i| { 'id' => i, 'name' => col } }
12
+ 'columns' => columns.each_with_index.map { |col, i| { 'id' => i, 'name' => col } },
20
13
  }
21
14
  end
22
15
 
@@ -25,7 +18,7 @@ describe RainforestCli::CSVImporter do
25
18
  .with('/generators', {
26
19
  name: 'variables',
27
20
  description: 'variables',
28
- columns: columns.map {|col| { name: col } }
21
+ columns: columns.map {|col| { name: col } },
29
22
  })
30
23
  .and_return success_response
31
24
 
@@ -33,16 +26,16 @@ describe RainforestCli::CSVImporter do
33
26
  .with('/generators/12345/rows', {
34
27
  data: {
35
28
  0 => 'russ@rainforestqa.com',
36
- 1 => 'abc123'
37
- }
29
+ 1 => 'abc123',
30
+ },
38
31
  }).and_return({})
39
32
 
40
33
  expect_any_instance_of(RainforestCli::HttpClient).to receive(:post)
41
34
  .with('/generators/12345/rows', {
42
35
  data: {
43
36
  0 => 'bob@example.com',
44
- 1 => 'hunter2'
45
- }
37
+ 1 => 'hunter2',
38
+ },
46
39
  }).and_return({})
47
40
 
48
41
  subject.import
@@ -53,5 +53,28 @@ describe RainforestCli::HttpClient do
53
53
  end
54
54
  end
55
55
  end
56
+
57
+ describe 'non 200 codes' do
58
+ context '404 not found'do
59
+ let(:url) { 'http://some.url.com' }
60
+ let(:response) { instance_double('HTTParty::Response', code: 404, body: {'error'=>'some error', 'type'=>'some type'}.to_json) }
61
+ subject { described_class.new({ token: 'foo' }).get(url, {}) }
62
+
63
+ before do
64
+ allow(HTTParty).to receive(:get).and_raise(SocketError)
65
+ end
66
+
67
+ it 'gets an error 404 and prints the error' do
68
+ expect(HTTParty).to receive(:get).and_return(response)
69
+ expect_any_instance_of(Logger).to receive(:warn).with('Status Code: 404, {"error":"some error","type":"some type"}')
70
+ expect(subject)
71
+ end
72
+
73
+ it 'returns nil' do
74
+ expect(HTTParty).to receive(:get).and_return(response)
75
+ expect(subject).to eq(nil)
76
+ end
77
+ end
78
+ end
56
79
  end
57
80
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ require 'json'
3
+ require 'stringio'
4
+
5
+ describe RainforestCli::JunitOutputter do
6
+ let(:spec_folder) { File.expand_path(File.dirname(__FILE__) + '/..') }
7
+ let(:runs_json_results) { JSON.parse(File.read("#{spec_folder}/fixtures/runs_response.json")) }
8
+ let(:tests_json_results) { JSON.parse(File.read("#{spec_folder}/fixtures/tests_response.json")) }
9
+ let(:failed_test_json) { JSON.parse(File.read("#{spec_folder}/fixtures/failed_test_response.json")) }
10
+ let(:test_io) { StringIO.new }
11
+
12
+ describe '.build_test_suite' do
13
+
14
+ subject { described_class.new('abc123', runs_json_results, tests_json_results) }
15
+
16
+ before do
17
+ allow(subject.client).to receive(:get).and_return(failed_test_json)
18
+ end
19
+
20
+ context 'With a valid response' do
21
+ it 'Parses the response' do
22
+ subject.parse
23
+ subject.output(test_io)
24
+
25
+ expect(test_io.string).to include('name="Test Description"')
26
+ expect(test_io.string).to include('failures="2"')
27
+ expect(test_io.string).to include('This feedback should appear')
28
+ expect(test_io.string).not_to include("This feedback shouldn't "appear")
29
+ end
30
+ end
31
+ end
32
+ end
@@ -80,6 +80,12 @@ describe RainforestCli::OptionParser do
80
80
  its(:foreground?) { is_expected.to eq(true) }
81
81
  end
82
82
 
83
+ context 'it parses the --wait flag' do
84
+ let(:args) { ['run', '--wait', '12345'] }
85
+ its(:wait?) { is_expected.to be true }
86
+ its(:run_id) { is_expected.to eq 12345 }
87
+ end
88
+
83
89
  context 'it parses the api token' do
84
90
  let(:args) { ['run', '--token', 'abc', 'all'] }
85
91
  its(:token) { should == 'abc'}
@@ -172,5 +178,32 @@ describe RainforestCli::OptionParser do
172
178
  it { raises_a_validation_exception }
173
179
  end
174
180
  end
181
+
182
+ context 'with junit output but not in foreground mode' do
183
+ let(:args) { %w(run --token foo --junit-file some_file.xml) }
184
+ it { raises_a_validation_exception }
185
+ end
186
+
187
+ context 'with junit output and in foreground mode' do
188
+ let(:args) { %w(--token foo --junit-file some_file.xml --fg) }
189
+ it { does_not_raise_a_validation_exception }
190
+ end
191
+
192
+ context 'valdiating the report command' do
193
+ context 'with a valid junit and run_id' do
194
+ let(:args) { ['report', '--junit-file', 'somefile.xml', '--run-id', '12345', '--token', 'foo'] }
195
+ it {does_not_raise_a_validation_exception }
196
+ end
197
+
198
+ context 'with a junit but no run_id' do
199
+ let(:args) { ['report', '--junit-file', 'somefile.xml', '--token', 'foo'] }
200
+ it { raises_a_validation_exception }
201
+ end
202
+
203
+ context 'with a run_id but no junit' do
204
+ let(:args) { ['report', '--run-id', '12345', '--token', 'foo'] }
205
+ end
206
+ end
207
+
175
208
  end
176
209
  end
@@ -0,0 +1,51 @@
1
+
2
+
3
+ describe RainforestCli::Reporter do
4
+ let(:args) { %w(report --token abc123 --run-id 12345 --junit-file somefile.xml) }
5
+ let(:options) { RainforestCli::OptionParser.new(args) }
6
+
7
+ subject { described_class.new(options) }
8
+
9
+ describe '#report' do
10
+ context 'on /runs/{run_id}.json API error' do
11
+ before do
12
+ allow(subject.client).to receive(:get).with('/runs/12345.json').and_return({'error'=>'Some API error'})
13
+ end
14
+
15
+ it 'errors out and exits' do
16
+ expect_any_instance_of(Logger).to receive(:fatal).with('Error retrieving results for your run: Some API error')
17
+ expect do
18
+ subject.report
19
+ end.to raise_error(SystemExit) { |error|
20
+ expect(error.status).to eq 1
21
+ }
22
+ end
23
+
24
+ end
25
+
26
+ context 'on /runs/{run_id}/tests.json API error' do
27
+ before do
28
+ allow(subject.client).to receive(:get).with('/runs/12345.json').and_return({'total_tests'=>'1'})
29
+ allow(subject.client).to receive(:get).with('/runs/12345/tests.json?page_size=1').and_return({'error'=>'Some API error'})
30
+ end
31
+
32
+ it 'errors and exits' do
33
+ expect_any_instance_of(Logger).to receive(:fatal).with('Error retrieving test details for your run: Some API error')
34
+ expect do
35
+ subject.report
36
+ end.to raise_error(SystemExit) { |error|
37
+ expect(error.status).to eq 1
38
+ }
39
+ end
40
+
41
+ end
42
+
43
+ context 'with working API calls creates JunitOutputter' do
44
+ before do
45
+ allow(subject.client).to receive(:get).with('/runs/12345.json').and_return()
46
+ allow(subject.client).to receive(:get).with('/runs/12345/tests.json?page_size=1').and_return()
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -4,7 +4,7 @@ describe RainforestCli::TestFiles do
4
4
  subject { described_class.new(options) }
5
5
 
6
6
  describe '#test_data' do
7
- let(:test_directory) { File.dirname(__FILE__) + '/rainforest-example' }
7
+ let(:test_directory) { File.dirname(__FILE__) + '/../rainforest-example' }
8
8
  let(:options) { instance_double('RainforestCli::Options', test_folder: test_directory, command: nil) }
9
9
 
10
10
  let(:rfml_test) { subject.test_data.first }
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+ describe RainforestCli::TestParser::Step do
3
+ subject { described_class.new }
4
+ let(:screenshot_string) do
5
+ 'Picture 1: {{ file.screenshot(./foo) }}. Picture 2: {{file.screenshot(bar/baz) }}'
6
+ end
7
+
8
+ let(:download_string) do
9
+ 'Download 1: {{ file.download(./foo) }}. Download 2: {{file.download(bar/baz) }}'
10
+ end
11
+
12
+ shared_examples 'a method that detects step variables' do |att|
13
+ it 'correctly detects a screenshot step variable' do
14
+ subject[att] = screenshot_string
15
+ expect(subject.send(:"uploadable_in_#{att}"))
16
+ .to eq([['screenshot', './foo'], ['screenshot', 'bar/baz']])
17
+ end
18
+
19
+ it 'correctly detects the download step variable' do
20
+ subject[att] = download_string
21
+ expect(subject.send(:"uploadable_in_#{att}"))
22
+ .to eq([['download', './foo'], ['download', 'bar/baz']])
23
+ end
24
+ end
25
+
26
+ describe '#uploadable_in_action' do
27
+ it_behaves_like 'a method that detects step variables', :action
28
+ end
29
+
30
+ describe '#uploadable_in_response' do
31
+ it_behaves_like 'a method that detects step variables', :response
32
+ end
33
+
34
+ describe '#has_uploadable_files?' do
35
+ let(:action) { 'Regular action' }
36
+ let(:response) { 'Regular response' }
37
+ subject { described_class.new(action, response).has_uploadable_files? }
38
+
39
+ context 'with no uploadables' do
40
+ it { is_expected.to be(false) }
41
+ end
42
+
43
+ context 'uploadable in action' do
44
+ let(:action) { 'Action with uploadable {{ file.download(/foo) }}' }
45
+ it { is_expected.to be(true) }
46
+ end
47
+
48
+ context 'uploadable in response' do
49
+ let(:response) { 'Response with uploadable {{ file.download(/foo) }}' }
50
+ it { is_expected.to be(true) }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ describe RainforestCli::TestParser do
3
+ describe RainforestCli::TestParser::Parser do
4
+ subject { described_class.new(file_name) }
5
+
6
+ describe '#initialize' do
7
+ let(:file_name) { './spec/rainforest-example/example_test.rfml' }
8
+
9
+ it 'expands the file name path' do
10
+ test = subject.instance_variable_get(:@test)
11
+ expect(test.file_name).to eq(File.expand_path(file_name))
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+ describe RainforestCli::Uploader::UploadableParser do
3
+ let(:rfml_test) { instance_double('RainforestCli::TestParser::Test', file_name: 'rfml_test_filename.rfml') }
4
+ let(:test_id) { 12345 }
5
+ let(:uploaded_files) { [] }
6
+ subject { described_class.new(rfml_test, test_id, uploaded_files) }
7
+
8
+ describe '#replace_paths_in_text' do
9
+ let(:file) { instance_double('File') }
10
+ let(:file_path) { 'path/to/my/file.ext' }
11
+ let(:file_id) { 9876 }
12
+ let(:file_sig) { 'abcdef' }
13
+ let(:aws_info) do
14
+ { 'file_id' => file_id, 'file_signature' => "#{file_sig}xyz123" }
15
+ end
16
+
17
+ before do
18
+ allow(subject).to receive(:test_directory).and_return('my/test/directory')
19
+ allow(File).to receive(:exist?).and_return(true)
20
+ allow(File).to receive(:open).and_return(file)
21
+ allow(subject).to receive(:get_aws_upload_info).with(file).and_return(aws_info)
22
+ end
23
+
24
+ context 'screenshot' do
25
+ let(:original_text) { "My screenshot is {{ file.screenshot(#{file_path}) }}" }
26
+ let(:match) { ['screenshot', file_path] }
27
+ let(:expected_text) { "My screenshot is {{ file.screenshot(#{file_id}, #{file_sig}) }}" }
28
+
29
+ it 'replaces the screenshot variable arguments with the correct values' do
30
+ expect(subject.replace_paths_in_text(original_text, match)).to eq(expected_text)
31
+ end
32
+ end
33
+
34
+ context 'download' do
35
+ let(:original_text) { "My download is {{ file.download(#{file_path}) }}" }
36
+ let(:match) { ['download', file_path] }
37
+ let(:file_name) { File.basename(file_path) }
38
+ let(:expected_text) { "My download is {{ file.download(#{file_id}, #{file_sig}, #{file_name}) }}" }
39
+
40
+ it 'replaces the download variable arguments with the correct values' do
41
+ expect(subject.replace_paths_in_text(original_text, match)).to eq(expected_text)
42
+ end
43
+ end
44
+
45
+ context 'file does not exist' do
46
+ let(:original_text) { "My download is {{ file.download(#{file_path}) }}" }
47
+ let(:match) { ['download', file_path] }
48
+ let(:file_name) { File.basename(file_path) }
49
+
50
+ before do
51
+ allow(File).to receive(:exist?).and_call_original # remove stub in previous before block
52
+ expect(File).to receive(:exist?).with(a_string_including(file_path)).and_return(false)
53
+ end
54
+
55
+ it 'warns the user and does not replace the variable values' do
56
+ expect_any_instance_of(Logger).to receive(:warn).with(a_string_including(rfml_test.file_name))
57
+ expect_any_instance_of(Logger).to receive(:warn).with(a_string_including(file_name))
58
+ expect(subject.replace_paths_in_text(original_text, match)).to eq(original_text)
59
+ end
60
+ end
61
+ end
62
+
63
+ describe '#upload_to_rainforest' do
64
+ let(:file_path) { 'test_file.txt' }
65
+ let(:mime_type) { 'text/plain' }
66
+ let(:size) { 4545 }
67
+ let(:file) { instance_double('File', path: file_path, size: size) }
68
+ let(:digest) { 'myDigest' }
69
+
70
+ before do
71
+ allow(subject).to receive(:file_digest).with(file).and_return(digest)
72
+ allow(MimeMagic).to receive(:by_path).with(file).and_return(mime_type)
73
+ end
74
+
75
+ it 'uploads the correct metadata to Rainforest' do
76
+ expect(RainforestCli.http_client).to receive(:post) do |url, params|
77
+ expect(url).to include(test_id.to_s)
78
+ expect(params).to include(mime_type: mime_type, size: size, name: file_path, digest: digest)
79
+ end.and_return({ 'aws_url' => 'http://aws.amazon.com/lol' })
80
+
81
+ subject.upload_to_rainforest(file)
82
+ end
83
+ end
84
+ end
@@ -11,7 +11,7 @@ describe RainforestCli::Uploader do
11
11
 
12
12
  describe '#upload' do
13
13
  context 'with new tests' do
14
- let(:test_directory) { File.expand_path(File.join(__FILE__, '../validation-examples/correct_embeds')) }
14
+ let(:test_directory) { File.expand_path(File.dirname(__FILE__) + '/../validation-examples/correct_embeds') }
15
15
  let(:rf_test_double) { instance_double('Rainforest::Test', id: 123) }
16
16
 
17
17
  before do
@@ -27,7 +27,7 @@ describe RainforestCli::Uploader do
27
27
  end
28
28
 
29
29
  describe 'uploaded test object' do
30
- let(:test_directory) { File.expand_path(File.join(__FILE__, '../rainforest-example')) }
30
+ let(:test_directory) { File.expand_path(File.dirname(__FILE__) + '/../rainforest-example') }
31
31
  let(:test_double) { instance_double('Rainforest::Test', id: 123) }
32
32
 
33
33
  before do
@@ -30,7 +30,7 @@ describe RainforestCli::Validator do
30
30
 
31
31
  context 'with parsing errors' do
32
32
  let(:notification_method) { :parsing_error_notification }
33
- let(:test_directory) { File.expand_path(File.join(__FILE__, '../validation-examples/parse_errors')) }
33
+ let(:test_directory) { File.expand_path(File.dirname(__FILE__) + '/../validation-examples/parse_errors') }
34
34
 
35
35
  context 'no rfml id' do
36
36
  let(:correct_file_name) { 'no_rfml_id.rfml' }
@@ -55,7 +55,7 @@ describe RainforestCli::Validator do
55
55
 
56
56
  context 'with a incorrect embedded RFML ID' do
57
57
  let(:notification_method) { :nonexisting_embedded_id_notification }
58
- let(:test_directory) { File.expand_path(File.join(__FILE__, '../validation-examples/missing_embeds')) }
58
+ let(:test_directory) { File.expand_path(File.dirname(__FILE__) + '/../validation-examples/missing_embeds') }
59
59
 
60
60
  context 'the file containing in the incorrect id' do
61
61
  let(:correct_file_name) { 'incorrect_test.rfml' }
@@ -69,7 +69,7 @@ describe RainforestCli::Validator do
69
69
  end
70
70
 
71
71
  context 'with circular embeds' do
72
- let(:test_directory) { File.expand_path(File.join(__FILE__, '../validation-examples/circular_embeds')) }
72
+ let(:test_directory) { File.expand_path(File.dirname(__FILE__) + '/../validation-examples/circular_embeds') }
73
73
  let(:file_name_a) { File.join(test_directory, 'test1.rfml') }
74
74
  let(:file_name_b) { File.join(test_directory, 'test2.rfml') }
75
75
 
@@ -87,7 +87,7 @@ describe RainforestCli::Validator do
87
87
  it_behaves_like 'it detects all the correct errors'
88
88
 
89
89
  context 'when multiple tests have the same rfml_ids' do
90
- let(:test_directory) { File.expand_path(File.join(__FILE__, '../validation-examples/duplicate_rfml_ids')) }
90
+ let(:test_directory) { File.expand_path(File.dirname(__FILE__) + '/../validation-examples/duplicate_rfml_ids') }
91
91
  let(:options) { instance_double('RainforestCli::Options', test_folder: test_directory, token: 'api_token', command: '') }
92
92
 
93
93
  subject { described_class.new(options) }
@@ -102,7 +102,6 @@ describe RainforestCli::Validator do
102
102
  expect { subject.validate }.to raise_error(SystemExit)
103
103
  end
104
104
 
105
-
106
105
  context 'when invalid' do
107
106
  before do
108
107
  allow(subject).to receive(:invalid?).and_return(true)
@@ -110,7 +109,7 @@ describe RainforestCli::Validator do
110
109
  it 'exits 1' do
111
110
  begin
112
111
  subject.validate
113
- fail "validate did not exit with status 1"
112
+ fail 'validate did not exit with status 1'
114
113
  rescue SystemExit => e
115
114
  expect(e.status).to eq(1)
116
115
  end
@@ -125,7 +124,7 @@ describe RainforestCli::Validator do
125
124
  it_behaves_like 'it detects all the correct errors'
126
125
 
127
126
  context 'without a token option' do
128
- let(:test_directory) { File.expand_path(File.join(__FILE__, '../validation-examples')) }
127
+ let(:test_directory) { File.expand_path(File.dirname(__FILE__) + '/../validation-examples') }
129
128
  let(:options) { instance_double('RainforestCli::Options', test_folder: test_directory, token: nil, command: '') }
130
129
  subject { described_class.new(options) }
131
130