Skip to content

Conversation

@TyMick
Copy link
Contributor

@TyMick TyMick commented Oct 7, 2025

This PR adds integration tests that record and replay real Resend API responses using Polly.JS. These tests complement the existing unit tests by verifying actual HTTP interactions.

Why?

The current unit tests mock all API responses, which doesn't catch certain bugs:

  • API changes: If Resend's API changes response format, mocked tests won't detect it.
  • Request format issues: Subtle bugs in request construction (headers, body encoding, etc.) can slip through.
  • Missing headers: feat: adds permissive mode for batch API #599 introduced a bug (fixed in fix: headers not sent to DELETE requests #635) where DELETE requests didn't send the Authorization header, causing 401 Unauthorized errors. Unit tests didn't catch this because they didn't verify actual HTTP requests.

How It Works

Test Modes

Default (Replay Mode)

pnpm test

Tests use pre-recorded API responses from __recordings__ directories (located alongside each integration test file). Fast and deterministic, no API key needed. Ideal for CI/CD workflows, so they don't have to make their own network requests.

Re-record All Tests

export RESEND_API_KEY='re_your_api_key'
pnpm test:record

Makes real API calls and saves responses to __recordings__ directories. Useful after API changes. Requires a valid RESEND_API_KEY.

Dev Mode (Record If Missing)

export RESEND_API_KEY='re_your_api_key'
pnpm test:dev

Uses existing recordings when available, records new ones when missing. Useful when adding new tests.

Setting API Key

You can set RESEND_API_KEY either in your shell or in a .env.test file (loaded via dotenv in vitest.setup.mts):

Note: The dotenv setup is optional and can be removed from this PR if preferred. I just found it convenient when developing these tests.

Security: API Key Redaction

Polly.JS is configured to automatically redact API keys before saving recordings (see polly-setup.ts): This means:

  • ✅ You can record with your own API key
  • ✅ Recordings are safe to commit (no keys stored)
  • ✅ Tests still verify Authorization headers are sent

Test Coverage

Integration tests currently cover API Keys, Audiences, and Contacts. They do catch the DELETE headers bug if I back out the fix in #635.

Additional SDK areas (domains, emails, broadcasts) would be best added by the Resend team, since test domains would need to be part of the test code. Once those recordings are committed, though, anyone can replay them without account access to those domains.

@TyMick TyMick requested a review from a team as a code owner October 7, 2025 14:15
@socket-security
Copy link

socket-security bot commented Oct 7, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedrimraf@​6.0.19910010078100
Added@​pollyjs/​persister-fs@​6.0.61001008379100
Added@​pollyjs/​core@​6.0.69910010080100
Added@​pollyjs/​adapter-fetch@​6.0.7961008981100
Addedcross-env@​10.1.010010010084100
Addeddotenv@​17.2.310010010093100

View full report

@socket-security
Copy link

socket-security bot commented Oct 7, 2025

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
[email protected] has Obfuscated code.

Confidence: 0.94

Location: Package overview

From: pnpm-lock.yamlnpm/@pollyjs/[email protected]npm/[email protected]

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at [email protected].

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/[email protected]. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 7, 2025

Open in StackBlitz

npm i https://pkg.pr.new/resend/resend-node/resend@663

commit: 56202eb

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

14 issues found across 40 files

Prompt for AI agents (all 14 issues)

Understand the root cause of the following 14 issues and fix them.


<file name="src/contacts/contacts.integration.spec.ts">

<violation number="1" location="src/contacts/contacts.integration.spec.ts:16">
Await polly.stop() so the afterEach hook doesn’t resolve before Polly finishes persisting recordings and shutting down adapters, which can leave flaky or incomplete recordings.</violation>

<violation number="2" location="src/contacts/contacts.integration.spec.ts:20">
Rule violated: **No `should` in tests**

Please rewrite this test description to avoid the word &quot;should&quot; and use a direct, declarative phrase instead (applies to this and the other new tests in this file).</violation>
</file>

<file name="src/audiences/__recordings__/Audiences-Integration-Tests-create-should-handle-validation-errors_2024921708/recording.har">

<violation number="1" location="src/audiences/__recordings__/Audiences-Integration-Tests-create-should-handle-validation-errors_2024921708/recording.har:3">
Rule violated: **No `should` in tests**

Rename this test description to avoid the word “should”; the project’s No `should` in tests rule requires declarative phrasing.</violation>
</file>

<file name="src/api-keys/__recordings__/API-Keys-Integration-Tests-create-should-create-an-API-key-with-sending-access_3080998429/recording.har">

<violation number="1" location="src/api-keys/__recordings__/API-Keys-Integration-Tests-create-should-create-an-API-key-with-sending-access_3080998429/recording.har:3">
Rule violated: **No `should` in tests**

The recorded test name still uses the word &quot;should&quot;, which violates the &quot;No `should` in tests&quot; guideline. Rename the test description to a declarative phrase like &quot;creates an API key with sending access&quot; so the recording and test stay compliant.</violation>
</file>

<file name="src/audiences/audiences.integration.spec.ts">

<violation number="1" location="src/audiences/audiences.integration.spec.ts:16">
Await polly.stop() in the async afterEach so the Polly recorder finishes flushing recordings before the next test runs.</violation>

<violation number="2" location="src/audiences/audiences.integration.spec.ts:20">
Rule violated: **No `should` in tests**

Test descriptions must avoid the word &quot;should&quot; per the No `should` in tests guideline—please rephrase this case to a direct statement.</violation>

<violation number="3" location="src/audiences/audiences.integration.spec.ts:34">
Rule violated: **No `should` in tests**

Please rewrite this test description without &quot;should&quot; so it reads as a declarative statement, in line with the No `should` in tests rule.</violation>

<violation number="4" location="src/audiences/audiences.integration.spec.ts:44">
Rule violated: **No `should` in tests**

Rephrase this test title to remove &quot;should&quot; and state the behavior directly to comply with the No `should` in tests guideline.</violation>

<violation number="5" location="src/audiences/audiences.integration.spec.ts:70">
Rule violated: **No `should` in tests**

Adjust this test description to drop &quot;should&quot; and make the statement declarative, per the No `should` in tests requirement.</violation>

<violation number="6" location="src/audiences/audiences.integration.spec.ts:127">
Rule violated: **No `should` in tests**

Update this test description to a direct statement without &quot;should&quot;, consistent with the No `should` in tests requirement.</violation>
</file>

<file name="src/api-keys/__recordings__/API-Keys-Integration-Tests-create-should-create-an-API-key-with-full-access_1681439770/recording.har">

<violation number="1" location="src/api-keys/__recordings__/API-Keys-Integration-Tests-create-should-create-an-API-key-with-full-access_1681439770/recording.har:47">
The recorded response stores the full Resend API token in plain text, leaking a sensitive secret. Please redact the token value before committing the cassette.</violation>
</file>

<file name="package.json">

<violation number="1" location="package.json:35">
Use double quotes around the glob so rimraf works on Windows; otherwise the pattern is passed with literal single quotes and the cleanup step fails on that platform.</violation>
</file>

<file name="src/api-keys/api-keys.integration.spec.ts">

<violation number="1" location="src/api-keys/api-keys.integration.spec.ts:16">
Await polly.stop() inside the async afterEach so its Promise settles before the next test begins; otherwise teardown can overlap and recordings may not persist correctly.</violation>
</file>

<file name="src/test-utils/polly-setup.ts">

<violation number="1" location="src/test-utils/polly-setup.ts:4">
Rule violated: **Initialisms and Acronyms Naming Conventions**

Rename the imported identifier so the `FS` acronym is camel-cased (e.g., `FsPersister`) to comply with the Initialisms and Acronyms Naming Conventions rule; update its usages accordingly.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

@TyMick
Copy link
Contributor Author

TyMick commented Oct 7, 2025

Thanks for the review, Cubic! I'll address those this evening.

@TyMick TyMick force-pushed the integration-tests branch 2 times, most recently from 04e9557 to 7bd7fbf Compare October 8, 2025 03:35
@TyMick TyMick changed the title Add integration tests with Polly.JS chore: Add integration tests with Polly.JS Oct 8, 2025
@TyMick TyMick force-pushed the integration-tests branch from 3ac88cd to 54d2cd5 Compare October 8, 2025 03:37
@TyMick TyMick changed the title chore: Add integration tests with Polly.JS chore: add integration tests with Polly.JS Oct 8, 2025
@gabrielmfern
Copy link
Member

This looks amazing, that's exactly a problem I was thinking of for a bit, thank you!

@gabrielmfern gabrielmfern requested review from gabrielmfern and removed request for pedro-stramantinoli October 10, 2025 19:41
});

// Redact API keys from recordings before saving them
polly.server.any().on('beforePersist', (_, recording) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

love this!

@gabrielmfern gabrielmfern changed the title chore: add integration tests with Polly.JS feat: partial non-mocked test coverage Oct 10, 2025
@gabrielmfern gabrielmfern changed the title feat: partial non-mocked test coverage feat: partial (API Keys, Audiences, and Contacts) non-mocked test coverage Oct 10, 2025
@TyMick
Copy link
Contributor Author

TyMick commented Oct 12, 2025

Glad it's filling a need! 😊

@TyMick
Copy link
Contributor Author

TyMick commented Oct 12, 2025

Hey @gabrielmfern, low priority, but would y'all be up for adding the "hacktoberfest" topic to this repo? Trying to get my numbers up over there. 😅 (Though that's far from the main reason I'm contributing.)

Copy link
Member

@gabrielmfern gabrielmfern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's try it out!

@gabrielmfern gabrielmfern merged commit 6f3b9ea into resend:canary Oct 14, 2025
12 checks passed
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