ace-test 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 (67) hide show
  1. checksums.yaml +7 -0
  2. data/.ace-defaults/nav/protocols/agent-sources/ace-test.yml +19 -0
  3. data/.ace-defaults/nav/protocols/guide-sources/ace-test.yml +19 -0
  4. data/.ace-defaults/nav/protocols/tmpl-sources/ace-test.yml +11 -0
  5. data/.ace-defaults/nav/protocols/wfi-sources/ace-test.yml +19 -0
  6. data/CHANGELOG.md +169 -0
  7. data/LICENSE +21 -0
  8. data/README.md +40 -0
  9. data/Rakefile +12 -0
  10. data/handbook/agents/mock.ag.md +164 -0
  11. data/handbook/agents/profile-tests.ag.md +132 -0
  12. data/handbook/agents/test.ag.md +99 -0
  13. data/handbook/guides/SUMMARY.md +95 -0
  14. data/handbook/guides/embedded-testing-guide.g.md +261 -0
  15. data/handbook/guides/mocking-patterns.g.md +464 -0
  16. data/handbook/guides/quick-reference.g.md +46 -0
  17. data/handbook/guides/test-driven-development-cycle/meta-documentation.md +26 -0
  18. data/handbook/guides/test-driven-development-cycle/ruby-application.md +18 -0
  19. data/handbook/guides/test-driven-development-cycle/ruby-gem.md +19 -0
  20. data/handbook/guides/test-driven-development-cycle/rust-cli.md +18 -0
  21. data/handbook/guides/test-driven-development-cycle/rust-wasm-zed.md +19 -0
  22. data/handbook/guides/test-driven-development-cycle/typescript-nuxt.md +18 -0
  23. data/handbook/guides/test-driven-development-cycle/typescript-vue.md +19 -0
  24. data/handbook/guides/test-layer-decision.g.md +261 -0
  25. data/handbook/guides/test-mocking-patterns.g.md +414 -0
  26. data/handbook/guides/test-organization.g.md +140 -0
  27. data/handbook/guides/test-performance.g.md +353 -0
  28. data/handbook/guides/test-responsibility-map.g.md +220 -0
  29. data/handbook/guides/test-review-checklist.g.md +231 -0
  30. data/handbook/guides/test-suite-health.g.md +337 -0
  31. data/handbook/guides/testable-code-patterns.g.md +315 -0
  32. data/handbook/guides/testing/ruby-rspec-config-examples.md +120 -0
  33. data/handbook/guides/testing/ruby-rspec.md +87 -0
  34. data/handbook/guides/testing/rust.md +52 -0
  35. data/handbook/guides/testing/test-maintenance.md +364 -0
  36. data/handbook/guides/testing/typescript-bun.md +47 -0
  37. data/handbook/guides/testing/vue-firebase-auth.md +546 -0
  38. data/handbook/guides/testing/vue-vitest.md +236 -0
  39. data/handbook/guides/testing-philosophy.g.md +82 -0
  40. data/handbook/guides/testing-strategy.g.md +151 -0
  41. data/handbook/guides/testing-tdd-cycle.g.md +146 -0
  42. data/handbook/guides/testing.g.md +170 -0
  43. data/handbook/skills/as-test-create-cases/SKILL.md +24 -0
  44. data/handbook/skills/as-test-fix/SKILL.md +26 -0
  45. data/handbook/skills/as-test-improve-coverage/SKILL.md +22 -0
  46. data/handbook/skills/as-test-optimize/SKILL.md +34 -0
  47. data/handbook/skills/as-test-performance-audit/SKILL.md +34 -0
  48. data/handbook/skills/as-test-plan/SKILL.md +34 -0
  49. data/handbook/skills/as-test-review/SKILL.md +34 -0
  50. data/handbook/skills/as-test-verify-suite/SKILL.md +45 -0
  51. data/handbook/templates/e2e-sandbox-checklist.template.md +289 -0
  52. data/handbook/templates/test-case.template.md +56 -0
  53. data/handbook/templates/test-performance-audit.template.md +132 -0
  54. data/handbook/templates/test-responsibility-map.template.md +92 -0
  55. data/handbook/templates/test-review-checklist.template.md +163 -0
  56. data/handbook/workflow-instructions/test/analyze-failures.wf.md +120 -0
  57. data/handbook/workflow-instructions/test/create-cases.wf.md +675 -0
  58. data/handbook/workflow-instructions/test/fix.wf.md +120 -0
  59. data/handbook/workflow-instructions/test/improve-coverage.wf.md +370 -0
  60. data/handbook/workflow-instructions/test/optimize.wf.md +368 -0
  61. data/handbook/workflow-instructions/test/performance-audit.wf.md +17 -0
  62. data/handbook/workflow-instructions/test/plan.wf.md +323 -0
  63. data/handbook/workflow-instructions/test/review.wf.md +16 -0
  64. data/handbook/workflow-instructions/test/verify-suite.wf.md +343 -0
  65. data/lib/ace/test/version.rb +7 -0
  66. data/lib/ace/test.rb +10 -0
  67. metadata +152 -0
@@ -0,0 +1,315 @@
1
+ ---
2
+ doc-type: guide
3
+ title: Testable Code Patterns
4
+ purpose: Testable code design
5
+ ace-docs:
6
+ last-updated: 2026-01-23
7
+ last-checked: 2026-03-21
8
+ ---
9
+
10
+ # Testable Code Patterns
11
+
12
+ ## Avoiding Exit Calls in Testable Code
13
+
14
+ Commands that call `exit` will terminate the entire test process, preventing test completion and reporting. This manifests as:
15
+ - Test runner stops mid-execution
16
+ - No test summary is printed
17
+ - `ace-test` reports "0 tests, 0 assertions"
18
+ - Rake test fails with "Command failed with status (1)"
19
+
20
+ ### Pattern: Return Status Codes in Commands
21
+
22
+ Commands should return status codes (0 for success, 1 for failure) and let the CLI entry point handle exit:
23
+
24
+ ```ruby
25
+ # BAD - Terminates test process
26
+ class MyCommand
27
+ def execute(args)
28
+ if args.include?("--help")
29
+ show_help
30
+ exit 0 # Kills tests!
31
+ end
32
+
33
+ do_work
34
+ rescue => e
35
+ puts "Error: #{e.message}"
36
+ exit 1 # Kills tests!
37
+ end
38
+ end
39
+
40
+ # GOOD - Returns status codes
41
+ class MyCommand
42
+ def execute(args)
43
+ if args.include?("--help")
44
+ show_help
45
+ return 0
46
+ end
47
+
48
+ do_work
49
+ 0
50
+ rescue => e
51
+ puts "Error: #{e.message}"
52
+ 1
53
+ end
54
+ end
55
+ ```
56
+
57
+ ### Pattern: Raise Exceptions in Organisms
58
+
59
+ Organisms (business logic) should raise exceptions instead of calling exit:
60
+
61
+ ```ruby
62
+ # BAD - Terminates test process
63
+ class IdeaWriter
64
+ def write(content, options)
65
+ if content.nil? || content.strip.empty?
66
+ puts "Error: No content provided"
67
+ exit 1 # Kills tests!
68
+ end
69
+ # ...
70
+ end
71
+ end
72
+
73
+ # GOOD - Raises exceptions
74
+ class IdeaWriter
75
+ class IdeaWriterError < StandardError; end
76
+
77
+ def write(content, options)
78
+ if content.nil? || content.strip.empty?
79
+ raise IdeaWriterError, "No content provided"
80
+ end
81
+ # ...
82
+ end
83
+ end
84
+ ```
85
+
86
+ ### CLI Entry Point Pattern
87
+
88
+ The CLI entry point (exe/ace-*) should handle status codes and exit only at the top level:
89
+
90
+ ```ruby
91
+ #!/usr/bin/env ruby
92
+ # exe/ace-taskflow
93
+
94
+ require_relative "../lib/ace/taskflow"
95
+
96
+ # CLI.start returns status code
97
+ exit_code = Ace::Taskflow::CLI.start(ARGV)
98
+ exit(exit_code || 0)
99
+ ```
100
+
101
+ ```ruby
102
+ # lib/ace/taskflow/cli.rb
103
+ class CLI
104
+ def self.start(args)
105
+ case args.shift
106
+ when "retro"
107
+ require_relative "commands/retro_command"
108
+ Commands::RetroCommand.new.execute(args) # Returns status code
109
+ when "--help"
110
+ show_help
111
+ 0 # Return status code
112
+ else
113
+ puts "Unknown command"
114
+ 1 # Return status code
115
+ end
116
+ end
117
+ end
118
+ ```
119
+
120
+ ### Testing Commands with Status Codes
121
+
122
+ Test commands by asserting on their return values:
123
+
124
+ ```ruby
125
+ def test_help_returns_success
126
+ output = capture_io do
127
+ exit_code = @command.execute(["--help"])
128
+ assert_equal 0, exit_code
129
+ end
130
+
131
+ assert_match(/Usage:/, output)
132
+ end
133
+
134
+ def test_error_returns_failure
135
+ output = capture_io do
136
+ exit_code = @command.execute(["invalid"])
137
+ assert_equal 1, exit_code
138
+ end
139
+
140
+ assert_match(/Error:/, output)
141
+ end
142
+ ```
143
+
144
+ ### Testing Organisms with Exceptions
145
+
146
+ Test organisms by asserting on raised exceptions:
147
+
148
+ ```ruby
149
+ def test_raises_error_on_invalid_input
150
+ error = assert_raises(Ace::Taskflow::Organisms::IdeaWriterError) do
151
+ @writer.write("")
152
+ end
153
+
154
+ assert_match(/No content provided/, error.message)
155
+ end
156
+ ```
157
+
158
+ ### Migration Strategy
159
+
160
+ When refactoring commands with exit calls:
161
+
162
+ 1. **Identify exit calls**: `grep -r "exit [01]" lib/`
163
+ 2. **Refactor commands**: Replace `exit N` with `return N`
164
+ 3. **Refactor organisms**: Replace `exit N` with `raise CustomError`
165
+ 4. **Update CLI**: Return status codes, exit only at entry point
166
+ 5. **Update tests**: Assert on return values instead of SystemExit
167
+ 6. **Verify**: Run full test suite to ensure completion
168
+
169
+ ### Benefits
170
+
171
+ 1. **Test Completion**: Tests run to completion and report properly
172
+ 2. **Better Debugging**: Exceptions provide stack traces
173
+ 3. **Composability**: Commands can be called from other commands
174
+ 4. **Isolation**: Test failures don't affect other tests
175
+
176
+ ## Designing for Testability
177
+
178
+ ### Explicit Dependencies
179
+
180
+ Pass dependencies (services, configurations, clients) into functions or classes rather than relying on global state or singletons. This makes mocking easier for unit tests.
181
+
182
+ ```ruby
183
+ # BAD - Hard to test, relies on global
184
+ class UserService
185
+ def create_user(params)
186
+ Database.connection.insert(:users, params)
187
+ EmailService.instance.send_welcome(params[:email])
188
+ end
189
+ end
190
+
191
+ # GOOD - Dependencies are injectable
192
+ class UserService
193
+ def initialize(database:, email_service:)
194
+ @database = database
195
+ @email_service = email_service
196
+ end
197
+
198
+ def create_user(params)
199
+ @database.insert(:users, params)
200
+ @email_service.send_welcome(params[:email])
201
+ end
202
+ end
203
+ ```
204
+
205
+ ### Pure Functions
206
+
207
+ Prefer functions that always return the same output for the same input and have no side effects. These are the easiest to test.
208
+
209
+ ```ruby
210
+ # PURE - Easy to test, deterministic
211
+ def calculate_discount(price, percentage)
212
+ price * (percentage / 100.0)
213
+ end
214
+
215
+ # IMPURE - Hard to test, depends on external state
216
+ def calculate_discount(product_id)
217
+ product = Product.find(product_id)
218
+ today_rate = DiscountService.current_rate
219
+ product.price * today_rate
220
+ end
221
+ ```
222
+
223
+ ### Separate Logic from I/O
224
+
225
+ Isolate core business logic from operations that interact with external systems (files, network, databases). Test the logic separately from the I/O.
226
+
227
+ ```ruby
228
+ # MIXED - Hard to test
229
+ class ReportGenerator
230
+ def generate
231
+ data = File.read("input.csv")
232
+ results = CSV.parse(data).map { |row| transform(row) }
233
+ File.write("output.json", results.to_json)
234
+ end
235
+ end
236
+
237
+ # SEPARATED - Logic is testable independently
238
+ class ReportGenerator
239
+ def generate(input_data)
240
+ CSV.parse(input_data).map { |row| transform(row) }
241
+ end
242
+ end
243
+
244
+ # I/O handled separately
245
+ class ReportService
246
+ def run(input_path, output_path)
247
+ data = File.read(input_path)
248
+ results = ReportGenerator.new.generate(data)
249
+ File.write(output_path, results.to_json)
250
+ end
251
+ end
252
+ ```
253
+
254
+ ### Clear Interfaces
255
+
256
+ Define clear, well-documented public interfaces for modules and classes. This clarifies boundaries for testing and for AI interaction.
257
+
258
+ ```ruby
259
+ # Clear interface with documented contract
260
+ class PaymentProcessor
261
+ # @param amount [Decimal] Amount to charge
262
+ # @param card_token [String] Payment card token
263
+ # @return [PaymentResult] Result with success/failure status
264
+ def charge(amount, card_token)
265
+ # ...
266
+ end
267
+ end
268
+ ```
269
+
270
+ ### Stateless Components
271
+
272
+ Where possible, favor stateless components or functions, as state management adds complexity to testing.
273
+
274
+ ```ruby
275
+ # STATEFUL - Harder to test, order matters
276
+ class Counter
277
+ def initialize
278
+ @count = 0
279
+ end
280
+
281
+ def increment
282
+ @count += 1
283
+ end
284
+
285
+ def current
286
+ @count
287
+ end
288
+ end
289
+
290
+ # STATELESS - Easy to test, no hidden state
291
+ def increment(count)
292
+ count + 1
293
+ end
294
+ ```
295
+
296
+ ## Summary
297
+
298
+ ### Core Principles
299
+ - Extract external dependencies to protected methods
300
+ - Use method stubbing instead of subprocess isolation
301
+ - Profile tests regularly with `ace-test --profile 10`
302
+ - Only use subprocesses when true process isolation is required
303
+
304
+ ### Testability Patterns
305
+ - **Never call exit in commands or organisms** - return status codes and raise exceptions
306
+ - **Handle exit only at the CLI entry point** (exe/ace-*)
307
+ - **Return status codes from commands**, let CLI handle exit
308
+ - **Inject dependencies** instead of using globals
309
+ - **Separate logic from I/O** for easier testing
310
+
311
+ ## Related Guides
312
+
313
+ - [Testing Philosophy](guide://testing-philosophy) - Why testability matters
314
+ - [Mocking Patterns](guide://mocking-patterns) - How to stub dependencies
315
+ - [Test Performance](guide://test-performance) - Fast test execution
@@ -0,0 +1,120 @@
1
+ ---
2
+ doc-type: guide
3
+ title: Ruby RSpec Configuration Examples
4
+ purpose: RSpec configuration reference
5
+ ace-docs:
6
+ last-updated: 2026-01-23
7
+ last-checked: 2026-03-21
8
+ ---
9
+
10
+ # Ruby RSpec Configuration Examples
11
+
12
+ ## Testing Framework Setup
13
+
14
+ ### 1. RSpec Configuration
15
+
16
+ ```ruby
17
+ # spec/spec_helper.rb
18
+ require 'rspec'
19
+ require 'faker'
20
+ require 'vcr'
21
+ require 'webmock/rspec'
22
+
23
+ RSpec.configure do |config|
24
+ config.before(:suite) do
25
+ # Setup test environment
26
+ Aira.env = :test
27
+ end
28
+
29
+ config.around(:each) do |example|
30
+ # Clear any cached data
31
+ Aira.reset!
32
+ example.run
33
+ end
34
+ end
35
+
36
+ # Mock external services
37
+ VCR.configure do |config|
38
+ config.cassette_library_dir = "spec/fixtures/vcr_cassettes"
39
+ config.hook_into :webmock
40
+ config.configure_rspec_metadata!
41
+
42
+ # Filter sensitive data
43
+ config.filter_sensitive_data('<API_KEY>') { ENV['API_KEY'] }
44
+ end
45
+ ```
46
+
47
+ ### 2. Test Data Management
48
+
49
+ ```ruby
50
+ # spec/factories/prompts.rb
51
+ FactoryBot.define do
52
+ factory :prompt, class: Hash do
53
+ content { Faker::Lorem.paragraph }
54
+ temperature { rand(0.0..1.0) }
55
+
56
+ trait :with_context do
57
+ context { { role: "user", history: [] } }
58
+ end
59
+
60
+ initialize_with { attributes }
61
+ end
62
+ end
63
+
64
+ # spec/fixtures/test_data.yml
65
+ prompts:
66
+ basic:
67
+ content: "What is 2+2?"
68
+ temperature: 0.7
69
+ complex:
70
+ content: "Analyze this code..."
71
+ temperature: 0.9
72
+ max_tokens: 1000
73
+ ```
74
+
75
+ ### 3. Integration Testing
76
+
77
+ ```ruby
78
+ RSpec.describe "Agent Integration", :integration do
79
+ let(:agent) { Aira::Agent.new }
80
+ let(:tool) { Aira::Tools::Calculator.new }
81
+
82
+ around(:each) do |example|
83
+ VCR.use_cassette("integration_#{example.description}") do
84
+ example.run
85
+ end
86
+ end
87
+
88
+ it "executes complete workflow" do
89
+ agent.add_tool(tool)
90
+ result = agent.execute(
91
+ prompt: build(:prompt, :with_context),
92
+ max_retries: 2
93
+ )
94
+
95
+ expect(result).to be_successful
96
+ expect(result.output).to include("calculation result")
97
+ end
98
+ end
99
+ ```
100
+
101
+ ### 4. Performance Testing
102
+
103
+ ```ruby
104
+ RSpec.describe "Performance", :performance do
105
+ include PerformanceHelpers
106
+
107
+ it "handles concurrent requests within threshold" do
108
+ measure_concurrent_execution(threads: 10) do |stats|
109
+ expect(stats.average_response_time).to be < 1.0
110
+ expect(stats.error_rate).to be < 0.01
111
+ end
112
+ end
113
+
114
+ it "manages memory usage" do
115
+ measure_memory_usage do |stats|
116
+ expect(stats.peak_memory_mb).to be < 200
117
+ expect(stats.memory_growth_mb).to be < 10
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,87 @@
1
+ ---
2
+ doc-type: guide
3
+ title: Ruby RSpec Testing Guide
4
+ purpose: Ruby RSpec testing conventions
5
+ ace-docs:
6
+ last-updated: 2026-01-23
7
+ last-checked: 2026-03-21
8
+ ---
9
+
10
+ # Ruby RSpec Testing Guide
11
+
12
+ This guide provides best practices and conventions for writing tests in Ruby using RSpec, tailored for the
13
+ coding-agent-workflow-toolkit project.
14
+
15
+ ## 1. Directory Structure
16
+
17
+ ```text
18
+ project-root/
19
+ └── spec/
20
+ ├── unit/
21
+ ├── integration/
22
+ ├── e2e/
23
+ └── support/
24
+ ```
25
+
26
+ Follow the mirrored structure of `lib/` when placing unit tests. Keep integration and E2E tests in their respective
27
+ folders.
28
+
29
+ ## 2. Configuration (`spec/spec_helper.rb`)
30
+
31
+ - Load `simplecov` when the `COVERAGE` env var is present.
32
+ - Enable the `--only-failures` and `--next-failure` flags via `.rspec`.
33
+ - Configure `rspec-mocks` to verify double constants.
34
+
35
+ ## 3. Factories & Fixtures
36
+
37
+ - Use `FactoryBot` for building domain objects.
38
+ - Place YAML/JSON fixtures in `spec/fixtures/`.
39
+
40
+ ## 4. Mocking External Services
41
+
42
+ - Use `WebMock` and `VCR` to record HTTP interactions.
43
+ - Filter sensitive data with `config.filter_sensitive_data`.
44
+
45
+ ## 5. Tag Conventions
46
+
47
+ | Tag | Purpose |
48
+ | --- | ------- |
49
+ | `:unit` | Fast unit tests (default) |
50
+ | `:integration` | Tests requiring multiple components |
51
+ | `:e2e` | End-to-end flows |
52
+ | `:slow` | Any test > 1s |
53
+
54
+ ## 6. Running Tests
55
+
56
+ Typically, you run your RSpec tests using Bundler to ensure the correct gem versions are used:
57
+
58
+ ```bash
59
+ # Run all specs
60
+ bundle exec rspec
61
+
62
+ # Run specs in a specific file
63
+ bundle exec rspec spec/models/user_spec.rb
64
+
65
+ # Run a specific example (by line number)
66
+ bundle exec rspec spec/models/user_spec.rb:25
67
+ ```
68
+
69
+ ## 7. Checking Test Coverage
70
+
71
+ If you have set up a coverage tool like SimpleCov, you might run it via an environment variable:
72
+
73
+ ```bash
74
+ # Run specs and generate coverage report
75
+ COVERAGE=true bundle exec rspec
76
+ ```
77
+
78
+ Refer to your project's specific setup (e.g., `spec_helper.rb` or `rails_helper.rb`) and the coverage tool's
79
+ documentation for configuration details.
80
+
81
+ ## 8. CI Integration
82
+
83
+ - Ensure the CI pipeline runs `bundle exec rspec` and uploads coverage.
84
+
85
+ ## 9. Linting Specs
86
+
87
+ Use `rubocop-rspec` to enforce spec style.
@@ -0,0 +1,52 @@
1
+ ---
2
+ doc-type: guide
3
+ title: Rust Testing Guide
4
+ purpose: Rust testing conventions
5
+ ace-docs:
6
+ last-updated: 2026-01-23
7
+ last-checked: 2026-03-21
8
+ ---
9
+
10
+ # Rust Testing Guide
11
+
12
+ This guide provides best practices for testing Rust code in the context of the coding-agent-workflow-toolkit project.
13
+
14
+ ## 1. Test Types
15
+
16
+ - **Unit Tests**: Inline `#[cfg(test)]` modules next to implementation.
17
+ - **Integration Tests**: Files in `tests/` directory.
18
+ - **Doc Tests**: Ensure examples in doc comments compile and run.
19
+
20
+ ## 2. Directory Layout
21
+
22
+ ```text
23
+ project-root/
24
+ ├── src/
25
+ │ └── lib.rs
26
+ ├── tests/
27
+ │ └── integration.rs
28
+ ```
29
+
30
+ ## 3. Running Tests
31
+
32
+ ```bash
33
+ cargo test # all tests
34
+ cargo test my_test # specific
35
+ ```
36
+
37
+ Use `-- --nocapture` to see stdout.
38
+
39
+ ## 4. Mocking & Fakes
40
+
41
+ - Use crates like `mockall` for trait-based mocking.
42
+ - For HTTP interactions, use `wiremock` crate.
43
+
44
+ ## 5. Coverage
45
+
46
+ ```bash
47
+ cargo tarpaulin --out Html
48
+ ```
49
+
50
+ ## 6. CI Integration
51
+
52
+ Ensure job uses `cargo test --all --locked`.