claude-code-templates 1.16.1 → 1.17.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.
- package/README.md +7 -7
- package/bin/create-claude-config.js +17 -8
- package/package.json +2 -3
- package/src/analytics/core/AgentAnalyzer.js +17 -3
- package/src/analytics/core/ProcessDetector.js +23 -7
- package/src/analytics/core/StateCalculator.js +102 -33
- package/src/analytics/data/DataCache.js +7 -7
- package/src/analytics-web/chats_mobile.html +2590 -0
- package/src/analytics-web/components/App.js +10 -10
- package/src/analytics-web/components/SessionTimer.js +1 -1
- package/src/analytics-web/components/Sidebar.js +5 -14
- package/src/analytics-web/index.html +932 -78
- package/src/analytics.js +263 -5
- package/src/chats-mobile.js +682 -0
- package/src/claude-api-proxy.js +460 -0
- package/src/file-operations.js +239 -36
- package/src/health-check.js +310 -0
- package/src/index.js +1245 -36
- package/src/tracking-service.js +31 -34
- package/components/agents/api-security-audit.md +0 -92
- package/components/agents/database-optimization.md +0 -94
- package/components/agents/react-performance-optimization.md +0 -64
- package/components/commands/check-file.md +0 -53
- package/components/commands/generate-tests.md +0 -68
- package/components/mcps/deepgraph-nextjs.json +0 -12
- package/components/mcps/deepgraph-react.json +0 -12
- package/components/mcps/deepgraph-typescript.json +0 -12
- package/components/mcps/deepgraph-vue.json +0 -12
- package/components/mcps/filesystem-access.json +0 -12
- package/components/mcps/github-integration.json +0 -11
- package/components/mcps/memory-integration.json +0 -8
- package/components/mcps/mysql-integration.json +0 -11
- package/components/mcps/postgresql-integration.json +0 -11
- package/components/mcps/web-fetch.json +0 -8
- package/src/analytics-web/components/AgentsPage.js +0 -4761
- package/templates/common/.claude/commands/git-workflow.md +0 -239
- package/templates/common/.claude/commands/project-setup.md +0 -316
- package/templates/common/.mcp.json +0 -41
- package/templates/common/CLAUDE.md +0 -109
- package/templates/common/README.md +0 -96
- package/templates/go/.mcp.json +0 -78
- package/templates/go/README.md +0 -25
- package/templates/javascript-typescript/.claude/commands/api-endpoint.md +0 -51
- package/templates/javascript-typescript/.claude/commands/debug.md +0 -52
- package/templates/javascript-typescript/.claude/commands/lint.md +0 -48
- package/templates/javascript-typescript/.claude/commands/npm-scripts.md +0 -48
- package/templates/javascript-typescript/.claude/commands/refactor.md +0 -55
- package/templates/javascript-typescript/.claude/commands/test.md +0 -61
- package/templates/javascript-typescript/.claude/commands/typescript-migrate.md +0 -51
- package/templates/javascript-typescript/.claude/settings.json +0 -142
- package/templates/javascript-typescript/.mcp.json +0 -80
- package/templates/javascript-typescript/CLAUDE.md +0 -185
- package/templates/javascript-typescript/README.md +0 -259
- package/templates/javascript-typescript/examples/angular-app/.claude/commands/components.md +0 -63
- package/templates/javascript-typescript/examples/angular-app/.claude/commands/services.md +0 -62
- package/templates/javascript-typescript/examples/node-api/.claude/commands/api-endpoint.md +0 -46
- package/templates/javascript-typescript/examples/node-api/.claude/commands/database.md +0 -56
- package/templates/javascript-typescript/examples/node-api/.claude/commands/middleware.md +0 -61
- package/templates/javascript-typescript/examples/node-api/.claude/commands/route.md +0 -57
- package/templates/javascript-typescript/examples/node-api/CLAUDE.md +0 -102
- package/templates/javascript-typescript/examples/react-app/.claude/commands/component.md +0 -29
- package/templates/javascript-typescript/examples/react-app/.claude/commands/hooks.md +0 -44
- package/templates/javascript-typescript/examples/react-app/.claude/commands/state-management.md +0 -45
- package/templates/javascript-typescript/examples/react-app/CLAUDE.md +0 -81
- package/templates/javascript-typescript/examples/react-app/agents/react-performance-optimization.md +0 -530
- package/templates/javascript-typescript/examples/react-app/agents/react-state-management.md +0 -295
- package/templates/javascript-typescript/examples/vue-app/.claude/commands/components.md +0 -46
- package/templates/javascript-typescript/examples/vue-app/.claude/commands/composables.md +0 -51
- package/templates/python/.claude/commands/lint.md +0 -111
- package/templates/python/.claude/commands/test.md +0 -73
- package/templates/python/.claude/settings.json +0 -153
- package/templates/python/.mcp.json +0 -78
- package/templates/python/CLAUDE.md +0 -276
- package/templates/python/examples/django-app/.claude/commands/admin.md +0 -264
- package/templates/python/examples/django-app/.claude/commands/django-model.md +0 -124
- package/templates/python/examples/django-app/.claude/commands/views.md +0 -222
- package/templates/python/examples/django-app/CLAUDE.md +0 -313
- package/templates/python/examples/django-app/agents/django-api-security.md +0 -642
- package/templates/python/examples/django-app/agents/django-database-optimization.md +0 -752
- package/templates/python/examples/fastapi-app/.claude/commands/api-endpoints.md +0 -513
- package/templates/python/examples/fastapi-app/.claude/commands/auth.md +0 -775
- package/templates/python/examples/fastapi-app/.claude/commands/database.md +0 -657
- package/templates/python/examples/fastapi-app/.claude/commands/deployment.md +0 -160
- package/templates/python/examples/fastapi-app/.claude/commands/testing.md +0 -927
- package/templates/python/examples/fastapi-app/CLAUDE.md +0 -229
- package/templates/python/examples/flask-app/.claude/commands/app-factory.md +0 -384
- package/templates/python/examples/flask-app/.claude/commands/blueprint.md +0 -243
- package/templates/python/examples/flask-app/.claude/commands/database.md +0 -410
- package/templates/python/examples/flask-app/.claude/commands/deployment.md +0 -620
- package/templates/python/examples/flask-app/.claude/commands/flask-route.md +0 -217
- package/templates/python/examples/flask-app/.claude/commands/testing.md +0 -559
- package/templates/python/examples/flask-app/CLAUDE.md +0 -391
- package/templates/ruby/.claude/commands/model.md +0 -360
- package/templates/ruby/.claude/commands/test.md +0 -480
- package/templates/ruby/.claude/settings.json +0 -146
- package/templates/ruby/.mcp.json +0 -83
- package/templates/ruby/CLAUDE.md +0 -284
- package/templates/ruby/examples/rails-app/.claude/commands/authentication.md +0 -490
- package/templates/ruby/examples/rails-app/CLAUDE.md +0 -376
- package/templates/rust/.mcp.json +0 -78
- package/templates/rust/README.md +0 -26
|
@@ -1,480 +0,0 @@
|
|
|
1
|
-
# Ruby Test Generator
|
|
2
|
-
|
|
3
|
-
Create comprehensive test files with RSpec or Minitest following Ruby testing best practices.
|
|
4
|
-
|
|
5
|
-
## Purpose
|
|
6
|
-
|
|
7
|
-
This command helps you quickly create test files with proper structure, examples, and testing patterns for Ruby applications.
|
|
8
|
-
|
|
9
|
-
## Usage
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
/test
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## What this command does
|
|
16
|
-
|
|
17
|
-
1. **Creates test files** with proper structure for RSpec or Minitest
|
|
18
|
-
2. **Includes test examples** for common scenarios
|
|
19
|
-
3. **Sets up test helpers** and support files
|
|
20
|
-
4. **Follows testing conventions** and best practices
|
|
21
|
-
5. **Generates factory/fixture data** when needed
|
|
22
|
-
|
|
23
|
-
## RSpec Example Output
|
|
24
|
-
|
|
25
|
-
```ruby
|
|
26
|
-
# spec/models/user_spec.rb
|
|
27
|
-
require 'spec_helper'
|
|
28
|
-
|
|
29
|
-
RSpec.describe User do
|
|
30
|
-
let(:user) { build(:user) }
|
|
31
|
-
let(:valid_attributes) do
|
|
32
|
-
{
|
|
33
|
-
name: 'John Doe',
|
|
34
|
-
email: 'john@example.com',
|
|
35
|
-
age: 30
|
|
36
|
-
}
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
describe 'validations' do
|
|
40
|
-
it { should validate_presence_of(:name) }
|
|
41
|
-
it { should validate_presence_of(:email) }
|
|
42
|
-
it { should validate_uniqueness_of(:email) }
|
|
43
|
-
it { should validate_numericality_of(:age).is_greater_than(0) }
|
|
44
|
-
|
|
45
|
-
context 'when email format is invalid' do
|
|
46
|
-
let(:user) { build(:user, email: 'invalid-email') }
|
|
47
|
-
|
|
48
|
-
it 'is not valid' do
|
|
49
|
-
expect(user).not_to be_valid
|
|
50
|
-
expect(user.errors[:email]).to include('is invalid')
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
describe 'associations' do
|
|
56
|
-
it { should have_many(:posts) }
|
|
57
|
-
it { should have_many(:comments) }
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
describe 'callbacks' do
|
|
61
|
-
describe 'before_save' do
|
|
62
|
-
it 'normalizes email' do
|
|
63
|
-
user = create(:user, email: 'JOHN@EXAMPLE.COM')
|
|
64
|
-
expect(user.email).to eq('john@example.com')
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
describe 'instance methods' do
|
|
70
|
-
describe '#full_name' do
|
|
71
|
-
let(:user) { build(:user, first_name: 'John', last_name: 'Doe') }
|
|
72
|
-
|
|
73
|
-
it 'returns the full name' do
|
|
74
|
-
expect(user.full_name).to eq('John Doe')
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
context 'when last_name is missing' do
|
|
78
|
-
let(:user) { build(:user, first_name: 'John', last_name: nil) }
|
|
79
|
-
|
|
80
|
-
it 'returns only first_name' do
|
|
81
|
-
expect(user.full_name).to eq('John')
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
describe '#active?' do
|
|
87
|
-
context 'when user is active' do
|
|
88
|
-
let(:user) { build(:user, status: 'active') }
|
|
89
|
-
|
|
90
|
-
it 'returns true' do
|
|
91
|
-
expect(user.active?).to be true
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
context 'when user is inactive' do
|
|
96
|
-
let(:user) { build(:user, status: 'inactive') }
|
|
97
|
-
|
|
98
|
-
it 'returns false' do
|
|
99
|
-
expect(user.active?).to be false
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
describe 'class methods' do
|
|
106
|
-
describe '.active' do
|
|
107
|
-
let!(:active_user) { create(:user, status: 'active') }
|
|
108
|
-
let!(:inactive_user) { create(:user, status: 'inactive') }
|
|
109
|
-
|
|
110
|
-
it 'returns only active users' do
|
|
111
|
-
expect(User.active).to include(active_user)
|
|
112
|
-
expect(User.active).not_to include(inactive_user)
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
describe '.find_by_email' do
|
|
117
|
-
let!(:user) { create(:user, email: 'test@example.com') }
|
|
118
|
-
|
|
119
|
-
it 'finds user by email' do
|
|
120
|
-
found_user = User.find_by_email('test@example.com')
|
|
121
|
-
expect(found_user).to eq(user)
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
it 'returns nil when user not found' do
|
|
125
|
-
found_user = User.find_by_email('nonexistent@example.com')
|
|
126
|
-
expect(found_user).to be_nil
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
describe 'scopes' do
|
|
132
|
-
describe '.recent' do
|
|
133
|
-
let!(:old_user) { create(:user, created_at: 1.year.ago) }
|
|
134
|
-
let!(:recent_user) { create(:user, created_at: 1.day.ago) }
|
|
135
|
-
|
|
136
|
-
it 'returns users created in the last 30 days' do
|
|
137
|
-
expect(User.recent).to include(recent_user)
|
|
138
|
-
expect(User.recent).not_to include(old_user)
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## Minitest Example Output
|
|
146
|
-
|
|
147
|
-
```ruby
|
|
148
|
-
# test/models/user_test.rb
|
|
149
|
-
require 'test_helper'
|
|
150
|
-
|
|
151
|
-
class UserTest < ActiveSupport::TestCase
|
|
152
|
-
def setup
|
|
153
|
-
@user = users(:john)
|
|
154
|
-
@valid_attributes = {
|
|
155
|
-
name: 'Jane Doe',
|
|
156
|
-
email: 'jane@example.com',
|
|
157
|
-
age: 25
|
|
158
|
-
}
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
# Validation tests
|
|
162
|
-
test 'should not save user without name' do
|
|
163
|
-
user = User.new(@valid_attributes.except(:name))
|
|
164
|
-
assert_not user.save
|
|
165
|
-
assert_includes user.errors[:name], "can't be blank"
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
test 'should not save user without email' do
|
|
169
|
-
user = User.new(@valid_attributes.except(:email))
|
|
170
|
-
assert_not user.save
|
|
171
|
-
assert_includes user.errors[:email], "can't be blank"
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
test 'should not save user with invalid email' do
|
|
175
|
-
user = User.new(@valid_attributes.merge(email: 'invalid-email'))
|
|
176
|
-
assert_not user.save
|
|
177
|
-
assert_includes user.errors[:email], 'is invalid'
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
test 'should not save user with duplicate email' do
|
|
181
|
-
user1 = User.create!(@valid_attributes)
|
|
182
|
-
user2 = User.new(@valid_attributes)
|
|
183
|
-
assert_not user2.save
|
|
184
|
-
assert_includes user2.errors[:email], 'has already been taken'
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
test 'should save user with valid attributes' do
|
|
188
|
-
user = User.new(@valid_attributes)
|
|
189
|
-
assert user.save
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
# Association tests
|
|
193
|
-
test 'should have many posts' do
|
|
194
|
-
assert_respond_to @user, :posts
|
|
195
|
-
assert_kind_of ActiveRecord::Associations::CollectionProxy, @user.posts
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
test 'should have many comments' do
|
|
199
|
-
assert_respond_to @user, :comments
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
# Instance method tests
|
|
203
|
-
test 'full_name should return first and last name' do
|
|
204
|
-
@user.first_name = 'John'
|
|
205
|
-
@user.last_name = 'Doe'
|
|
206
|
-
assert_equal 'John Doe', @user.full_name
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
test 'full_name should return first name only when last name is missing' do
|
|
210
|
-
@user.first_name = 'John'
|
|
211
|
-
@user.last_name = nil
|
|
212
|
-
assert_equal 'John', @user.full_name
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
test 'active? should return true for active users' do
|
|
216
|
-
@user.status = 'active'
|
|
217
|
-
assert @user.active?
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
test 'active? should return false for inactive users' do
|
|
221
|
-
@user.status = 'inactive'
|
|
222
|
-
assert_not @user.active?
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
# Class method tests
|
|
226
|
-
test 'active scope should return only active users' do
|
|
227
|
-
active_user = User.create!(@valid_attributes.merge(status: 'active'))
|
|
228
|
-
inactive_user = User.create!(@valid_attributes.merge(
|
|
229
|
-
email: 'inactive@example.com',
|
|
230
|
-
status: 'inactive'
|
|
231
|
-
))
|
|
232
|
-
|
|
233
|
-
active_users = User.active
|
|
234
|
-
assert_includes active_users, active_user
|
|
235
|
-
assert_not_includes active_users, inactive_user
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
test 'find_by_email should find user by email' do
|
|
239
|
-
user = User.create!(@valid_attributes)
|
|
240
|
-
found_user = User.find_by_email(@valid_attributes[:email])
|
|
241
|
-
assert_equal user, found_user
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
test 'find_by_email should return nil when user not found' do
|
|
245
|
-
found_user = User.find_by_email('nonexistent@example.com')
|
|
246
|
-
assert_nil found_user
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
## Controller Test Example
|
|
252
|
-
|
|
253
|
-
```ruby
|
|
254
|
-
# spec/controllers/users_controller_spec.rb
|
|
255
|
-
require 'rails_helper'
|
|
256
|
-
|
|
257
|
-
RSpec.describe UsersController, type: :controller do
|
|
258
|
-
let(:user) { create(:user) }
|
|
259
|
-
let(:valid_attributes) { attributes_for(:user) }
|
|
260
|
-
let(:invalid_attributes) { { name: '', email: 'invalid' } }
|
|
261
|
-
|
|
262
|
-
describe 'GET #index' do
|
|
263
|
-
it 'returns a success response' do
|
|
264
|
-
get :index
|
|
265
|
-
expect(response).to be_successful
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
it 'assigns @users' do
|
|
269
|
-
user1 = create(:user)
|
|
270
|
-
user2 = create(:user)
|
|
271
|
-
get :index
|
|
272
|
-
expect(assigns(:users)).to match_array([user1, user2])
|
|
273
|
-
end
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
describe 'GET #show' do
|
|
277
|
-
it 'returns a success response' do
|
|
278
|
-
get :show, params: { id: user.to_param }
|
|
279
|
-
expect(response).to be_successful
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
it 'assigns the requested user' do
|
|
283
|
-
get :show, params: { id: user.to_param }
|
|
284
|
-
expect(assigns(:user)).to eq(user)
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
describe 'POST #create' do
|
|
289
|
-
context 'with valid parameters' do
|
|
290
|
-
it 'creates a new User' do
|
|
291
|
-
expect {
|
|
292
|
-
post :create, params: { user: valid_attributes }
|
|
293
|
-
}.to change(User, :count).by(1)
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
it 'redirects to the created user' do
|
|
297
|
-
post :create, params: { user: valid_attributes }
|
|
298
|
-
expect(response).to redirect_to(User.last)
|
|
299
|
-
end
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
context 'with invalid parameters' do
|
|
303
|
-
it 'does not create a new User' do
|
|
304
|
-
expect {
|
|
305
|
-
post :create, params: { user: invalid_attributes }
|
|
306
|
-
}.to change(User, :count).by(0)
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
it 'renders the new template' do
|
|
310
|
-
post :create, params: { user: invalid_attributes }
|
|
311
|
-
expect(response).to render_template(:new)
|
|
312
|
-
end
|
|
313
|
-
end
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
describe 'PUT #update' do
|
|
317
|
-
context 'with valid parameters' do
|
|
318
|
-
let(:new_attributes) { { name: 'Updated Name' } }
|
|
319
|
-
|
|
320
|
-
it 'updates the requested user' do
|
|
321
|
-
put :update, params: { id: user.to_param, user: new_attributes }
|
|
322
|
-
user.reload
|
|
323
|
-
expect(user.name).to eq('Updated Name')
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
it 'redirects to the user' do
|
|
327
|
-
put :update, params: { id: user.to_param, user: new_attributes }
|
|
328
|
-
expect(response).to redirect_to(user)
|
|
329
|
-
end
|
|
330
|
-
end
|
|
331
|
-
|
|
332
|
-
context 'with invalid parameters' do
|
|
333
|
-
it 'renders the edit template' do
|
|
334
|
-
put :update, params: { id: user.to_param, user: invalid_attributes }
|
|
335
|
-
expect(response).to render_template(:edit)
|
|
336
|
-
end
|
|
337
|
-
end
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
describe 'DELETE #destroy' do
|
|
341
|
-
it 'destroys the requested user' do
|
|
342
|
-
user # Create user
|
|
343
|
-
expect {
|
|
344
|
-
delete :destroy, params: { id: user.to_param }
|
|
345
|
-
}.to change(User, :count).by(-1)
|
|
346
|
-
end
|
|
347
|
-
|
|
348
|
-
it 'redirects to the users list' do
|
|
349
|
-
delete :destroy, params: { id: user.to_param }
|
|
350
|
-
expect(response).to redirect_to(users_url)
|
|
351
|
-
end
|
|
352
|
-
end
|
|
353
|
-
end
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
## Factory Configuration
|
|
357
|
-
|
|
358
|
-
```ruby
|
|
359
|
-
# spec/factories/users.rb
|
|
360
|
-
FactoryBot.define do
|
|
361
|
-
factory :user do
|
|
362
|
-
sequence(:name) { |n| "User #{n}" }
|
|
363
|
-
sequence(:email) { |n| "user#{n}@example.com" }
|
|
364
|
-
age { rand(18..80) }
|
|
365
|
-
status { 'active' }
|
|
366
|
-
|
|
367
|
-
trait :inactive do
|
|
368
|
-
status { 'inactive' }
|
|
369
|
-
end
|
|
370
|
-
|
|
371
|
-
trait :admin do
|
|
372
|
-
admin { true }
|
|
373
|
-
end
|
|
374
|
-
|
|
375
|
-
trait :with_posts do
|
|
376
|
-
after(:create) do |user|
|
|
377
|
-
create_list(:post, 3, user: user)
|
|
378
|
-
end
|
|
379
|
-
end
|
|
380
|
-
|
|
381
|
-
factory :admin_user, traits: [:admin]
|
|
382
|
-
factory :inactive_user, traits: [:inactive]
|
|
383
|
-
end
|
|
384
|
-
end
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
## Test Helper Configuration
|
|
388
|
-
|
|
389
|
-
```ruby
|
|
390
|
-
# spec/spec_helper.rb
|
|
391
|
-
require 'simplecov'
|
|
392
|
-
SimpleCov.start 'rails' do
|
|
393
|
-
add_filter '/spec/'
|
|
394
|
-
add_filter '/config/'
|
|
395
|
-
add_filter '/vendor/'
|
|
396
|
-
|
|
397
|
-
add_group 'Controllers', 'app/controllers'
|
|
398
|
-
add_group 'Models', 'app/models'
|
|
399
|
-
add_group 'Services', 'app/services'
|
|
400
|
-
add_group 'Libraries', 'lib'
|
|
401
|
-
end
|
|
402
|
-
|
|
403
|
-
RSpec.configure do |config|
|
|
404
|
-
config.expect_with :rspec do |expectations|
|
|
405
|
-
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
|
406
|
-
end
|
|
407
|
-
|
|
408
|
-
config.mock_with :rspec do |mocks|
|
|
409
|
-
mocks.verify_partial_doubles = true
|
|
410
|
-
end
|
|
411
|
-
|
|
412
|
-
config.shared_context_metadata_behavior = :apply_to_host_groups
|
|
413
|
-
config.filter_run_when_matching :focus
|
|
414
|
-
config.example_status_persistence_file_path = 'spec/examples.txt'
|
|
415
|
-
config.disable_monkey_patching!
|
|
416
|
-
config.warnings = true
|
|
417
|
-
|
|
418
|
-
if config.files_to_run.one?
|
|
419
|
-
config.default_formatter = 'doc'
|
|
420
|
-
end
|
|
421
|
-
|
|
422
|
-
config.profile_examples = 10
|
|
423
|
-
config.order = :random
|
|
424
|
-
Kernel.srand config.seed
|
|
425
|
-
end
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
## Integration Test Example
|
|
429
|
-
|
|
430
|
-
```ruby
|
|
431
|
-
# spec/requests/api/users_spec.rb
|
|
432
|
-
require 'rails_helper'
|
|
433
|
-
|
|
434
|
-
RSpec.describe 'API::Users', type: :request do
|
|
435
|
-
let(:user) { create(:user) }
|
|
436
|
-
let(:valid_headers) {
|
|
437
|
-
{ 'Authorization' => "Bearer #{user.auth_token}" }
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
describe 'GET /api/users' do
|
|
441
|
-
it 'returns users' do
|
|
442
|
-
create_list(:user, 3)
|
|
443
|
-
|
|
444
|
-
get '/api/users', headers: valid_headers
|
|
445
|
-
|
|
446
|
-
expect(response).to have_http_status(:ok)
|
|
447
|
-
expect(JSON.parse(response.body)['users'].size).to eq(3)
|
|
448
|
-
end
|
|
449
|
-
end
|
|
450
|
-
|
|
451
|
-
describe 'POST /api/users' do
|
|
452
|
-
let(:valid_params) do
|
|
453
|
-
{
|
|
454
|
-
user: {
|
|
455
|
-
name: 'New User',
|
|
456
|
-
email: 'new@example.com'
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
end
|
|
460
|
-
|
|
461
|
-
it 'creates a new user' do
|
|
462
|
-
post '/api/users', params: valid_params, headers: valid_headers
|
|
463
|
-
|
|
464
|
-
expect(response).to have_http_status(:created)
|
|
465
|
-
expect(JSON.parse(response.body)['user']['name']).to eq('New User')
|
|
466
|
-
end
|
|
467
|
-
end
|
|
468
|
-
end
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
## Best Practices Included
|
|
472
|
-
|
|
473
|
-
- **Descriptive test names** that explain expected behavior
|
|
474
|
-
- **Proper test organization** with contexts and describes
|
|
475
|
-
- **Factory usage** for test data generation
|
|
476
|
-
- **Mocking and stubbing** for external dependencies
|
|
477
|
-
- **Coverage configuration** with SimpleCov
|
|
478
|
-
- **Test helpers** and shared examples
|
|
479
|
-
- **Request/Integration tests** for API endpoints
|
|
480
|
-
- **Feature tests** for user workflows
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash",
|
|
5
|
-
"Edit",
|
|
6
|
-
"MultiEdit",
|
|
7
|
-
"Write",
|
|
8
|
-
"Bash(ruby:*)",
|
|
9
|
-
"Bash(bundle:*)",
|
|
10
|
-
"Bash(rails:*)",
|
|
11
|
-
"Bash(rake:*)",
|
|
12
|
-
"Bash(rspec:*)",
|
|
13
|
-
"Bash(rubocop:*)",
|
|
14
|
-
"Bash(brakeman:*)",
|
|
15
|
-
"Bash(irb:*)",
|
|
16
|
-
"Bash(pry:*)",
|
|
17
|
-
"Bash(gem:*)",
|
|
18
|
-
"Bash(rbenv:*)",
|
|
19
|
-
"Bash(rvm:*)",
|
|
20
|
-
"Bash(kamal:*)",
|
|
21
|
-
"Bash(git:*)"
|
|
22
|
-
],
|
|
23
|
-
"deny": [
|
|
24
|
-
"Bash(curl:*)",
|
|
25
|
-
"Bash(wget:*)",
|
|
26
|
-
"Bash(rm -rf:*)"
|
|
27
|
-
],
|
|
28
|
-
"defaultMode": "allowEdits"
|
|
29
|
-
},
|
|
30
|
-
"env": {
|
|
31
|
-
"BASH_DEFAULT_TIMEOUT_MS": "60000",
|
|
32
|
-
"BASH_MAX_OUTPUT_LENGTH": "20000",
|
|
33
|
-
"CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR": "1",
|
|
34
|
-
"BUNDLE_PATH": "vendor/bundle",
|
|
35
|
-
"BUNDLE_JOBS": "4"
|
|
36
|
-
},
|
|
37
|
-
"includeCoAuthoredBy": true,
|
|
38
|
-
"cleanupPeriodDays": 30,
|
|
39
|
-
"hooks": {
|
|
40
|
-
"PreToolUse": [
|
|
41
|
-
{
|
|
42
|
-
"matcher": "Bash",
|
|
43
|
-
"hooks": [
|
|
44
|
-
{
|
|
45
|
-
"type": "command",
|
|
46
|
-
"command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"No description\")\"' >> ~/.claude/bash-command-log.txt"
|
|
47
|
-
}
|
|
48
|
-
]
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
"matcher": "Write",
|
|
52
|
-
"hooks": [
|
|
53
|
-
{
|
|
54
|
-
"type": "command",
|
|
55
|
-
"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"); CONTENT=$(echo $STDIN_JSON | jq -r '.tool_input.content // \"\"); if [[ \"$FILE\" =~ \\.rb$ ]] && echo \"$CONTENT\" | grep -q 'puts\\|p '; then echo 'Warning: puts/p statements should be replaced with proper logging' >&2; exit 2; fi"
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
"matcher": "Write",
|
|
61
|
-
"hooks": [
|
|
62
|
-
{
|
|
63
|
-
"type": "command",
|
|
64
|
-
"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"'); if [[ \"$FILE\" == \"Gemfile\" ]] || [[ \"$FILE\" == \"Gemfile.lock\" ]] || [[ \"$FILE\" =~ gemspec$ ]]; then echo 'Checking for vulnerable gems...'; if command -v bundle >/dev/null 2>&1 && bundle show bundler-audit >/dev/null 2>&1; then bundle audit; elif command -v bundle >/dev/null 2>&1; then echo 'Run: bundle add bundler-audit --group development to enable security audits'; else echo 'Bundler not found for security audit'; fi; fi",
|
|
65
|
-
"timeout": 60
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
}
|
|
69
|
-
],
|
|
70
|
-
"PostToolUse": [
|
|
71
|
-
{
|
|
72
|
-
"matcher": "Write|Edit|MultiEdit",
|
|
73
|
-
"hooks": [
|
|
74
|
-
{
|
|
75
|
-
"type": "command",
|
|
76
|
-
"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"'); if [[ \"$FILE\" =~ \\.rb$ ]]; then if command -v rubocop >/dev/null 2>&1; then rubocop -A \"$FILE\" 2>/dev/null || echo 'RuboCop auto-correction applied'; elif command -v bundle >/dev/null 2>&1 && bundle show rubocop >/dev/null 2>&1; then bundle exec rubocop -A \"$FILE\" 2>/dev/null || echo 'RuboCop auto-correction applied'; else echo 'RuboCop not available for auto-correction'; fi; fi",
|
|
77
|
-
"timeout": 30
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
"matcher": "Write|Edit|MultiEdit",
|
|
83
|
-
"hooks": [
|
|
84
|
-
{
|
|
85
|
-
"type": "command",
|
|
86
|
-
"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"'); if [[ \"$FILE\" =~ \\.rb$ ]]; then RESULT=$(if command -v rubocop >/dev/null 2>&1; then rubocop \"$FILE\" 2>&1; elif command -v bundle >/dev/null 2>&1 && bundle show rubocop >/dev/null 2>&1; then bundle exec rubocop \"$FILE\" 2>&1; fi); if [ $? -ne 0 ] && [[ -n \"$RESULT\" ]]; then echo \"RuboCop linting issues found: $RESULT\" >&2; exit 2; fi; fi",
|
|
87
|
-
"timeout": 30
|
|
88
|
-
}
|
|
89
|
-
]
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
"matcher": "Write|Edit|MultiEdit",
|
|
93
|
-
"hooks": [
|
|
94
|
-
{
|
|
95
|
-
"type": "command",
|
|
96
|
-
"command": "FILE=$(echo $STDIN_JSON | jq -r '.tool_input.file_path // \"\"'); if [[ \"$FILE\" =~ \\.rb$ && \"$FILE\" != *\"spec/\"* && \"$FILE\" != *\"_spec.rb\" && \"$FILE\" != *\"test/\"* && \"$FILE\" != *\"_test.rb\" ]]; then DIR=$(dirname \"$FILE\"); BASENAME=$(basename \"$FILE\" .rb); for TEST_FILE in \"spec/${BASENAME}_spec.rb\" \"test/${BASENAME}_test.rb\" \"spec/models/${BASENAME}_spec.rb\" \"spec/controllers/${BASENAME}_spec.rb\" \"spec/services/${BASENAME}_spec.rb\"; do if [ -f \"$TEST_FILE\" ]; then echo \"Running tests for $TEST_FILE...\"; if command -v rspec >/dev/null 2>&1; then rspec \"$TEST_FILE\"; elif command -v bundle >/dev/null 2>&1 && bundle show rspec >/dev/null 2>&1; then bundle exec rspec \"$TEST_FILE\"; elif command -v ruby >/dev/null 2>&1; then ruby -Itest \"$TEST_FILE\" 2>/dev/null || echo 'Test runner not available'; fi; break; fi; done; fi",
|
|
97
|
-
"timeout": 60
|
|
98
|
-
}
|
|
99
|
-
]
|
|
100
|
-
}
|
|
101
|
-
],
|
|
102
|
-
"Notification": [
|
|
103
|
-
{
|
|
104
|
-
"matcher": "",
|
|
105
|
-
"hooks": [
|
|
106
|
-
{
|
|
107
|
-
"type": "command",
|
|
108
|
-
"command": "echo \"Claude Code notification: $(date)\" >> ~/.claude/notifications.log"
|
|
109
|
-
}
|
|
110
|
-
]
|
|
111
|
-
}
|
|
112
|
-
],
|
|
113
|
-
"Stop": [
|
|
114
|
-
{
|
|
115
|
-
"matcher": "",
|
|
116
|
-
"hooks": [
|
|
117
|
-
{
|
|
118
|
-
"type": "command",
|
|
119
|
-
"command": "if [[ -f Gemfile || -f Rakefile ]] && [[ $(git status --porcelain | grep '\\.rb$') ]]; then echo 'Running RuboCop on changed Ruby files...'; if command -v rubocop >/dev/null 2>&1; then rubocop $(git diff --name-only --diff-filter=ACMR | grep '\\.rb$'); elif command -v bundle >/dev/null 2>&1 && bundle show rubocop >/dev/null 2>&1; then bundle exec rubocop $(git diff --name-only --diff-filter=ACMR | grep '\\.rb$'); else echo 'RuboCop not found for linting'; fi; fi",
|
|
120
|
-
"timeout": 60
|
|
121
|
-
}
|
|
122
|
-
]
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
"matcher": "",
|
|
126
|
-
"hooks": [
|
|
127
|
-
{
|
|
128
|
-
"type": "command",
|
|
129
|
-
"command": "if [[ -f Gemfile || -f Rakefile ]] && [[ $(git status --porcelain | grep '\\.rb$') ]]; then echo 'Running security scan with Brakeman...'; if command -v brakeman >/dev/null 2>&1; then brakeman --quiet --no-pager || echo 'Brakeman scan completed with findings'; elif command -v bundle >/dev/null 2>&1 && bundle show brakeman >/dev/null 2>&1; then bundle exec brakeman --quiet --no-pager || echo 'Brakeman scan completed with findings'; else echo 'Brakeman not found for security scanning'; fi; fi",
|
|
130
|
-
"timeout": 60
|
|
131
|
-
}
|
|
132
|
-
]
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
"matcher": "",
|
|
136
|
-
"hooks": [
|
|
137
|
-
{
|
|
138
|
-
"type": "command",
|
|
139
|
-
"command": "if [[ -f Gemfile ]]; then echo 'Checking for gem vulnerabilities...'; if command -v bundle >/dev/null 2>&1 && bundle show bundler-audit >/dev/null 2>&1; then bundle audit || echo 'Security audit completed with findings'; else echo 'bundler-audit not found. Run: bundle add bundler-audit --group development'; fi; fi",
|
|
140
|
-
"timeout": 30
|
|
141
|
-
}
|
|
142
|
-
]
|
|
143
|
-
}
|
|
144
|
-
]
|
|
145
|
-
}
|
|
146
|
-
}
|