tng 0.1.6 → 0.2.2

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.
@@ -24,89 +24,32 @@ class ShowHelp
24
24
  @pastel.public_send(Tng::UI::Theme.color(:accent)).bold("Usage:"),
25
25
  @pastel.public_send(Tng::UI::Theme.color(:primary),
26
26
  " bundle exec tng") + @pastel.public_send(Tng::UI::Theme.color(:muted),
27
- " # Interactive mode"),
28
- @pastel.public_send(Tng::UI::Theme.color(:primary),
29
- " bundle exec tng --type=TYPE --file=FILE") + @pastel.public_send(
30
- Tng::UI::Theme.color(:muted), " # Direct mode"
31
- ),
32
- @pastel.public_send(Tng::UI::Theme.color(:primary),
33
- " bundle exec tng -t TYPE -f FILE") + @pastel.public_send(Tng::UI::Theme.color(:muted),
34
- " # Short aliases"),
35
- @pastel.public_send(Tng::UI::Theme.color(:primary),
36
- " bundle exec tng -t=TYPE f=FILE") + @pastel.public_send(Tng::UI::Theme.color(:muted),
37
- " # Mixed format"),
27
+ " # Interactive mode only"),
38
28
  "",
39
- @pastel.public_send(Tng::UI::Theme.color(:accent)).bold("Examples:"),
40
- @pastel.public_send(Tng::UI::Theme.color(:success),
41
- " bundle exec tng -t c -f ping") + @pastel.public_send(Tng::UI::Theme.color(:muted),
42
- " # Controller test"),
29
+ @pastel.public_send(Tng::UI::Theme.color(:accent)).bold("Features:"),
43
30
  @pastel.public_send(Tng::UI::Theme.color(:success),
44
- " bundle exec tng -t=c f=ping") + @pastel.public_send(Tng::UI::Theme.color(:muted),
45
- " # Mixed format"),
31
+ " #{Tng::UI::Theme.icon(:bullet)} Controllers, Models, Services"),
46
32
  @pastel.public_send(Tng::UI::Theme.color(:success),
47
- " bundle exec tng -t m -f user") + @pastel.public_send(Tng::UI::Theme.color(:muted),
48
- " # Model test"),
33
+ " #{Tng::UI::Theme.icon(:bullet)} 17+ other file types (Jobs, Helpers, Lib, Policies, Presenters, Mailers, GraphQL, etc.)"),
49
34
  @pastel.public_send(Tng::UI::Theme.color(:success),
50
- " bundle exec tng -t s -f user_service") + @pastel.public_send(Tng::UI::Theme.color(:muted),
51
- " # Service test"),
35
+ " #{Tng::UI::Theme.icon(:bullet)} Per-method test generation"),
52
36
  @pastel.public_send(Tng::UI::Theme.color(:success),
53
- " bundle exec tng --type=controller --file=users_controller"),
54
- @pastel.public_send(Tng::UI::Theme.color(:success),
55
- " bundle exec tng -t c -f \"admin/users_controller\"") + @pastel.public_send(Tng::UI::Theme.color(:muted),
56
- " # Namespaced"),
37
+ " #{Tng::UI::Theme.icon(:bullet)} Searchable method lists"),
57
38
  "",
58
39
  @pastel.public_send(Tng::UI::Theme.color(:accent)).bold("Options:"),
59
- @pastel.public_send(Tng::UI::Theme.color(:primary),
60
- " -t, --type=TYPE") + @pastel.public_send(Tng::UI::Theme.color(:muted),
61
- " Test type (controller, model, service)"),
62
- @pastel.public_send(Tng::UI::Theme.color(:primary),
63
- " -f, --file=FILE") + @pastel.public_send(Tng::UI::Theme.color(:muted),
64
- " File name (without .rb extension)"),
65
- @pastel.public_send(Tng::UI::Theme.color(:primary),
66
- " -m, --method=METHOD") + @pastel.public_send(Tng::UI::Theme.color(:muted),
67
- " Method name (for per-method tests)"),
68
40
  @pastel.public_send(Tng::UI::Theme.color(:primary),
69
41
  " -h, --help") + @pastel.public_send(Tng::UI::Theme.color(:muted),
70
42
  " Show this help message"),
71
43
  "",
72
- @pastel.public_send(Tng::UI::Theme.color(:accent)).bold("Type Aliases:"),
44
+ @pastel.public_send(Tng::UI::Theme.color(:accent)).bold("How to Use:"),
73
45
  @pastel.public_send(Tng::UI::Theme.color(:muted),
74
- " #{Tng::UI::Theme.icon(:bullet)} Controllers: ") + @pastel.public_send(Tng::UI::Theme.color(:secondary),
75
- "c, controller"),
76
- @pastel.public_send(Tng::UI::Theme.color(:muted),
77
- " #{Tng::UI::Theme.icon(:bullet)} Models: ") + @pastel.public_send(
78
- Tng::UI::Theme.color(:secondary), "m, mo, model"
79
- ),
80
- @pastel.public_send(Tng::UI::Theme.color(:muted),
81
- " #{Tng::UI::Theme.icon(:bullet)} Services: ") + @pastel.public_send(
82
- Tng::UI::Theme.color(:secondary), "s, se, service"
83
- ),
84
- "",
85
- @pastel.public_send(Tng::UI::Theme.color(:accent)).bold("File Format:"),
86
- @pastel.public_send(Tng::UI::Theme.color(:muted),
87
- " #{Tng::UI::Theme.icon(:bullet)} Controllers: ") + @pastel.public_send(Tng::UI::Theme.color(:success),
88
- "users_controller, api/v1/posts_controller"),
89
- @pastel.public_send(Tng::UI::Theme.color(:muted),
90
- " #{Tng::UI::Theme.icon(:bullet)} Models: ") + @pastel.public_send(
91
- Tng::UI::Theme.color(:success), "user, blog/post"
92
- ),
93
- @pastel.public_send(Tng::UI::Theme.color(:muted),
94
- " #{Tng::UI::Theme.icon(:bullet)} Services: ") + @pastel.public_send(
95
- Tng::UI::Theme.color(:success), "user_service, payment/stripe_service"
96
- ),
97
- @pastel.public_send(Tng::UI::Theme.color(:muted),
98
- " #{Tng::UI::Theme.icon(:bullet)} Don't include .rb extension"),
99
- "",
100
- @pastel.public_send(Tng::UI::Theme.color(:accent)).bold("Pro Tips:"),
46
+ " #{Tng::UI::Theme.icon(:bullet)} Run 'bundle exec tng' to start the interactive interface"),
101
47
  @pastel.public_send(Tng::UI::Theme.color(:muted),
102
- " #{Tng::UI::Theme.icon(:bullet)} Mix formats: ") + @pastel.public_send(Tng::UI::Theme.color(:secondary),
103
- "-t=c f=ping") + @pastel.public_send(
104
- Tng::UI::Theme.color(:muted), " works perfectly"
105
- ),
48
+ " #{Tng::UI::Theme.icon(:bullet)} Select Controller, Model, Service, or Other to test"),
106
49
  @pastel.public_send(Tng::UI::Theme.color(:muted),
107
- " #{Tng::UI::Theme.icon(:bullet)} Use filtering in interactive mode for large projects"),
50
+ " #{Tng::UI::Theme.icon(:bullet)} Choose a specific method from the list"),
108
51
  @pastel.public_send(Tng::UI::Theme.color(:muted),
109
- " #{Tng::UI::Theme.icon(:bullet)} All formats are equivalent - use what feels natural"),
52
+ " #{Tng::UI::Theme.icon(:bullet)} Use search/filter to find methods quickly"),
110
53
  "",
111
54
  @pastel.public_send(Tng::UI::Theme.color(:secondary)).bold("Happy testing! ") + @pastel.public_send(
112
55
  Tng::UI::Theme.color(:accent), "★"
data/lib/tng/utils.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require "yaml"
2
2
  require "json"
3
+ require "fileutils"
4
+ require "prism"
3
5
 
4
6
  module Tng
5
7
  module Utils
@@ -98,26 +100,39 @@ module Tng
98
100
  puts "📋 Raw API response: #{test_content[0..200]}..." if ENV["DEBUG"]
99
101
  parsed_response = JSON.parse(test_content)
100
102
 
103
+ if parsed_response["error"]
104
+ puts "❌ API responded with an error: #{parsed_response["error"]}"
105
+ return
106
+ end
101
107
  # Validate required fields
102
108
  unless parsed_response["file_content"]
103
109
  puts "❌ API response missing file_content field"
104
110
  puts "📋 Response keys: #{parsed_response.keys.inspect}"
105
- return nil
111
+ return
106
112
  end
107
113
 
108
114
  # Handle both possible field names for file path
109
- file_path = parsed_response["test_file_path"] || parsed_response["file_path"]
115
+ file_path = parsed_response["test_file_path"] || parsed_response["file_path"] || parsed_response["file_name"] || parsed_response["file"]
110
116
  unless file_path
111
117
  puts "❌ API response missing test_file_path or file_path field"
112
118
  puts "📋 Response keys: #{parsed_response.keys.inspect}"
113
- return nil
119
+ return
114
120
  end
115
121
 
116
- File.write(file_path, parsed_response["file_content"])
122
+ begin
123
+ File.write(file_path, parsed_response["file_content"])
124
+ rescue Errno::ENOENT
125
+ # Create directory if it doesn't exist
126
+ FileUtils.mkdir_p(File.dirname(file_path))
127
+ File.write(file_path, parsed_response["file_content"])
128
+ end
117
129
  puts "✅ Test generated successfully!"
118
130
  absolute_path = File.expand_path(file_path)
119
131
  puts "Please review the generated tests at \e]8;;file://#{absolute_path}\e\\#{file_path}\e]8;;\e\\"
120
132
 
133
+ # Count tests in the generated file
134
+ test_count = count_tests_in_file(file_path)
135
+
121
136
  # Determine run command based on test framework
122
137
  run_command = if file_path.include?("/spec/")
123
138
  "bundle exec rspec #{file_path}"
@@ -130,7 +145,8 @@ module Tng
130
145
  file_path: file_path,
131
146
  absolute_path: absolute_path,
132
147
  run_command: run_command,
133
- test_class_name: parsed_response["test_class_name"]
148
+ test_class_name: parsed_response["test_class_name"],
149
+ test_count: test_count
134
150
  }
135
151
  end
136
152
 
@@ -257,7 +273,53 @@ module Tng
257
273
  end
258
274
 
259
275
  def self.load_all_active_record_data
260
- []
276
+ {}
277
+ end
278
+
279
+ def self.count_tests_in_file(file_path)
280
+ return 0 unless File.exist?(file_path)
281
+
282
+ begin
283
+ content = File.read(file_path)
284
+ result = Prism.parse(content)
285
+ return 0 unless result.success?
286
+
287
+ count_test_nodes(result.value)
288
+ rescue StandardError => e
289
+ puts "⚠️ Warning: Could not parse #{file_path}: #{e.message}" if ENV["DEBUG"]
290
+ 0
291
+ end
292
+ end
293
+
294
+ private_class_method def self.count_test_nodes(node)
295
+ return 0 unless node.respond_to?(:child_nodes)
296
+
297
+ count = 0
298
+
299
+ # Check if current node is a test
300
+ count += 1 if test_node?(node)
301
+
302
+ # Recursively check child nodes
303
+ node.child_nodes.each do |child|
304
+ count += count_test_nodes(child) if child
305
+ end
306
+
307
+ count
308
+ end
309
+
310
+ private_class_method def self.test_node?(node)
311
+ case node
312
+ when Prism::DefNode
313
+ # Minitest: def test_something
314
+ node.name.to_s.start_with?("test_")
315
+ when Prism::CallNode
316
+ # RSpec: it "...", specify "..."
317
+ # Minitest: test "..."
318
+ method_name = node.name.to_s
319
+ %w[it specify test].include?(method_name)
320
+ else
321
+ false
322
+ end
261
323
  end
262
324
  end
263
325
  end
data/lib/tng/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tng
4
- VERSION = "0.1.6"
4
+ VERSION = "0.2.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tng
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - ralucab
@@ -214,9 +214,12 @@ files:
214
214
  - lib/tng.rb
215
215
  - lib/tng/analyzers/controller.rb
216
216
  - lib/tng/analyzers/model.rb
217
+ - lib/tng/analyzers/other.rb
217
218
  - lib/tng/analyzers/service.rb
218
219
  - lib/tng/api/http_client.rb
219
220
  - lib/tng/railtie.rb
221
+ - lib/tng/services/direct_generation.rb
222
+ - lib/tng/services/extract_methods.rb
220
223
  - lib/tng/services/test_generator.rb
221
224
  - lib/tng/services/testng.rb
222
225
  - lib/tng/services/user_app_config.rb
@@ -227,6 +230,7 @@ files:
227
230
  - lib/tng/ui/display_banner.rb
228
231
  - lib/tng/ui/goodbye_display.rb
229
232
  - lib/tng/ui/model_test_flow_display.rb
233
+ - lib/tng/ui/other_test_flow_display.rb
230
234
  - lib/tng/ui/post_install_box.rb
231
235
  - lib/tng/ui/service_test_flow_display.rb
232
236
  - lib/tng/ui/show_help.rb
@@ -259,16 +263,16 @@ post_install_message: "┌ TNG ────────────────
259
263
  \ │\n│ \U0001F680
260
264
  Usage: │\n│ │\n│
261
265
  \ Interactive mode: │\n│ • bundle
262
- exec tng - Full interactive CLI │\n│ │\n│
263
- \ Direct generation: │\n│ • bundle
264
- exec tng -t c -f ping - Short │\n│ bundle exec tng
265
- -t=c f=ping - Mixed │\n│ • bundle exec tng --type=controller
266
- --file=ping │\n│ │\n│
267
- \ Help: │\n│ • bundle
268
- exec tng --help - Show all options │\n│ │\n│
269
- \ \U0001F4A1 Use -t c for controller, -t m for model │\n│
270
- \ │\n└────────────────────────────────────────────────────────────
271
- v0.1.6 ┘\n"
266
+ exec tng - Interactive CLI with method selection │\n│ │\n│
267
+ \ Features: │\n│ • Test
268
+ 20+ file types: Controllers, Models, Services + Jobs, │\n│ Helpers, Lib, Policies,
269
+ Presenters, Mailers, GraphQL, and more │\n│ • Select specific methods to test
270
+ \ │\n│ • Search and filter through methods │\n│
271
+ \ │\n│ Help:
272
+ \ │\n│ bundle exec
273
+ tng --help - Show help information │\n│ │\n│
274
+ \ \U0001F4A1 Generate tests for individual methods with precision │\n└────────────────────────────────────────────────────────────
275
+ v0.2.2 ┘\n"
272
276
  rdoc_options: []
273
277
  require_paths:
274
278
  - lib