Testing
This application supports two testing modes to handle external service dependencies.
Test Modes
Stubbed Mode (Default)
In stubbed mode, all external services are mocked with realistic responses. This is the default mode and is used in CI.
External services that are stubbed:
- OpenAI API (GPT models)
- AWS Translate
- AWS Polly (Text-to-Speech)
To run in stubbed mode:
# Default behavior
bin/rails test
# Explicit stubbed mode
bundle exec rake test:stubbed
Live Mode
In live mode, tests make real API calls to external services. This is useful for integration testing and verifying that the application works with actual external APIs.
Warning: Live mode will make real API calls and may incur costs.
To run in live mode:
# With confirmation prompt
bundle exec rake test:live
# Without confirmation (for CI/automation)
LIVE_MODE=true bin/rails test
Configuration
Environment Variables
LIVE_MODE=true- Enables live mode (external services make real API calls)LIVE_MODEnot set or any other value - Uses stubbed mode (default)
CI Configuration
The CI pipeline runs in stubbed mode only to:
- Avoid API costs
- Ensure consistent test results
- Prevent rate limiting issues
- Speed up test execution
Stubbed Responses
The stubbing system provides realistic responses:
OpenAI Responses
- Sentence generation: Returns realistic sentence pairs
- Document coaching: Returns helpful suggestions
- Default: Generic response for other prompts
AWS Translate Responses
- Common words: Returns actual translations for basic vocabulary
- Other text: Returns formatted translation strings
AWS Polly Responses
- Returns fake audio data with text-specific identifiers
Adding New External Services
To add stubbing for a new external service:
- Add the service to
test/support/external_services.rb - Create a
stub_service_name!method - Add realistic response generation logic
- Call the stub method in
stub_all!
Example:
def stub_new_service!
new_service_client = mock("NewService::Client")
new_service_client.stubs(:api_method).returns(
stub(result: "stubbed_result")
)
NewService::Client.stubs(:new).returns(new_service_client)
end
Browser Timeout Handling
System tests using Capybara with Cuprite (Ferrum) can occasionally experience timeouts, especially in CI environments. These timeouts are often environmental (resource constraints, network issues) rather than actual test failures.
Automatic Timeout Handling
The test suite includes an automatic handler (test/support/capybara_timeout_handler.rb) that:
- Detects timeout errors from Capybara/Ferrum:
Ferrum::ProcessTimeoutErrorCapybara::TimeoutErrorFerrum::TimeoutError- “Browser did not produce websocket url” errors
- Other timeout-related errors
- Soft-fails tests - Clears the exception so the test doesn’t fail CI
- Logs warnings - Still reports the timeout for visibility
Example Output
When a timeout occurs, you’ll see a warning like:
⚠️ Soft-failed due to Capybara/Ferrum timeout: Document sentence translation clicking on a sentence to translate makes a request to the frontend API and displays the translation
Error: Ferrum::ProcessTimeoutError
Message: Browser did not produce websocket url within 10 seconds, try to increase :process_timeout...
Location: test/system/documents/document_sentence_translation_test.rb:11
The test will pass, but the warning indicates a timeout occurred.
Disabling Timeout Handling
To disable the timeout handler (e.g., for debugging):
DISABLE_TIMEOUT_HANDLER=true bin/rails test
This will allow timeout errors to fail tests normally.
When Timeouts Occur
Timeouts are most common in:
- CI environments with limited resources
- System tests that interact with JavaScript-heavy pages
- Tests that wait for network requests or animations
If timeouts become frequent, consider:
- Increasing browser timeouts in
test/test_helper.rb - Optimizing slow system tests
- Using request specs instead of system specs when possible
Best Practices
- Always use stubbed mode for unit tests
- Use live mode sparingly - only for integration testing
- Keep stubbed responses realistic - they should match expected API behavior
- Test both modes - ensure your code works with both stubbed and real responses
- Document API changes - update stubbed responses when external APIs change
- Monitor timeout warnings - frequent timeouts may indicate test or infrastructure issues