Testing
This guide covers how to test your PocketDNS integration effectively.
Sandbox Environment
The PocketDNS sandbox environment provides a safe space to test your integration without affecting real domains or billing.
Sandbox Features
- Test domains: Use
.testTLD for testing - Simulated transactions: No real charges occur
- Isolated data: Separate from production data
- Full API compatibility: Same endpoints and responses as production
Sandbox URLs
- API:
https://api.sandbox.pocketdns.com - Embed:
https://embed.sandbox.pocketdns.com - Dashboard:
https://dashboard.sandbox.pocketdns.com
Test Domain Purchases
In sandbox, you can purchase test domains:
javascript
// Test domains are automatically available in sandbox
const testDomains = [
'example1.test',
'example2.test',
'mysite.test'
];
// Purchase will succeed immediately without paymentIntegration Testing Checklist
Basic Integration Tests
[ ] User Session Creation
- [ ] Create session with valid user identifier
- [ ] Handle invalid user identifiers
- [ ] Session expires after 24 hours
- [ ] Email parameter is optional
[ ] Iframe Embedding
- [ ] Iframe loads successfully
- [ ] Responsive design works on mobile
- [ ] Payment flows complete in sandbox
- [ ] Session expiration is handled gracefully
[ ] Domain Management
- [ ] Fetch user domains after purchase
- [ ] Get individual domain details
- [ ] Handle users with no domains
Advanced Integration Tests
[ ] DNS Management
- [ ] Create DNS records programmatically
- [ ] Update existing DNS records
- [ ] Delete DNS records
- [ ] Apply DNS templates
- [ ] Handle DNS propagation delays
[ ] Error Handling
- [ ] API errors are caught and handled
- [ ] User-friendly error messages displayed
- [ ] Network timeouts handled gracefully
- [ ] Rate limiting respected
[ ] Security
- [ ] API keys never exposed client-side
- [ ] User identifiers are validated
- [ ] HTTPS enforced for all requests
- [ ] CORS headers configured correctly
Unit Testing
Testing API Calls
javascript
// __tests__/pocketdns.test.js
import { createUserSession } from '../src/services/pocketdns';
// Mock fetch for testing
global.fetch = jest.fn();
describe('PocketDNS API', () => {
beforeEach(() => {
fetch.mockClear();
});
test('creates user session successfully', async () => {
const mockResponse = {
user_identifier: 'test_user_123',
login_url: 'https://embed.sandbox.pocketdns.com/session/abc123',
expires_at: '2025-01-07T12:00:00Z'
};
fetch.mockResolvedValueOnce({
ok: true,
json: async () => mockResponse
});
const result = await createUserSession('test_user_123', 'test@example.com');
expect(result).toEqual(mockResponse);
expect(fetch).toHaveBeenCalledWith(
'https://api.sandbox.pocketdns.com/api/v1/users',
expect.objectContaining({
method: 'POST',
headers: expect.objectContaining({
'Authorization': expect.stringContaining('Bearer'),
'Content-Type': 'application/json'
})
})
);
});
test('handles API errors gracefully', async () => {
fetch.mockResolvedValueOnce({
ok: false,
status: 401,
statusText: 'Unauthorized'
});
await expect(
createUserSession('invalid_user')
).rejects.toThrow('Failed to create session: Unauthorized');
});
});Testing React Components
javascript
// __tests__/PocketDNSEmbed.test.js
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import PocketDNSEmbed from '../src/components/PocketDNSEmbed';
// Mock the API service
jest.mock('../src/services/pocketdns', () => ({
createUserSession: jest.fn()
}));
import { createUserSession } from '../src/services/pocketdns';
describe('PocketDNSEmbed', () => {
test('shows loading state initially', () => {
render(<PocketDNSEmbed userIdentifier="test_user" />);
expect(screen.getByText('Loading domain interface...')).toBeInTheDocument();
});
test('renders iframe when session loads', async () => {
createUserSession.mockResolvedValue({
login_url: 'https://embed.sandbox.pocketdns.com/session/abc123'
});
render(<PocketDNSEmbed userIdentifier="test_user" />);
await waitFor(() => {
const iframe = screen.getByTitle('Domain Management');
expect(iframe).toBeInTheDocument();
expect(iframe.src).toBe('https://embed.sandbox.pocketdns.com/session/abc123');
});
});
test('shows error state on API failure', async () => {
createUserSession.mockRejectedValue(new Error('API Error'));
render(<PocketDNSEmbed userIdentifier="test_user" />);
await waitFor(() => {
expect(screen.getByText('Error: API Error')).toBeInTheDocument();
});
});
});Integration Testing
End-to-End Testing with Cypress
javascript
// cypress/integration/domain-purchase.spec.js
describe('Domain Purchase Flow', () => {
beforeEach(() => {
// Set up test user
cy.request('POST', 'https://api.sandbox.pocketdns.com/api/v1/users', {
user_identifier: 'cypress_test_user',
email: 'test@example.com'
}).then((response) => {
cy.window().then((win) => {
win.testSession = response.body;
});
});
});
it('completes domain purchase flow', () => {
cy.visit('/domains');
// Load the embed
cy.get('[data-testid="pocketdns-embed"]').should('be.visible');
// Switch to iframe context
cy.get('iframe').then(($iframe) => {
const iframe = $iframe.contents();
// Search for a domain
cy.wrap(iframe.find('input[placeholder="Search for a domain"]'))
.type('cypress-test.test{enter}');
// Click purchase button
cy.wrap(iframe.find('button[data-testid="purchase-button"]'))
.click();
// Complete purchase (in sandbox, this is instant)
cy.wrap(iframe.find('button[data-testid="confirm-purchase"]'))
.click();
// Verify success message
cy.wrap(iframe.find('[data-testid="purchase-success"]'))
.should('contain', 'Domain purchased successfully');
});
// Verify domain appears in user's account
cy.request({
url: `https://api.sandbox.pocketdns.com/api/v1/users/cypress_test_user/domains`,
headers: {
'Authorization': `Bearer ${Cypress.env('POCKETDNS_SANDBOX_API_KEY')}`
}
}).then((response) => {
expect(response.body.domains).to.have.length.greaterThan(0);
expect(response.body.domains[0].name).to.equal('cypress-test.test');
});
});
});Testing Webhooks
javascript
// __tests__/webhooks.test.js
import request from 'supertest';
import app from '../src/app';
describe('PocketDNS Webhooks', () => {
test('handles domain purchase webhook', async () => {
const webhookPayload = {
event: 'domain.purchased',
data: {
domain_id: 'dom_123456',
user_identifier: 'test_user_123',
domain_name: 'example.test',
purchased_at: '2025-01-06T12:00:00Z'
}
};
const response = await request(app)
.post('/webhooks/pocketdns')
.send(webhookPayload)
.expect(200);
expect(response.body.success).toBe(true);
// Verify that DNS records were created
// Verify user notification was sent
// etc.
});
});Performance Testing
API Response Time Testing
javascript
// __tests__/performance.test.js
import { createUserSession, getUserDomains } from '../src/services/pocketdns';
describe('PocketDNS Performance', () => {
test('user session creation completes within 2 seconds', async () => {
const start = Date.now();
await createUserSession('perf_test_user', 'test@example.com');
const duration = Date.now() - start;
expect(duration).toBeLessThan(2000);
});
test('domain fetching handles large datasets', async () => {
// Test with user that has many domains
const start = Date.now();
const domains = await getUserDomains('user_with_many_domains');
const duration = Date.now() - start;
expect(domains.length).toBeGreaterThan(0);
expect(duration).toBeLessThan(5000);
});
});Load Testing with Artillery
yaml
# load-test.yml
config:
target: 'https://api.sandbox.pocketdns.com'
phases:
- duration: 60
arrivalRate: 10
defaults:
headers:
Authorization: 'Bearer {{ $env.POCKETDNS_SANDBOX_API_KEY }}'
Content-Type: 'application/json'
scenarios:
- name: 'Create user sessions'
weight: 80
flow:
- post:
url: '/api/v1/users'
json:
user_identifier: 'load_test_{{ $randomString() }}'
email: 'test{{ $randomInt(1, 1000) }}@example.com'
capture:
- json: '$.user_identifier'
as: 'userId'
- get:
url: '/api/v1/users/{{ userId }}/domains'
- name: 'Health check'
weight: 20
flow:
- get:
url: '/health'Run the load test:
bash
npx artillery run load-test.ymlManual Testing
Testing Checklist
User Session Testing
- Create session with valid user ID
- Create session with email parameter
- Try to reuse expired session
- Test with invalid API key
- Test with malformed requests
Domain Interface Testing
- Load iframe in different browsers
- Test responsive design on mobile
- Search for available domains
- Purchase a test domain
- Verify domain appears in account
API Integration Testing
- Fetch user domains after purchase
- Create DNS records programmatically
- Update existing DNS records
- Test error handling scenarios
- Verify webhook delivery
Monitoring and Debugging
Test Data Cleanup
javascript
// scripts/cleanup-test-data.js
const cleanupTestData = async () => {
const testUsers = await getUsersWithPrefix('test_');
for (const user of testUsers) {
const domains = await getUserDomains(user.user_identifier);
for (const domain of domains) {
if (domain.name.endsWith('.test')) {
await deleteDomain(domain.id);
}
}
await deleteUser(user.user_identifier);
}
console.log(`Cleaned up ${testUsers.length} test users`);
};Debug Logging
javascript
// utils/debug.js
const debug = require('debug');
const pocketDNSDebug = debug('app:pocketdns');
export const logAPICall = (method, url, data) => {
pocketDNSDebug(`${method} ${url}`, data);
};
export const logAPIResponse = (response) => {
pocketDNSDebug('Response:', response.status, response.data);
};Best Practices
- Always test in sandbox first before production deployment
- Use test data that's easy to identify and clean up
- Test error scenarios as thoroughly as success scenarios
- Monitor API response times and set performance budgets
- Clean up test data regularly to avoid clutter
- Test across different browsers and devices
- Validate all user inputs before sending to API
- Test webhook delivery and handling
- Use proper test isolation to avoid test interference
- Keep test credentials separate from production credentials
