Integration testing examples using Vitest with Mailoverse. Learn to test email verification, password reset, and authentication flows with typed helpers and complete test suites.
Vitest
Integration testing examples using Vitest to test email functionality in your applications.
Configuration
Configure Vitest to use your Mailoverse credentials and set appropriate timeouts:
// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
// Load environment variables from .env.test
env: {
MAILOVERSE_DOMAIN: process.env.MAILOVERSE_DOMAIN,
MAILOVERSE_API_KEY: process.env.MAILOVERSE_API_KEY,
},
// Increase timeout for email tests
testTimeout: 60000,
hookTimeout: 60000,
},
});Helper Functions
Create a helper file with typed email retrieval functions:
// tests/helpers/mailoverse.ts
const MAILOVERSE_API_KEY = process.env.MAILOVERSE_API_KEY!;
const MAILOVERSE_DOMAIN = process.env.MAILOVERSE_DOMAIN!;
interface Email {
id: string;
from: string[];
to: string[];
subject?: string;
body?: string;
htmlBody?: string;
parsedHtml?: {
links: Array<{ href: string; text: string }>;
images: string[];
body: string;
};
parsedText?: {
links: Array<{ href: string; text: string }>;
images: string[];
body: string;
};
receivedAt: string;
}
export function generateTestEmail(prefix = 'test'): string {
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}@${MAILOVERSE_DOMAIN}`;
}
export async function waitForEmail(
address: string,
options: { timeout?: number; interval?: number } = {}
): Promise<Email> {
const { timeout = 30000, interval = 1000 } = options;
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const response = await fetch(
`https://api.mailoverse.com/email?address=${encodeURIComponent(address)}`,
{
headers: { 'Authorization': `Bearer ${MAILOVERSE_API_KEY}` },
}
);
const data = await response.json();
if (data.email) {
return data.email;
}
await new Promise(resolve => setTimeout(resolve, interval));
}
throw new Error(`Timeout waiting for email to ${address}`);
}Basic Test
A simple test example:
// tests/email.test.ts
import { describe, it, expect } from 'vitest';
import { generateTestEmail, waitForEmail } from './helpers/mailoverse';
describe('Email Service', () => {
it('sends verification email on signup', async () => {
const testEmail = generateTestEmail('signup');
// Trigger your application to send an email
await yourApp.signup({ email: testEmail, password: 'test123' });
// Wait for and verify the email
const email = await waitForEmail(testEmail);
expect(email.subject).toContain('Verify');
expect(email.parsedHtml?.links).toHaveLength(1);
expect(email.parsedHtml?.links[0].href).toContain('/verify?token=');
});
});Global Setup
Optional global setup for shared fixtures:
// tests/globalSetup.ts
import { beforeAll, afterAll } from 'vitest';
import { generateTestEmail, waitForEmail } from './helpers/mailoverse';
// Re-export for convenience
export { generateTestEmail, waitForEmail };
// Optional: Set up test fixtures
let testServer: any;
beforeAll(async () => {
// Start your test server
testServer = await startTestServer();
});
afterAll(async () => {
// Clean up
await testServer?.close();
});Advanced Examples
A comprehensive test suite for authentication flows:
// tests/auth.test.ts
import { describe, it, expect, beforeAll } from 'vitest';
import { generateTestEmail, waitForEmail } from './helpers/mailoverse';
describe('Authentication Flow', () => {
let app: any;
beforeAll(async () => {
// Set up your app client
app = await createTestApp();
});
describe('Signup', () => {
it('sends welcome email with verification link', async () => {
const email = generateTestEmail('welcome');
await app.signup({ email, password: 'SecurePass123!' });
const received = await waitForEmail(email);
expect(received.subject).toBe('Welcome to Our App');
expect(received.from).toContain('noreply@yourapp.com');
expect(received.parsedHtml?.links).toHaveLength(1);
const verifyLink = received.parsedHtml?.links[0];
expect(verifyLink?.href).toMatch(/\/verify\?token=[a-zA-Z0-9]+/);
expect(verifyLink?.text).toBe('Verify your email');
});
it('includes logo in email', async () => {
const email = generateTestEmail('logo');
await app.signup({ email, password: 'SecurePass123!' });
const received = await waitForEmail(email);
expect(received.parsedHtml?.images).toContain(
'https://yourapp.com/logo.png'
);
});
});
describe('Password Reset', () => {
it('sends reset email with secure link', async () => {
const email = generateTestEmail('reset');
// First create and verify account
await app.signup({ email, password: 'OldPassword123!' });
const signupEmail = await waitForEmail(email);
const token = new URL(signupEmail.parsedHtml?.links[0].href).searchParams.get('token');
await app.verifyEmail(token);
// Request password reset
await app.requestPasswordReset(email);
const resetEmail = await waitForEmail(email);
expect(resetEmail.subject).toBe('Reset your password');
expect(resetEmail.parsedHtml?.links).toHaveLength(1);
expect(resetEmail.parsedHtml?.links[0].href).toMatch(
/\/reset-password\?token=[a-zA-Z0-9]+/
);
});
it('reset link expires after 1 hour', async () => {
const email = generateTestEmail('expire');
await app.signup({ email, password: 'Password123!' });
await waitForEmail(email);
await app.requestPasswordReset(email);
const resetEmail = await waitForEmail(email);
const resetUrl = new URL(resetEmail.parsedHtml?.links[0].href);
const token = resetUrl.searchParams.get('token');
// Token should be valid initially
expect(await app.validateResetToken(token)).toBe(true);
// Mock time passing (if your test framework supports it)
// vi.advanceTimersByTime(60 * 60 * 1000 + 1);
// expect(await app.validateResetToken(token)).toBe(false);
});
});
});See Also
- Playwright Examples — E2E testing
- JavaScript Examples — Generic JS/TS helpers
- All Examples