.do
Implementation Guides

Quality Assurance Guide

Complete guide to testing Services-as-Software with unit tests, integration tests, performance testing, and quality metrics

Learn how to build comprehensive quality assurance systems for your Services-as-Software, ensuring reliability, performance, and customer satisfaction through automated testing and continuous monitoring.

Why Quality Assurance Matters

Quality assurance is essential for Services-as-Software success:

  1. Customer Trust - Reliable services build confidence and loyalty
  2. Revenue Protection - Quality issues directly impact revenue
  3. Cost Reduction - Catch bugs early before they reach customers
  4. Competitive Advantage - High-quality services win and retain customers
  5. Regulatory Compliance - Meet quality standards and SLAs
  6. Continuous Improvement - Metrics drive optimization

Unit Testing Services

Basic Service Unit Tests

Test individual service components:

import { describe, it, expect, beforeEach } from 'vitest'
import $ from 'sdk.do'

describe('Email Summarizer Service', () => {
  let service: any

  beforeEach(async () => {
    service = await $.Service.findOne({
      where: { name: 'Email Summarizer' },
    })
  })

  it('should summarize email content', async () => {
    const input = {
      emailContent: `
        Dear Team,

        I wanted to follow up on our discussion from yesterday's meeting...
        [Long email content here]
      `,
      maxLength: 100,
    }

    const result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: input,
    })

    expect(result.summary).toBeDefined()
    expect(result.summary.length).toBeLessThanOrEqual(100)
    expect(result.keyPoints).toBeInstanceOf(Array)
    expect(result.keyPoints.length).toBeGreaterThan(0)
  })

  it('should handle empty input', async () => {
    const input = {
      emailContent: '',
      maxLength: 100,
    }

    await expect(
      $.ServiceRequest.execute({
        serviceId: service.id,
        inputs: input,
      })
    ).rejects.toThrow('Email content is required')
  })

  it('should respect max length constraint', async () => {
    const input = {
      emailContent: 'Test email content',
      maxLength: 50,
    }

    const result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: input,
    })

    const wordCount = result.summary.split(' ').length
    expect(wordCount).toBeLessThanOrEqual(50)
  })

  it('should extract action items', async () => {
    const input = {
      emailContent: `
        Please complete the following tasks:
        1. Review the document by Friday
        2. Submit your feedback
        3. Schedule follow-up meeting
      `,
      maxLength: 100,
    }

    const result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: input,
    })

    expect(result.actionItems).toBeDefined()
    expect(result.actionItems).toContain('Review document by Friday')
  })

  it('should detect sentiment', async () => {
    const input = {
      emailContent: `
        I'm extremely frustrated with the delays.
        This is completely unacceptable.
      `,
      maxLength: 100,
    }

    const result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: input,
    })

    expect(result.sentiment).toBe('negative')
  })
})

Testing Input Validation

Validate input handling:

describe('Input Validation', () => {
  it('should reject invalid email format', async () => {
    const input = {
      email: 'invalid-email',
    }

    await expect(
      $.ServiceRequest.execute({
        serviceId: service.id,
        inputs: input,
      })
    ).rejects.toThrow('Invalid email format')
  })

  it('should apply default values', async () => {
    const input = {
      emailContent: 'Test content',
      // maxLength not provided
    }

    const result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: input,
    })

    // Should use default maxLength
    expect(result.summary.split(' ').length).toBeLessThanOrEqual(150)
  })

  it('should validate required fields', async () => {
    const input = {}

    await expect(
      $.ServiceRequest.execute({
        serviceId: service.id,
        inputs: input,
      })
    ).rejects.toThrow('Missing required field: emailContent')
  })

  it('should enforce type constraints', async () => {
    const input = {
      emailContent: 'Test content',
      maxLength: 'invalid', // Should be number
    }

    await expect(
      $.ServiceRequest.execute({
        serviceId: service.id,
        inputs: input,
      })
    ).rejects.toThrow('Invalid type for maxLength: expected number')
  })
})

Testing Output Format

Verify output structure:

describe('Output Format', () => {
  it('should return all required fields', async () => {
    const input = {
      emailContent: 'Test email content',
    }

    const result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: input,
    })

    expect(result).toHaveProperty('summary')
    expect(result).toHaveProperty('keyPoints')
    expect(result).toHaveProperty('actionItems')
    expect(result).toHaveProperty('sentiment')
  })

  it('should format output correctly', async () => {
    const input = {
      emailContent: 'Test email content',
    }

    const result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: input,
    })

    expect(typeof result.summary).toBe('string')
    expect(Array.isArray(result.keyPoints)).toBe(true)
    expect(Array.isArray(result.actionItems)).toBe(true)
    expect(['positive', 'negative', 'neutral']).toContain(result.sentiment)
  })

  it('should include metadata', async () => {
    const input = {
      emailContent: 'Test email content',
    }

    const result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: input,
    })

    expect(result.metadata).toBeDefined()
    expect(result.metadata.originalLength).toBeGreaterThan(0)
    expect(result.metadata.compressionRatio).toBeGreaterThan(0)
  })
})

Integration Testing

Service Integration Tests

Test service interactions:

import { describe, it, expect, beforeAll } from 'vitest'
import { db } from 'sdk.do'

describe('Content Marketing Service Integration', () => {
  let service: any
  let customer: any

  beforeAll(async () => {
    service = await $.Service.findOne({
      where: { name: 'Content Marketing Suite' },
    })

    customer = await db.create($.Customer, {
      name: 'Test Customer',
      email: '[email protected]',
    })
  })

  it('should execute complete workflow', async () => {
    const request = await $.ServiceRequest.create({
      serviceId: service.id,
      customerId: customer.id,
      inputs: {
        topic: 'AI in Healthcare',
        targetKeywords: ['ai', 'healthcare', 'diagnosis'],
        targetAudience: {
          demographic: 'healthcare-professionals',
          industry: 'healthcare',
          expertiseLevel: 'intermediate',
        },
      },
    })

    // Wait for completion
    const result = await waitForCompletion(request.id, 900000) // 15 min timeout

    // Verify all stages completed
    expect(result.research).toBeDefined()
    expect(result.outline).toBeDefined()
    expect(result.content).toBeDefined()
    expect(result.seo).toBeDefined()

    // Verify content quality
    expect(result.content.length).toBeGreaterThan(500)
    expect(result.seo.score).toBeGreaterThan(70)
  })

  it('should handle stage failures gracefully', async () => {
    const request = await $.ServiceRequest.create({
      serviceId: service.id,
      customerId: customer.id,
      inputs: {
        topic: '', // Invalid input to trigger failure
        targetKeywords: [],
      },
    })

    const result = await waitForCompletion(request.id, 60000)

    expect(result.status).toBe('failed')
    expect(result.error).toBeDefined()
    expect(result.failedStage).toBe('research')
  })

  it('should track progress through stages', async () => {
    const request = await $.ServiceRequest.create({
      serviceId: service.id,
      customerId: customer.id,
      inputs: {
        topic: 'Cloud Computing Trends',
        targetKeywords: ['cloud', 'computing', 'trends'],
        targetAudience: { expertiseLevel: 'beginner' },
      },
    })

    // Check progress updates
    const progress = await trackProgress(request.id)

    expect(progress).toContainEqual({
      stage: 'research',
      status: 'completed',
    })
    expect(progress).toContainEqual({
      stage: 'outline',
      status: 'completed',
    })
    expect(progress).toContainEqual({
      stage: 'content',
      status: 'completed',
    })
  })

  it('should handle optional stages', async () => {
    const request = await $.ServiceRequest.create({
      serviceId: service.id,
      customerId: customer.id,
      inputs: {
        topic: 'Test Topic',
        targetKeywords: ['test'],
        targetAudience: { expertiseLevel: 'beginner' },
        includeImages: true,
        generateSocial: true,
      },
    })

    const result = await waitForCompletion(request.id, 900000)

    expect(result.images).toBeDefined()
    expect(result.socialPosts).toBeDefined()
  })
})

// Helper functions
async function waitForCompletion(requestId: string, timeout: number) {
  const startTime = Date.now()

  while (Date.now() - startTime < timeout) {
    const request = await db.findOne($.ServiceRequest, {
      where: { id: requestId },
    })

    if (request.status === 'completed' || request.status === 'failed') {
      return request
    }

    await new Promise((resolve) => setTimeout(resolve, 1000))
  }

  throw new Error('Request timed out')
}

async function trackProgress(requestId: string) {
  const progressUpdates: any[] = []

  // Subscribe to progress events
  const unsubscribe = $.ServiceProgress.subscribe({
    where: { requestId },
    callback: (update) => {
      progressUpdates.push(update)
    },
  })

  // Wait for completion
  await waitForCompletion(requestId, 900000)

  unsubscribe()
  return progressUpdates
}

Database Integration Tests

Test database operations:

describe('Database Integration', () => {
  it('should persist service results', async () => {
    const request = await $.ServiceRequest.create({
      serviceId: service.id,
      customerId: customer.id,
      inputs: { emailContent: 'Test content' },
    })

    const result = await waitForCompletion(request.id, 60000)

    // Verify result persisted
    const stored = await db.findOne($.ServiceResult, {
      where: { requestId: request.id },
    })

    expect(stored).toBeDefined()
    expect(stored.outputs).toEqual(result.outputs)
  })

  it('should update usage records', async () => {
    const initialUsage = await db.findOne($.UsageRecord, {
      where: { customerId: customer.id },
      orderBy: { timestamp: 'desc' },
    })

    await $.ServiceRequest.execute({
      serviceId: service.id,
      customerId: customer.id,
      inputs: { emailContent: 'Test content' },
    })

    const newUsage = await db.findOne($.UsageRecord, {
      where: { customerId: customer.id },
      orderBy: { timestamp: 'desc' },
    })

    expect(newUsage.id).not.toBe(initialUsage?.id)
    expect(newUsage.quantity).toBeGreaterThan(0)
  })

  it('should maintain referential integrity', async () => {
    const request = await $.ServiceRequest.create({
      serviceId: service.id,
      customerId: customer.id,
      inputs: { emailContent: 'Test content' },
    })

    // Verify relationships
    const customerRequests = await db.related(customer, $.has, $.ServiceRequest)
    expect(customerRequests).toContainEqual(expect.objectContaining({ id: request.id }))

    const serviceRequests = await db.related(service, $.receives, $.ServiceRequest)
    expect(serviceRequests).toContainEqual(expect.objectContaining({ id: request.id }))
  })
})

External Service Integration Tests

Test external API integrations:

describe('External Service Integration', () => {
  it('should call AI API correctly', async () => {
    const mockAI = vi.fn().mockResolvedValue({
      content: 'Generated summary',
      tokensUsed: 150,
    })

    // Mock AI service
    vi.mock('sdk.do', () => ({
      ai: {
        generate: mockAI,
      },
    }))

    await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: { emailContent: 'Test content' },
    })

    expect(mockAI).toHaveBeenCalledWith(
      expect.objectContaining({
        model: 'gpt-5',
        prompt: expect.any(String),
      })
    )
  })

  it('should handle API errors gracefully', async () => {
    const mockAI = vi.fn().mockRejectedValue(new Error('API Error'))

    vi.mock('sdk.do', () => ({
      ai: {
        generate: mockAI,
      },
    }))

    const result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: { emailContent: 'Test content' },
    })

    expect(result.status).toBe('failed')
    expect(result.error).toContain('API Error')
  })

  it('should retry failed API calls', async () => {
    let callCount = 0
    const mockAI = vi.fn().mockImplementation(() => {
      callCount++
      if (callCount < 3) {
        throw new Error('Temporary error')
      }
      return { content: 'Success after retries' }
    })

    vi.mock('sdk.do', () => ({
      ai: {
        generate: mockAI,
      },
    }))

    const result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: { emailContent: 'Test content' },
    })

    expect(callCount).toBe(3)
    expect(result.status).toBe('completed')
  })
})

End-to-End Testing

Complete User Journey Tests

Test entire customer workflows:

import { describe, it, expect } from 'vitest'

describe('End-to-End User Journey', () => {
  it('should complete signup to service execution', async () => {
    // 1. Customer signup
    const customer = await $.Customer.create({
      name: 'John Doe',
      email: '[email protected]',
      password: 'secure-password',
    })

    expect(customer.id).toBeDefined()

    // 2. Subscribe to plan
    const subscription = await $.Subscription.create({
      customerId: customer.id,
      planId: 'starter',
    })

    expect(subscription.status).toBe('active')

    // 3. Execute service
    const request = await $.ServiceRequest.create({
      serviceId: service.id,
      customerId: customer.id,
      inputs: { emailContent: 'Test email' },
    })

    const result = await waitForCompletion(request.id, 60000)
    expect(result.status).toBe('completed')

    // 4. Verify billing
    const usage = await db.findOne($.UsageRecord, {
      where: { customerId: customer.id, requestId: request.id },
    })

    expect(usage).toBeDefined()
    expect(usage.quantity).toBeGreaterThan(0)

    // 5. Generate invoice
    const invoice = await $.Invoice.findOne({
      where: { customerId: customer.id },
    })

    expect(invoice).toBeDefined()
    expect(invoice.total).toBeGreaterThan(0)
  })

  it('should handle subscription lifecycle', async () => {
    const customer = await $.Customer.create({
      name: 'Jane Doe',
      email: '[email protected]',
    })

    // Start with basic plan
    let subscription = await $.Subscription.create({
      customerId: customer.id,
      planId: 'basic',
    })

    expect(subscription.plan.name).toBe('Basic')

    // Upgrade to pro
    subscription = await $.Subscription.upgrade({
      subscriptionId: subscription.id,
      newPlanId: 'pro',
    })

    expect(subscription.plan.name).toBe('Pro')

    // Cancel subscription
    await $.Subscription.cancel({
      subscriptionId: subscription.id,
    })

    subscription = await $.Subscription.findOne({
      where: { id: subscription.id },
    })

    expect(subscription.cancelAtPeriodEnd).toBe(true)
  })
})

Performance Testing

Load Testing

Test service performance under load:

import { describe, it, expect } from 'vitest'

describe('Performance Tests', () => {
  it('should handle concurrent requests', async () => {
    const concurrentRequests = 100
    const requests = []

    const startTime = Date.now()

    // Create concurrent requests
    for (let i = 0; i < concurrentRequests; i++) {
      requests.push(
        $.ServiceRequest.execute({
          serviceId: service.id,
          inputs: { emailContent: `Test email ${i}` },
        })
      )
    }

    // Wait for all to complete
    const results = await Promise.all(requests)
    const endTime = Date.now()

    // Verify all succeeded
    expect(results.every((r) => r.status === 'completed')).toBe(true)

    // Check performance
    const duration = endTime - startTime
    const avgTime = duration / concurrentRequests

    expect(avgTime).toBeLessThan(5000) // 5 seconds per request
  })

  it('should maintain SLA under load', async () => {
    const testDuration = 60000 // 1 minute
    const requestsPerSecond = 10
    const startTime = Date.now()
    const results: any[] = []

    while (Date.now() - startTime < testDuration) {
      const batchStart = Date.now()

      // Send batch of requests
      const batch = []
      for (let i = 0; i < requestsPerSecond; i++) {
        batch.push(
          $.ServiceRequest.execute({
            serviceId: service.id,
            inputs: { emailContent: 'Test email' },
          })
        )
      }

      const batchResults = await Promise.all(batch)
      results.push(...batchResults)

      // Wait for next second
      const batchDuration = Date.now() - batchStart
      if (batchDuration < 1000) {
        await new Promise((resolve) => setTimeout(resolve, 1000 - batchDuration))
      }
    }

    // Calculate metrics
    const successful = results.filter((r) => r.status === 'completed')
    const failed = results.filter((r) => r.status === 'failed')
    const successRate = successful.length / results.length

    const responseTimes = successful.map((r) => r.duration)
    const avgResponseTime = responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length
    const p95ResponseTime = responseTimes.sort()[Math.floor(responseTimes.length * 0.95)]

    // Verify SLA
    expect(successRate).toBeGreaterThan(0.99) // 99% success rate
    expect(avgResponseTime).toBeLessThan(5000) // 5 seconds average
    expect(p95ResponseTime).toBeLessThan(10000) // 10 seconds p95
  })

  it('should scale with increased load', async () => {
    const loadLevels = [10, 50, 100, 200]
    const results: Record<number, any> = {}

    for (const load of loadLevels) {
      const requests = []
      const startTime = Date.now()

      for (let i = 0; i < load; i++) {
        requests.push(
          $.ServiceRequest.execute({
            serviceId: service.id,
            inputs: { emailContent: 'Test email' },
          })
        )
      }

      const batchResults = await Promise.all(requests)
      const duration = Date.now() - startTime

      results[load] = {
        totalTime: duration,
        avgTime: duration / load,
        successRate: batchResults.filter((r) => r.status === 'completed').length / load,
      }
    }

    // Verify linear scaling (within tolerance)
    const baselineAvg = results[10].avgTime
    const highLoadAvg = results[200].avgTime

    expect(highLoadAvg).toBeLessThan(baselineAvg * 2) // Should not degrade more than 2x
  })
})

Stress Testing

Test service limits:

describe('Stress Tests', () => {
  it('should handle maximum input size', async () => {
    const maxSize = 100000 // 100k characters
    const largeContent = 'a'.repeat(maxSize)

    const result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: { emailContent: largeContent },
    })

    expect(result.status).toBe('completed')
    expect(result.summary).toBeDefined()
  })

  it('should reject over-limit inputs', async () => {
    const overLimit = 200000 // Exceeds max
    const tooLarge = 'a'.repeat(overLimit)

    await expect(
      $.ServiceRequest.execute({
        serviceId: service.id,
        inputs: { emailContent: tooLarge },
      })
    ).rejects.toThrow('Input exceeds maximum size')
  })

  it('should handle timeout scenarios', async () => {
    // Mock a slow service
    vi.fn().mockImplementation(() => {
      return new Promise((resolve) => {
        setTimeout(resolve, 120000) // 2 minutes
      })
    })

    const result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: { emailContent: 'Test' },
    })

    expect(result.status).toBe('timeout')
    expect(result.error).toContain('timeout')
  })

  it('should recover from failures', async () => {
    // Simulate service failure
    await $.Service.disable({ serviceId: service.id })

    // Attempt execution
    let result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: { emailContent: 'Test' },
    })

    expect(result.status).toBe('failed')

    // Re-enable service
    await $.Service.enable({ serviceId: service.id })

    // Retry should succeed
    result = await $.ServiceRequest.execute({
      serviceId: service.id,
      inputs: { emailContent: 'Test' },
    })

    expect(result.status).toBe('completed')
  })
})

Validation Strategies

Input Validation

Comprehensive input validation:

class InputValidator {
  async validate(service: any, inputs: any) {
    const errors: string[] = []

    // Required fields
    for (const field of service.input.required) {
      if (inputs[field] === undefined || inputs[field] === null) {
        errors.push(`Missing required field: ${field}`)
      }
    }

    // Type validation
    for (const [field, value] of Object.entries(inputs)) {
      const schema = service.input.schema[field]
      if (!schema) continue

      const typeError = this.validateType(field, value, schema)
      if (typeError) {
        errors.push(typeError)
      }

      const constraintError = this.validateConstraints(field, value, schema)
      if (constraintError) {
        errors.push(constraintError)
      }
    }

    // Cross-field validation
    if (service.input.validation?.rules) {
      for (const rule of service.input.validation.rules) {
        const ruleError = this.validateRule(rule, inputs)
        if (ruleError) {
          errors.push(ruleError)
        }
      }
    }

    return {
      valid: errors.length === 0,
      errors,
    }
  }

  private validateType(field: string, value: any, schema: any): string | null {
    const actualType = Array.isArray(value) ? 'array' : typeof value
    if (actualType !== schema.type) {
      return `Invalid type for ${field}: expected ${schema.type}, got ${actualType}`
    }
    return null
  }

  private validateConstraints(field: string, value: any, schema: any): string | null {
    // String constraints
    if (schema.type === 'string') {
      if (schema.minLength && value.length < schema.minLength) {
        return `${field} must be at least ${schema.minLength} characters`
      }
      if (schema.maxLength && value.length > schema.maxLength) {
        return `${field} must be at most ${schema.maxLength} characters`
      }
      if (schema.pattern && !new RegExp(schema.pattern).test(value)) {
        return `${field} does not match required pattern`
      }
      if (schema.enum && !schema.enum.includes(value)) {
        return `${field} must be one of: ${schema.enum.join(', ')}`
      }
    }

    // Number constraints
    if (schema.type === 'number') {
      if (schema.min !== undefined && value < schema.min) {
        return `${field} must be at least ${schema.min}`
      }
      if (schema.max !== undefined && value > schema.max) {
        return `${field} must be at most ${schema.max}`
      }
    }

    // Array constraints
    if (schema.type === 'array') {
      if (schema.minItems && value.length < schema.minItems) {
        return `${field} must have at least ${schema.minItems} items`
      }
      if (schema.maxItems && value.length > schema.maxItems) {
        return `${field} must have at most ${schema.maxItems} items`
      }
    }

    return null
  }

  private validateRule(rule: any, inputs: any): string | null {
    // Conditional requirements
    if (rule.condition && rule.requires) {
      // Evaluate condition
      const conditionMet = this.evaluateCondition(rule.condition, inputs)
      if (conditionMet) {
        // Check required fields
        for (const field of rule.requires) {
          if (!inputs[field]) {
            return rule.message || `${field} is required when ${rule.condition}`
          }
        }
      }
    }

    // Custom validator
    if (rule.validator) {
      const valid = rule.validator(inputs)
      if (!valid) {
        return rule.message || 'Validation failed'
      }
    }

    return null
  }

  private evaluateCondition(condition: string, inputs: any): boolean {
    // Simple condition evaluation
    // In production, use a proper expression evaluator
    try {
      return new Function('inputs', `return ${condition}`)(inputs)
    } catch {
      return false
    }
  }
}

// Tests for validator
describe('InputValidator', () => {
  const validator = new InputValidator()

  it('should validate required fields', async () => {
    const service = {
      input: {
        required: ['email', 'message'],
        schema: {},
      },
    }

    const result = await validator.validate(service, { email: '[email protected]' })

    expect(result.valid).toBe(false)
    expect(result.errors).toContain('Missing required field: message')
  })

  it('should validate types', async () => {
    const service = {
      input: {
        required: ['count'],
        schema: {
          count: { type: 'number' },
        },
      },
    }

    const result = await validator.validate(service, { count: 'invalid' })

    expect(result.valid).toBe(false)
    expect(result.errors).toContain('Invalid type for count: expected number, got string')
  })

  it('should validate constraints', async () => {
    const service = {
      input: {
        required: ['password'],
        schema: {
          password: {
            type: 'string',
            minLength: 8,
            maxLength: 32,
          },
        },
      },
    }

    const result = await validator.validate(service, { password: 'short' })

    expect(result.valid).toBe(false)
    expect(result.errors).toContain('password must be at least 8 characters')
  })
})

Output Validation

Validate service outputs:

class OutputValidator {
  async validate(service: any, outputs: any) {
    const errors: string[] = []

    // Required output fields
    const requiredFields = Object.keys(service.output.schema)
    for (const field of requiredFields) {
      if (outputs[field] === undefined) {
        errors.push(`Missing required output: ${field}`)
      }
    }

    // Type and constraint validation
    for (const [field, value] of Object.entries(outputs)) {
      const schema = service.output.schema[field]
      if (!schema) continue

      const typeError = this.validateOutputType(field, value, schema)
      if (typeError) {
        errors.push(typeError)
      }

      const constraintError = this.validateOutputConstraints(field, value, schema)
      if (constraintError) {
        errors.push(constraintError)
      }
    }

    return {
      valid: errors.length === 0,
      errors,
    }
  }

  private validateOutputType(field: string, value: any, schema: any): string | null {
    const actualType = Array.isArray(value) ? 'array' : typeof value
    if (actualType !== schema.type) {
      return `Invalid output type for ${field}: expected ${schema.type}, got ${actualType}`
    }
    return null
  }

  private validateOutputConstraints(field: string, value: any, schema: any): string | null {
    if (schema.type === 'number') {
      if (schema.min !== undefined && value < schema.min) {
        return `${field} is below minimum: ${value} < ${schema.min}`
      }
      if (schema.max !== undefined && value > schema.max) {
        return `${field} exceeds maximum: ${value} > ${schema.max}`
      }
    }

    if (schema.type === 'string') {
      if (schema.minLength && value.length < schema.minLength) {
        return `${field} is too short: ${value.length} < ${schema.minLength}`
      }
      if (schema.maxLength && value.length > schema.maxLength) {
        return `${field} is too long: ${value.length} > ${schema.maxLength}`
      }
    }

    return null
  }
}

Test Automation

Continuous Integration Tests

Automate testing in CI/CD:

// vitest.config.ts
import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    // Run tests in parallel
    pool: 'threads',
    poolOptions: {
      threads: {
        singleThread: false,
      },
    },

    // Coverage configuration
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      exclude: ['node_modules/', 'dist/', '**/*.test.ts'],
      thresholds: {
        lines: 80,
        functions: 80,
        branches: 80,
        statements: 80,
      },
    },

    // Test timeouts
    testTimeout: 30000,
    hookTimeout: 30000,

    // Setup files
    setupFiles: ['./tests/setup.ts'],

    // Global test utilities
    globals: true,
  },
})
// tests/setup.ts
import { beforeAll, afterAll, afterEach } from 'vitest'
import { db } from 'sdk.do'

// Setup test database
beforeAll(async () => {
  await db.connect(process.env.TEST_DATABASE_URL)
  await db.migrate()
})

// Cleanup after tests
afterEach(async () => {
  await db.truncate()
})

// Teardown
afterAll(async () => {
  await db.disconnect()
})

Automated Quality Checks

Run automated quality assessments:

class QualityChecker {
  async checkServiceQuality(serviceId: string, sampleSize: number = 100) {
    const results = []

    // Run sample executions
    for (let i = 0; i < sampleSize; i++) {
      const result = await this.runSampleExecution(serviceId)
      results.push(result)
    }

    // Calculate metrics
    const metrics = this.calculateMetrics(results)

    // Generate report
    return {
      serviceId,
      sampleSize,
      metrics,
      passed: this.meetsThresholds(metrics),
      timestamp: new Date(),
    }
  }

  private async runSampleExecution(serviceId: string) {
    const startTime = Date.now()

    try {
      const result = await $.ServiceRequest.execute({
        serviceId,
        inputs: this.generateTestInput(serviceId),
      })

      return {
        success: true,
        duration: Date.now() - startTime,
        outputs: result.outputs,
      }
    } catch (error) {
      return {
        success: false,
        duration: Date.now() - startTime,
        error: error.message,
      }
    }
  }

  private calculateMetrics(results: any[]) {
    const successful = results.filter((r) => r.success)
    const failed = results.filter((r) => !r.success)

    const durations = successful.map((r) => r.duration)
    durations.sort((a, b) => a - b)

    return {
      successRate: successful.length / results.length,
      failureRate: failed.length / results.length,
      avgDuration: durations.reduce((a, b) => a + b, 0) / durations.length,
      p50Duration: durations[Math.floor(durations.length * 0.5)],
      p95Duration: durations[Math.floor(durations.length * 0.95)],
      p99Duration: durations[Math.floor(durations.length * 0.99)],
    }
  }

  private meetsThresholds(metrics: any): boolean {
    return (
      metrics.successRate >= 0.99 && // 99% success rate
      metrics.avgDuration <= 5000 && // 5 second average
      metrics.p95Duration <= 10000 // 10 second p95
    )
  }

  private generateTestInput(serviceId: string): any {
    // Generate appropriate test inputs based on service
    // This would be customized per service type
    return {
      emailContent: 'Sample test email for quality checking',
    }
  }
}

// Run quality checks periodically
on($.Schedule.hourly, async () => {
  const checker = new QualityChecker()
  const services = await db.list($.Service, {
    where: { status: 'active' },
  })

  for (const service of services) {
    const report = await checker.checkServiceQuality(service.id)

    if (!report.passed) {
      await send($.Alert.create, {
        type: 'quality-degradation',
        serviceId: service.id,
        metrics: report.metrics,
      })
    }
  }
})

Quality Metrics

Service Quality Score

Calculate comprehensive quality scores:

class QualityMetrics {
  async calculateQualityScore(serviceId: string, period: { start: Date; end: Date }) {
    const executions = await db.list($.ServiceExecution, {
      where: {
        serviceId,
        timestamp: {
          gte: period.start,
          lte: period.end,
        },
      },
    })

    // Calculate component scores
    const reliability = this.calculateReliability(executions)
    const performance = this.calculatePerformance(executions)
    const accuracy = this.calculateAccuracy(executions)
    const customerSatisfaction = await this.calculateSatisfaction(serviceId, period)

    // Weighted overall score
    const overallScore = reliability * 0.3 + performance * 0.3 + accuracy * 0.25 + customerSatisfaction * 0.15

    return {
      overall: overallScore,
      components: {
        reliability,
        performance,
        accuracy,
        customerSatisfaction,
      },
      period,
      executionCount: executions.length,
    }
  }

  private calculateReliability(executions: any[]): number {
    const successful = executions.filter((e) => e.status === 'completed')
    return successful.length / executions.length
  }

  private calculatePerformance(executions: any[]): number {
    const successful = executions.filter((e) => e.status === 'completed')
    const durations = successful.map((e) => e.duration)

    const avgDuration = durations.reduce((a, b) => a + b, 0) / durations.length
    const targetDuration = 5000 // 5 seconds

    // Score based on how close to target
    return Math.max(0, 1 - avgDuration / (targetDuration * 2))
  }

  private calculateAccuracy(executions: any[]): number {
    const withQuality = executions.filter((e) => e.qualityScore !== undefined)
    if (withQuality.length === 0) return 1.0

    const avgQuality = withQuality.reduce((a, b) => a + b.qualityScore, 0) / withQuality.length

    return avgQuality
  }

  private async calculateSatisfaction(serviceId: string, period: { start: Date; end: Date }): Promise<number> {
    const feedback = await db.list($.CustomerFeedback, {
      where: {
        serviceId,
        timestamp: {
          gte: period.start,
          lte: period.end,
        },
      },
    })

    if (feedback.length === 0) return 1.0

    const avgRating = feedback.reduce((a, b) => a + b.rating, 0) / feedback.length

    return avgRating / 5 // Normalize to 0-1
  }
}

// Track quality over time
on($.Schedule.daily, async () => {
  const metrics = new QualityMetrics()
  const services = await db.list($.Service, { where: { status: 'active' } })

  for (const service of services) {
    const score = await metrics.calculateQualityScore(service.id, {
      start: new Date(Date.now() - 24 * 60 * 60 * 1000), // Last 24 hours
      end: new Date(),
    })

    // Store quality score
    await db.create($.QualityReport, {
      serviceId: service.id,
      score: score.overall,
      components: score.components,
      timestamp: new Date(),
    })

    // Alert if quality drops
    if (score.overall < 0.9) {
      await send($.Alert.create, {
        type: 'quality-drop',
        serviceId: service.id,
        score: score.overall,
      })
    }
  }
})

Best Practices

1. Test Early and Often

Write tests before or alongside implementation:

// ✅ Good: Write test first
it('should summarize email', async () => {
  // Test implementation
})

// Then implement the feature

2. Test Real Scenarios

Use realistic test data:

// ✅ Good: Real-world data
const testEmail = `
  From: [email protected]
  Subject: Q4 Planning Meeting

  Hi team, let's discuss Q4 goals...
`

// ❌ Bad: Artificial data
const testEmail = 'test'

3. Comprehensive Coverage

Test all code paths:

// Test success cases
// Test error cases
// Test edge cases
// Test boundary conditions

4. Isolate Tests

Each test should be independent:

// ✅ Good: Isolated test
beforeEach(() => {
  // Clean setup for each test
})

// ❌ Bad: Tests depend on each other

5. Monitor Quality Continuously

Track quality metrics over time:

// Regular quality checks
// Automated alerts
// Performance monitoring
// Customer feedback tracking

Next Steps