Keep test subscriptions lean
Clean up test subscriptions to reduce unnecessary activity and preserve capacity for live workloads.
Stripe test resources share infrastructure with live resources. For example, the same systems cycle subscriptions, generate invoices, and send webhooks. Keeping your active test subscription count lean reduces unnecessary background activity, which helps preserve capacity and performance for live workloads.
Automated tests can leave subscriptions active for a long time after a test run finishes. As test suites and development workflows scale, these subscriptions continue cycling, generating invoices, and sending events. Design each test to create only the resources it needs and remove them as soon as the test finishes.
Use test clocks instead of separate subscriptions
Use test clocks to test subscription behavior that depends on time, including renewals, trials, prorations, and payment retries. A test clock lets you move one set of associated objects through multiple lifecycle states instead of creating a separate subscription for every state you need to test.
Follow the test clock API workflow to create a simulation, add a customer and subscription, advance time, and monitor the resulting changes. The amount of time you can advance depends on the shortest billing interval in the simulation. See advance the simulated time for details.
Delete the simulation during teardown. Deleting it also deletes its associated test customers and cancels their subscriptions, preventing those resources from continuing to generate activity after the test.
Command Line
Select a language
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
Review the current test clock limits and restrictions when designing parallel tests.
Cancel subscriptions during teardown
When a test creates a subscription without a test clock, record its ID immediately and cancel it in a teardown hook. Keep the IDs scoped to the current test run so cleanup doesn’t affect subscriptions created by another test or developer.
This Jest example attempts every cancellation even if the test fails or one cancellation returns an error:
let createdSubscriptionIds = [];
afterEach(async () => {
const subscriptionIds = createdSubscriptionIds;
createdSubscriptionIds = [];
const results = await Promise.allSettled(
subscriptionIds.map((id) => stripe.subscriptions.cancel(id)),
);
const failures = results.filter((result) => result.status === 'rejected');
if (failures.length > 0) {
throw new Error(`Failed to cancel ${failures.length} test subscriptions`);
}
});
test('creates a subscription', async () => {
const subscription = await stripe.subscriptions.create({
customer: testCustomerId,
items: [{price: recurringPriceId}],
});
createdSubscriptionIds.push(subscription.id);
expect(subscription.id).toBeDefined();
});
Register each object as soon as its create request succeeds. If setup creates other objects, such as Customer objects, track and remove those objects in dependency order. Use your test framework’s teardown hooks or a finally block so cleanup runs after assertion and setup failures.
Add metadata for backup cleanup
Teardown is the primary way to limit active test resources. A process interruption can prevent teardown from running, so add metadata that identifies the test suite and CI run that created each subscription.
Command Line
Select a language
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
Run a scheduled cleanup job that searches for your suite’s metadata and cancels only subscriptions older than a threshold you define. Choose a threshold that exceeds the longest expected test run, and record cleanup failures for investigation.
If the Search API isn’t available for your account, paginate through the list Subscriptions API instead. In your cleanup worker, filter the returned subscriptions by their metadata and creation time before canceling them. Use a test API key so the worker can’t affect live subscriptions. See search query syntax and the Subscription cancellation API.
Test webhook handlers without persistent subscriptions
When you only need to test webhook routing, signature handling, or application behavior, use the Stripe CLI to forward fixture events to your local webhook handler.
Start your local server, then run the listener in one terminal. Replace localhost:4242/webhook with your local webhook URL:
Command Line
stripe listen --forward-to localhost:4242/webhook
Configure your handler to verify signatures with the signing secret printed by the listener. Keep the listener running, then trigger the fixture from another terminal:
Command Line
stripe trigger invoice.payment_succeeded
This approach tests your handler without requiring your test to maintain an active subscription. The CLI creates fixture data for the event, which might not correspond to a subscription your test created. Use an end-to-end subscription test when you need to verify the complete sequence of API changes and event notifications. See test subscription webhook notifications for other testing options.
Keep ongoing test activity lean
- Use test clocks to move one set of resources through time instead of creating subscriptions for every lifecycle state.
- Cancel subscriptions and remove related resources after each test, including when setup or assertions fail.
- Add run-specific metadata and schedule backup cleanup for interrupted test runs.
- Use mocks or fakes when a test doesn’t need to call Stripe.
- Use Stripe CLI fixtures when you only need to exercise webhook-handler behavior.
These practices prevent test subscriptions from cycling after they serve their purpose, limiting unnecessary invoice generation and webhook delivery on infrastructure shared with live resources.
