Guide: Testing Password Resets
Automate the full password reset flow: trigger the email, wait for it, extract the reset link, and verify the reset completes successfully.
Overview
Password reset testing follows this pattern:
- Generate a unique test email address for this test run.
- Trigger your application's "forgot password" flow using that address.
- Wait for the reset email to arrive using
waitFor(). - Extract the reset link from the email's parsed links.
- Visit the reset link and complete the password change.
- Assert the reset was successful.
TypeScript Example
TypeScript
import { ReceiverClient } from "@receiverdotemail/sdk";
const receiver = new ReceiverClient({
apiKey: process.env.RECEIVER_API_KEY,
});
describe("Password Reset", () => {
it("sends a reset email and allows password change", async () => {
// 1. Generate a unique email address
const testEmail = `reset-${Date.now()}[email protected]`;
// 2. Trigger password reset in your app
await fetch("https://your-app.com/api/forgot-password", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: testEmail }),
});
// 3. Wait for the email (long-polls for up to 30s)
const email = await receiver.emails.waitFor({
projectId: "proj_abc123",
recipient: testEmail,
timeout: 30,
});
// 4. Assert email was received
expect(email).not.toBeNull();
expect(email.subject.toLowerCase()).toContain("reset");
// 5. Extract the reset link
const resetLink = email.links.find((link) =>
link.includes("/reset-password") || link.includes("/reset")
);
expect(resetLink).toBeDefined();
// 6. Complete the reset (visit the link with new password)
const response = await fetch(resetLink!, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ password: "newSecurePassword123!" }),
});
expect(response.ok).toBe(true);
// 7. Verify login with new password works
const loginResponse = await fetch("https://your-app.com/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: testEmail,
password: "newSecurePassword123!",
}),
});
expect(loginResponse.ok).toBe(true);
});
});Python Example
Python
import pytest
import time
import httpx
from receiverdotemail import ReceiverClient
@pytest.fixture
async def receiver():
async with ReceiverClient(
api_key=os.environ["RECEIVER_API_KEY"]
) as client:
yield client
@pytest.mark.asyncio
async def test_password_reset_flow(receiver):
# 1. Generate a unique email address
test_email = f"reset-{int(time.time())}[email protected]"
# 2. Trigger password reset
async with httpx.AsyncClient() as http:
await http.post(
"https://your-app.com/api/forgot-password",
json={"email": test_email},
)
# 3. Wait for the email
email = await receiver.emails.wait_for(
project_id="proj_abc123",
recipient=test_email,
timeout=30,
)
# 4. Assert email was received
assert email is not None
assert "reset" in email.subject.lower()
# 5. Extract the reset link
reset_link = next(
(link for link in email.links if "/reset" in link), None
)
assert reset_link is not None
# 6. Complete the reset
async with httpx.AsyncClient() as http:
response = await http.post(
reset_link,
json={"password": "newSecurePassword123!"},
)
assert response.status_code == 200Tips
- Unique addresses: Always generate a unique email per test run using timestamps or UUIDs. This prevents interference between parallel tests.
- Link filtering: Reset emails often contain multiple links (unsubscribe, privacy policy, etc.). Filter by URL path to find the right one.
- Timeout: Set the
waitFortimeout higher than your app's email delivery time. 30 seconds is usually sufficient. - Test framework timeout: Make sure your test framework's timeout is higher than the
waitFortimeout (e.g. Jest default is 5s, so increase it).