brut 0.18.2 → 0.19.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.
@@ -3,19 +3,22 @@ require "brut/cli"
3
3
 
4
4
  class Brut::CLI::Apps::Scaffold < Brut::CLI::Commands::BaseCommand
5
5
  def description = "Create scaffolds of various files to help develop more quckly"
6
- def opts = [
7
- [ "--overwrite", "If set, any files that exists already will be overwritten by new scaffolds" ],
8
- [ "--dry-run", "If set, no files are changed. You will see output of what would happen without this flag"],
9
- ]
10
6
 
11
- def default_rack_env = "development"
7
+ class BaseCommand < Brut::CLI::Commands::BaseCommand
8
+ def bootstrap? = false
9
+ def default_rack_env = "development"
10
+ def opts = [
11
+ [ "--overwrite", "If set, any files that exists already will be overwritten by new scaffolds" ],
12
+ [ "--dry-run", "If set, no files are changed. You will see output of what would happen without this flag"],
13
+ ]
14
+ end
12
15
 
13
- class Test < Brut::CLI::Commands::BaseCommand
16
+ class Test < BaseCommand
14
17
  def description = "Create the shell of a unit test based on an existing source file"
15
18
  def args_description = "source_file_paths..."
16
19
  def run
17
20
  if argv.empty?
18
- stderr.puts "'test' requires one or more files to scaffold a test for"
21
+ error "'test' requires one or more files to scaffold a test for"
19
22
  return 1
20
23
  end
21
24
  files_to_test_files = argv.map { |arg|
@@ -31,18 +34,18 @@ class Brut::CLI::Apps::Scaffold < Brut::CLI::Commands::BaseCommand
31
34
 
32
35
  if non_existent_sources.any?
33
36
  relative_paths = non_existent_sources.map { |pathname| pathname.relative_path_from(Brut.container.project_root) }
34
- stderr.puts "Not all input files exist:"
37
+ error "Not all input files exist:"
35
38
  relative_paths.each do |file|
36
- stderr.puts file
39
+ error file
37
40
  end
38
41
  return 1
39
42
  end
40
43
 
41
- if existent_destinations.any? && !global_options.overwrite?
44
+ if existent_destinations.any? && !options.overwrite?
42
45
  relative_paths = existent_destinations.map { |pathname| pathname.relative_path_from(Brut.container.project_root) }
43
- stderr.puts "Some files to be generated already exist. Set --overwrite to overwrite them:"
46
+ error "Some files to be generated already exist. Set --overwrite to overwrite them:"
44
47
  relative_paths.each do |file|
45
- stderr.puts file
48
+ error file
46
49
  end
47
50
  return 1
48
51
  end
@@ -57,7 +60,7 @@ class Brut::CLI::Apps::Scaffold < Brut::CLI::Commands::BaseCommand
57
60
  }
58
61
 
59
62
 
60
- stdout.puts "#{destination} will contain tests for:\n#{classes.join("\n")}\n\n"
63
+ puts "#{destination} will contain tests for:\n#{classes.join("\n")}\n\n"
61
64
 
62
65
  code = ["require \"spec_helper\"\n"] + classes.map { |class_name|
63
66
  %{RSpec.describe #{class_name} do
@@ -67,8 +70,8 @@ class Brut::CLI::Apps::Scaffold < Brut::CLI::Commands::BaseCommand
67
70
  end}
68
71
  }
69
72
 
70
- if global_options.dry_run?
71
- stdout.puts code
73
+ if options.dry_run?
74
+ puts code
72
75
  else
73
76
  FileUtils.mkdir_p destination.dirname
74
77
  File.open(destination,"w") do |file|
@@ -103,10 +106,10 @@ end}
103
106
  end
104
107
  end
105
108
 
106
- class E2ETest < Brut::CLI::Commands::BaseCommand
109
+ class E2ETest < BaseCommand
107
110
  def description = "Create the shell of an end-to-end test"
108
111
  def args_description = "test_name"
109
- def self.command_name = "test:e2e"
112
+ def name = "e2e_test"
110
113
 
111
114
  def opts = [
112
115
  ["--path PATH","Path within the e2e tests to create the file"],
@@ -114,7 +117,7 @@ end}
114
117
 
115
118
  def run
116
119
  if argv.empty?
117
- stderr.puts "'#{self.class.command_name}' requires a name"
120
+ error "'#{self.class.command_name}' requires a name"
118
121
  return 1
119
122
  end
120
123
  test_name = argv.join(" ").gsub(/\"/,"'")
@@ -130,11 +133,11 @@ end}
130
133
  dry_run_verb = "create"
131
134
 
132
135
  if path_to_test_file.exist?
133
- if global_options.overwrite?
136
+ if options.overwrite?
134
137
  verb = "Overwrote"
135
138
  dry_run_verb = "overwrite"
136
139
  else
137
- stderr.puts "#{path_to_test_file.relative_path_from(Brut.container.project_root)} exists. Use --overwrite to replace it"
140
+ error "#{path_to_test_file.relative_path_from(Brut.container.project_root)} exists. Use --overwrite to replace it"
138
141
  return 1
139
142
  end
140
143
  end
@@ -148,16 +151,16 @@ RSpec.describe "#{test_name}" do
148
151
  expect(page).to be_page_for(page_class_here)
149
152
  end
150
153
  end}
151
- if global_options.dry_run?
152
- stdout.puts "Will #{dry_run_verb} #{path_to_test_file.relative_path_from(Brut.container.project_root)} with this code:"
153
- stdout.puts_no_prefix
154
- stdout.puts_no_prefix code
154
+ if options.dry_run?
155
+ puts "Will #{dry_run_verb} #{path_to_test_file.relative_path_from(Brut.container.project_root)} with this code:"
156
+ puts
157
+ puts code
155
158
  else
156
159
  FileUtils.mkdir_p test_file_dir
157
160
  File.open(path_to_test_file,"w") do |file|
158
161
  file.puts code
159
162
  end
160
- stdout.puts "#{verb} #{path_to_test_file.relative_path_from(Brut.container.project_root)}"
163
+ puts "#{verb} #{path_to_test_file.relative_path_from(Brut.container.project_root)}"
161
164
  end
162
165
  0
163
166
  end
@@ -185,7 +188,7 @@ end}
185
188
  end
186
189
  end
187
190
 
188
- class Component < Brut::CLI::Commands::BaseCommand
191
+ class Component < BaseCommand
189
192
  def description = "Create a new component and associated test"
190
193
  def args_description = "ComponentName"
191
194
  def detailed_description = "New components go in the `components/` folder of your app, however using --page will create a 'page private' component. To do that, the component name must be an inner class of an existing page, for example HomePage::Welcome. This component goes in a sub-folder inside the `pages/` area of your app"
@@ -230,17 +233,17 @@ end}
230
233
  spec_path,
231
234
  ].select(&:exist?)
232
235
 
233
- if exists.any? && !global_options.overwrite?
236
+ if exists.any? && !options.overwrite?
234
237
  exists.each do |path|
235
- stderr.puts "'#{path.relative_path_from(Brut.container.project_root)}' exists already"
238
+ error "'#{path.relative_path_from(Brut.container.project_root)}' exists already"
236
239
  end
237
- stderr.puts "Re-run with --overwrite to overwrite these files"
240
+ error "Re-run with --overwrite to overwrite these files"
238
241
  return 1
239
242
  end
240
243
 
241
- if global_options.dry_run?
242
- stdout.puts "FileUtils.mkdir_p #{source_path.dirname}"
243
- stdout.puts "FileUtils.mkdir_p #{spec_path.dirname}"
244
+ if options.dry_run?
245
+ puts "FileUtils.mkdir_p #{source_path.dirname}"
246
+ puts "FileUtils.mkdir_p #{spec_path.dirname}"
244
247
  else
245
248
  FileUtils.mkdir_p source_path.dirname
246
249
  FileUtils.mkdir_p spec_path.dirname
@@ -265,12 +268,12 @@ RSpec.describe #{class_name} do
265
268
  end}
266
269
  end
267
270
  end
268
- stdout.puts "Component source is in #{source_path.relative_path_from(Brut.container.project_root)}"
269
- stdout.puts "Component test is in #{spec_path.relative_path_from(Brut.container.project_root)}"
271
+ puts "Component source is in #{source_path.relative_path_from(Brut.container.project_root)}"
272
+ puts "Component test is in #{spec_path.relative_path_from(Brut.container.project_root)}"
270
273
  0
271
274
  end
272
275
  end
273
- class Page < Brut::CLI::Commands::BaseCommand
276
+ class Page < BaseCommand
274
277
  class Route < Brut::FrontEnd::Routing::PageRoute
275
278
  def initialize(path_template)
276
279
  path_template = "/#{path_template}".gsub(/\/\//,"/")
@@ -310,16 +313,16 @@ end}
310
313
  page_spec_path,
311
314
  ].select(&:exist?)
312
315
 
313
- if exists.any? && !global_options.overwrite?
316
+ if exists.any? && !options.overwrite?
314
317
  exists.each do |path|
315
- stderr.puts "'#{path.relative_path_from(Brut.container.project_root)}' exists already"
318
+ error "'#{path.relative_path_from(Brut.container.project_root)}' exists already"
316
319
  end
317
- stderr.puts "Re-run with --overwrite to overwrite these files"
320
+ error "Re-run with --overwrite to overwrite these files"
318
321
  return 1
319
322
  end
320
323
 
321
- FileUtils.mkdir_p page_source_path.dirname, noop: global_options.dry_run?
322
- FileUtils.mkdir_p page_spec_path.dirname, noop: global_options.dry_run?
324
+ FileUtils.mkdir_p page_source_path.dirname, noop: options.dry_run?
325
+ FileUtils.mkdir_p page_spec_path.dirname, noop: options.dry_run?
323
326
 
324
327
  route_code = "page \"#{route.path_template}\""
325
328
 
@@ -349,15 +352,15 @@ end}
349
352
  title = RichString.new(page_class_name).underscorized.humanized.to_s.capitalize
350
353
  translations_code = " \"#{page_class_name}\": {\n title: \"#{title}\",\n \},"
351
354
 
352
- if global_options.dry_run?
353
- stdout.puts app_path.relative_path_from(Brut.container.project_root)
354
- stdout.puts "will contain:\n\n#{route_code}\n\n"
355
- stdout.puts page_source_path.relative_path_from(Brut.container.project_root)
356
- stdout.puts "will contain:\n\n#{page_class_code}\n\n"
357
- stdout.puts page_spec_path.relative_path_from(Brut.container.project_root)
358
- stdout.puts "will contain:\n\n#{page_spec_code}\n\n"
359
- stdout.puts app_translations.relative_path_from(Brut.container.project_root)
360
- stdout.puts "will contain:\n\n#{translations_code}\n\n"
355
+ if options.dry_run?
356
+ puts app_path.relative_path_from(Brut.container.project_root)
357
+ puts "will contain:\n\n#{route_code}\n\n"
358
+ puts page_source_path.relative_path_from(Brut.container.project_root)
359
+ puts "will contain:\n\n#{page_class_code}\n\n"
360
+ puts page_spec_path.relative_path_from(Brut.container.project_root)
361
+ puts "will contain:\n\n#{page_spec_code}\n\n"
362
+ puts app_translations.relative_path_from(Brut.container.project_root)
363
+ puts "will contain:\n\n#{translations_code}\n\n"
361
364
  else
362
365
 
363
366
  File.open(page_source_path,"w") { it.puts page_class_code }
@@ -377,29 +380,29 @@ end}
377
380
  end
378
381
  end
379
382
  if !inserted_translation
380
- stderr.puts "WARNING: Could not find a place to insert the translation for this page's title"
381
- stderr.puts " The page may not render properly the first time you load it"
383
+ error "WARNING: Could not find a place to insert the translation for this page's title"
384
+ error " The page may not render properly the first time you load it"
382
385
  end
383
386
 
384
387
  routes_editor = RoutesEditor.new(app_path:,out:)
385
388
  routes_editor.add_route!(route_code:)
386
389
 
387
390
  if !routes_editor.found_routes?
388
- stdout.puts "Could not find routes declaration in #{app_path.relative_path_from(Brut.container.project_root)}"
389
- stdout.puts "Please add this to wherever you have defined your routes:\n\n#{route_code}\n\n"
391
+ puts "Could not find routes declaration in #{app_path.relative_path_from(Brut.container.project_root)}"
392
+ puts "Please add this to wherever you have defined your routes:\n\n#{route_code}\n\n"
390
393
  elsif routes_editor.routes_existed?
391
- stdout.puts "Routes declaration in #{app_path.relative_path_from(Brut.container.project_root)} contained the route defition already"
392
- stdout.puts "Please make sure everything is correct. Here is the defintion that was not inserted:\n\n#{route_code}"
394
+ puts "Routes declaration in #{app_path.relative_path_from(Brut.container.project_root)} contained the route defition already"
395
+ puts "Please make sure everything is correct. Here is the defintion that was not inserted:\n\n#{route_code}"
393
396
  end
394
397
  end
395
- stdout.puts "Page source is in #{page_source_path.relative_path_from(Brut.container.project_root)}"
396
- stdout.puts "Page test is in #{page_spec_path.relative_path_from(Brut.container.project_root)}"
397
- stdout.puts "Added title to #{app_translations.relative_path_from(Brut.container.project_root)}"
398
- stdout.puts "Added route to #{app_path.relative_path_from(Brut.container.project_root)}"
398
+ puts "Page source is in #{page_source_path.relative_path_from(Brut.container.project_root)}"
399
+ puts "Page test is in #{page_spec_path.relative_path_from(Brut.container.project_root)}"
400
+ puts "Added title to #{app_translations.relative_path_from(Brut.container.project_root)}"
401
+ puts "Added route to #{app_path.relative_path_from(Brut.container.project_root)}"
399
402
  0
400
403
  end
401
404
  end
402
- class Action < Brut::CLI::Commands::BaseCommand
405
+ class Action < BaseCommand
403
406
  class Route < Brut::FrontEnd::Routing::FormRoute
404
407
  def initialize(path_template)
405
408
  path_template = "/#{path_template}".gsub(/\/\//,"/")
@@ -451,19 +454,19 @@ end}
451
454
 
452
455
  exists = paths_to_check.select(&:exist?)
453
456
 
454
- if exists.any? && !global_options.overwrite?
457
+ if exists.any? && !options.overwrite?
455
458
  exists.each do |path|
456
- stderr.puts "'#{path.relative_path_from(Brut.container.project_root)}' exists already"
459
+ error "'#{path.relative_path_from(Brut.container.project_root)}' exists already"
457
460
  end
458
- stderr.puts "Re-run with global option --overwrite to overwrite these files"
461
+ error "Re-run with global option --overwrite to overwrite these files"
459
462
  return 1
460
463
  end
461
464
 
462
465
  if form
463
- FileUtils.mkdir_p form_source_path.dirname, noop: global_options.dry_run?
466
+ FileUtils.mkdir_p form_source_path.dirname, noop: options.dry_run?
464
467
  end
465
- FileUtils.mkdir_p handler_source_path.dirname, noop: global_options.dry_run?
466
- FileUtils.mkdir_p handler_spec_path.dirname, noop: global_options.dry_run?
468
+ FileUtils.mkdir_p handler_source_path.dirname, noop: options.dry_run?
469
+ FileUtils.mkdir_p handler_spec_path.dirname, noop: options.dry_run?
467
470
 
468
471
  form_code = %{class #{form_class_name} < AppForm
469
472
  input :some_field, minlength: 3
@@ -504,26 +507,26 @@ end}
504
507
  "path \"#{route.path_template}\", method: :#{options.http_method.downcase}"
505
508
  end
506
509
 
507
- if global_options.dry_run?
508
- stdout.puts app_path.relative_path_from(Brut.container.project_root)
509
- stdout.puts "will contain:\n\n#{route_code}\n\n"
510
+ if options.dry_run?
511
+ puts app_path.relative_path_from(Brut.container.project_root)
512
+ puts "will contain:\n\n#{route_code}\n\n"
510
513
  if form
511
- stdout.puts form_source_path.relative_path_from(Brut.container.project_root)
512
- stdout.puts "will contain:\n\n#{form_code}\n\n"
514
+ puts form_source_path.relative_path_from(Brut.container.project_root)
515
+ puts "will contain:\n\n#{form_code}\n\n"
513
516
  end
514
- stdout.puts handler_source_path.relative_path_from(Brut.container.project_root)
515
- stdout.puts "will contain:\n\n#{handler_code}\n\n"
516
- stdout.puts handler_spec_path.relative_path_from(Brut.container.project_root)
517
- stdout.puts "will contain:\n\n#{spec_code}\n\n"
517
+ puts handler_source_path.relative_path_from(Brut.container.project_root)
518
+ puts "will contain:\n\n#{handler_code}\n\n"
519
+ puts handler_spec_path.relative_path_from(Brut.container.project_root)
520
+ puts "will contain:\n\n#{spec_code}\n\n"
518
521
  else
519
522
  class_name_length = [ form_class_name.length, handler_class_name.length, "Spec".length ].max
520
523
  printf_string = "%-#{class_name_length}s in %s\n"
521
- stdout.puts "\n\n"
524
+ puts "\n\n"
522
525
  if form
523
- stdout.printf printf_string,form_class_name,form_source_path.relative_path_from(Brut.container.project_root)
526
+ execution_context.stdout.printf printf_string,form_class_name,form_source_path.relative_path_from(Brut.container.project_root)
524
527
  end
525
- stdout.printf printf_string,handler_class_name, handler_source_path.relative_path_from(Brut.container.project_root)
526
- stdout.printf printf_string,"Spec", handler_spec_path.relative_path_from(Brut.container.project_root)
528
+ execution_context.stdout.printf printf_string,handler_class_name, handler_source_path.relative_path_from(Brut.container.project_root)
529
+ execution_context.stdout.printf printf_string,"Spec", handler_spec_path.relative_path_from(Brut.container.project_root)
527
530
 
528
531
  routes_editor = RoutesEditor.new(app_path:,out:)
529
532
  routes_editor.add_route!(route_code:)
@@ -534,11 +537,11 @@ end}
534
537
  File.open(handler_source_path,"w") { it.puts handler_code }
535
538
  File.open(handler_spec_path,"w") { it.puts spec_code }
536
539
  if !routes_editor.found_routes?
537
- stdout.puts "Could not find routes declaration in #{app_path.relative_path_from(Brut.container.project_root)}"
538
- stdout.puts "Please add this to wherever you have defined your routes:\n\n#{route_code}\n\n"
540
+ puts "Could not find routes declaration in #{app_path.relative_path_from(Brut.container.project_root)}"
541
+ puts "Please add this to wherever you have defined your routes:\n\n#{route_code}\n\n"
539
542
  elsif routes_editor.routes_existed?
540
- stdout.puts "Routes declaration in #{app_path.relative_path_from(Brut.container.project_root)} contained the route defition already"
541
- stdout.puts "Please make sure everything is correct. Here is the defintion that was not inserted:\n\n#{route_code}"
543
+ puts "Routes declaration in #{app_path.relative_path_from(Brut.container.project_root)} contained the route defition already"
544
+ puts "Please make sure everything is correct. Here is the defintion that was not inserted:\n\n#{route_code}"
542
545
  end
543
546
  end
544
547
  0
@@ -554,17 +557,17 @@ end}
554
557
  end
555
558
  end
556
559
 
557
- class CustomElementTest < Brut::CLI::Commands::BaseCommand
560
+ class CustomElementTest < BaseCommand
558
561
  def description = "Create a test for a custom element in your app"
559
562
  def args_description = "path_to_js_files..."
560
563
  def run
561
564
  if argv.empty?
562
- stderr.puts "'custom-element-test' requires one or more files to scaffold a test for"
565
+ error "'custom-element-test' requires one or more files to scaffold a test for"
563
566
  return 1
564
567
  end
565
568
 
566
569
  if argv.any? { |file| Pathname(file).extname != ".js" }
567
- stderr.puts "'custom-element-test' must be given only .js files"
570
+ error "'custom-element-test' must be given only .js files"
568
571
  return 1
569
572
  end
570
573
 
@@ -580,11 +583,11 @@ end}
580
583
  spec.exist?
581
584
  }
582
585
 
583
- if existing_files.any? && !global_options.overwrite?
586
+ if existing_files.any? && !options.overwrite?
584
587
  relative_paths = existing_files.map { |_,pathname| pathname.relative_path_from(Brut.container.project_root) }
585
- stderr.puts "Some files to be generated already exist. Set global option --overwrite to overwrite them:"
588
+ error "Some files to be generated already exist. Set global option --overwrite to overwrite them:"
586
589
  relative_paths.each do |file|
587
- stderr.puts file
590
+ error file
588
591
  end
589
592
  return 1
590
593
  end
@@ -609,8 +612,8 @@ describe("#{description}", () => {
609
612
  assert.fail("test goes here")
610
613
  })
611
614
  })}
612
- if global_options.dry_run?
613
- stdout.puts "Would generate this code:\n\n#{code}"
615
+ if options.dry_run?
616
+ puts "Would generate this code:\n\n#{code}"
614
617
  else
615
618
  File.open(spec_file, "w") do |file|
616
619
  file.puts code
@@ -622,7 +625,7 @@ describe("#{description}", () => {
622
625
  end
623
626
  end
624
627
 
625
- class DbModel < Brut::CLI::Commands::BaseCommand
628
+ class DbModel < BaseCommand
626
629
  def description = "Creates a DB models, factories, and a single placeholder migration"
627
630
  def args_description = "model_name..."
628
631
 
@@ -648,31 +651,31 @@ describe("#{description}", () => {
648
651
  }
649
652
  end
650
653
  migration_name = "create_" + argv.join("_").gsub(/[^\w]/,"_").gsub(/__/,"_")
651
- if global_options.dry_run?
652
- @stdout.puts "Would create the following DB models:"
654
+ if options.dry_run?
655
+ puts "Would create the following DB models:"
653
656
  actions.each do |action|
654
- @stdout.puts "#{action[:class_name]}"
655
- @stdout.puts " prefix: #{action[:prefix]}"
656
- @stdout.puts " in: #{action[:path]}"
657
- @stdout.puts " spec: #{action[:spec_path]}"
658
- @stdout.puts " factory: #{action[:factory_path]}"
659
- @stdout.puts " name: #{action[:factory_name]}"
657
+ puts "#{action[:class_name]}"
658
+ puts " prefix: #{action[:prefix]}"
659
+ puts " in: #{action[:path]}"
660
+ puts " spec: #{action[:spec_path]}"
661
+ puts " factory: #{action[:factory_path]}"
662
+ puts " name: #{action[:factory_name]}"
660
663
 
661
664
  end
662
- @stdout.puts "Would create a migration file"
663
- @stdout.puts " via: brut db new_migration #{migration_name}"
665
+ puts "Would create a migration file"
666
+ puts " via: brut db new_migration #{migration_name}"
664
667
  else
665
668
  system!("brut db new_migration #{migration_name}")
666
669
  actions.each do |action|
667
670
  FileUtils.mkdir_p action[:path].dirname
668
- @stdout.puts "Creating #{action[:class_name]} in #{action[:path].relative_path_from(Brut.container.project_root)}"
671
+ puts "Creating #{action[:class_name]} in #{action[:path].relative_path_from(Brut.container.project_root)}"
669
672
  File.open(action[:path].to_s,"w") do |file|
670
673
  file.puts %{class #{action[:class_name]} < AppDataModel
671
674
  has_external_id :#{action[:prefix]} # !IMPORTANT: Make sure this is unique amongst your DB models
672
675
  end}
673
676
  end
674
677
  FileUtils.mkdir_p action[:spec_path].dirname
675
- @stdout.puts "Creating spec for #{action[:class_name]} in #{action[:spec_path].relative_path_from(Brut.container.project_root)}"
678
+ puts "Creating spec for #{action[:class_name]} in #{action[:spec_path].relative_path_from(Brut.container.project_root)}"
676
679
  File.open(action[:spec_path].to_s,"w") do |file|
677
680
  file.puts %{require "spec_helper"
678
681
  RSpec.describe #{action[:class_name]} do
@@ -682,7 +685,7 @@ RSpec.describe #{action[:class_name]} do
682
685
  end}
683
686
  end
684
687
  FileUtils.mkdir_p action[:factory_path].dirname
685
- @stdout.puts "Creating factory for #{action[:class_name]} in #{action[:factory_path].relative_path_from(Brut.container.project_root)}"
688
+ puts "Creating factory for #{action[:class_name]} in #{action[:factory_path].relative_path_from(Brut.container.project_root)}"
686
689
  File.open(action[:factory_path].to_s,"w") do |file|
687
690
  file.puts %{FactoryBot.define do
688
691
  factory :#{action[:factory_name]}, class: "#{action[:class_name]}" do
@@ -5,7 +5,11 @@ class Brut::CLI::Apps::Test < Brut::CLI::Commands::BaseCommand
5
5
  def description = "Run and audit tests of the app"
6
6
 
7
7
  def default_rack_env = "development"
8
- def default_command_class = Run
8
+ def default_command = Run.new
9
+ def opts = default_command.opts
10
+ def run
11
+ delegate_to_command(default_command)
12
+ end
9
13
 
10
14
  class Run < Brut::CLI::Commands::BaseCommand
11
15
  def default_rack_env = "development"
@@ -16,6 +20,9 @@ class Brut::CLI::Apps::Test < Brut::CLI::Commands::BaseCommand
16
20
  [ "--seed SEED", "Set the random seed to allow duplicating a test run" ],
17
21
  ]
18
22
  def args_description = "specs_to_run..."
23
+ def detailed_description = %{
24
+ Runs all non end-to-end tests for the app, or runs a subset of non-end-to-end tests using RSpec-style syntax. Do note that you cannot use this command to run an end-to-end test, since those require the test server to be running.
25
+ }
19
26
 
20
27
  def env_vars = [
21
28
  [ "LOGGER_LEVEL_FOR_TESTS","Can be set to debug, info, warn, error, or fatal to control logging during tests. Defaults to 'warn' to avoid verbose test output" ],
@@ -23,13 +30,11 @@ class Brut::CLI::Apps::Test < Brut::CLI::Commands::BaseCommand
23
30
  [ "RSPEC_PROFILE_EXAMPLES", "If set to any value, it is converted to an int and set as RSpec's number of examples to profile. NOTE: this is used in the app's spec_helper.rb so could've been removed" ],
24
31
  ]
25
32
 
26
-
27
33
  def rspec_command
28
34
  parts = [
29
35
  "bin/rspec",
30
36
  "-I", Brut.container.app_specs_dir,
31
37
  "-I", Brut.container.app_src_dir,
32
- #"-I lib/", # not needed when Brut is gemified
33
38
  rspec_cli_args,
34
39
  "-P '**/*.spec.rb'",
35
40
  ]
@@ -46,14 +51,14 @@ class Brut::CLI::Apps::Test < Brut::CLI::Commands::BaseCommand
46
51
 
47
52
  def run
48
53
  if options.rebuild?(default: rebuild_by_default?)
49
- stdout.puts "Rebuilding test database schema"
54
+ puts "Rebuilding test database schema"
50
55
  Bundler.with_unbundled_env do
51
56
  system! "brut db rebuild --env=test"
52
57
  end
53
58
  end
54
59
  run_tests
55
60
  if options.rebuild_after?(default: rebuild_after_by_default?)
56
- stdout.puts "Re-Rebuilding test database schema"
61
+ puts "Re-Rebuilding test database schema"
57
62
  Bundler.with_unbundled_env do
58
63
  system! "brut db rebuild --env=test"
59
64
  end
@@ -65,17 +70,17 @@ class Brut::CLI::Apps::Test < Brut::CLI::Commands::BaseCommand
65
70
 
66
71
  def run_tests
67
72
  command = if argv.empty?
68
- stdout.puts "Running all tests"
73
+ puts "Running all unit tests"
69
74
  "#{rspec_command} #{Brut.container.app_specs_dir}/"
70
75
  else
71
- stdout.puts "Running only #{argv.join(", ")}"
76
+ puts "Running only #{argv.join(", ")}"
72
77
  test_args = argv.map { |_|
73
78
  '"' + Shellwords.escape(_) + '"'
74
79
  }.join(" ")
75
80
  "#{rspec_command} #{test_args}"
76
81
  end
77
82
  Bundler.with_unbundled_env do
78
- system! command
83
+ execution_context.executor.system! command
79
84
  end
80
85
  end
81
86
  end
@@ -90,6 +95,9 @@ class Brut::CLI::Apps::Test < Brut::CLI::Commands::BaseCommand
90
95
  def rspec_cli_args = "--tag e2e"
91
96
  def rebuild_by_default? = true
92
97
  def rebuild_after_by_default? = true
98
+ def detailed_description = %{
99
+ Runs all end-to-end tests for the app, or runs a subset of end-to-end tests using RSpec-style syntax. This will run bin/test-server first, so if that fails for some reason, no tests are run.
100
+ }
93
101
 
94
102
  private
95
103
 
@@ -107,6 +115,9 @@ class Brut::CLI::Apps::Test < Brut::CLI::Commands::BaseCommand
107
115
  def opts = [
108
116
  [ "--[no-]build-assets","Build all assets before running the tests" ],
109
117
  ]
118
+ def detailed_description = %{
119
+ Runs all JavaScript unit tests for the app. This does not support running individual tests.
120
+ }
110
121
 
111
122
  def run
112
123
  options.set_default(:"build-assets", true)
@@ -115,7 +126,7 @@ class Brut::CLI::Apps::Test < Brut::CLI::Commands::BaseCommand
115
126
  system!({ "RACK_ENV" => "test" }, "brut build-assets all")
116
127
  end
117
128
  end
118
- system!({ "NODE_DISABLE_COLORS" => "1" },"npx mocha #{Brut.container.js_specs_dir} --no-color --extension 'spec.js' --recursive")
129
+ execution_context.executor.system!({ "NODE_DISABLE_COLORS" => "1" },"npx mocha #{Brut.container.js_specs_dir} --no-color --extension 'spec.js' --recursive")
119
130
  0
120
131
  end
121
132
  end
@@ -208,36 +219,44 @@ class Brut::CLI::Apps::Test < Brut::CLI::Commands::BaseCommand
208
219
  hash
209
220
  }.compact.sort_by { it[:type].to_s + it[:source_file].to_s }
210
221
 
211
- files_missing = []
212
- printed_header = false
222
+ rows = []
213
223
  audit.each do |file_audit|
214
224
  if !file_audit[:test_file].exist?
215
225
  if options.type.nil? || file_audit[:type] == options.type.to_sym
216
226
  if file_audit[:test_expected]
217
- files_missing << file_audit[:source_file]
218
- if !printed_header
219
- stdout.puts "These files are missing tests:"
220
- stdout.puts ""
221
- stdout.printf "%-25s %s\n","Type", "Path"
222
- stdout.puts "-------------------------------------------"
223
- printed_header = true
224
- end
225
- stdout.puts "#{file_audit[:type].to_s.ljust(25)} - #{file_audit[:source_file]}"
227
+ rows << [ file_audit[:type].to_s, file_audit[:source_file].to_s ]
226
228
  end
227
229
  end
228
230
  end
229
231
  end
230
- if files_missing.empty?
231
- stdout.puts "All tests exists!"
232
+ if rows.empty?
233
+ puts theme.success.render("All tests exists!")
232
234
  0
233
235
  else
236
+ puts
237
+ puts theme.warning.render("The following source files are missing tests:")
238
+ puts
239
+ table = Lipgloss::Table.new.
240
+ headers(["Type", "Path"]).
241
+ rows(rows).
242
+ style_func(rows: rows.length, columns: 2) { |row,column|
243
+ if row == Lipgloss::Table::HEADER_ROW
244
+ Lipgloss::Style.new.inherit(theme.header).padding_left(1).padding_right(1)
245
+ else
246
+ Lipgloss::Style.new.inherit(theme.none).padding_left(1).padding_right(1)
247
+ end
248
+ }
249
+ puts table.render
234
250
  if options.show_scaffold?
235
- stdout.puts
236
- files_missing_args = files_missing.map { |file|
237
- ' "' + Shellwords.escape(file.to_s) + '"'
251
+ puts
252
+ files_missing_args = rows.map { |(_,file)|
253
+ ' "' + Shellwords.escape(file.to_s) + '"'
238
254
  }.join(" \\\n")
239
255
 
240
- stdout.puts "Run this command to generate empty tests:\n\nbrut scaffold test \\\n#{files_missing_args}"
256
+ puts theme.subheader.render("Run this command to generate empty tests")
257
+ puts
258
+ puts theme.code.render(" brut scaffold test \\\n#{files_missing_args}")
259
+ puts
241
260
  end
242
261
  1
243
262
  end