app_archetype 1.2.8 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -1
  3. data/Gemfile.lock +102 -73
  4. data/README.md +166 -29
  5. data/app_archetype.gemspec +22 -19
  6. data/bin/app_archetype +20 -0
  7. data/bin/archetype +1 -1
  8. data/lib/app_archetype/cli.rb +171 -139
  9. data/lib/app_archetype/commands/delete_template.rb +58 -0
  10. data/lib/app_archetype/commands/find_templates.rb +66 -0
  11. data/lib/app_archetype/commands/list_templates.rb +49 -0
  12. data/lib/app_archetype/commands/new_template.rb +42 -0
  13. data/lib/app_archetype/commands/open_manifest.rb +48 -0
  14. data/lib/app_archetype/commands/print_path.rb +20 -0
  15. data/lib/app_archetype/commands/print_template_variables.rb +67 -0
  16. data/lib/app_archetype/commands/print_version.rb +19 -0
  17. data/lib/app_archetype/commands/render_template.rb +178 -0
  18. data/lib/app_archetype/commands.rb +13 -0
  19. data/lib/app_archetype/generators.rb +4 -3
  20. data/lib/app_archetype/template/manifest.rb +17 -1
  21. data/lib/app_archetype/template_manager.rb +13 -6
  22. data/lib/app_archetype/version.rb +1 -1
  23. data/lib/app_archetype.rb +40 -23
  24. data/lib/core_ext/string.rb +18 -12
  25. data/scripts/create_new_command +32 -0
  26. data/scripts/generators/command/manifest.json +15 -0
  27. data/scripts/generators/command/template/lib/app_archetype/commands/{{command_name.snake_case}}.rb.hbs +17 -0
  28. data/spec/app_archetype/cli/presenters_spec.rb +99 -99
  29. data/spec/app_archetype/cli/prompts_spec.rb +291 -291
  30. data/spec/app_archetype/cli_spec.rb +296 -65
  31. data/spec/app_archetype/commands/delete_template_spec.rb +132 -0
  32. data/spec/app_archetype/commands/find_templates_spec.rb +130 -0
  33. data/spec/app_archetype/commands/list_templates_spec.rb +55 -0
  34. data/spec/app_archetype/commands/new_template_spec.rb +84 -0
  35. data/spec/app_archetype/commands/open_manifest_spec.rb +113 -0
  36. data/spec/app_archetype/commands/print_path_spec.rb +22 -0
  37. data/spec/app_archetype/commands/print_template_variables_spec.rb +158 -0
  38. data/spec/app_archetype/commands/print_version_spec.rb +21 -0
  39. data/spec/app_archetype/commands/render_template_spec.rb +479 -0
  40. data/spec/app_archetype/generators_spec.rb +1 -1
  41. data/spec/app_archetype/template/manifest_spec.rb +31 -1
  42. data/spec/app_archetype/template_manager_spec.rb +32 -0
  43. data/spec/app_archetype_spec.rb +65 -0
  44. metadata +155 -80
  45. data/lib/app_archetype/cli/presenters.rb +0 -106
  46. data/lib/app_archetype/cli/prompts.rb +0 -152
@@ -1,132 +1,363 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe AppArchetype::CLI do
4
+ let(:options) { Hashie::Mash.new }
5
+
4
6
  subject { described_class.new }
5
7
 
6
- describe '.manager' do
8
+ before do
9
+ allow(subject).to receive(:options)
10
+ .and_return(options)
11
+ end
12
+
13
+ describe '#version' do
14
+ let(:command) { double }
15
+
16
+ before do
17
+ allow(command).to receive(:run)
18
+ allow(AppArchetype::Commands::PrintVersion)
19
+ .to receive(:new)
20
+ .and_return(command)
21
+
22
+ subject.version
23
+ end
24
+
25
+ it 'passes options to command' do
26
+ expect(AppArchetype::Commands::PrintVersion)
27
+ .to have_received(:new).with(options)
28
+ end
29
+
30
+ it 'runs command' do
31
+ expect(command).to have_received(:run)
32
+ end
33
+ end
34
+
35
+ describe '#list' do
36
+ let(:command) { double }
7
37
  let(:manager) { double }
38
+
39
+ before do
40
+ allow(command).to receive(:run)
41
+ allow(subject).to receive(:manager).and_return(manager)
42
+ allow(AppArchetype::Commands::ListTemplates)
43
+ .to receive(:new)
44
+ .and_return(command)
45
+
46
+ subject.list
47
+ end
48
+
49
+ it 'passes manager and options to command' do
50
+ expect(AppArchetype::Commands::ListTemplates)
51
+ .to have_received(:new).with(manager, options)
52
+ end
53
+
54
+ it 'runs command' do
55
+ expect(command).to have_received(:run)
56
+ end
57
+ end
58
+
59
+ describe '#path' do
60
+ let(:command) { double }
8
61
  let(:template_dir) { 'path/to/templates' }
9
62
 
10
63
  before do
11
- allow(described_class).to receive(:template_dir).and_return(template_dir)
12
- allow(AppArchetype::TemplateManager).to receive(:new).and_return(manager)
64
+ allow(command).to receive(:run)
65
+ allow(subject).to receive(:template_dir)
66
+ .and_return(template_dir)
13
67
 
14
- allow(manager).to receive(:load)
68
+ allow(AppArchetype::Commands::PrintPath)
69
+ .to receive(:new)
70
+ .and_return(command)
15
71
 
16
- @manager = described_class.manager
72
+ subject.path
17
73
  end
18
74
 
19
- it 'creates a manager' do
20
- expect(AppArchetype::TemplateManager)
21
- .to have_received(:new)
22
- .with(template_dir)
75
+ it 'passes template path and options to command' do
76
+ expect(AppArchetype::Commands::PrintPath)
77
+ .to have_received(:new).with(template_dir, options)
78
+ end
23
79
 
24
- expect(manager).to have_received(:load)
25
- expect(@manager).to eq manager
80
+ it 'runs command' do
81
+ expect(command).to have_received(:run)
26
82
  end
27
83
  end
28
84
 
29
- describe '.template_dir' do
30
- let(:env_template_dir) { 'path/to/templates' }
31
- let(:exist) { true }
85
+ describe '#open' do
86
+ let(:command) { double }
87
+ let(:manager) { double }
88
+ let(:editor) { 'vi' }
32
89
 
33
90
  before do
34
- allow(ENV).to receive(:[])
35
- .with('ARCHETYPE_TEMPLATE_DIR')
36
- .and_return(env_template_dir)
91
+ allow(command).to receive(:run)
92
+ allow(subject).to receive(:manager).and_return(manager)
93
+ allow(subject).to receive(:editor).and_return(editor)
94
+ allow(AppArchetype::Commands::OpenManifest)
95
+ .to receive(:new)
96
+ .and_return(command)
97
+
98
+ subject.open
99
+ end
100
+
101
+ it 'passes manager, editor and options to command' do
102
+ expect(AppArchetype::Commands::OpenManifest)
103
+ .to have_received(:new).with(manager, editor, options)
104
+ end
105
+
106
+ it 'runs command' do
107
+ expect(command).to have_received(:run)
108
+ end
109
+ end
110
+
111
+ describe '#new' do
112
+ let(:command) { double }
113
+ let(:template_dir) { 'path/to/templates' }
114
+
115
+ before do
116
+ allow(command).to receive(:run)
117
+ allow(subject).to receive(:template_dir)
118
+ .and_return(template_dir)
119
+
120
+ allow(AppArchetype::Commands::NewTemplate)
121
+ .to receive(:new)
122
+ .and_return(command)
37
123
 
38
- allow(File).to receive(:exist?).and_return(exist)
124
+ subject.new
39
125
  end
40
126
 
41
- it 'returns template dir' do
42
- expect(described_class.template_dir).to eq env_template_dir
127
+ it 'passes template path and options to command' do
128
+ expect(AppArchetype::Commands::NewTemplate)
129
+ .to have_received(:new).with(template_dir, options)
43
130
  end
44
131
 
45
- context 'when ARCHETYPE_TEMPLATE_DIR environment variable not set' do
46
- let(:env_template_dir) { nil }
132
+ it 'runs command' do
133
+ expect(command).to have_received(:run)
134
+ end
135
+ end
136
+
137
+ describe '#delete' do
138
+ let(:command) { double }
139
+ let(:manager) { double }
140
+
141
+ before do
142
+ allow(command).to receive(:run)
143
+ allow(subject).to receive(:manager).and_return(manager)
144
+ allow(AppArchetype::Commands::DeleteTemplate)
145
+ .to receive(:new)
146
+ .and_return(command)
147
+
148
+ subject.delete
149
+ end
150
+
151
+ it 'passes manager and options to command' do
152
+ expect(AppArchetype::Commands::DeleteTemplate)
153
+ .to have_received(:new).with(manager, options)
154
+ end
155
+
156
+ it 'runs command' do
157
+ expect(command).to have_received(:run)
158
+ end
159
+ end
160
+
161
+ describe '#variables' do
162
+ let(:command) { double }
163
+ let(:manager) { double }
164
+
165
+ before do
166
+ allow(command).to receive(:run)
167
+ allow(subject).to receive(:manager).and_return(manager)
168
+ allow(AppArchetype::Commands::PrintTemplateVariables)
169
+ .to receive(:new)
170
+ .and_return(command)
47
171
 
48
- it 'raises environment not set error' do
49
- expect { described_class.template_dir }.to raise_error(
172
+ subject.variables
173
+ end
174
+
175
+ it 'passes manager and options to command' do
176
+ expect(AppArchetype::Commands::PrintTemplateVariables)
177
+ .to have_received(:new).with(manager, options)
178
+ end
179
+
180
+ it 'runs command' do
181
+ expect(command).to have_received(:run)
182
+ end
183
+ end
184
+
185
+ describe '#find' do
186
+ let(:command) { double }
187
+ let(:manager) { double }
188
+
189
+ before do
190
+ allow(command).to receive(:run)
191
+ allow(subject).to receive(:manager).and_return(manager)
192
+ allow(AppArchetype::Commands::FindTemplates)
193
+ .to receive(:new)
194
+ .and_return(command)
195
+
196
+ subject.find
197
+ end
198
+
199
+ it 'passes manager and options to command' do
200
+ expect(AppArchetype::Commands::FindTemplates)
201
+ .to have_received(:new).with(manager, options)
202
+ end
203
+
204
+ it 'runs command' do
205
+ expect(command).to have_received(:run)
206
+ end
207
+ end
208
+
209
+ describe '#render' do
210
+ let(:command) { double }
211
+ let(:manager) { double }
212
+ let(:out_path) { 'path/to/out' }
213
+ let(:options) { Hashie::Mash.new(out: out_path) }
214
+
215
+ before do
216
+ allow(command).to receive(:run)
217
+ allow(subject).to receive(:manager).and_return(manager)
218
+ allow(AppArchetype::Commands::RenderTemplate)
219
+ .to receive(:new)
220
+ .and_return(command)
221
+
222
+ subject.render
223
+ end
224
+
225
+ it 'passes manager, out path and options to command' do
226
+ expect(AppArchetype::Commands::RenderTemplate)
227
+ .to have_received(:new).with(manager, out_path, options)
228
+ end
229
+
230
+ it 'runs command' do
231
+ expect(command).to have_received(:run)
232
+ end
233
+ end
234
+
235
+ describe '#template_dir' do
236
+ let(:template_dir) { 'path/to/template/dir' }
237
+ let(:template_dir_exist) { false }
238
+
239
+ before do
240
+ allow(ENV)
241
+ .to receive(:[])
242
+ .with('ARCHETYPE_TEMPLATE_DIR')
243
+ .and_return(template_dir)
244
+
245
+ allow(File)
246
+ .to receive(:exist?)
247
+ .and_return(template_dir_exist)
248
+ end
249
+
250
+ context 'when environment variable not set' do
251
+ let(:template_dir) { nil }
252
+
253
+ it 'raises env var not set runtime error' do
254
+ expect do
255
+ subject.template_dir
256
+ end.to raise_error(
50
257
  RuntimeError,
51
258
  'ARCHETYPE_TEMPLATE_DIR environment variable not set'
52
259
  )
53
260
  end
54
261
  end
55
262
 
56
- context 'when templates do not exist' do
57
- let(:exist) { false }
58
-
59
- it 'raises environment not set error' do
60
- expect { described_class.template_dir }.to raise_error(
263
+ context 'when template directory does not exist' do
264
+ it 'raises env var not exist runtime error' do
265
+ expect do
266
+ subject.template_dir
267
+ end.to raise_error(
61
268
  RuntimeError,
62
- "ARCHETYPE_TEMPLATE_DIR #{env_template_dir} does not exist"
269
+ "ARCHETYPE_TEMPLATE_DIR #{template_dir} does not exist"
63
270
  )
64
271
  end
65
272
  end
273
+
274
+ context 'when environment variable set and directory exists' do
275
+ let(:template_dir_exist) { true }
276
+
277
+ it 'returns template dir' do
278
+ expect(subject.template_dir).to eq template_dir
279
+ end
280
+ end
66
281
  end
67
282
 
68
- describe '.editor' do
69
- let(:env_editor) { 'ivm' }
70
- let(:exit_status) { 0 }
283
+ describe '#editor' do
284
+ let(:editor) { 'vi' }
285
+ let(:editor_check_process_result) { double }
71
286
 
72
287
  before do
73
- allow(ENV).to receive(:[])
288
+ allow(ENV)
289
+ .to receive(:[])
74
290
  .with('ARCHETYPE_EDITOR')
75
- .and_return(env_editor)
76
-
77
- allow(described_class).to receive(:`)
78
- allow($?).to receive(:exitstatus).and_return(exit_status)
79
- end
291
+ .and_return(editor)
80
292
 
81
- it 'returns editor' do
82
- expect(described_class.editor).to eq env_editor
293
+ allow(subject).to receive(:puts)
83
294
  end
84
295
 
85
- context 'when ARCHETYPE_EDITOR environment variable not set' do
86
- let(:env_editor) { nil }
296
+ context 'when editor is not set' do
297
+ let(:editor) { nil }
87
298
 
88
- it 'raises environment not set error' do
89
- expect { described_class.editor }.to raise_error(
299
+ it 'raises archetype editor runtime error' do
300
+ expect do
301
+ subject.editor
302
+ end.to raise_error(
90
303
  RuntimeError,
91
304
  'ARCHETYPE_EDITOR environment variable not set'
92
305
  )
93
306
  end
94
307
  end
95
308
 
96
- context 'when editor check does not pass' do
97
- let(:exit_status) { 1 }
309
+ context 'when check exit status is non zero' do
310
+ let(:editor) { 'not-valid-editor' }
98
311
 
99
- before do
100
- allow(AppArchetype::CLI).to receive(:print_warning)
101
- described_class.editor
102
- end
312
+ it 'warns user that the editor is not installed correctly' do
313
+ subject.editor
103
314
 
104
- it 'logs a warning' do
105
- expect(AppArchetype::CLI)
106
- .to have_received(:print_warning)
315
+ expect(subject)
316
+ .to have_received(:puts)
107
317
  .with(
108
- "WARN: Configured editor #{env_editor} is not installed correctly "\
318
+ "WARN: Configured editor #{editor} is not installed correctly "\
109
319
  'please check your configuration'
110
320
  )
111
321
  end
112
322
  end
113
- end
114
323
 
115
- describe '.exit_on_failure?' do
116
- it 'returns true' do
117
- expect(described_class.exit_on_failure?).to be true
324
+ context 'when editor is set and check exit status is zero' do
325
+ it 'returns editor' do
326
+ expect(subject.editor).to eq editor
327
+ end
118
328
  end
119
329
  end
120
330
 
121
- describe '#version' do
331
+ describe '#manager' do
332
+ let(:template_dir) { 'path/to/template/dir' }
333
+ let(:manager) { double(AppArchetype::TemplateManager) }
334
+
122
335
  before do
123
- allow(subject).to receive(:print_message)
124
- subject.version
336
+ allow(subject)
337
+ .to receive(:template_dir)
338
+ .and_return(template_dir)
339
+
340
+ allow(AppArchetype::TemplateManager)
341
+ .to receive(:new)
342
+ .and_return(manager)
343
+
344
+ allow(manager).to receive(:load)
345
+
346
+ @manager = subject.manager
125
347
  end
126
348
 
127
- it 'prints current version number' do
128
- expect(subject).to have_received(:print_message)
129
- .with(AppArchetype::VERSION)
349
+ it 'creates a new template with template dir' do
350
+ expect(AppArchetype::TemplateManager)
351
+ .to have_received(:new)
352
+ .with(template_dir)
353
+ end
354
+
355
+ it 'loads manager' do
356
+ expect(manager).to have_received(:load)
357
+ end
358
+
359
+ it 'returns manager' do
360
+ expect(@manager).to eq manager
130
361
  end
131
362
  end
132
363
  end
@@ -0,0 +1,132 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe AppArchetype::Commands::DeleteTemplate do
4
+ let(:manager) { double(AppArchetype::TemplateManager) }
5
+ let(:options) { Hashie::Mash.new }
6
+ let(:prompt) { double(TTY::Prompt) }
7
+
8
+ subject { described_class.new(manager, options) }
9
+
10
+ before do
11
+ subject.instance_variable_set(:@prompt, prompt)
12
+ end
13
+
14
+ describe '#run' do
15
+ let(:ok_to_proceed) { true }
16
+ let(:manifest) { double(AppArchetype::Template::Manifest) }
17
+ let(:manifest_parent_path) { 'path/to/template' }
18
+ let(:manifest_name) { 'some-manifest' }
19
+
20
+ before do
21
+ allow(manager).to receive(:find_by_name).and_return(manifest)
22
+ allow(manager).to receive(:manifest_names).and_return([manifest_name])
23
+
24
+ allow(prompt).to receive(:select).and_return(manifest_name)
25
+ allow(prompt).to receive(:yes?).and_return(ok_to_proceed)
26
+
27
+ allow(manifest)
28
+ .to receive(:parent_path)
29
+ .and_return(manifest_parent_path)
30
+
31
+ allow(FileUtils).to receive(:rm_rf)
32
+ allow(subject).to receive(:puts)
33
+ subject.run
34
+ end
35
+
36
+ context 'when name is provided in options' do
37
+ let(:options) do
38
+ Hashie::Mash.new(
39
+ name: manifest_name
40
+ )
41
+ end
42
+
43
+ describe 'and the manifest is found' do
44
+ it 'finds the manifest' do
45
+ expect(manager)
46
+ .to have_received(:find_by_name)
47
+ .with(manifest_name)
48
+ end
49
+
50
+ it 'asks whether to proceed' do
51
+ expect(prompt)
52
+ .to have_received(:yes?)
53
+ .with("Are you sure you want to delete #{manifest_name}?")
54
+ end
55
+
56
+ describe 'when we should delete the template' do
57
+ it 'removes template' do
58
+ expect(FileUtils).to have_received(:rm_rf)
59
+ .with(manifest_parent_path)
60
+ end
61
+
62
+ it 'prints success message' do
63
+ expect(subject).to have_received(:puts)
64
+ .with("✔ Template `#{manifest_name}` has been removed")
65
+ end
66
+ end
67
+
68
+ describe 'when we should not delete the template' do
69
+ let(:ok_to_proceed) { false }
70
+
71
+ it 'does not remove the template' do
72
+ expect(FileUtils).not_to have_received(:rm_rf)
73
+ end
74
+ end
75
+ end
76
+
77
+ describe 'and the manifest is not found' do
78
+ let(:manifest) { nil }
79
+
80
+ it 'attempts to find the manifest' do
81
+ expect(manager)
82
+ .to have_received(:find_by_name)
83
+ .with(manifest_name)
84
+ end
85
+
86
+ it 'prints manifest not found message' do
87
+ expect(subject).to have_received(:puts)
88
+ .with("✖ No template with name `#{manifest_name}` found.")
89
+ end
90
+ end
91
+ end
92
+
93
+ context 'when name is not provided in options' do
94
+ before do
95
+ allow(prompt)
96
+ .to receive(:select)
97
+ .and_return(manifest_name)
98
+ end
99
+
100
+ it 'prompts the user to choose the manifest for deletion' do
101
+ expect(prompt)
102
+ .to have_received(:select)
103
+ .with('Please choose template for deletion', [manifest_name])
104
+ end
105
+
106
+ it 'asks whether to proceed' do
107
+ expect(prompt).to have_received(:yes?)
108
+ .with("Are you sure you want to delete #{manifest_name}?")
109
+ end
110
+
111
+ describe 'when we should delete the template' do
112
+ it 'removes template' do
113
+ expect(FileUtils).to have_received(:rm_rf)
114
+ .with(manifest_parent_path)
115
+ end
116
+
117
+ it 'prints success message' do
118
+ expect(subject).to have_received(:puts)
119
+ .with("✔ Template `#{manifest_name}` has been removed")
120
+ end
121
+ end
122
+
123
+ describe 'when we should not delete the template' do
124
+ let(:ok_to_proceed) { false }
125
+
126
+ it 'does not remove the template' do
127
+ expect(FileUtils).not_to have_received(:rm_rf)
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,130 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe AppArchetype::Commands::FindTemplates do
4
+ let(:manager) { double(AppArchetype::TemplateManager) }
5
+ let(:options) { Hashie::Mash.new }
6
+ let(:prompt) { double(TTY::Prompt) }
7
+
8
+ subject { described_class.new(manager, options) }
9
+
10
+ before do
11
+ subject.instance_variable_set(:@prompt, prompt)
12
+ end
13
+
14
+ describe '#run' do
15
+ let(:prompt_response) { nil }
16
+ let(:found_manifests) { [] }
17
+
18
+ let(:manifest_name) { 'some-template' }
19
+ let(:manifest_version) { '1.0.0' }
20
+
21
+ let(:manifest) do
22
+ double(
23
+ AppArchetype::Template::Manifest,
24
+ name: manifest_name,
25
+ version: manifest_version
26
+ )
27
+ end
28
+
29
+ before do
30
+ allow(prompt)
31
+ .to receive(:ask)
32
+ .and_return(prompt_response)
33
+
34
+ allow(manager)
35
+ .to receive(:search_by_name)
36
+ .and_return(found_manifests)
37
+
38
+ allow(subject).to receive(:puts)
39
+ end
40
+
41
+ context 'when name is provided in options' do
42
+ let(:options) do
43
+ Hashie::Mash.new(
44
+ name: manifest_name
45
+ )
46
+ end
47
+
48
+ describe 'and the template is not found' do
49
+ before { subject.run }
50
+
51
+ it 'uses manager to search for template by name' do
52
+ expect(manager)
53
+ .to have_received(:search_by_name)
54
+ .with(manifest_name)
55
+ end
56
+
57
+ it 'prints no manifests found message' do
58
+ expect(subject)
59
+ .to have_received(:puts)
60
+ .with("✖ No manifests with name `#{manifest_name}` found.")
61
+ end
62
+ end
63
+
64
+ describe 'and the template is found' do
65
+ let(:found_manifests) { [manifest] }
66
+
67
+ before { subject.run }
68
+
69
+ it 'uses manager to search for template by name' do
70
+ expect(manager)
71
+ .to have_received(:search_by_name)
72
+ .with(manifest_name)
73
+ end
74
+
75
+ it 'prints manifest list table' do
76
+ expected_table = <<~TABLE
77
+ NAME VERSION
78
+ #{manifest_name} #{manifest_version}
79
+ TABLE
80
+
81
+ expect(subject)
82
+ .to have_received(:puts)
83
+ .with(expected_table.strip)
84
+ end
85
+ end
86
+ end
87
+
88
+ context 'when the name is not provided in options' do
89
+ before do
90
+ allow(prompt).to receive(:ask).and_return(manifest_name)
91
+ subject.run
92
+ end
93
+
94
+ it 'prompts user for a template name' do
95
+ expect(prompt)
96
+ .to have_received(:ask)
97
+ .with('Please enter a template name')
98
+ end
99
+
100
+ it 'uses manager to search for template by name' do
101
+ expect(manager)
102
+ .to have_received(:search_by_name)
103
+ .with(manifest_name)
104
+ end
105
+
106
+ describe 'when there are results' do
107
+ let(:found_manifests) { [manifest] }
108
+
109
+ it 'prints manifest list table' do
110
+ expected_table = <<~TABLE
111
+ NAME VERSION
112
+ #{manifest_name} #{manifest_version}
113
+ TABLE
114
+
115
+ expect(subject)
116
+ .to have_received(:puts)
117
+ .with(expected_table.strip)
118
+ end
119
+ end
120
+
121
+ describe 'when there are no results' do
122
+ it 'prints no manifests found messsage' do
123
+ expect(subject)
124
+ .to have_received(:puts)
125
+ .with("✖ No manifests with name `#{manifest_name}` found.")
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end