Automating QBO Sandbox Test Environments in CI/CD
The challenge
QBO integration testing in CI/CD pipelines has a bootstrapping problem: your tests need a populated sandbox, but populating it manually defeats the purpose of automation.
You need a way to:
- Programmatically create realistic test data
- Load it into a QBO sandbox
- Run your integration tests
- Clean up the sandbox for the next run
- Do all of this deterministically so failures are reproducible
Using the CLI
Install EasyTestData globally:
npm install -g easytestdata
Then use it in your pipeline:
# Load test data with a fixed seed
easytestdata load \
--template professional-services \
--preset healthy-small \
--seed 42 \
--customers 50 \
--revenue 500000
# Run your tests
npm test
# Clean up
easytestdata purge --mode generated
The --seed 42 flag ensures the same data is generated every run. Your test assertions can reference specific entity names, amounts, and dates.
Using the REST API
For more control, use the REST API with an API key:
# Create a load job
curl -s -X POST https://easytestdata.com/api/v1/jobs \
-H "Authorization: Bearer qbs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"type": "load",
"scenarioId": "sc_your_scenario",
"connectionId": "conn_your_connection"
}'
The API returns a job ID you can poll for completion, or subscribe to WebSocket updates for real-time progress.
Deterministic seeds
Deterministic seeds are the key to reproducible CI/CD testing. With the same seed, template, and parameters:
- The same customers are generated with the same names
- The same invoices are created with the same amounts
- The same payment patterns are applied
This means you can write specific test assertions:
// This customer will always exist with seed 42 + SaaS template
const customer = await qbo.findCustomer("Meridian Analytics");
expect(customer).toBeDefined();
expect(customer.Balance).toBeGreaterThan(0);
The load-test-purge cycle
The recommended pipeline pattern:
- Load: Generate and load data with a fixed seed
- Test: Run your integration tests against the populated sandbox
- Purge: Remove generated entities (tagged with EZTD prefix)
Purging only removes entities created by EasyTestData. Any manually created test fixtures or reference data stays intact.
Pipeline configuration
Here is an example GitHub Actions workflow:
- name: Populate QBO sandbox
run: easytestdata load --template saas --preset rapid-growth --seed 42
env:
EASYTESTDATA_API_KEY: ${{ secrets.ETD_API_KEY }}
- name: Run integration tests
run: npm run test:integration
- name: Cleanup sandbox
if: always()
run: easytestdata purge --mode generated
env:
EASYTESTDATA_API_KEY: ${{ secrets.ETD_API_KEY }}
The if: always() on the cleanup step ensures the sandbox is reset even if tests fail.
Getting started
Create a free account at easytestdata.com, connect a QBO sandbox, and generate an API key from your dashboard. The free tier includes 5 jobs per month.