This file provides specific guidelines for organizing and writing Robot Framework tests in this project.
Each resource file should have a clear purpose and contain related keywords. Resource files should include documentation explaining what types of functions belong in that file.
setup_resources.robot
- Docker service management (start/stop services)
- Environment validation
- Health checks and service dependency verification
- System preparation keywords
- Any keywords that prepare the testing environment
session_resources.robot
- API session creation and management
- Authentication workflows
- Token management (when needed for external tools like curl)
- Session validation and cleanup
- Keywords that handle API authentication and session state
user_resources.robot
- User account creation, deletion, and management
- User-related operations and utilities
- User permission validation
- Keywords specific to user account lifecycle
integration_keywords.robot
- Core integration workflow keywords
- File processing and upload operations
- System interaction keywords that don't fit in other categories
- Complex multi-step operations that combine multiple services
Verification Steps
- MUST be written directly in test files, not abstracted into resource keywords
- Keep verifications close to the test logic for readability and maintainability
- Use descriptive assertion messages that explain what is being verified
- Example:
Should Be Equal As Integers ${response.status_code} 200 Health check should return 200 - Verification keywords should only exist in resource files if they perform complex multi-step verification that needs to be reused across multiple test suites
Setup/Action Keywords
- Environment setup, service management, and system actions belong in resource files
- These can be reused across multiple tests and suites
- Focus on "what to do" rather than "what to verify"
- Examples:
Get Admin API Session,Upload Audio File For Processing,Start Docker Services
Suite-Level Keywords
- If a specific set of verifications needs to be repeated multiple times within a single test suite, create keywords at the suite level (in the *** Keywords *** section of the test file)
- These should be specific to that suite's testing needs
- Only create suite-level keywords when the same verification logic is used 3+ times in the same suite
- Tests should be readable by domain experts without deep Robot Framework knowledge
- Use descriptive keyword names that explain the business purpose
- Prefer explicit over implicit - make test intentions clear
- Use meaningful variable names and comments where helpful
- Avoid Robot Framework-specific jargon in test names and documentation
*** Test Cases ***
Test Name Should Describe Business Scenario
[Documentation] Clear explanation of what this test validates
[Tags] relevant tags
# Arrange - Setup test data and environment
${session}= Get Admin API Session
# Act - Perform the operation being tested
${result}= Upload Audio File For Processing ${session} ${TEST_FILE}
# Assert - Verify results directly in test (NOT in resource keywords)
Should Be True ${result}[successful] > 0 At least one file should be processed successfully
Should Contain ${result}[message] processing completed Processing should complete successfullyEach resource file should start with clear documentation:
*** Settings ***
Documentation Brief description of this resource file's purpose
...
... This file contains keywords for [specific purpose].
... Keywords in this file should handle [what types of operations].
...
... Examples of keywords that belong here:
... - Keyword type 1
... - Keyword type 2
...
... Keywords that should NOT be in this file:
... - Verification/assertion keywords (belong in tests)
... - Keywords specific to other domains- Tests should use session-based authentication via
session_resources.robot - Avoid passing tokens directly in tests - use sessions instead
- Extract tokens from sessions only when required for external tools (like curl)
Example:
# Good - Session-based approach
${admin_session}= Get Admin API Session
${conversations}= Get User Conversations ${admin_session}
# Avoid - Direct token handling in tests
${token}= Get Admin Token
${conversations}= Get User Conversations ${token}- Use descriptive names that indicate the testing scope
- Example:
full_pipeline_test.robot,user_management_test.robot - Use
_test.robotsuffix for test files
- Use
_resources.robotsuffix - Name should indicate the domain:
session_resources.robot,user_resources.robot
- Use descriptive names with clear action words
- Start with action verb when possible:
Get User Conversations,Upload Audio File,Create Test User - Avoid abbreviations unless they're widely understood in the domain
- Use consistent naming patterns across similar keywords
- Should handle expected error conditions gracefully
- Use appropriate Robot Framework error handling (TRY/EXCEPT blocks)
- Log meaningful error messages for debugging
- Fail fast with clear error messages when setup fails
- Write verification steps directly in tests with clear failure messages
- Use descriptive assertion messages that explain what went wrong
- Example:
Should Be Equal ${status} active User should be in active status after creation - Include relevant context in failure messages (expected vs actual values)
CRITICAL: Always review existing resource files before writing any test code.
Before implementing ANY test logic:
- Open and scan ALL relevant resource files for existing keywords
- Read keyword documentation to understand what they do
- Look for similar patterns - if your test needs to do something common (like "create conversation", "wait for job", "send audio"), a keyword likely exists
- Check the keyword's dependencies - keywords often call other helper keywords you should also use
Why this matters:
- Prevents code duplication and maintenance burden
- Ensures consistent test patterns across the suite
- Leverages battle-tested, optimized implementations
- Reduces test complexity and improves readability
How to do this:
# Bad - Writing inline code without checking
${jobs}= Get Jobs By Type And Client open_conversation ${device}
${count}= Get Length ${jobs}
# ... manual logic to wait for new job ...
# Good - Using existing keyword
${jobs}= Wait Until Keyword Succeeds 30s 2s
... Wait For New Job To Appear open_conversation ${device} ${baseline_count}Resource Files to Check (based on your test domain):
websocket_keywords.robot- WebSocket streaming, audio chunks, conversation creationconversation_keywords.robot- Conversation CRUD, transcript operationsqueue_keywords.robot- Job tracking, waiting for job states, queue monitoringmemory_keywords.robot- Memory operations, search, retrievalaudio_keywords.robot- Audio file handling, processingsession_resources.robot- Authentication, API sessionsintegration_keywords.robot- Complex multi-step workflows
- Reusable operations that are used across multiple tests or suites
- Complex multi-step setup or teardown operations
- Operations that encapsulate business logic or domain concepts
- Operations that interact with external systems (APIs, databases, files)
- ONLY after confirming no existing keyword does what you need
- Verification steps (assertions) - these should almost always be inline in tests
- Simple operations that are only used once
- Test-specific logic that doesn't need to be reused
- Variable assignments and simple data manipulation
- Use meaningful variable names that describe the data's purpose
- Define test data at the appropriate scope (suite variables for shared data, test variables for test-specific data)
- Store complex test data in separate variable files when it becomes large
- Use descriptive names:
${VALID_USER_EMAIL}instead of${EMAIL1}
- Load environment variables through
test_env.py - Use consistent variable naming across tests
- Document required environment variables and their purposes
Chronicle runs one test suite. Tests are never selected by whether a credential happens to be present.
What varies between runs is a service profile: a declaration of which backing
services are real and which are stubbed, defined in
tests/profiles.yml.
make test # profile: mock (default) -- no credentials
make test PROFILE=deepgram-openai # real Deepgram STT + real OpenAI LLM
make test PROFILE=deepgram-openai-speaker # ...plus the real speaker service
make test PROFILE=parakeet-ollama # real local ASR + local OllamaEvery test runs in every profile. A profile that names a real service declares
what it needs (requires_env, requires_service); the harness verifies that
up-front and fails with the exact remedy, so a missing key is a clear setup error
rather than a pile of confusing test failures.
Gating tests on credentials meant a test skipped on pull requests was a test nobody ran, and because fork pull requests cannot read repository secrets under any circumstance, "run it later with a label" never covered the case it was added for. Tags tied to credentials also rot silently: the suite hid genuinely broken tests for as long as they stayed gated.
So the credential axis is gone. If a test appears to need a real provider, that is a statement about stub fidelity, not about the test.
A stub that invents its own output forces a choice between skipping the test and
asserting something meaningless. Instead, stubs replay cassettes -- recorded
real provider responses, keyed by the sha256 of the audio that produced them and
committed under tests/cassettes/.
That makes a content assertion identical in both directions:
# Holds against real Deepgram AND against the stub, because the stub replays
# a real recorded transcript of the same fixture.
Verify Transcription Quality ${conversation} ${EXPECTED_TRANSCRIPT_PHRASES}Record or refresh them with real credentials, once:
make record-cassettes PROFILE=deepgram-openaiThis is the same rule the rest of the project follows for paid APIs: record once, commit, never spend again. A normal test run makes no external calls.
Assert on behaviour and content, not on one provider's formatting.
# Good - content words any competent engine produces
Should Contain ${transcript} glass
# Bad - encodes Deepgram's tokenization; other engines emit "glassblowing",
# so this silently means "only run against Deepgram"
Should Contain ${transcript} glass blowing
# Bad - pins an exact snapshot of one provider's segmentation, which drifts
# whenever that provider updates its model
Should Be Equal ${segment}[end] 10.08If an assertion can only hold for one provider, either widen it to the invariant you actually care about, or anchor it to a cassette.
Chronicle excludes certain tests from default test runs to provide faster feedback and cleaner test execution.
Purpose: Mark tests that require long timeouts (>30s) or infrastructure operations like service restarts.
Add this tag when tests:
- Restart backend or other services (stop/start cycles)
- Test connection resilience after service failures
- Require timeouts longer than 30 seconds
- Test infrastructure operations that significantly slow down test execution
Do NOT add this tag when tests:
- Complete within normal timeouts (<30s)
- Don't restart or rebuild services
- Are simple endpoint or integration tests
Example:
*** Test Cases ***
Test Job Persistence Through Backend Restart
[Documentation] Test that RQ jobs persist when backend service restarts
[Tags] queue slow
[Timeout] 120s
${job_id}= Reprocess Transcript ${conversation_id}
Restart Backend Service wait_timeout=90s # Longer timeout for slow test
${jobs_after}= Get job queue
Should Be True ${jobs_count_after} >= 0Running Slow Tests:
cd tests
# Default test run (EXCLUDES slow tests)
make test # Faster feedback, no service restarts
# Run ONLY slow tests
make test-slow # Explicit slow test execution
# Run ALL tests including slow
make test-all-with-slow-and-sdkPurpose: Mark tests for unreleased SDK functionality that should be excluded until the SDK is published.
Add this tag when tests:
- Test SDK client library features
- Require SDK installation or SDK-specific imports
- Are for SDK features not yet released to users
- Test SDK authentication, upload, or retrieval methods
Do NOT add this tag when tests:
- Test backend API endpoints directly (these should always run)
- Test features available through direct HTTP/WebSocket calls
- Are part of the core backend functionality
Example:
*** Test Cases ***
SDK Can Upload Audio File
[Documentation] Test SDK audio upload functionality
[Tags] audio-upload sdk
${result}= Run Process uv run python
... ${CURDIR}/../scripts/sdk_test_upload.py
... ${BACKEND_URL} ${ADMIN_EMAIL} ${ADMIN_PASSWORD} ${test_audio}
Should Be Equal As Integers ${result.rc} 0Running SDK Tests:
cd tests
# Default test run (EXCLUDES sdk tests)
make test # SDK not released yet
# Run ONLY SDK tests (when developing SDK)
make test-sdk
# Run ALL tests including SDK
make test-all-with-slow-and-sdkWhen to Re-enable SDK Tests: Once the SDK is released and published:
- Remove
--exclude sdkfrom default Makefile target (make test) - Keep the
sdktag for organization (allows filtering SDK-specific tests) - Update
tests/README.mdto reflect that SDK tests are included
Faster Default Test Runs:
- Default
make testexcludes slow tests (service restarts, long timeouts) - Provides faster feedback during development (saves 2-5 minutes per run)
- Developers can iterate quickly on endpoint and integration tests
Cleaner Test Reports:
- SDK tests won't fail in CI when SDK isn't released yet
- No confusing failures for unreleased features
- Clear separation of released vs unreleased functionality
Explicit Execution When Needed:
- Run slow tests explicitly when testing infrastructure resilience
- Run SDK tests explicitly when developing SDK features
- Full test suite available via
make test-all-with-slow-and-sdk
# Good - Slow infrastructure test
[Tags] queue slow
[Timeout] 120s
# Good - Unreleased SDK feature
[Tags] audio-upload sdk
# Good - Multiple component tags
[Tags] conversation memory
# Bad - Don't combine slow and sdk (different purposes)
[Tags] slow sdkAs we develop more conventions and encounter new patterns, we will add them to this file:
- Performance testing guidelines
- Data management patterns
- Mock and test double strategies
- Continuous integration considerations
- Test reporting and metrics
- Parallel test execution patterns
- Test data isolation strategies