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:
- Customer Trust - Reliable services build confidence and loyalty
- Revenue Protection - Quality issues directly impact revenue
- Cost Reduction - Catch bugs early before they reach customers
- Competitive Advantage - High-quality services win and retain customers
- Regulatory Compliance - Meet quality standards and SLAs
- 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 feature2. 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 conditions4. Isolate Tests
Each test should be independent:
// ✅ Good: Isolated test
beforeEach(() => {
// Clean setup for each test
})
// ❌ Bad: Tests depend on each other5. Monitor Quality Continuously
Track quality metrics over time:
// Regular quality checks
// Automated alerts
// Performance monitoring
// Customer feedback trackingNext Steps
- Implement Monitoring → - Track service performance
- Deploy Services → - Go to production
- Learn Best Practices → - Service optimization
- Explore Examples → - Real-world implementations