spec_forge 0.4.0 → 0.6.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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.standard.yml +4 -0
  3. data/CHANGELOG.md +145 -1
  4. data/README.md +49 -638
  5. data/flake.lock +3 -3
  6. data/flake.nix +8 -2
  7. data/lib/spec_forge/attribute/chainable.rb +208 -20
  8. data/lib/spec_forge/attribute/factory.rb +141 -12
  9. data/lib/spec_forge/attribute/faker.rb +64 -15
  10. data/lib/spec_forge/attribute/global.rb +96 -0
  11. data/lib/spec_forge/attribute/literal.rb +15 -2
  12. data/lib/spec_forge/attribute/matcher.rb +188 -13
  13. data/lib/spec_forge/attribute/parameterized.rb +45 -20
  14. data/lib/spec_forge/attribute/regex.rb +55 -5
  15. data/lib/spec_forge/attribute/resolvable.rb +48 -5
  16. data/lib/spec_forge/attribute/resolvable_array.rb +62 -4
  17. data/lib/spec_forge/attribute/resolvable_hash.rb +62 -4
  18. data/lib/spec_forge/attribute/store.rb +65 -0
  19. data/lib/spec_forge/attribute/transform.rb +33 -5
  20. data/lib/spec_forge/attribute/variable.rb +37 -6
  21. data/lib/spec_forge/attribute.rb +168 -66
  22. data/lib/spec_forge/backtrace_formatter.rb +26 -3
  23. data/lib/spec_forge/callbacks.rb +79 -0
  24. data/lib/spec_forge/cli/actions.rb +27 -0
  25. data/lib/spec_forge/cli/command.rb +78 -24
  26. data/lib/spec_forge/cli/init.rb +11 -1
  27. data/lib/spec_forge/cli/new.rb +54 -3
  28. data/lib/spec_forge/cli/run.rb +20 -0
  29. data/lib/spec_forge/cli.rb +16 -5
  30. data/lib/spec_forge/configuration.rb +94 -25
  31. data/lib/spec_forge/context/callbacks.rb +91 -0
  32. data/lib/spec_forge/context/global.rb +72 -0
  33. data/lib/spec_forge/context/store.rb +148 -0
  34. data/lib/spec_forge/context/variables.rb +91 -0
  35. data/lib/spec_forge/context.rb +36 -0
  36. data/lib/spec_forge/core_ext/rspec.rb +24 -4
  37. data/lib/spec_forge/error.rb +267 -113
  38. data/lib/spec_forge/factory.rb +33 -14
  39. data/lib/spec_forge/filter.rb +87 -0
  40. data/lib/spec_forge/forge.rb +170 -0
  41. data/lib/spec_forge/http/backend.rb +99 -29
  42. data/lib/spec_forge/http/client.rb +23 -13
  43. data/lib/spec_forge/http/request.rb +74 -62
  44. data/lib/spec_forge/http/verb.rb +79 -0
  45. data/lib/spec_forge/http.rb +105 -0
  46. data/lib/spec_forge/loader.rb +254 -0
  47. data/lib/spec_forge/matchers.rb +130 -0
  48. data/lib/spec_forge/normalizer/configuration.rb +24 -11
  49. data/lib/spec_forge/normalizer/constraint.rb +22 -9
  50. data/lib/spec_forge/normalizer/expectation.rb +31 -12
  51. data/lib/spec_forge/normalizer/factory.rb +24 -11
  52. data/lib/spec_forge/normalizer/factory_reference.rb +32 -13
  53. data/lib/spec_forge/normalizer/global_context.rb +88 -0
  54. data/lib/spec_forge/normalizer/spec.rb +39 -16
  55. data/lib/spec_forge/normalizer.rb +255 -41
  56. data/lib/spec_forge/runner/callbacks.rb +246 -0
  57. data/lib/spec_forge/runner/debug_proxy.rb +213 -0
  58. data/lib/spec_forge/runner/listener.rb +54 -0
  59. data/lib/spec_forge/runner/metadata.rb +58 -0
  60. data/lib/spec_forge/runner/state.rb +99 -0
  61. data/lib/spec_forge/runner.rb +133 -119
  62. data/lib/spec_forge/spec/expectation/constraint.rb +95 -20
  63. data/lib/spec_forge/spec/expectation.rb +43 -51
  64. data/lib/spec_forge/spec.rb +83 -96
  65. data/lib/spec_forge/type.rb +36 -4
  66. data/lib/spec_forge/version.rb +4 -1
  67. data/lib/spec_forge.rb +161 -76
  68. metadata +20 -5
  69. data/spec_forge/factories/user.yml +0 -4
  70. data/spec_forge/forge_helper.rb +0 -37
  71. data/spec_forge/specs/users.yml +0 -65
data/README.md CHANGED
@@ -4,30 +4,50 @@
4
4
  ![Ruby Version](https://img.shields.io/badge/ruby-3.3.7-ruby)
5
5
  [![Tests](https://github.com/itsthedevman/spec_forge/actions/workflows/main.yml/badge.svg)](https://github.com/itsthedevman/spec_forge/actions/workflows/main.yml)
6
6
 
7
+ > Note: The code in this repository represents the latest development version with new features and improvements that are being prepared for future releases. For the current stable version, check out [v0.6.0](https://github.com/itsthedevman/spec_forge/releases/tag/v0.6.0) on GitHub releases.
8
+
7
9
  Write API tests in YAML that read like documentation:
8
10
 
9
11
  ```yaml
10
- user_profile:
11
- path: /users/1
12
+ show_user:
13
+ path: /users/{id}
14
+ variables:
15
+ expected_status: 200
16
+ user_id: 1
17
+ query:
18
+ id: variables.user_id
12
19
  expectations:
13
20
  - expect:
14
- status: 200
21
+ status: variables.expected_status
15
22
  json:
16
23
  name: kind_of.string
17
- email: /@/
24
+ email:
25
+ matcher.and:
26
+ - kind_of.string
27
+ - /@/
18
28
  ```
19
29
 
20
30
  That's a complete test. No Ruby code, no configuration files, no HTTP client setup - just a clear description of what you're testing. Under the hood, you get all the power of RSpec's matchers, Faker's data generation, and FactoryBot's test objects.
21
31
 
22
32
  ## Why SpecForge?
23
33
 
24
- SpecForge shines when you need:
34
+ 1. **Living Documentation**: Your tests should serve as clear, readable documentation of your API's behavior.
35
+ 2. **Reduce Boilerplate**: Write tests without repetitive setup code and HTTP configuration.
36
+ 3. **Quick Setup**: Start testing APIs in minutes instead of spending hours on test infrastructure.
37
+ 4. **Gradual Adoption**: Use alongside your existing test suite, introducing it incrementally where it makes sense.
38
+ 5. **Developer & QA Collaboration**: Create a testing format that everyone can understand and maintain, regardless of Ruby expertise.
25
39
 
26
- 1. **Accessible API Testing**: Non-developers can write and maintain tests without Ruby knowledge. The YAML syntax reads like documentation.
27
- 2. **Living Documentation**: Tests serve as clear, maintainable documentation of your API's expected behavior.
28
- 3. **Power Without Complexity**: Get the benefits of Ruby-based tests (dynamic data, factories, matchers) without writing Ruby code.
29
- 4. **Quick Setup**: Start testing APIs without configuring HTTP clients or writing boilerplate code.
30
- 5. **Gradual Adoption**: Use alongside your existing test suite. Keep complex tests in RSpec while making simple API tests more accessible.
40
+ ## Key Features
41
+
42
+ - **YAML-Based Tests**: Write clear, declarative tests that read like documentation
43
+ - **RSpec Integration**: Leverage all the power of RSpec matchers and expectations
44
+ - **FactoryBot Integration**: Generate test data with FactoryBot integration
45
+ - **Faker Integration**: Create realistic test data with Faker
46
+ - **Variable System**: Define and reference variables for dynamic test data
47
+ - **Context Storage**: Store API responses and reference them in subsequent tests
48
+ - **Compound Matchers**: Combine multiple validations with `matcher.and` for precise expectations
49
+ - **Global Variables**: Define shared configuration at the file level
50
+ - **Callback System**: Hook into the test lifecycle using Ruby for setup, teardown, and much more!
31
51
 
32
52
  ## When Not to Use SpecForge
33
53
 
@@ -38,75 +58,6 @@ Consider alternatives when you need:
38
58
  3. **Custom Response Validation**: For validation logic beyond what matchers provide.
39
59
  4. **Complex Non-JSON Testing**: While SpecForge handles basic XML/HTML responses (coming soon), complex validation might need specialized tools.
40
60
 
41
- ## Roadmap
42
-
43
- Current development priorities:
44
- - [ ] Array support for `json` expectations
45
- - [ ] Negated matchers: `matcher.not`
46
- - [ ] `create_list/build_list` factory strategies
47
- - [ ] `transform.map` support
48
- - [ ] XML/HTML response handling
49
- - [ ] OpenAPI generation from tests
50
- - [x] Support for running individual specs
51
- - [x] Improved error handling
52
-
53
- Have a feature request? Open an issue on GitHub!
54
-
55
- ## Looking for a Software Engineer?
56
-
57
- I'm currently looking for opportunities where I can tackle meaningful problems and help build reliable software while mentoring the next generation of developers. If you're looking for a senior engineer with full-stack Rails expertise and a passion for clean, maintainable code, let's talk!
58
-
59
- [bryan@itsthedevman.com](mailto:bryan@itsthedevman.com)
60
-
61
- ## Table of Contents
62
-
63
- - [Compatibility](#compatibility)
64
- - [Installation](#installation)
65
- - [Getting Started](#getting-started)
66
- - [Forging Your First Test](#forging-your-first-test)
67
- - [Running Tests](#running-tests)
68
- - [Targeting Specific Files](#targeting-specific-files)
69
- - [Targeting Specific Specs](#targeting-specific-specs)
70
- - [Targeting Individual Expectations](#targeting-individual-expectations)
71
- - [Configuration](#configuration)
72
- - [Basic Configuration](#basic-configuration)
73
- - [Framework Integration](#framework-integration)
74
- - [Factory Configuration](#factory-configuration)
75
- - [Debug Configuration](#debug-configuration)
76
- - [Test Framework Configuration](#test-framework-configuration)
77
- - [Configuration Inheritance](#configuration-inheritance)
78
- - [Writing Tests](#writing-tests)
79
- - [Basic Structure](#basic-structure)
80
- - [Testing Response Data](#testing-response-data)
81
- - [Multiple Expectations](#multiple-expectations)
82
- - [Request Data](#request-data)
83
- - [Path Parameters](#path-parameters)
84
- - [Dynamic Features](#dynamic-features)
85
- - [Variables](#variables)
86
- - [Transformations](#transformations)
87
- - [Chaining Support](#chaining-support)
88
- - [Factory Support](#factory-support)
89
- - [Automatic Discovery](#automatic-discovery)
90
- - [Custom Factory Paths](#custom-factory-paths)
91
- - [Build Strategies](#build-strategies)
92
- - [YAML Factory Definitions](#yaml-factory-definitions)
93
- - [RSpec Matchers](#rspec-matchers)
94
- - ["be" namespace](#be-namespace)
95
- - ["kind_of" namespace](#kind_of-namespace)
96
- - ["matchers" namespace](#matchers-namespace)
97
- - [How Tests Work](#how-tests-work)
98
- - [Contributing](#contributing)
99
- - [License](#license)
100
- - [Credits](#credits)
101
-
102
- Also see: [API Documentation](https://itsthedevman.com/docs/spec_forge)
103
-
104
- ## Compatibility
105
-
106
- Currently tested on:
107
- - MRI Ruby 3.2+
108
- - NixOS (see `flake.nix` for details)
109
-
110
61
  ## Installation
111
62
 
112
63
  Add this line to your application's Gemfile:
@@ -135,587 +86,47 @@ Initialize the required directory structure:
135
86
  spec_forge init
136
87
  ```
137
88
 
138
- Or with bundle:
139
- ```bash
140
- bundle exec spec_forge init
141
- ```
142
-
143
- This creates the `spec_forge` directory containing factory definitions, test specifications, and global configuration.
144
-
145
- ## Forging Your First Test
146
-
147
- Let's write a simple test to verify a user endpoint. Create a new spec file:
89
+ Create your first test:
148
90
 
149
91
  ```bash
150
92
  spec_forge new spec users
151
93
  ```
152
94
 
153
- This creates `spec_forge/specs/users.yml`. Here's a basic example:
154
-
155
- ```yaml
156
- get_user:
157
- path: /users/1
158
- method: GET
159
- expectations:
160
- - expect:
161
- status: 200
162
- json:
163
- id: 1
164
- name: kind_of.string
165
- email: /@/
166
- ```
167
-
168
- Run your tests with:
95
+ Run your tests:
169
96
 
170
97
  ```bash
171
98
  spec_forge run
172
99
  ```
173
100
 
174
- Since `run` is the default command, you can just use:
175
-
176
- ```bash
177
- spec_forge
178
- ```
179
-
180
- ## Running Tests
181
-
182
- As your test suite grows, you'll want more control over which tests to run.
101
+ ## Documentation
183
102
 
184
- #### Targeting Specific Files
185
-
186
- When working on a specific feature, run tests from a single file:
187
-
188
- ```bash
189
- spec_forge users # Runs all tests in specs/users.yml
190
- ```
103
+ For comprehensive documentation, visit the [SpecForge Wiki](https://github.com/itsthedevman/spec_forge/wiki) which includes:
191
104
 
192
- #### Targeting Specific Specs
105
+ - [Getting Started Guide](https://github.com/itsthedevman/spec_forge/wiki/Getting-Started)
106
+ - [Configuration Options](https://github.com/itsthedevman/spec_forge/wiki/Configuration)
107
+ - [Writing Tests](https://github.com/itsthedevman/spec_forge/wiki/Writing-Tests)
108
+ - [Running Tests](https://github.com/itsthedevman/spec_forge/wiki/Running-Tests)
109
+ - [Debugging Guide](https://github.com/itsthedevman/spec_forge/wiki/Debugging)
110
+ - [Dynamic Features](https://github.com/itsthedevman/spec_forge/wiki/Dynamic-Features)
111
+ - [Factory Support](https://github.com/itsthedevman/spec_forge/wiki/Factory-Support)
112
+ - [RSpec Matchers](https://github.com/itsthedevman/spec_forge/wiki/RSpec-Matchers)
193
113
 
194
- Focus on a specific endpoint by running a single spec:
114
+ Also see the [API Documentation](https://itsthedevman.com/docs/spec_forge).
195
115
 
196
- ```bash
197
- spec_forge users:destroy_user # Runs all expectations in the destroy_user spec
198
- ```
199
-
200
- #### Targeting Individual Expectations
201
-
202
- You can also run individual expectations within a spec. The format depends on whether the expectation has a name:
203
-
204
- ```yaml
205
- # specs/users.yml
206
- destroy_user:
207
- path: /users/:id
208
- method: delete
209
- expectations:
210
- - expect: # Unnamed expectation
211
- status: 200
212
- - name: "Destroys a User" # Named expectation
213
- expect:
214
- status: 200
215
- ```
216
-
217
- For named expectations:
218
- ```bash
219
- # Format: <file>:<spec>:'<verb> <path> - <name>'
220
- spec_forge users:destroy_user:'DELETE /users/:id - Destroys a User'
221
- ```
222
-
223
- For unnamed expectations:
224
- ```bash
225
- # Format: <file>:<spec>:'<verb> <path>'
226
- spec_forge users:destroy_user:'DELETE /users/:id'
227
- ```
228
-
229
- **Note**: When targeting an unnamed expectation, SpecForge executes all matching expectations within that spec. This means if you have multiple unnamed expectations with the same verb and path, they will all run.
230
-
231
- ## Configuration
232
-
233
- ### Basic Configuration
234
-
235
- When you initialize SpecForge, it creates a `forge_helper.rb` file in your `spec_forge` directory. This serves as your central configuration file:
236
-
237
- ```ruby
238
- SpecForge.configure do |config|
239
- # Base URL for all requests
240
- config.base_url = "http://localhost:3000"
241
-
242
- # Default headers sent with every request
243
- config.headers = {
244
- "Authorization" => "Bearer #{ENV.fetch("API_TOKEN", "")}",
245
- "Accept" => "application/json"
246
- }
247
-
248
- # Optional: Default query parameters for all requests
249
- config.query = {
250
- api_key: ENV["API_KEY"]
251
- }
252
- end
253
- ```
116
+ ## Future Development
254
117
 
255
- ### Framework Integration
256
-
257
- SpecForge works seamlessly with Rails and RSpec:
258
-
259
- ```ruby
260
- # Rails Integration
261
- require_relative "../config/environment"
262
-
263
- # RSpec Integration (includes your existing configurations)
264
- require_relative "../spec/spec_helper"
265
-
266
- # Load custom files (models, libraries, etc)
267
- Dir[File.join(__dir__, "..", "lib", "**", "*.rb")].sort.each { |f| require f }
268
- ```
269
-
270
- ### Factory Configuration
271
-
272
- SpecForge provides flexible configuration options for working with FactoryBot factories:
273
-
274
- ```ruby
275
- SpecForge.configure do |config|
276
- # Disable auto-discovery if needed (default: true)
277
- config.factories.auto_discover = false
278
-
279
- # Add custom factory paths (appends to default paths)
280
- config.factories.paths += ["lib/factories"]
281
- end
282
- ```
283
-
284
- ### Debug Configuration
285
-
286
- Enable debugging by adding `debug: true` (aliases: `breakpoint`, `pry`) at either the spec or expectation level:
287
-
288
- ```ruby
289
- SpecForge.configure do |config|
290
- # Custom debug handler (defaults to printing state overview)
291
- config.on_debug { binding.pry } # Requires 'pry' gem
292
- end
293
- ```
294
-
295
- ```yaml
296
- get_users:
297
- debug: true # Debug all expectations in this spec
298
- path: /users
299
- expectations:
300
- - expect:
301
- status: 200
302
- - debug: true # Debug just this expectation
303
- expect:
304
- status: 404
305
- json:
306
- error: kind_of.string
307
- ```
308
-
309
- When debugging, you have access to:
310
- - `expectation` - Current expectation being validated
311
- - `variables` - Resolved variables for the current expectation
312
- - `request` - Request details (url, method, headers, etc.)
313
- - `response` - Full response including headers, status, and parsed body
314
- - `expected_status` - Expected HTTP status code
315
- - `expected_json` - Expected JSON structure with matchers
316
-
317
- Or call `self` from an interactive session to see everything as a hash
318
-
319
- ### Test Framework Configuration
320
-
321
- Access RSpec's configuration through the `specs` attribute:
322
-
323
- ```ruby
324
- SpecForge.configure do |config|
325
- # Setup before all tests
326
- config.specs.before(:suite) do
327
- DatabaseCleaner.strategy = :truncation
328
- DatabaseCleaner.clean_with(:truncation)
329
- end
330
-
331
- # Wrap each test
332
- config.specs.around do |example|
333
- DatabaseCleaner.cleaning do
334
- example.run
335
- end
336
- end
337
- end
338
- ```
339
-
340
- ### Configuration Inheritance
341
-
342
- All configuration options can be overridden at three levels (in order of precedence):
343
-
344
- 1. Individual expectation
345
- 2. Spec level
346
- 3. Global configuration (forge_helper.rb)
347
-
348
- For example:
349
-
350
- ```yaml
351
- # Override at spec level
352
- get_user:
353
- base_url: https://staging.example.com
354
- headers:
355
- x_custom_header: "overridden" # Underscore keys automatically convert to "X-Custom-Header"
356
-
357
- expectations:
358
- # Override for a specific expectation
359
- - base_url: https://prod.example.com
360
- headers:
361
- X-Custom-Header: "expectation-specific" # HTTP-style headers used as-is
362
- expect:
363
- status: 200
364
- ```
365
-
366
- ## Writing Tests
367
-
368
- ### Basic Structure
369
-
370
- Every spec needs a path, HTTP method, and at least one expectation:
371
-
372
- ```yaml
373
- show_user:
374
- path: /users/1
375
- method: GET # Optional for GET requests
376
- expectations:
377
- - expect:
378
- status: 200
379
- ```
380
-
381
- ### Testing Response Data
382
-
383
- Verify the response JSON:
384
-
385
- ```yaml
386
- show_user:
387
- path: /users/1
388
- expectations:
389
- - expect:
390
- status: 200
391
- json:
392
- id: 1
393
- name: kind_of.string
394
- role: admin
395
- ```
396
-
397
- ### Multiple Expectations
398
-
399
- Each expectation can override any spec-level setting:
400
-
401
- ```yaml
402
- show_user:
403
- path: /users/1
404
- expectations:
405
- - expect:
406
- status: 200
407
- json:
408
- id: 1
409
- role: admin
410
- - path: /users/999 # Overrides spec-level path
411
- expect:
412
- status: 404
413
- ```
414
-
415
- ### Request Data
416
-
417
- Add query parameters and body data:
418
-
419
- ```yaml
420
- create_user:
421
- path: /users
422
- method: POST
423
- query: # or "params" if you prefer
424
- team_id: 123
425
- body: # or "data" if you prefer
426
- name: John Doe
427
- email: john@example.com
428
- expectations:
429
- - expect:
430
- status: 201
431
- ```
432
-
433
- ### Path Parameters
434
-
435
- Use placeholders for dynamic path parameters:
436
-
437
- ```yaml
438
- show_user:
439
- path: /users/{id} # Use {id} or :id
440
- query:
441
- id: 1 # Replaces the placeholder
442
- expectations:
443
- - expect:
444
- status: 200
445
- ```
446
-
447
- ## Dynamic Features
448
-
449
- ### Variables
450
-
451
- Variables let you define and reuse values:
452
-
453
- ```yaml
454
- list_posts:
455
- variables:
456
- author: factories.user
457
- category_name: faker.lorem.word
458
- query:
459
- author_id: variables.author.id
460
- category: variables.category_name
461
- expectations:
462
- - expect:
463
- status: 200
464
- json:
465
- posts:
466
- matcher.include:
467
- - author:
468
- id: variables.author.id
469
- name: variables.author.name
470
- category: variables.category_name
471
- ```
472
-
473
- ### Transformations
474
-
475
- Transform data using built-in helpers:
476
-
477
- ```yaml
478
- create_user:
479
- variables:
480
- first_name: faker.name.first_name
481
- last_name: faker.name.last_name
482
- full_name:
483
- transform.join:
484
- - variables.first_name
485
- - " "
486
- - variables.last_name
487
- body:
488
- name: variables.full_name
489
- email: faker.internet.email
490
- ```
491
-
492
- ### Chaining
493
-
494
- Access nested attributes and methods through chaining:
495
-
496
- ```yaml
497
- list_posts:
498
- variables:
499
- # Factory chaining examples
500
- owner: factories.user # Creates a user
501
- name: factories.user.name # Gets just the name
502
- company: variables.owner.company # Access factory attributes
503
-
504
- # Variable chaining for relationships
505
- first_post: variables.user.posts.first
506
-
507
- # You can use array indices directly
508
- comment_author: variables.first_post.comments.2.author.name
509
-
510
- # Faker method chaining
511
- lowercase_email: faker.internet.email.downcase
512
- title_name: faker.name.first_name.titleize
513
- ```
514
-
515
- ### Factory Build Strategies
516
-
517
- Control how factories create objects and customize their attributes:
518
-
519
- ```yaml
520
- create_user:
521
- variables:
522
- # Default strategy (create)
523
- regular_user: factories.user
524
-
525
- # Custom build strategy and attributes
526
- custom_user:
527
- factory.user:
528
- strategy: build # 'create' (default) or 'build'
529
- attributes:
530
- name: "Custom Name"
531
- email: faker.internet.email
532
- ```
533
-
534
- ## Factory Support
535
-
536
- ### Automatic Discovery
537
-
538
- SpecForge automatically discovers factories in standard paths:
539
-
540
- ```ruby
541
- SpecForge.configure do |config|
542
- # Disable automatic factory discovery if needed (default: true)
543
- config.factories.auto_discover = false
544
- end
545
- ```
546
-
547
- ### Custom Factory Paths
548
-
549
- Add custom paths to the factory search list:
550
-
551
- ```ruby
552
- SpecForge.configure do |config|
553
- # Add custom factory paths (appends to default paths)
554
- # Ignored if `auto_discovery` is false
555
- config.factories.paths += ["lib/factories"]
556
- end
557
- ```
558
-
559
- ### Factory Build Strategies
560
-
561
- Control how factories create objects and customize their attributes:
562
-
563
- ```yaml
564
- create_user:
565
- variables:
566
- # Default strategy (create)
567
- regular_user: factories.user
568
-
569
- # Custom build strategy and attributes
570
- custom_user:
571
- factory.user:
572
- strategy: build # 'create' (default) or 'build'
573
- attributes:
574
- name: "Custom Name"
575
- email: faker.internet.email
576
- ```
577
-
578
- ### YAML Factory Definitions
579
-
580
- Define factories in YAML with a simple declarative syntax:
581
-
582
- ```yaml
583
- # spec_forge/factories/user.yml
584
- user:
585
- class: User # Optional model class name
586
- variables:
587
- department: faker.company.department
588
- team_size:
589
- faker.number.between:
590
- from: 5
591
- to: 20
592
- attributes:
593
- name: faker.name.name
594
- email: faker.internet.email
595
- role: admin
596
- department: variables.department
597
- team_count: variables.team_size
598
- ```
599
-
600
- ## RSpec Matchers
601
-
602
- ### "be" namespace
603
-
604
- ```yaml
605
- expect:
606
- json:
607
- # Simple predicates
608
- active: be.true
609
- deleted: be.false
610
- description: be.nil
611
- tags: be.empty
612
- email: be.present
613
-
614
- # Comparisons
615
- price:
616
- be.greater_than: 18
617
- stock:
618
- be.less_than_or_equal: 100
619
- rating:
620
- be.between:
621
- - 1
622
- - 5
623
-
624
- # Dynamic predicate methods
625
- published: be.published
626
- admin: be.admin
627
- ```
628
-
629
- ### "kind_of" namespace
630
-
631
- ```yaml
632
- expect:
633
- json:
634
- id: kind_of.integer
635
- name: kind_of.string
636
- metadata: kind_of.hash
637
- scores: kind_of.array
638
- ```
639
-
640
- ### "matchers" namespace
641
-
642
- ```yaml
643
- expect:
644
- json:
645
- tags:
646
- matcher.include:
647
- - featured
648
- - published
649
-
650
- slug: /^[a-z0-9-]+$/ # Shorthand for matching regexes
651
-
652
- config:
653
- matcher.have_key: api_version
654
- ```
655
-
656
- ## How Tests Work
657
-
658
- When you write a YAML spec, SpecForge converts it into an RSpec test structure. For example, this YAML:
659
-
660
- ```yaml
661
- create_user:
662
- path: /users
663
- method: POST
664
- variables:
665
- full_name: faker.name.name
666
- body:
667
- name: variables.full_name
668
- expectations:
669
- - expect:
670
- status: 201
671
- json:
672
- name: variables.full_name
673
- ```
674
-
675
- Becomes this RSpec test:
676
-
677
- ```ruby
678
- RSpec.describe "create_user" do
679
- describe "POST /users" do
680
- let(:full_name) { Faker::Name.name }
681
-
682
- let!(:expected_status) { 201 }
683
- let!(:expected_json) do
684
- {
685
- name: eq(full_name)
686
- }
687
- end
688
-
689
- subject(:response) do
690
- post("/users", body: { name: full_name })
691
- end
692
-
693
- it do
694
- expect(response.status).to eq(expected_status)
695
- expect(response.body).to include(expected_json)
696
- end
697
- end
698
- end
699
- ```
118
+ For the latest development priorities and feature ideas, check out our [Github Project](https://github.com/itsthedevman/spec_forge/projects?query=is%3Aopen). Have a feature request? Open an issue on GitHub!
700
119
 
701
120
  ## Contributing
702
121
 
703
- 1. Fork it
704
- 2. Create your feature branch (`git checkout -b feature/my-new-feature`)
705
- 3. Commit your changes (`git commit -am 'Add some feature'`)
706
- 4. Push to the branch (`git push origin feature/my-new-feature`)
707
- 5. Create new Pull Request
708
-
709
- Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
122
+ Contributions are welcome! See the [Contributing Guide](https://github.com/itsthedevman/spec_forge/wiki/Contributing) for details on how to get started.
710
123
 
711
124
  ## License
712
125
 
713
126
  The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
714
127
 
715
- ## Changelog
716
-
717
- See [CHANGELOG.md](CHANGELOG.md) for a list of changes.
128
+ ## Looking for a Software Engineer?
718
129
 
719
- ## Credits
130
+ I'm currently looking for opportunities where I can tackle meaningful problems and help build reliable software while mentoring the next generation of developers. If you're looking for a senior engineer with full-stack Rails expertise and a passion for clean, maintainable code, let's talk!
720
131
 
721
- - Author: Bryan "itsthedevman"
132
+ [bryan@itsthedevman.com](mailto:bryan@itsthedevman.com)