howitzer 2.0.0 → 2.0.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +21 -1
  4. data/features/cli_new.feature +1 -0
  5. data/features/cli_update.feature +1 -0
  6. data/generators/base_generator.rb +3 -1
  7. data/generators/config/templates/capybara.rb +1 -1
  8. data/generators/config/templates/default.yml +4 -2
  9. data/generators/cucumber/cucumber_generator.rb +1 -0
  10. data/generators/cucumber/templates/common_steps.rb +1 -1
  11. data/generators/cucumber/templates/env.rb +0 -28
  12. data/generators/cucumber/templates/hooks.rb +29 -0
  13. data/generators/prerequisites/templates/user.rb +2 -0
  14. data/generators/prerequisites/templates/users.rb +2 -2
  15. data/generators/root/templates/Gemfile.erb +1 -1
  16. data/generators/rspec/templates/spec_helper.rb +9 -2
  17. data/generators/turnip/templates/spec_helper.rb +9 -2
  18. data/generators/web/templates/example_page.rb +0 -1
  19. data/howitzer.gemspec +1 -3
  20. data/lib/howitzer.rb +7 -0
  21. data/lib/howitzer/cache.rb +1 -1
  22. data/lib/howitzer/capybara_helpers.rb +2 -2
  23. data/lib/howitzer/email.rb +26 -8
  24. data/lib/howitzer/exceptions.rb +19 -19
  25. data/lib/howitzer/mail_adapters/abstract.rb +4 -3
  26. data/lib/howitzer/mail_adapters/mailgun.rb +6 -5
  27. data/lib/howitzer/mailgun_api/client.rb +1 -1
  28. data/lib/howitzer/version.rb +1 -1
  29. data/lib/howitzer/web/base_section.rb +3 -3
  30. data/lib/howitzer/web/capybara_context_holder.rb +19 -0
  31. data/lib/howitzer/web/capybara_methods_proxy.rb +27 -19
  32. data/lib/howitzer/web/element_dsl.rb +52 -13
  33. data/lib/howitzer/web/iframe_dsl.rb +3 -7
  34. data/lib/howitzer/web/page.rb +14 -21
  35. data/lib/howitzer/web/page_dsl.rb +32 -4
  36. data/lib/howitzer/web/page_validator.rb +15 -16
  37. data/lib/howitzer/web/section_dsl.rb +3 -7
  38. data/spec/config/custom.yml +1 -1
  39. data/spec/spec_helper.rb +1 -7
  40. data/spec/support/shared_examples/capybara_context_holder.rb +3 -3
  41. data/spec/support/shared_examples/element_dsl.rb +128 -18
  42. data/spec/unit/generators/base_generator_spec.rb +15 -16
  43. data/spec/unit/generators/cucumber_generator_spec.rb +2 -0
  44. data/spec/unit/generators/root_generator_spec.rb +1 -1
  45. data/spec/unit/lib/capybara_helpers_spec.rb +2 -2
  46. data/spec/unit/lib/email_spec.rb +37 -6
  47. data/spec/unit/lib/{howitzer.rb → howitzer_spec.rb} +9 -0
  48. data/spec/unit/lib/mail_adapters/abstract_spec.rb +1 -1
  49. data/spec/unit/lib/mail_adapters/mailgun_spec.rb +4 -4
  50. data/spec/unit/lib/web/base_section_spec.rb +3 -1
  51. data/spec/unit/lib/web/element_dsl_spec.rb +7 -2
  52. data/spec/unit/lib/web/page_dsl_spec.rb +22 -0
  53. data/spec/unit/lib/web/page_spec.rb +79 -44
  54. data/spec/unit/lib/web/page_validator_spec.rb +94 -51
  55. data/spec/unit/lib/web/section_spec.rb +4 -2
  56. metadata +10 -8
@@ -16,13 +16,6 @@ module Howitzer
16
16
  @validations ||= {}
17
17
  end
18
18
 
19
- # Returns page list
20
- # @return [Array]
21
-
22
- def self.pages
23
- @pages ||= []
24
- end
25
-
26
19
  # Checks if any validations are defined for the page
27
20
  # @raise [Howitzer::NoValidationError] if no one validation is defined for the page
28
21
 
@@ -60,13 +53,13 @@ module Howitzer
60
53
  end
61
54
 
62
55
  # Check whether current page is opened or no
56
+ # @param sync [Boolean] if true then waits until validation true during Howitzer.capybara_wait_time
57
+ # or returns false. If false, returns result immediately
63
58
  # @return [Boolean]
64
59
  # @raise [Howitzer::NoValidationError] if no one validation is defined for the page
65
60
 
66
- def opened?
67
- if validations.present?
68
- return !validations.any? { |(_, validation)| !validation.call(self) }
69
- end
61
+ def opened?(sync: true)
62
+ return validations.all? { |(_, validation)| validation.call(self, sync) } if validations.present?
70
63
  raise Howitzer::NoValidationError, "No any page validation was found for '#{name}' page"
71
64
  end
72
65
 
@@ -74,30 +67,36 @@ module Howitzer
74
67
  # @return [Array] page name list
75
68
 
76
69
  def matched_pages
77
- PageValidator.pages.select(&:opened?)
70
+ PageValidator.validations.keys.select { |klass| klass.opened?(sync: false) }
78
71
  end
79
72
 
80
73
  # @return [Hash] defined validations for current page class
81
74
 
82
75
  def validations
83
- PageValidator.validations[name] ||= {}
76
+ PageValidator.validations[self] ||= {}
84
77
  end
85
78
 
86
79
  private
87
80
 
88
81
  def validate_element(element_name, value = nil)
89
82
  validations[:element_presence] =
90
- ->(web_page) { web_page.public_send(*["has_#{element_name}_element?", value].compact) }
83
+ lambda do |web_page, sync|
84
+ if sync
85
+ web_page.instance.public_send(*["has_#{element_name}_element?", value].compact)
86
+ else
87
+ !web_page.instance.public_send(*["has_no_#{element_name}_element?", value].compact)
88
+ end
89
+ end
91
90
  end
92
91
 
93
92
  def validate_by_url(pattern)
94
93
  validations[:url] =
95
- -> (web_page) { pattern === web_page.instance.current_url }
94
+ ->(web_page, _sync) { pattern === web_page.instance.current_url }
96
95
  end
97
96
 
98
97
  def validate_by_title(pattern)
99
98
  validations[:title] =
100
- -> (web_page) { pattern === web_page.instance.title }
99
+ ->(web_page, sync) { sync ? web_page.instance.has_title?(pattern) : pattern === web_page.instance.title }
101
100
  end
102
101
 
103
102
  def validate_by_type(type, value, additional_value)
@@ -1,18 +1,14 @@
1
+ require 'howitzer/web/capybara_context_holder'
1
2
  module Howitzer
2
3
  module Web
3
4
  # This module combines section dsl methods
4
5
  module SectionDsl
6
+ include CapybaraContextHolder
7
+
5
8
  def self.included(base) #:nodoc:
6
9
  base.extend(ClassMethods)
7
10
  end
8
11
 
9
- # Returns capybara context. For example, capybara session, parent element, etc.
10
- # @abstract should be defined in parent context
11
-
12
- def capybara_context
13
- raise NotImplementedError, "Please define 'capybara_context' method for class holder"
14
- end
15
-
16
12
  # This module holds section dsl class methods
17
13
  module ClassMethods
18
14
  # This class is for private usage only
@@ -1,10 +1,10 @@
1
1
  log_dir: "spec/log"
2
2
  driver: selenium
3
3
  mailgun_domain: mailgun@test.domain
4
- mailgun_idle_timeout: 0.5
5
4
  mailgun_sleep_time: 0.05
6
5
  page_load_idle_timeout: 0.1
7
6
  capybara_wait_time: 5
8
7
  cloud_http_idle_timeout: 10
9
8
  hide_datetime_from_log: true
10
9
  maximized_window: false
10
+ mailgun_idle_timeout: 0.5
data/spec/spec_helper.rb CHANGED
@@ -69,11 +69,5 @@ Dir[File.join(__dir__, 'support', '**', '*.rb')].each { |f| require f }
69
69
  RSpec.configure do |config|
70
70
  config.include Howitzer::GeneratorHelper
71
71
  config.disable_monkey_patching = true
72
- config.around(:each) do |ex|
73
- $stdout = StringIO.new
74
- $stderr = StringIO.new
75
- ex.run
76
- $stdout = STDOUT
77
- $stderr = STDERR
78
- end
72
+ config.around(:each, &:run)
79
73
  end
@@ -12,8 +12,8 @@ RSpec.shared_examples :capybara_context_holder do
12
12
  context 'when parent class has the method' do
13
13
  before do
14
14
  web_page_class.class_eval do
15
- def capybara_context
16
- true
15
+ def capybara_scopes
16
+ @_scopes ||= [true]
17
17
  end
18
18
  end
19
19
  end
@@ -25,7 +25,7 @@ RSpec.shared_examples :capybara_context_holder do
25
25
  it 'should raise error' do
26
26
  expect { subject }.to raise_error(
27
27
  NotImplementedError,
28
- "Please define 'capybara_context' method for class holder"
28
+ "Please define 'capybara_scopes' method for class holder"
29
29
  )
30
30
  end
31
31
  end
@@ -14,6 +14,9 @@ RSpec.shared_examples :element_dsl do
14
14
  it 'should create private :foo_elements instance method' do
15
15
  expect(klass_object.private_methods(false)).to include(:foo_elements)
16
16
  end
17
+ it 'should create private :wait_for_foo_element instance method' do
18
+ expect(klass_object.private_methods(false)).to include(:wait_for_foo_element)
19
+ end
17
20
  it 'should create public :has_foo_element? instance method' do
18
21
  expect(klass_object.public_methods(false)).to include(:has_foo_element?)
19
22
  end
@@ -37,6 +40,9 @@ RSpec.shared_examples :element_dsl do
37
40
  it 'should create private :foo_elements instance method' do
38
41
  expect(klass_object.private_methods(false)).to include(:foo_elements)
39
42
  end
43
+ it 'should create private :wait_for_foo_element instance method' do
44
+ expect(klass_object.private_methods(false)).to include(:wait_for_foo_element)
45
+ end
40
46
  it 'should create public :has_foo_element? instance method' do
41
47
  expect(klass_object.public_methods(false)).to include(:has_foo_element?)
42
48
  end
@@ -69,50 +75,154 @@ RSpec.shared_examples :element_dsl do
69
75
  before do
70
76
  allow(Capybara).to receive(:current_session) { kontext }
71
77
  klass.class_eval do
72
- element :foo, :xpath, ->(title) { "//a[.='#{title}']" }
78
+ element :foo, :xpath, ->(title, name) { "//a[.='#{title}']/*[@name='#{name}']" }
73
79
  element :bar, '.someclass'
80
+ element :top_panel, '.top'
74
81
  end
75
82
  end
76
- after { subject }
77
83
 
78
84
  describe '#name_element' do
79
85
  context 'when simple selector' do
80
- subject { klass_object.send(:bar_element) }
81
- it { expect(kontext).to receive(:find).with('.someclass') }
86
+ subject { klass_object.send(:bar_element, wait: 10) }
87
+ after { subject }
88
+ it { expect(klass_object.capybara_context).to receive(:find).with('.someclass', wait: 10) }
82
89
  end
83
90
  context 'when lambda selector' do
84
- subject { klass_object.send(:foo_element, 'Hello') }
85
- it { expect(kontext).to receive(:find).with(:xpath, "//a[.='Hello']") }
91
+ subject { klass_object.send(:foo_element, 'Hello', 'super', wait: 10) }
92
+ after { subject }
93
+ it do
94
+ expect(
95
+ klass_object.capybara_context
96
+ ).to receive(:find).with(:xpath, "//a[.='Hello']/*[@name='super']", wait: 10)
97
+ end
98
+
99
+ context 'when several execution with different data' do
100
+ it 'does not cache previous data' do
101
+ expect(
102
+ klass_object.capybara_context
103
+ ).to receive(:find).with(:xpath, "//a[.='Hello']/*[@name='super']", wait: 10).at_least(:once)
104
+ klass_object.send(:foo_element, 'Hello', 'super', wait: 10)
105
+
106
+ expect(
107
+ klass_object.capybara_context
108
+ ).to receive(:find).with(:xpath, "//a[.='Bye']/*[@name='puper']", wait: 15).at_least(:once)
109
+ klass_object.send(:foo_element, 'Bye', 'puper', wait: 15)
110
+ end
111
+ end
86
112
  end
87
113
  end
88
114
  describe '#name_elements' do
115
+ after { subject }
89
116
  context 'when simple selector' do
90
- subject { klass_object.send(:bar_elements) }
91
- it { expect(kontext).to receive(:all).with('.someclass') }
117
+ subject { klass_object.send(:bar_elements, wait: 10) }
118
+ it { expect(klass_object.capybara_context).to receive(:all).with('.someclass', wait: 10) }
92
119
  end
93
120
  context 'when lambda selector' do
94
- subject { klass_object.send(:foo_elements, 'Hello') }
95
- it { expect(kontext).to receive(:all).with(:xpath, "//a[.='Hello']") }
121
+ subject { klass_object.send(:foo_elements, 'Hello', 'super', wait: 10) }
122
+ it do
123
+ expect(
124
+ klass_object.capybara_context
125
+ ).to receive(:all).with(:xpath, "//a[.='Hello']/*[@name='super']", wait: 10)
126
+ end
127
+ end
128
+ end
129
+ describe '#wait_for_name_element' do
130
+ context 'when simple selector' do
131
+ subject { klass_object.send(:wait_for_bar_element, wait: 10) }
132
+ it do
133
+ expect(klass_object.capybara_context).to receive(:find).with('.someclass', wait: 10)
134
+ is_expected.to eq(nil)
135
+ end
136
+ end
137
+ context 'when lambda selector' do
138
+ subject { klass_object.send(:wait_for_foo_element, 'Hello', 'super', wait: 10) }
139
+ it do
140
+ expect(
141
+ klass_object.capybara_context
142
+ ).to receive(:find).with(:xpath, "//a[.='Hello']/*[@name='super']", wait: 10)
143
+ is_expected.to eq(nil)
144
+ end
145
+ end
146
+ end
147
+ describe '#within_name_element' do
148
+ let(:within_scope) { double }
149
+ after { subject }
150
+ context 'not nested' do
151
+ context 'when simple selector' do
152
+ subject do
153
+ klass_object.instance_eval do
154
+ within_bar_element(wait: 10) do
155
+ foo_element('Hello', 'super', wait: 10)
156
+ end
157
+ end
158
+ end
159
+ it do
160
+ expect(klass_object.capybara_context).to receive(:find).with('.someclass', wait: 10) { within_scope }
161
+ expect(within_scope).to receive(:find).with(:xpath, "//a[.='Hello']/*[@name='super']", wait: 10)
162
+ end
163
+ end
164
+ context 'when lambda selector' do
165
+ subject do
166
+ klass_object.instance_eval do
167
+ within_foo_element('Hello', 'super', wait: 10) do
168
+ bar_element(wait: 10)
169
+ end
170
+ end
171
+ end
172
+ it do
173
+ expect(
174
+ klass_object.capybara_context
175
+ ).to receive(:find).with(:xpath, "//a[.='Hello']/*[@name='super']", wait: 10) { within_scope }
176
+ expect(within_scope).to receive(:find).with('.someclass', wait: 10)
177
+ end
178
+ end
179
+ end
180
+ context 'nested' do
181
+ let(:nested_within_scope) { double }
182
+ subject do
183
+ klass_object.instance_eval do
184
+ within_top_panel_element(wait: 10) do
185
+ within_bar_element(wait: 10) do
186
+ foo_element('Hello', 'super', wait: 10)
187
+ end
188
+ end
189
+ end
190
+ end
191
+ it do
192
+ expect(klass_object.capybara_context).to receive(:find).with('.top', wait: 10) { within_scope }
193
+ expect(within_scope).to receive(:find).with('.someclass', wait: 10) { nested_within_scope }
194
+ expect(nested_within_scope).to receive(:find).with(:xpath, "//a[.='Hello']/*[@name='super']", wait: 10)
195
+ end
96
196
  end
97
197
  end
98
198
  describe '#has_name_element?' do
199
+ after { subject }
99
200
  context 'when simple selector' do
100
- subject { klass_object.send(:has_bar_element?) }
101
- it { expect(kontext).to receive(:has_selector?).with('.someclass') }
201
+ subject { klass_object.send(:has_bar_element?, wait: 10) }
202
+ it { expect(klass_object.capybara_context).to receive(:has_selector?).with('.someclass', wait: 10) }
102
203
  end
103
204
  context 'when lambda selector' do
104
- subject { klass_object.send(:has_foo_element?, 'Hello') }
105
- it { expect(kontext).to receive(:has_selector?).with(:xpath, "//a[.='Hello']") }
205
+ subject { klass_object.send(:has_foo_element?, 'Hello', 'super', wait: 10) }
206
+ it do
207
+ expect(
208
+ klass_object.capybara_context
209
+ ).to receive(:has_selector?).with(:xpath, "//a[.='Hello']/*[@name='super']", wait: 10)
210
+ end
106
211
  end
107
212
  end
108
213
  describe '#has_no_name_element?' do
214
+ after { subject }
109
215
  context 'when simple selector' do
110
- subject { klass_object.send(:has_no_bar_element?) }
111
- it { expect(kontext).to receive(:has_no_selector?).with('.someclass') }
216
+ subject { klass_object.send(:has_no_bar_element?, wait: 10) }
217
+ it { expect(klass_object.capybara_context).to receive(:has_no_selector?).with('.someclass', wait: 10) }
112
218
  end
113
219
  context 'when lambda selector' do
114
- subject { klass_object.send(:has_no_foo_element?, 'Hello') }
115
- it { expect(kontext).to receive(:has_no_selector?).with(:xpath, "//a[.='Hello']") }
220
+ subject { klass_object.send(:has_no_foo_element?, 'Hello', 'super', wait: 10) }
221
+ it do
222
+ expect(
223
+ klass_object.capybara_context
224
+ ).to receive(:has_no_selector?).with(:xpath, "//a[.='Hello']/*[@name='super']", wait: 10)
225
+ end
116
226
  end
117
227
  end
118
228
  end
@@ -52,19 +52,19 @@ RSpec.describe Howitzer::BaseGenerator do
52
52
 
53
53
  describe '#manifest' do
54
54
  subject { described_class.new({}).manifest }
55
- before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
56
- it { is_expected.to be_nil }
55
+ before { allow_any_instance_of(described_class).to receive(:print_banner) { nil } }
56
+ it { is_expected.to eq([]) }
57
57
  end
58
58
 
59
59
  describe '#banner' do
60
60
  subject { described_class.new({}).send(:banner) }
61
- before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
61
+ before { allow_any_instance_of(described_class).to receive(:print_banner) { nil } }
62
62
  it { is_expected.to be_nil }
63
63
  end
64
64
 
65
65
  describe '#logger' do
66
66
  subject { described_class.new({}).send(:logger) }
67
- before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
67
+ before { allow_any_instance_of(described_class).to receive(:print_banner) { nil } }
68
68
  context 'when not specified' do
69
69
  before { described_class.instance_variable_set('@logger', nil) }
70
70
  it { is_expected.to eq($stdout) }
@@ -79,7 +79,7 @@ RSpec.describe Howitzer::BaseGenerator do
79
79
  describe '#destination' do
80
80
  subject { described_class.new({}).send(:destination) }
81
81
  before do
82
- allow_any_instance_of(described_class).to receive(:initialize) { nil }
82
+ allow_any_instance_of(described_class).to receive(:print_banner) { nil }
83
83
  allow(described_class).to receive(:destination) { '/' }
84
84
  end
85
85
  it { is_expected.to eq('/') }
@@ -91,7 +91,7 @@ RSpec.describe Howitzer::BaseGenerator do
91
91
  let(:generator) { described_class.new({}) }
92
92
  subject { generator.send(:copy_files, list) }
93
93
  before do
94
- allow_any_instance_of(described_class).to receive(:initialize) { nil }
94
+ allow_any_instance_of(described_class).to receive(:print_banner) { nil }
95
95
  allow(generator).to receive(:source_path).with(list.first[:source]) { source_path }
96
96
  end
97
97
  after { subject }
@@ -112,7 +112,7 @@ RSpec.describe Howitzer::BaseGenerator do
112
112
  let(:generator) { described_class.new('rspec' => true) }
113
113
  subject { generator.send(:copy_templates, list) }
114
114
  before do
115
- allow_any_instance_of(described_class).to receive(:initialize) { nil }
115
+ allow_any_instance_of(described_class).to receive(:print_banner) { nil }
116
116
  allow(generator).to receive(:source_path).with(list.first[:source]) { source_path }
117
117
  allow(generator).to receive(:dest_path).with(list.first[:destination]) { destination_path }
118
118
  allow(generator).to receive(:write_template).with(destination_path, source_path)
@@ -147,13 +147,12 @@ RSpec.describe Howitzer::BaseGenerator do
147
147
  let(:generator) { described_class.new({}) }
148
148
  subject { generator.send(:print_banner) }
149
149
  before do
150
- allow_any_instance_of(described_class).to receive(:initialize) { nil }
151
- allow(generator).to receive(:banner) { banner }
150
+ allow_any_instance_of(described_class).to receive(:banner) { banner }
152
151
  end
153
152
  after { subject }
154
153
  context 'when banner present' do
155
154
  let(:banner) { 'banner' }
156
- it { expect(described_class.logger).to receive(:puts).with(banner).once }
155
+ it { expect(described_class.logger).to receive(:puts).with(banner).twice }
157
156
  end
158
157
  context 'when banner blank' do
159
158
  let(:banner) { '' }
@@ -163,21 +162,21 @@ RSpec.describe Howitzer::BaseGenerator do
163
162
 
164
163
  describe '#print_info' do
165
164
  subject { described_class.new({}).send(:print_info, 'data') }
166
- before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
165
+ before { allow_any_instance_of(described_class).to receive(:print_banner) { nil } }
167
166
  after { subject }
168
167
  it { expect(described_class.logger).to receive(:print).with(' data') }
169
168
  end
170
169
 
171
170
  describe '#puts_info' do
172
171
  subject { described_class.new({}).send(:puts_info, 'data') }
173
- before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
172
+ before { allow_any_instance_of(described_class).to receive(:print_banner) { nil } }
174
173
  after { subject }
175
174
  it { expect(described_class.logger).to receive(:puts).with(' data') }
176
175
  end
177
176
 
178
177
  describe '#puts_error' do
179
178
  subject { described_class.new({}).send(:puts_error, 'data') }
180
- before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
179
+ before { allow_any_instance_of(described_class).to receive(:print_banner) { nil } }
181
180
  after { subject }
182
181
  it { expect(described_class.logger).to receive(:puts).with(' ERROR: data') }
183
182
  end
@@ -185,14 +184,14 @@ RSpec.describe Howitzer::BaseGenerator do
185
184
  describe '#source_path' do
186
185
  subject { described_class.new({}).send(:source_path, 'example.txt') }
187
186
  before do
188
- allow_any_instance_of(described_class).to receive(:initialize) { nil }
187
+ allow_any_instance_of(described_class).to receive(:print_banner) { nil }
189
188
  end
190
189
  it { is_expected.to include('/base/templates/example.txt') }
191
190
  end
192
191
 
193
192
  describe '#dest_path' do
194
193
  subject { described_class.new({}).send(:dest_path, 'example.txt') }
195
- before { allow_any_instance_of(described_class).to receive(:initialize) { nil } }
194
+ before { allow_any_instance_of(described_class).to receive(:print_banner) { nil } }
196
195
  it { is_expected.to include('/example.txt') }
197
196
  end
198
197
 
@@ -203,7 +202,7 @@ RSpec.describe Howitzer::BaseGenerator do
203
202
  let(:dst) { '/path/to/d.txt' }
204
203
  subject { generator.send(:copy_with_path, data) }
205
204
  before do
206
- allow_any_instance_of(described_class).to receive(:initialize) { nil }
205
+ allow_any_instance_of(described_class).to receive(:print_banner) { nil }
207
206
  allow(generator).to receive(:source_path).with('s.txt') { src }
208
207
  allow(generator).to receive(:dest_path).with('d.txt') { dst }
209
208
  allow(FileUtils).to receive(:mkdir_p).with('/path/to') { true }