Skip to content

test: split integration suite by resource and tighten SDK/API contract#166

Merged
Gabrielpanga merged 2 commits into
masterfrom
test/integration-suite-per-resource
Jun 10, 2026
Merged

test: split integration suite by resource and tighten SDK/API contract#166
Gabrielpanga merged 2 commits into
masterfrom
test/integration-suite-per-resource

Conversation

@Gabrielpanga

@Gabrielpanga Gabrielpanga commented May 26, 2026

Copy link
Copy Markdown
Member

Summary

Restructures the integration test suite from one 338-line tests/integration.test.ts monolith into per-resource specs under tests/integration/. Per-resource isolation: each spec that needs server state owns the full lifecycle of its own sandbox item (beforeAll creates and waits for UPDATED, afterAll deletes defensively).

What's new

Helpers — tests/integration/helpers.ts

  • createClient / createSandboxItem / deleteItemSafely.
  • retry() for sandbox eventual consistency (some endpoints lag a beat after the item flips UPDATED).
  • RUN_ID + TEST_TAG — every test run is tagged with GITHUB_RUN_ID (CI) or local-<timestamp>. Resources that accept free-form identifiers (connect token's clientUserId, webhook URLs) get tagged so orphans from failed runs are identifiable.
  • captureRejection()BaseApi rejects with the parsed error response body (not a thrown Error with .statusCode), so error tests capture the body and let each test inspect it.
  • describeIntegration — auto-skip via describe.skip when PLUGGY_CLIENT_ID / PLUGGY_CLIENT_SECRET are absent.

Coverage additions vs the monolith

Spec New coverage
items.test.ts fetchItem shape + date instances
bills.test.ts fetchCreditCardBills / fetchCreditCardBill (skips silently when sandbox has no CREDIT account)
errors.test.ts 4xx responses for non-existent ids on fetchItem, fetchAccount, fetchTransaction, fetchConnector
accounts.test.ts fetchAccountStatements
transactions.test.ts updateTransactionCategory
connectors.test.ts validateParameters

Coverage retained from the monolith

Connectors list/get, accounts, transactions (cursor + by-id + dedup), investments + fetchAllInvestmentTransactions dedup, identity (by item + by id), consents, loans, categories, connect token, webhooks CRUD.

Cleanup is mandatory

Pluggy items are heavy enough that leaked fixtures pile up against the test tenant's quota. So every spec that creates an item registers afterAll with deleteItemSafely (try/catch + stderr on failure so leaks are visible but never mask test failures).

Why per-suite items (not shared via globalSetup)

Trade-off: ~30+ minutes of wall time per run (each suite waits a full sandbox sync) vs. true isolation between suites. Per-suite isolation means one broken test can't poison the next.

Out of scope (next PR)

PluggyPaymentsClient — recipients, requests, intents, payment customers, institutions, bulk, smart accounts, automatic PIX, scheduled, smart transfers. These need their own credentials path and live in a separate domain, so they belong in a focused follow-up (#167).

package.json script tweaks

  • test: ignores tests/integration (directory) instead of the deleted single file.
  • test:integration: matches tests/integration explicitly.

Test plan

  • pnpm build — clean.
  • pnpm test — 11/11 passing (unit suite unchanged).
  • pnpm test:integration without credentials — 13 suites, 31 tests, all auto-skipped.
  • Nightly SDK Integration Tests workflow run against sandbox is green after merge.

🤖 Generated with Claude Code

@Gabrielpanga Gabrielpanga force-pushed the test/integration-suite-per-resource branch from c990d6a to efbdc32 Compare May 26, 2026 20:18
…tract

Restructures tests/integration.test.ts (one 338-line file) into per-resource
specs under tests/integration/, modeled on plaid/plaid-node. Each spec
that needs server state owns the full lifecycle of its sandbox item:
beforeAll creates and waits for UPDATED, afterAll deletes defensively
(non-throwing). Plaid skips cleanup; Pluggy items are heavier so we keep
it.

Helpers (tests/integration/helpers.ts):
- createClient / createSandboxItem / deleteItemSafely
- retry() for sandbox eventual consistency (mirrors Plaid's
  getTransactionsWithRetries pattern)
- RUN_ID + TEST_TAG so resources created in a single run can be spotted
  later (clientUserId on connect tokens, webhook URLs, etc.)
- captureRejection() because BaseApi rejects with the parsed error body,
  not a thrown Error with .statusCode — we let each test inspect the
  body rather than fake a uniform shape

Coverage additions vs the monolith:
- items.test.ts (fetchItem shape, dates)
- bills.test.ts (fetchCreditCardBills / fetchCreditCardBill)
- errors.test.ts (4xx for fetchItem / fetchAccount / fetchTransaction /
  fetchConnector with non-existent ids)
- accounts.test.ts now exercises fetchAccountStatements
- transactions.test.ts now exercises updateTransactionCategory
- connectors.test.ts now exercises validateParameters

Coverage retained from the monolith: connectors list/get, accounts,
transactions (cursor + by-id + dedup on fetchAllTransactions),
investments (+ fetchAllInvestmentTransactions dedup), identity (by item
+ by id), consents, loans, categories, connect token, webhooks CRUD.

Out of scope (next PR): PluggyPaymentsClient (recipients, requests,
intents, smart accounts, automatic PIX, scheduled, smart transfers).

package.json:
- "test" ignores tests/integration (directory) instead of the deleted
  single file.
- "test:integration" matches tests/integration explicitly.

Local verification:
- pnpm build clean
- pnpm test still 11/11
- pnpm test:integration without creds: 13 suites skipped, 31 tests
  skipped (auto-skip via describeIntegration).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Gabrielpanga Gabrielpanga force-pushed the test/integration-suite-per-resource branch from efbdc32 to ab4056d Compare June 9, 2026 19:01
…ty refs

Review follow-ups (test-only, no production code touched):

- createSandboxItem: poll only while the item is genuinely still syncing
  (UPDATING / MERGING). Previously the loop only treated LOGIN_ERROR as
  terminal, so an item landing in OUTDATED / WAITING_USER_* would spin until
  the 5-min timeout instead of failing fast.
- transactions updateTransactionCategory: compare candidate categories against
  tx.categoryId (the id) instead of tx.category (the name), so the "pick a
  different category" dedup actually works as intended.
- Remove references to a third-party SDK (plaid-node) from helpers.ts and the
  README — the suite stands on its own description.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Gabrielpanga Gabrielpanga force-pushed the test/integration-suite-per-resource branch from f170777 to 2d1ff19 Compare June 10, 2026 11:05
@Gabrielpanga Gabrielpanga merged commit a7daf23 into master Jun 10, 2026
2 of 3 checks passed
@Gabrielpanga Gabrielpanga deleted the test/integration-suite-per-resource branch June 10, 2026 11:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants