Skip to content

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 .test TLD 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 payment

Integration 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', '[email protected]');
    
    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: '[email protected]'
    }).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', '[email protected]');
    
    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.yml

Manual Testing

Testing Checklist

User Session Testing

  1. Create session with valid user ID
  2. Create session with email parameter
  3. Try to reuse expired session
  4. Test with invalid API key
  5. Test with malformed requests

Domain Interface Testing

  1. Load iframe in different browsers
  2. Test responsive design on mobile
  3. Search for available domains
  4. Purchase a test domain
  5. Verify domain appears in account

API Integration Testing

  1. Fetch user domains after purchase
  2. Create DNS records programmatically
  3. Update existing DNS records
  4. Test error handling scenarios
  5. 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

  1. Always test in sandbox first before production deployment
  2. Use test data that's easy to identify and clean up
  3. Test error scenarios as thoroughly as success scenarios
  4. Monitor API response times and set performance budgets
  5. Clean up test data regularly to avoid clutter
  6. Test across different browsers and devices
  7. Validate all user inputs before sending to API
  8. Test webhook delivery and handling
  9. Use proper test isolation to avoid test interference
  10. Keep test credentials separate from production credentials

Built with ❤️ for PocketDNS Partners