This guide covers enterprise-level API testing patterns implemented in this framework, going beyond basic CRUD operations to validate production-grade API requirements.
The advanced testing patterns cover six critical areas:
- HTTP Protocol Validation - Protocol compliance and header handling
- Identity Validation - ID format, uniqueness, and referential integrity
- Sorting & Pagination - Deterministic ordering and page boundaries
- Idempotency - Stability and side-effect validation
- Performance - Response times and payload constraints
- Data Quality - Sanitization and format validation
Validates that the API adheres to HTTP standards and returns correct status codes, headers, and error responses.
Scenario: Validate successful response status codes
When I send a GET request to "/posts/1"
Then the response status code should be 200
When I send a POST request to "/posts" with the data:
| title | Test Post |
| body | Content |
| userId | 1 |
Then the response status code should be 201Why: Ensures proper HTTP semantics (200 for GET, 201 for POST creation, 404 for not found).
Scenario: Validate Content-Type header
When I send a GET request to "/posts/1"
Then the response header "content-type" should contain "application/json"
And the response should have header "cache-control"Why: Verifies that API returns appropriate headers for client processing and caching.
Scenario: Validate error response structure
When I send a GET request to "/posts/999999"
Then the response status code should be 404
And the response should be valid JSONWhy: Ensures errors are returned in a consistent, parseable format.
- API gateway configuration testing
- Ensuring HTTP compliance across services
- Validating error handling consistency
- Cache behavior verification
Validates ID format, uniqueness, immutability, and referential integrity across resources.
Scenario: Validate ID is numeric and positive
When I send a GET request to "/posts/1"
And the response field "id" should be of type "number"
And the response field "id" should be a positive numberWhy: Ensures consistent ID format (prevents negative IDs, nulls, or string IDs when numbers expected).
Scenario: Validate ID uniqueness in collection
When I send a GET request to "/posts?_limit=20"
And each array item field "id" should be uniqueWhy: Prevents duplicate IDs which can cause data corruption or cache inconsistencies.
Scenario: Validate ID immutability on update
When I send a GET request to "/posts/1"
And I store the response field "id" as "originalId"
When I send a PUT request to "/posts/1" with the data:
| id | 1 |
| title | Updated Title |
Then the response field "id" should equal stored value "originalId"Why: Ensures IDs remain stable across updates (critical for caching, indexing).
Scenario: Validate foreign key references exist
When I send a GET request to "/posts/1"
And I store the response field "userId" as "referencedUserId"
When I send a GET request to "/users/{referencedUserId}"
Then the response status code should be 200Why: Validates referential integrity - ensures foreign key relationships are valid.
- Database migration testing
- Cache consistency validation
- Referential integrity checks
- Data import/export validation
Ensures deterministic ordering and proper pagination behavior across requests.
Scenario: Validate default sorting order
When I send a GET request to "/posts?_limit=10"
And the response array should be sorted by "id" in "ascending" orderWhy: Ensures predictable default ordering (critical for UIs, caching, pagination).
Scenario: Validate stable ordering across pages
When I send a GET request to "/posts?_page=1&_limit=5"
And I store the last array item field "id" as "lastIdPage1"
When I send a GET request to "/posts?_page=2&_limit=5"
Then the first array item field "id" should be greater than stored value "lastIdPage1"Why: Prevents duplicate/missing items when paginating (ensures stable sort).
Scenario: Validate empty page returns empty array
When I send a GET request to "/posts?_page=1000&_limit=10"
Then the response array should be emptyWhy: Ensures graceful handling of out-of-range page requests.
Scenario: Validate pagination does not skip or duplicate items
When I send a GET request to "/posts?_page=1&_limit=5"
And I store all array item field "id" values as "page1Ids"
When I send a GET request to "/posts?_page=2&_limit=5"
Then the array should not contain any stored "page1Ids" valuesWhy: Critical for data consistency - ensures every item appears exactly once.
- Infinite scroll implementations
- Data export features
- Report generation
- List view consistency
Validates that GET requests are idempotent (safe, cacheable, no side effects).
Scenario: Validate GET is idempotent
When I send a GET request to "/posts/1"
And I store the entire response as "firstResponse"
When I send a GET request to "/posts/1"
Then the response should match stored "firstResponse"Why: GET must return identical data on repeated calls (required for caching, retries).
Scenario: Validate GET has no side effects
When I send a GET request to "/posts/1"
And I store the response field "title" as "originalTitle"
When I send a GET request to "/posts/1"
Then the response field "title" should equal stored value "originalTitle"Why: Reading data must not modify it (critical for read replicas, caching).
Scenario: Validate stable response across multiple rapid requests
When I send 5 GET requests to "/posts/1"
Then all responses should have status code 200
And all responses should have consistent data structureWhy: Validates stability under concurrent access patterns.
Scenario: Validate collection endpoint stability
When I send a GET request to "/posts?_limit=10"
And I store the response array length as "firstCount"
When I send a GET request to "/posts?_limit=10"
Then the response array length should equal stored value "firstCount"Why: Collection size should be stable (detects race conditions, cache issues).
- API contract testing
- Cache validation
- Load balancer configuration testing
- Retry logic verification
Establishes performance baselines and validates response times and payload sizes.
Scenario: Validate response time is acceptable
When I send a GET request to "/posts/1"
Then the response time should be less than 2000 msWhy: SLAs often include response time requirements (e.g., p95 < 500ms).
Scenario: Validate reasonable payload size for single resource
When I send a GET request to "/posts/1"
Then the response payload size should be less than 10 KBWhy: Prevents over-fetching, reduces bandwidth costs, improves mobile performance.
Scenario: Establish performance baseline
When I send a GET request to "/posts/1"
And I measure the response time as "baseline"
When I send a GET request to "/posts/1"
Then the response time should be within 200% of "baseline"Why: Detects performance regressions (alerts if response time doubles).
- Pre-deployment smoke tests
- Performance regression detection
- Monitoring critical path latencies
- Bandwidth optimization validation
Validates data sanitization, format consistency, and cleanliness.
Scenario: Validate string fields are properly trimmed
When I send a GET request to "/users/1"
Then the response field "name" should not have leading whitespace
And the response field "name" should not have trailing whitespaceWhy: Leading/trailing whitespace causes UI issues, comparison failures.
Scenario: Validate no empty strings in required fields
When I send a GET request to "/posts/1"
Then the response field "title" should be a non-empty string
And the response field "body" should be a non-empty stringWhy: Required fields should have values (empty strings != null).
Scenario: Validate email format is valid
When I send a GET request to "/users/1"
Then the response field "email" should match email format
And the response field "email" should not contain spacesWhy: Ensures data can be used for its intended purpose (emails, URLs).
Scenario: Validate no control characters in text fields
When I send a GET request to "/posts/1"
Then the response field "title" should not contain control characters
And the response field "body" should not contain control charactersWhy: Control characters can break JSON parsing, UI rendering, logging.
Scenario: Validate data consistency across all posts
When I send a GET request to "/posts?_limit=10"
And each array item field "title" should be a non-empty string
And each array item field "id" should be a positive numberWhy: Validates quality across entire dataset, not just single records.
- Data import validation
- User-generated content validation
- Third-party API integration testing
- Data warehouse ETL validation
npx cucumber-js features/http-protocol.feature features/identity-validation.feature features/sorting-pagination.feature features/idempotency.feature features/performance.feature features/data-quality.feature# HTTP Protocol tests
npx cucumber-js features/http-protocol.feature
# Identity tests
npx cucumber-js features/identity-validation.feature
# Sorting and Pagination tests
npx cucumber-js features/sorting-pagination.feature
# Idempotency tests
npx cucumber-js features/idempotency.feature
# Performance tests
npx cucumber-js features/performance.feature
# Data Quality tests
npx cucumber-js features/data-quality.feature# Run all smoke tests
npx cucumber-js --tags @smoke
# Run protocol validation
npx cucumber-js --tags @protocol
# Run performance tests
npx cucumber-js --tags @performance
# Run identity tests
npx cucumber-js --tags @identityresponse header {string} should contain {string}- Validates header valueresponse should have header {string}- Checks header presencesend a POST request to {string} with the data:- POST with data table
each array item field {string} should be unique- Validates uniquenesseach array item should have valid foreign key {string} in resource {string}- FK validation
response array should be sorted by {string} in {string} order- Sort validationstore the last array item field {string} as {string}- Store last itemfirst array item field {string} should be greater than stored value {string}- Ordering checkresponse array should be empty- Empty array checkstore all array item field {string} values as {string}- Store array valuesarray should not contain any stored {string} values- No duplicates check
store the entire response as {string}- Store full responseresponse should match stored {string}- Compare responsessend {int} GET requests to {string}- Send multiple requestsall responses should have status code {int}- Validate all responsesall responses should have consistent data structure- Structure consistencystore the response array length as {string}- Store lengthresponse array length should equal stored value {string}- Compare lengths
response time should be less than {int} ms- Response time thresholdresponse payload size should be less than {int} KB- Payload size limitmeasure the response time as {string}- Record baselineresponse time should be within {int}% of {string}- Regression detection
response field {string} should not have leading whitespace- Trimming checkresponse field {string} should not have trailing whitespace- Trimming checkresponse field {string} should not be an empty string- Empty checkresponse field {string} should not contain spaces- Space validationresponse field {string} should not contain control characters- Control char checkeach array item field {string} should be a non-empty string- Collection validation
- Each scenario should be independent
- Use stored variables for cross-request validation
- Clean up state between scenarios (handled by Before/After hooks)
- Use query parameters to limit collection sizes (
_limit=10) - Test edge cases (empty pages, large IDs, special characters)
- Validate both single resources and collections
- Check both positive cases (what should be there) and negative cases (what shouldn't)
- Validate data types, formats, and constraints
- Test boundary conditions
- Set realistic thresholds based on your SLAs
- Measure baseline performance before regression testing
- Consider network latency in thresholds
- Use descriptive scenario names
- Group related scenarios with tags
- Document why tests exist (not just what they test)
Add these patterns to your CI/CD pipeline:
# Example GitHub Actions
- name: Run Advanced API Tests
run: |
npx cucumber-js features/http-protocol.feature
npx cucumber-js features/identity-validation.feature
npx cucumber-js features/sorting-pagination.feature
npx cucumber-js features/idempotency.feature
npx cucumber-js features/performance.feature
npx cucumber-js features/data-quality.featureOr run all non-skipped tests:
npx cucumber-js features/ --parallel 2These advanced patterns go beyond basic CRUD testing to validate:
✅ Protocol Compliance - HTTP standards, headers, status codes
✅ Data Integrity - IDs, foreign keys, referential integrity
✅ Deterministic Behavior - Sorting, pagination, ordering
✅ Safety - Idempotency, no side effects
✅ Performance - Response times, payload sizes, baselines
✅ Data Quality - Sanitization, formats, consistency
By implementing these patterns, you ensure your API is production-ready, reliable, and meets enterprise-grade quality standards.